@@ -47,8 +47,10 @@ function displaySecureMenyItems() {
47
47
hideAElement ( "show-login-form-btn" ) ;
48
48
}
49
49
50
+ /**
51
+ * @returns {string } containing UUID v4
52
+ */
50
53
const generateUUID = ( ) => {
51
- //UUID v4
52
54
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' . replace ( / [ x y ] / g, function ( c ) {
53
55
var r = Math . random ( ) * 16 | 0 , v = c === 'x' ? r : ( r & 0x3 | 0x8 ) ;
54
56
return v . toString ( 16 ) ;
@@ -628,6 +630,7 @@ function buildDocumentsTableWithoutContent() {
628
630
const headerRow = document . createElement ( 'tr' ) ;
629
631
630
632
const headers = [
633
+ { title : 'Action' , abbr : null } ,
631
634
{ title : 'Document ID' , abbr : null } ,
632
635
{ title : 'Collect ID' , abbr : null } ,
633
636
{ title : 'Document type' , abbr : null } ,
@@ -636,7 +639,7 @@ function buildDocumentsTableWithoutContent() {
636
639
{ title : 'Family name' , abbr : null } ,
637
640
{ title : 'Given name' , abbr : null } ,
638
641
{ title : 'Birthdate' , abbr : null } ,
639
- { title : 'Action ' , abbr : null }
642
+ { title : 'QR credential offer url ' , abbr : null }
640
643
] ;
641
644
642
645
headers . forEach ( header => {
@@ -938,6 +941,46 @@ function displayDeleteDocumentInModal(rowData) {
938
941
function buildDocumentTableRow ( doc ) {
939
942
const row = document . createElement ( 'tr' ) ;
940
943
944
+ //------select start-------------------
945
+ const tdActions = document . createElement ( 'td' ) ;
946
+ const divSelect = document . createElement ( 'div' ) ;
947
+ divSelect . className = 'select' ; // is-small';
948
+
949
+ const select = document . createElement ( 'select' ) ;
950
+ select . id = generateUUID ( ) ;
951
+
952
+ const optionDefault = document . createElement ( 'option' ) ;
953
+ optionDefault . value = '' ;
954
+ optionDefault . textContent = 'select...' ;
955
+ select . appendChild ( optionDefault ) ;
956
+
957
+ const optionViewDocument = document . createElement ( 'option' ) ;
958
+ optionViewDocument . value = 'VIEW_COMPLETE_DOCUMENT' ;
959
+ optionViewDocument . textContent = 'View complete document' ;
960
+ select . appendChild ( optionViewDocument ) ;
961
+
962
+ const optionViewQR = document . createElement ( 'option' ) ;
963
+ optionViewQR . value = 'VIEW_QR' ;
964
+ optionViewQR . textContent = 'View QR' ;
965
+ select . appendChild ( optionViewQR ) ;
966
+
967
+ const optionCreateCredential = document . createElement ( 'option' ) ;
968
+ optionCreateCredential . value = 'CREATE_CREDENTIAL' ;
969
+ optionCreateCredential . textContent = 'Create credential' ;
970
+ select . appendChild ( optionCreateCredential ) ;
971
+
972
+ select . appendChild ( document . createElement ( 'hr' ) ) ;
973
+
974
+ const optionDeleteDocument = document . createElement ( 'option' ) ;
975
+ optionDeleteDocument . value = 'DELETE_DOCUMENT' ;
976
+ optionDeleteDocument . textContent = 'Delete document' ;
977
+ select . appendChild ( optionDeleteDocument ) ;
978
+
979
+ divSelect . appendChild ( select ) ;
980
+ tdActions . appendChild ( divSelect ) ;
981
+ row . appendChild ( tdActions ) ;
982
+ //-------------------------
983
+
941
984
const tdDocumentId = document . createElement ( 'td' ) ;
942
985
const documentId = doc . meta ?. document_id || "" ;
943
986
tdDocumentId . textContent = documentId ;
@@ -990,39 +1033,10 @@ function buildDocumentTableRow(doc) {
990
1033
tdBirthDate . innerHTML = bdStringBuilder . join ( "<br>" ) ;
991
1034
row . appendChild ( tdBirthDate ) ;
992
1035
993
- const tdActions = document . createElement ( 'td' ) ;
994
- const divSelect = document . createElement ( 'div' ) ;
995
- divSelect . className = 'select' ; // is-small';
996
-
997
- const select = document . createElement ( 'select' ) ;
998
- select . id = generateUUID ( ) ;
999
-
1000
- const optionDefault = document . createElement ( 'option' ) ;
1001
- optionDefault . value = '' ;
1002
- optionDefault . textContent = 'select...' ;
1003
- select . appendChild ( optionDefault ) ;
1004
-
1005
- const optionViewDocument = document . createElement ( 'option' ) ;
1006
- optionViewDocument . value = 'VIEW_COMPLETE_DOCUMENT' ;
1007
- optionViewDocument . textContent = 'View complete document' ;
1008
- select . appendChild ( optionViewDocument ) ;
1009
-
1010
- const optionViewQR = document . createElement ( 'option' ) ;
1011
- optionViewQR . value = 'VIEW_QR' ;
1012
- optionViewQR . textContent = 'View QR' ;
1013
- select . appendChild ( optionViewQR ) ;
1014
-
1015
- const optionCreateCredential = document . createElement ( 'option' ) ;
1016
- optionCreateCredential . value = 'CREATE_CREDENTIAL' ;
1017
- optionCreateCredential . textContent = 'Create credential' ;
1018
- select . appendChild ( optionCreateCredential ) ;
1019
-
1020
- select . appendChild ( document . createElement ( 'hr' ) ) ;
1021
-
1022
- const optionDeleteDocument = document . createElement ( 'option' ) ;
1023
- optionDeleteDocument . value = 'DELETE_DOCUMENT' ;
1024
- optionDeleteDocument . textContent = 'Delete document' ;
1025
- select . appendChild ( optionDeleteDocument ) ;
1036
+ const tdQRCredentialOfferUrl = document . createElement ( 'td' ) ;
1037
+ const credentialOfferUrl = doc . qr ?. credential_offer || "" ;
1038
+ tdQRCredentialOfferUrl . textContent = credentialOfferUrl ;
1039
+ row . appendChild ( tdQRCredentialOfferUrl ) ;
1026
1040
1027
1041
const rowData = {
1028
1042
documentId : documentId ,
@@ -1054,31 +1068,62 @@ function buildDocumentTableRow(doc) {
1054
1068
this . value = '' ;
1055
1069
} ) ;
1056
1070
1057
- divSelect . appendChild ( select ) ;
1058
- tdActions . appendChild ( divSelect ) ;
1059
- row . appendChild ( tdActions ) ;
1060
-
1061
1071
return row ;
1062
1072
}
1063
1073
1064
1074
function displayDocumentsTable ( data , divResultContainer ) {
1065
1075
divResultContainer . appendChild ( document . createElement ( "br" ) ) ;
1066
1076
divResultContainer . appendChild ( document . createElement ( "br" ) ) ;
1067
1077
1068
- if ( Array . isArray ( data . documents ) && data . documents . length === 0 ) {
1078
+ if ( data . documents == null || ( Array . isArray ( data . documents ) && data . documents . length === 0 ) ) {
1069
1079
displayInfoTag ( "No matching documents found" , divResultContainer ) ;
1070
1080
return ;
1071
1081
} else if ( data . has_more_results ) {
1072
1082
displayWarningTag ( "There are more search results available. Narrow down your search criteria to view them all." , divResultContainer ) ;
1073
1083
}
1074
1084
1085
+ const exportToCsvButton = document . createElement ( "button" ) ;
1086
+ exportToCsvButton . id = generateUUID ( ) ;
1087
+ exportToCsvButton . classList . add ( "button" ) ;
1088
+ exportToCsvButton . textContent = "Export result to csv file" ;
1089
+ exportToCsvButton . disabled = false ;
1090
+ divResultContainer . appendChild ( exportToCsvButton ) ;
1091
+
1075
1092
const tableBasis = buildDocumentsTableWithoutContent ( ) ;
1093
+ exportToCsvButton . addEventListener ( 'click' , ( ) => exportTableToCSV ( tableBasis . table ) ) ;
1076
1094
divResultContainer . appendChild ( tableBasis . table ) ;
1077
1095
data . documents . forEach ( doc => {
1078
1096
tableBasis . tbody . appendChild ( buildDocumentTableRow ( doc ) ) ;
1079
1097
} ) ;
1080
1098
}
1081
1099
1100
+ function exportTableToCSV ( table ) {
1101
+ const rows = table . querySelectorAll ( 'tr' ) ;
1102
+ let csvContent = "" ;
1103
+
1104
+
1105
+ rows . forEach ( row => {
1106
+ const cells = row . querySelectorAll ( 'th, td' ) ;
1107
+ const rowContent = Array . from ( cells )
1108
+ . map ( cell => `"${ cell . innerText } "` ) // Wrap cell values in quotes to handle commas
1109
+ . join ( "," ) ; // Join cell values with a comma
1110
+ csvContent += rowContent + "\n" ;
1111
+ } ) ;
1112
+
1113
+
1114
+ const blob = new Blob ( [ csvContent ] , { type : 'text/csv' } ) ;
1115
+ const url = URL . createObjectURL ( blob ) ;
1116
+
1117
+ const a = document . createElement ( 'a' ) ;
1118
+ a . href = url ;
1119
+ a . download = 'search_result.csv' ;
1120
+ document . body . appendChild ( a ) ;
1121
+ a . click ( ) ;
1122
+
1123
+ document . body . removeChild ( a ) ;
1124
+ URL . revokeObjectURL ( url ) ;
1125
+ }
1126
+
1082
1127
const addSearchDocumentsFormArticleToContainer = ( ) => {
1083
1128
const buildFormElements = ( ) => {
1084
1129
@@ -1133,7 +1178,7 @@ const addSearchDocumentsFormArticleToContainer = () => {
1133
1178
1134
1179
limit : parseInt ( limitInput . value , 10 ) ,
1135
1180
1136
- fields : [ "meta.document_id" , "meta.authentic_source" , "meta.document_type" , "meta.collect.id" , "identities" ] ,
1181
+ fields : [ "meta.document_id" , "meta.authentic_source" , "meta.document_type" , "meta.collect.id" , "identities" , "qr.credential_offer" ] ,
1137
1182
} ;
1138
1183
1139
1184
if ( checkboxShowCompleteDocsAsRawJson . checked ) {
@@ -1195,7 +1240,6 @@ const addSearchDocumentsFormArticleToContainer = () => {
1195
1240
document . getElementById ( articleIdBasis . articleID ) . querySelector ( 'input' ) . focus ( ) ;
1196
1241
} ;
1197
1242
1198
-
1199
1243
const addUploadDocumentsUsingCsvFormArticleToContainer = ( ) => {
1200
1244
const buildFormElements = ( ) => {
1201
1245
const fileDiv = document . createElement ( 'div' ) ;
@@ -1208,7 +1252,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1208
1252
input . className = 'file-input' ;
1209
1253
input . type = 'file' ;
1210
1254
input . name = 'resume' ;
1211
- //input.id = 'csvFile';
1212
1255
input . id = generateUUID ( ) ;
1213
1256
input . accept = '.csv' ;
1214
1257
@@ -1230,7 +1273,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1230
1273
1231
1274
const fileName = document . createElement ( 'span' ) ;
1232
1275
fileName . className = 'file-name' ;
1233
- //fileName.id = 'fileName';
1234
1276
fileName . id = generateUUID ( ) ;
1235
1277
fileName . textContent = 'No file selected' ;
1236
1278
@@ -1318,44 +1360,40 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1318
1360
articleContainer . prepend ( articleDiv ) ;
1319
1361
1320
1362
function createUploadRequestFrom ( row ) {
1363
+ const generatedDocumentId = generateUUID ( ) ;
1321
1364
return {
1322
- //TODO remove default values (or maybe some needs to be hardcoded?)
1323
1365
meta : {
1324
1366
authentic_source : row . authentic_source ,
1325
1367
document_version : row . document_version || "1.0.0" ,
1326
- document_type : row . document_type || "EHIC" , //ta in via dropdown alt. analys av csv
1327
- document_id : row . document_id || generateUUID ( ) ,
1368
+ document_type : row . document_type || "EHIC" ,
1369
+ document_id : row . document_id || generatedDocumentId ,
1328
1370
real_data : row . real_data === "true" ,
1329
1371
credential_valid_from : row . credential_valid_from || null ,
1330
1372
credential_valid_to : row . credential_valid_to || null ,
1331
1373
document_data_validation : row . document_data_validation || null ,
1332
- " collect" : {
1333
- id : generateUUID ( ) ,
1334
- valid_until : 909567558
1374
+ collect : {
1375
+ id : row . collect_id || generatedDocumentId ,
1376
+ valid_until : convertToUnixTimestampOrNull ( row . ehic_expiry_date ) ,
1335
1377
} ,
1336
1378
} ,
1337
1379
identities : [
1338
1380
{
1339
- authentic_source_person_id : row . pid_id || generateUUID ( ) ,
1381
+ authentic_source_person_id : prefixWithAuthenticSourcePersonIdOrNull ( row . pid_id ) ,
1340
1382
schema : {
1341
1383
name : row . pid_issuing_country ,
1342
1384
version : row . schema_version || "1.0.0" ,
1343
1385
} ,
1344
1386
family_name : row . family_name ,
1345
1387
given_name : row . given_name ,
1346
- birth_date : "1973-05-02" , //TODO: row.birth_date -> hantera felaktigt format i csv YYYY/MM/DD
1347
- gender : row . gender || null ,
1348
- nationality : row . nationality || null ,
1349
- resident_address : row . resident_address || null ,
1350
- resident_country : row . resident_country || null ,
1388
+ birth_date : row . birth_date ,
1351
1389
} ,
1352
1390
] ,
1353
1391
document_display : null ,
1354
1392
document_data : {
1355
1393
subject : {
1356
1394
forename : row . given_name ,
1357
1395
family_name : row . family_name ,
1358
- date_of_birth : "1973-05-02" //TODO: row.birth_date -> hantera felaktigt format i csv YYYY/MM/DD
1396
+ date_of_birth : row . birth_date ,
1359
1397
} ,
1360
1398
social_security_pin : row . social_security_pin ,
1361
1399
period_entitlement : {
@@ -1366,7 +1404,7 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1366
1404
competent_institution : {
1367
1405
institution_id : row . ehic_institution_id ,
1368
1406
institution_name : row . ehic_institution_name ,
1369
- institution_country : row . ehic_institution_country_code_
1407
+ institution_country : row . ehic_institution_country_code ,
1370
1408
}
1371
1409
} ,
1372
1410
document_data_version : row . document_data_version || "1.0.0" ,
@@ -1375,7 +1413,6 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1375
1413
1376
1414
function displayCSV ( data , table ) {
1377
1415
const rows = data . split ( '\n' ) ;
1378
- //const table = document.getElementById('csvTable');
1379
1416
table . innerHTML = '' ; // Clear previous content
1380
1417
1381
1418
rows . forEach ( ( row , rowIndex ) => {
@@ -1390,6 +1427,10 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1390
1427
} ) ;
1391
1428
}
1392
1429
1430
+ function prefixWithAuthenticSourcePersonIdOrNull ( pid_id ) {
1431
+ return pid_id ? `authentic_source_person_id_${ pid_id } ` : null ;
1432
+ }
1433
+
1393
1434
function csvToJson ( csv ) {
1394
1435
const lines = csv . split ( '\n' ) ;
1395
1436
const headers = lines [ 0 ] . split ( ',' ) . map ( ( header ) => header . trim ( ) ) ;
@@ -1408,6 +1449,15 @@ const addUploadDocumentsUsingCsvFormArticleToContainer = () => {
1408
1449
}
1409
1450
} ;
1410
1451
1452
+ /**
1453
+ * @param dateString YYYY-MM-DD
1454
+ */
1455
+ function convertToUnixTimestampOrNull ( dateString ) {
1456
+ if ( dateString == null ) return null ;
1457
+ const date = new Date ( dateString ) ;
1458
+ return Math . floor ( date . getTime ( ) / 1000 ) ;
1459
+ }
1460
+
1411
1461
async function fetchData ( url , options ) {
1412
1462
const response = await fetch ( url , options ) ;
1413
1463
if ( ! response . ok ) {
0 commit comments