added i18next
parent
2ce8b86b5d
commit
88acf8c6ba
|
@ -14,8 +14,12 @@
|
|||
"@testing-library/user-event": "^13.5.0",
|
||||
"antd": "^5.4.2",
|
||||
"buffer": "^6.0.3",
|
||||
"i18next": "^23.2.3",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.0.1",
|
||||
"react-qr-scanner": "^1.0.0-alpha.11",
|
||||
"react-router-dom": "^6.10.0",
|
||||
"react-scripts": "5.0.1",
|
||||
|
@ -1860,9 +1864,9 @@
|
|||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
|
||||
"integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz",
|
||||
"integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
|
@ -6413,6 +6417,14 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz",
|
||||
"integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.11"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -9202,6 +9214,14 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-webpack-plugin": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
|
||||
|
@ -9336,6 +9356,44 @@
|
|||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "23.2.3",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.2.3.tgz",
|
||||
"integrity": "sha512-5spO7L0rNmW0jFuNhz+gfirlFt1anle4mTy4+gFkgsH0+T3R5++4oncBrzeKa7v8pweRyGBoGmOpboqlxovg6A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com/i18next.html"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-browser-languagedetector": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz",
|
||||
"integrity": "sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.19.4"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-http-backend": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.2.1.tgz",
|
||||
"integrity": "sha512-ZXIdn/8NJIBJ0X4hzXfc3STYxKrCKh1fYjji9HPyIpEJfvTvy8/ZlTl8RuTizzCPj2ZcWrfaecyOMKs6bQ7u5A==",
|
||||
"dependencies": {
|
||||
"cross-fetch": "3.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
|
@ -12650,6 +12708,44 @@
|
|||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
|
@ -15435,6 +15531,27 @@
|
|||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
|
||||
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.0.1.tgz",
|
||||
"integrity": "sha512-gMO6N2GfSfuH7xlHSsZ/mZf+Py9bLm/+EDKIn5fNTuDTjcCcwmMU5UEuGCDk5mdfivbo7ySyYXBN7B9tbGUxiA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.22.5",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 23.2.3",
|
||||
"react": ">= 16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
@ -17683,6 +17800,14 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-hr-time": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
"@testing-library/user-event": "^13.5.0",
|
||||
"antd": "^5.4.2",
|
||||
"buffer": "^6.0.3",
|
||||
"i18next": "^23.2.3",
|
||||
"i18next-browser-languagedetector": "^7.1.0",
|
||||
"i18next-http-backend": "^2.2.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.0.1",
|
||||
"react-qr-scanner": "^1.0.0-alpha.11",
|
||||
"react-router-dom": "^6.10.0",
|
||||
"react-scripts": "5.0.1",
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"contactAdmin": "Bitte kontaktieren Sie einen Administrator",
|
||||
"buttonCancel": "Abbrechen",
|
||||
"buttonClose": "Schließen",
|
||||
"buttonSave": "Speichern",
|
||||
"sideMenu.dashboard": "Dashboard",
|
||||
"sideMenu.groupTasks": "Gruppenaufgaben",
|
||||
"sideMenu.groupTasks.overview": "Übersicht",
|
||||
"sideMenu.groupTasks.history": "Verlauf",
|
||||
"sideMenu.adminArea": "Adminbereich",
|
||||
"sideMenu.adminArea.roles": "Rollen",
|
||||
"sideMenu.adminArea.logs": "Logs",
|
||||
"sideMenu.adminArea.noScannerSelected": "Kein Scanner ausgewählt",
|
||||
"sideMenu.usersCount": "Benutzer online",
|
||||
"sideMenu.usersCount.multiple": "Benutzer online",
|
||||
"sideMenu.logout": "Abmelden",
|
||||
"groupTasks.categoryGroups.length0": "Keine Gruppenaufgaben gefunden",
|
||||
"groupTasks.categoryGroups.assignedToNoTask.title": "Sie wurden keiner Gruppenaufgabe zugewiesen",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.message": "Globale Eingaben können nicht leer sein",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.description": "Bitte füllen Sie alle globalen Eingaben aus",
|
||||
"groupTasks.groupTypeSelectionModal.title": "Wählen Sie einen Gruppentyp",
|
||||
"groupTasks.groupTypeSelectionModal.button.startTask": "Aufgabe starten",
|
||||
"groupTasks.groupTypeSelectionModal.select.placeholder": "Wählen Sie einen Gruppentyp",
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.label": "Beschreibung",
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.tooltip.title": "Diese Beschreibung hilft, im Nachhinein zu verstehen, worum es bei dieser Aufgabe ging",
|
||||
"groupTasks.tag.global": "Global",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message": "Typ {{globalInputType}} nicht implementiert",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description": "Wurde festgelegt in: {{globalInputDisplayName}}",
|
||||
"groupTasks.groupTypeSelectionModal.h3": "Füllen Sie die globalen Werte aus",
|
||||
"groupTasks.groupTasksViewModal.groupTaskNotFound": "Gruppenaufgabe nicht gefunden",
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message": "Eingaben können nicht leer sein",
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description": "Bitte füllen Sie alle Felder aus",
|
||||
"groupTasks.groupTasksViewModal.button.tryAgain": "Erneut versuchen",
|
||||
"groupTasks.groupTasksViewModal.button.continue": "Weiter",
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedTaskInputs": "Spezifizierte Aufgaben-Eingaben",
|
||||
"groupTasks.groupTasksViewModal.startedAt": "Gestartet am",
|
||||
"groupTasks.groupTasksViewModal.endedAt": "Beendet am",
|
||||
"groupTasks.groupTasksViewModal.duration": "Laufzeit",
|
||||
"groupTasks.groupTasksViewModal.category": "Kategorie",
|
||||
"groupTasks.groupTasksViewModal.popover.details": "Einzelheiten",
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs": "Spezifizierte globale Eingaben",
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message": "Typ {{groupTaskParameterType}} nicht implementiert",
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description": "Wurde festgelegt in: {{groupTaskParameterDisplayName}}",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.successful": "Erfolgreich",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskIsRunning": "Aufgabe wird ausgeführt",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskCanceled": "Aufgabe abgebrochen",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskFailed": "Aufgabe fehlgeschlagen",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskInputRequired": "Eingabe erforderlich",
|
||||
"groupTasks.groupTasksTableList.column.creator": "Ersteller",
|
||||
"groupTasks.groupTasksTableList.column.groupName": "Gruppenname",
|
||||
"groupTasks.groupTasksTableList.column.description": "Beschreibung",
|
||||
"groupTasks.groupTasksTableList.column.step": "Schritt",
|
||||
"groupTasks.groupTasksTableList.column.status": "Status",
|
||||
"groupTasks.groupTasksTableList.column.startedAt": "Gestartet am",
|
||||
"groupTasks.groupTasksTableList.column.endedAt": "Beendet am",
|
||||
"groupTasks.groupTasksTableList.column.duration": "Laufzeit",
|
||||
"groupTasks.groupTasksTableList.column.action": "Maßnahme",
|
||||
"groupTasks.groupTasksTableList.column.action.view": "Ansehen",
|
||||
"groupTasks.groupTasksTableList.statusBadge.finished": "Abgeschlossen",
|
||||
"groupTasks.groupTasksTableList.statusBadge.running": "Laufend",
|
||||
"groupTasks.groupTasksTableList.statusBadge.canceled": "Abgebrochen",
|
||||
"groupTasks.groupTasksTableList.statusBadge.failed": "Fehlgeschlagen",
|
||||
"groupTasks.groupTasksTableList.statusBadge.inputRequired": "Eingabe erforderlich",
|
||||
"groupTasks.groupTasksTableList.button.newTask": "Neue Aufgabe",
|
||||
"groupTasks.groupTasksTableList.button.reload": "Neu laden",
|
||||
"groupTasks.groupTasksTableList.popover.title": "Sind Sie sicher, dass Sie die Gruppenkonfigurationen neu laden wollen?",
|
||||
"groupTasks.groupTasksTableList.popover.buttonOk": "Ja",
|
||||
"logCard.popover.groupTaskId.title": "Gruppenaufgabe",
|
||||
"logCard.popover.groupTaskStep.title": "Gruppenaufgabe Schritt",
|
||||
"logCard.popover.role.title": "Rolle",
|
||||
"logCard.card.checkbox.info": "INFO",
|
||||
"logCard.card.checkbox.error": "FEHLER",
|
||||
"logCard.tooltip.previous": "Vorige",
|
||||
"logCard.tooltip.next": "Nächste",
|
||||
"logCard.tooltip.reload": "Neu laden",
|
||||
"pageNotFound.subTitle": "Die Seite, die Sie besucht haben, existiert leider nicht.",
|
||||
"pageNotFound.buttonBackHome": "Zurück zur Startseite",
|
||||
"allUsers.column.avatar": "Avatar",
|
||||
"allUsers.column.username": "Benutzername",
|
||||
"allUsers.column.role": "Rolle",
|
||||
"allUsers.column.connectionStatus": "Verbindungsstatus",
|
||||
"allUsers.column.lastOnline": "Zuletzt online",
|
||||
"allUsers.column.action": "Maßnahme",
|
||||
"allUsers.column.action.roleChange.popconfirm.title": "Rolle ändern in",
|
||||
"allUsers.column.action.roleChange.popconfirm.okText": "Ändern",
|
||||
"allUsers.column.action.changeRole": "Rolle ändern",
|
||||
"allUsers.column.action.delete.popconfirm.okText": "User löschen",
|
||||
"allUsers.column.action.delete.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer löschen wollen?",
|
||||
"allUsers.column.action.delete": "Löschen",
|
||||
"allUsers.column.action.deactivate.popconfirm.okText": "Benutzer deaktivieren",
|
||||
"allUsers.column.action.deactivate.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer deaktivieren wollen?",
|
||||
"allUsers.column.action.deactivate": "Deaktivieren",
|
||||
"allUsers.column.action.activate.popconfirm.okText": "Benutzer aktivieren",
|
||||
"allUsers.column.action.activate.popconfirm.title": "Sind Sie sicher, dass Sie den Benutzer aktivieren wollen?",
|
||||
"allUsers.column.action.activate": "Aktivieren",
|
||||
"allUsers.roleChangeError.notification.message": "Benutzerrolle konnte nicht geändert werden",
|
||||
"allUsers.roleChangeError.notification.description": "Die Rolle existiert nicht mehr",
|
||||
"allUsers.header.allUsers": "Alle Benutzer",
|
||||
"allUsers.button.createNewUser": "Neuen Benutzer anlegen",
|
||||
"allUsers.header.deactivatedUsers": "Deaktivierte Benutzer",
|
||||
"allUsers.createUserModal.title": "Einen neuen Benutzer anlegen",
|
||||
"allUsers.createUserModal.okText": "Benutzer anlegen",
|
||||
"allUsers.createUserModal.form.username": "Benutzername",
|
||||
"allUsers.createUserModal.form.email": "E-Mail",
|
||||
"allUsers.createUserModal.form.password": "Passwort",
|
||||
"allUsers.createUserModal.form.role": "Rolle",
|
||||
"allUsers.createUserModal.form.role.placeholder": "Wählen Sie eine Rolle",
|
||||
"adminArea.createNewRole.popconfirm.okText": "Erstellen",
|
||||
"adminArea.createNewRole.popconfirm.title": "Sind Sie sicher, dass Sie eine neue Rolle anlegen wollen?",
|
||||
"adminArea.createNewRole.button": "Neue Rolle erstellen",
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.message": "Der angezeigte Name muss größer sein als {{MIN_ROLE_DISPLAY_NAME}} sein",
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.description": "Bitte geben Sie einen längeren Anzeigenamen ein",
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.message": "Der Anzeigename muss kleiner sein als {{MAX_ROLE_DISPLAY_NAME}} sein",
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.description": "Bitte geben Sie einen kürzeren Anzeigenamen ein",
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.message": "Die Beschreibung muss kleiner sein als {{MAX_ROLE_DESCRIPTION}} sein",
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.description": "Bitte geben Sie eine kürzere Beschreibung ein",
|
||||
"adminArea.deleteRole.popconfirm.title": "Rolle löschen",
|
||||
"adminArea.deleteRole.popconfirm.description": "Sind Sie sicher, dass Sie diese Rolle löschen wollen?",
|
||||
"adminArea.deleteRole.tooltip.title": "Löschen",
|
||||
"adminArea.moveRoleUp.tooltip.title": "Rolle nach oben verschieben",
|
||||
"adminArea.moveRoleDown.tooltip.title": "Rolle nach unten verschieben",
|
||||
"adminArea.save.tooltip.title": "Speichern",
|
||||
"adminArea.close.tooltip.title": "Schließen",
|
||||
"adminArea.edit.tooltip.title": "Bearbeiten",
|
||||
"adminArea.masterRoleRightsMessage": "Rechte können nicht bearbeitet werden, da diese Rolle der Master ist und alle Rechte besitzt.",
|
||||
"userProfile.header.yourProfile": "Ihr Profil",
|
||||
"userProfile.column.userAgent": "User-Agent",
|
||||
"userProfile.column.connectionStatus": "Verbindungsstatus",
|
||||
"userProfile.column.lastUsed": "Zuletzt verwendet",
|
||||
"userProfile.column.expiresAt": "Läuft ab am",
|
||||
"userProfile.column.action": "Maßnahme",
|
||||
"userProfile.column.action.signOut": "Abmelden",
|
||||
"userProfile.changeAvatarError.notification.message": "Ihr Avatar konnte nicht geändert werden",
|
||||
"userProfile.changeAvatarError.notification.description": "Avatar muss kleiner sein als {{MAX_AVATAR_SIZE}} MB sein",
|
||||
"userProfile.form.username": "Benutzername",
|
||||
"userProfile.form.email": "E-Mail",
|
||||
"userProfile.form.oldPassword": "Altes passwort",
|
||||
"userProfile.form.newPassword": "Neues passwort",
|
||||
"userProfile.form.repeatNewPassword": "Neues Passwort wiederholen",
|
||||
"userProfile.form.language": "Sprache",
|
||||
"userProfile.header.yourSessions": "Ihre Sitzungen",
|
||||
"scanners.column.name": "Name",
|
||||
"scanners.column.usedBy": "Verwendet von",
|
||||
"scanners.column.lastUsed": "Zuletzt verwendet",
|
||||
"scanners.column.registeredAt": "Registriert am",
|
||||
"scanners.column.userAgent": "User-Agent",
|
||||
"scanners.column.action": "Maßnahme",
|
||||
"scanners.column.action.disconnect.popconfirm.title": "Sind Sie sicher, dass Sie die Verbindung zu diesem Scanner trennen wollen?",
|
||||
"scanners.column.action.disconnect.popconfirm.okText": "Verbindung trennen",
|
||||
"scanners.column.action.disconnect": "Verbindung trennen",
|
||||
"scanners.column.action.use.popconfirm.title": "Sind Sie sicher, dass Sie diesen Scanner verwenden möchten?",
|
||||
"scanners.column.action.use.popconfirm.description": "Benutzer, die mit diesem Scanner verbunden sind, werden von der Verbindung getrennt.",
|
||||
"scanners.column.action.use.popconfirm.okText": "Verwenden",
|
||||
"scanners.column.action.use": "Scanner verwenden",
|
||||
"scanners.header.scanners": "Scanner"
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"contactAdmin": "Please contact an administrator",
|
||||
"buttonCancel": "Cancel",
|
||||
"buttonClose": "Close",
|
||||
"buttonSave": "Save",
|
||||
"sideMenu.dashboard": "Dashboard",
|
||||
"sideMenu.groupTasks": "Group Tasks",
|
||||
"sideMenu.groupTasks.overview": "Overview",
|
||||
"sideMenu.groupTasks.history": "History",
|
||||
"sideMenu.adminArea": "Admin Area",
|
||||
"sideMenu.adminArea.roles": "Roles",
|
||||
"sideMenu.adminArea.logs": "Logs",
|
||||
"sideMenu.adminArea.noScannerSelected": "No scanner selected",
|
||||
"sideMenu.usersCount": "user connected",
|
||||
"sideMenu.usersCount.multiple": "users connected",
|
||||
"sideMenu.logout": "Logout",
|
||||
"groupTasks.categoryGroups.length0": "No group tasks found",
|
||||
"groupTasks.categoryGroups.assignedToNoTask.title": "You were not assigned to any group tasks",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.message": "Global inputs cannot be empty",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.description": "Please fill in all global inputs",
|
||||
"groupTasks.groupTypeSelectionModal.title": "Select a group type",
|
||||
"groupTasks.groupTypeSelectionModal.button.startTask": "Start task",
|
||||
"groupTasks.groupTypeSelectionModal.select.placeholder": "Choose a group type",
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.label": "Description",
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.tooltip.title": "This description helps to understand afterwards what this task was about",
|
||||
"groupTasks.tag.global": "Global",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message": "Type {{globalInputType}} not implemented",
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description": "Was specified in: {{globalInputDisplayName}}",
|
||||
"groupTasks.groupTypeSelectionModal.h3": "Fill in the global values",
|
||||
"groupTasks.groupTasksViewModal.groupTaskNotFound": "Group Task not found",
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message": "Inputs cannot be empty",
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description": "Please fill in all inputs",
|
||||
"groupTasks.groupTasksViewModal.button.tryAgain": "Try again",
|
||||
"groupTasks.groupTasksViewModal.button.continue": "Continue",
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedTaskInputs": "Specified Task Inputs",
|
||||
"groupTasks.groupTasksViewModal.startedAt": "Started at",
|
||||
"groupTasks.groupTasksViewModal.endedAt": "Ended at",
|
||||
"groupTasks.groupTasksViewModal.duration": "Duration",
|
||||
"groupTasks.groupTasksViewModal.category": "Category",
|
||||
"groupTasks.groupTasksViewModal.popover.details": "Details",
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs": "Specified Global Inputs",
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message": "Type {{groupTaskParameterType}} not implemented",
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description": "Was specified in: {{groupTaskParameterDisplayName}}",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.successful": "Successful",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskIsRunning": "Task is running",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskCanceled": "Task canceled",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskFailed": "Task failed",
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskInputRequired": "Input required",
|
||||
"groupTasks.groupTasksTableList.column.creator": "Creator",
|
||||
"groupTasks.groupTasksTableList.column.groupName": "Group Name",
|
||||
"groupTasks.groupTasksTableList.column.description": "Description",
|
||||
"groupTasks.groupTasksTableList.column.step": "Step",
|
||||
"groupTasks.groupTasksTableList.column.status": "Status",
|
||||
"groupTasks.groupTasksTableList.column.startedAt": "Started At",
|
||||
"groupTasks.groupTasksTableList.column.endedAt": "Ended At",
|
||||
"groupTasks.groupTasksTableList.column.duration": "Duration",
|
||||
"groupTasks.groupTasksTableList.column.action": "Action",
|
||||
"groupTasks.groupTasksTableList.column.action.view": "View",
|
||||
"groupTasks.groupTasksTableList.statusBadge.finished": "Finished",
|
||||
"groupTasks.groupTasksTableList.statusBadge.running": "Running",
|
||||
"groupTasks.groupTasksTableList.statusBadge.canceled": "Canceled",
|
||||
"groupTasks.groupTasksTableList.statusBadge.failed": "Failed",
|
||||
"groupTasks.groupTasksTableList.statusBadge.inputRequired": "Input required",
|
||||
"groupTasks.groupTasksTableList.button.newTask": "New task",
|
||||
"groupTasks.groupTasksTableList.button.reload": "Reload",
|
||||
"groupTasks.groupTasksTableList.popover.title": "Are you sure you want to reload the group configs?",
|
||||
"groupTasks.groupTasksTableList.popover.buttonOk": "Yes",
|
||||
"logCard.popover.groupTaskId.title": "Group Task",
|
||||
"logCard.popover.groupTaskStep.title": "Group Task Step",
|
||||
"logCard.popover.role.title": "Role",
|
||||
"logCard.card.checkbox.info": "INFO",
|
||||
"logCard.card.checkbox.error": "ERROR",
|
||||
"logCard.tooltip.previous": "Previous",
|
||||
"logCard.tooltip.next": "Next",
|
||||
"logCard.tooltip.reload": "Reload",
|
||||
"pageNotFound.subTitle": "Sorry, the page you visited does not exist.",
|
||||
"pageNotFound.buttonBackHome": "Back Home",
|
||||
"allUsers.column.avatar": "Avatar",
|
||||
"allUsers.column.username": "Username",
|
||||
"allUsers.column.role": "Role",
|
||||
"allUsers.column.connectionStatus": "Connection status",
|
||||
"allUsers.column.lastOnline": "Last online",
|
||||
"allUsers.column.action": "Action",
|
||||
"allUsers.column.action.roleChange.popconfirm.title": "Change role to",
|
||||
"allUsers.column.action.roleChange.popconfirm.okText": "Change",
|
||||
"allUsers.column.action.changeRole": "Change role",
|
||||
"allUsers.column.action.delete.popconfirm.okText": "Delete user",
|
||||
"allUsers.column.action.delete.popconfirm.title": "Are you sure you want to delete the user?",
|
||||
"allUsers.column.action.delete": "Delete",
|
||||
"allUsers.column.action.deactivate.popconfirm.okText": "Deactivate user",
|
||||
"allUsers.column.action.deactivate.popconfirm.title": "Are you sure you want to deactivate the user?",
|
||||
"allUsers.column.action.deactivate": "Deactivate",
|
||||
"allUsers.column.action.activate.popconfirm.okText": "Activate user",
|
||||
"allUsers.column.action.activate.popconfirm.title": "Are you sure you want to activate the user?",
|
||||
"allUsers.column.action.activate": "Activate",
|
||||
"allUsers.roleChangeError.notification.message": "User role could not be changed",
|
||||
"allUsers.roleChangeError.notification.description": "The role does not exist anymore",
|
||||
"allUsers.header.allUsers": "All users",
|
||||
"allUsers.button.createNewUser": "Create new user",
|
||||
"allUsers.header.deactivatedUsers": "Deactivated users",
|
||||
"allUsers.createUserModal.title": "Create a new user",
|
||||
"allUsers.createUserModal.okText": "Create user",
|
||||
"allUsers.createUserModal.form.username": "Username",
|
||||
"allUsers.createUserModal.form.email": "E-Mail",
|
||||
"allUsers.createUserModal.form.password": "Password",
|
||||
"allUsers.createUserModal.form.role": "Role",
|
||||
"allUsers.createUserModal.form.role.placeholder": "Select a role",
|
||||
"adminArea.createNewRole.popconfirm.okText": "Create",
|
||||
"adminArea.createNewRole.popconfirm.title": "Are you sure you want to create a new role?",
|
||||
"adminArea.createNewRole.button": "Create new role",
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.message": "Display name must be greater than {{MIN_ROLE_DISPLAY_NAME}}",
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.description": "Please enter a longer display name",
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.message": "Display name must be less than {{MIN_ROLE_DISPLAY_NAME}}",
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.description": "Please enter a shorter display name",
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.message": "Description must be less than {{MAX_ROLE_DESCRIPTION}}",
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.description": "Please enter a shorter description",
|
||||
"adminArea.deleteRole.popconfirm.title": "Delete role",
|
||||
"adminArea.deleteRole.popconfirm.description": "Are you sure to delete this role?",
|
||||
"adminArea.deleteRole.tooltip.title": "Delete",
|
||||
"adminArea.moveRoleUp.tooltip.title": "Move role up",
|
||||
"adminArea.moveRoleDown.tooltip.title": "Move role down",
|
||||
"adminArea.save.tooltip.title": "Save",
|
||||
"adminArea.close.tooltip.title": "Close",
|
||||
"adminArea.edit.tooltip.title": "Edit",
|
||||
"adminArea.masterRoleRightsMessage": "Rights cannot be edited, because this role is the master and has all rights.",
|
||||
"userProfile.header.yourProfile": "Your profile",
|
||||
"userProfile.column.userAgent": "User-Agent",
|
||||
"userProfile.column.connectionStatus": "Connection status",
|
||||
"userProfile.column.lastUsed": "Last used",
|
||||
"userProfile.column.expiresAt": "Expires at",
|
||||
"userProfile.column.action": "Action",
|
||||
"userProfile.column.action.signOut": "Sign out",
|
||||
"userProfile.changeAvatarError.notification.message": "Your avatar could not be changed",
|
||||
"userProfile.changeAvatarError.notification.description": "Avatar must be smaller than {{MAX_AVATAR_SIZE}} MB",
|
||||
"userProfile.form.username": "Username",
|
||||
"userProfile.form.email": "E-Mail",
|
||||
"userProfile.form.oldPassword": "Old password",
|
||||
"userProfile.form.newPassword": "New password",
|
||||
"userProfile.form.repeatNewPassword": "Repeat new password",
|
||||
"userProfile.form.language": "Language",
|
||||
"userProfile.header.yourSessions": "Your sessions",
|
||||
"scanners.column.name": "Name",
|
||||
"scanners.column.usedBy": "Used by",
|
||||
"scanners.column.lastUsed": "Last used",
|
||||
"scanners.column.registeredAt": "Registered at",
|
||||
"scanners.column.userAgent": "User-Agent",
|
||||
"scanners.column.action": "Action",
|
||||
"scanners.column.action.disconnect.popconfirm.title": "Are you sure you want to disconnect from this scanner?",
|
||||
"scanners.column.action.disconnect.popconfirm.okText": "Disconnect",
|
||||
"scanners.column.action.disconnect": "Disconnect",
|
||||
"scanners.column.action.use.popconfirm.title": "Are you sure you want to use this scanner?",
|
||||
"scanners.column.action.use.popconfirm.description": "Users connected to this scanner will be disconnected",
|
||||
"scanners.column.action.use.popconfirm.okText": "Use",
|
||||
"scanners.column.action.use": "Use scanner",
|
||||
"scanners.header.scanners": "Scanners"
|
||||
}
|
|
@ -13,9 +13,11 @@ import {
|
|||
handleUnauthorizedStatus,
|
||||
} from "../../utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function LogCard({ type }) {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
const [checkboxInfoChecked, setCheckboxInfoChecked] = useState(true);
|
||||
const [checkboxErrorChecked, setCheckboxErrorChecked] = useState(true);
|
||||
|
||||
|
@ -38,14 +40,6 @@ export default function LogCard({ type }) {
|
|||
const colorIndex = index % colorCodes.length;
|
||||
return colorCodes[colorIndex];
|
||||
};
|
||||
/*
|
||||
const getLogDataValue = (logData, splittedMessage) => {
|
||||
const logDataIndex = logData.findIndex(
|
||||
(data) => data.Type === splittedMessage.replace(new RegExp("%", "g"), "")
|
||||
);
|
||||
|
||||
return logData[logDataIndex].Value;
|
||||
};*/
|
||||
|
||||
const ColoredSpanItem = ({ dataLogs, splittedMessage, children }) => {
|
||||
const logDataIndex = dataLogs.LogData.findIndex(
|
||||
|
@ -187,7 +181,7 @@ export default function LogCard({ type }) {
|
|||
</Link>
|
||||
</div>
|
||||
}
|
||||
title="Group Task"
|
||||
title={t("logCard.popover.groupTaskId.title")}
|
||||
trigger="click"
|
||||
>
|
||||
<span style={{ cursor: "pointer" }}>
|
||||
|
@ -236,7 +230,7 @@ export default function LogCard({ type }) {
|
|||
</span>
|
||||
</div>
|
||||
}
|
||||
title="Group Task Step"
|
||||
title={t("logCard.popover.groupTaskStep.title")}
|
||||
trigger="click"
|
||||
>
|
||||
{" "}
|
||||
|
@ -281,7 +275,7 @@ export default function LogCard({ type }) {
|
|||
<span>{foundData.Value}</span>
|
||||
</div>
|
||||
}
|
||||
title="Role"
|
||||
title={t("logCard.popover.role.title")}
|
||||
trigger="click"
|
||||
>
|
||||
{" "}
|
||||
|
@ -358,17 +352,17 @@ export default function LogCard({ type }) {
|
|||
checked={checkboxInfoChecked}
|
||||
onChange={(e) => setCheckboxInfoChecked(e.target.checked)}
|
||||
>
|
||||
INFO
|
||||
{t("logCard.card.checkbox.info")}
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={checkboxErrorChecked}
|
||||
onChange={(e) => setCheckboxErrorChecked(e.target.checked)}
|
||||
>
|
||||
ERROR
|
||||
{t("logCard.card.checkbox.error")}
|
||||
</Checkbox>
|
||||
|
||||
{logData.Dates.findIndex((date) => date === selectedDate) > 0 ? (
|
||||
<Tooltip title="Previous">
|
||||
<Tooltip title={t("logCard.tooltip.previous")}>
|
||||
<ArrowLeftOutlined
|
||||
onClick={() =>
|
||||
setSelectedDate(
|
||||
|
@ -391,7 +385,7 @@ export default function LogCard({ type }) {
|
|||
|
||||
{logData.Dates.findIndex((date) => date === selectedDate) + 1 <
|
||||
logData.Dates.length ? (
|
||||
<Tooltip title="Next">
|
||||
<Tooltip title={t("logCard.tooltip.next")}>
|
||||
<ArrowRightOutlined
|
||||
onClick={() =>
|
||||
setSelectedDate(
|
||||
|
@ -412,7 +406,7 @@ export default function LogCard({ type }) {
|
|||
/>
|
||||
)}
|
||||
|
||||
<Tooltip title="Reload">
|
||||
<Tooltip title={t("logCard.tooltip.reload")}>
|
||||
<ReloadOutlined onClick={() => loadLogs(selectedDate)} />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
|
|
|
@ -21,11 +21,13 @@ import {
|
|||
hasOnePermission,
|
||||
hasPermission,
|
||||
} from "../../utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function SideMenu({ userSession, setUserSession }) {
|
||||
const location = useLocation();
|
||||
const [selectedKeys, setSelectedKeys] = useState("/");
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const pathName = location.pathname;
|
||||
|
@ -39,24 +41,26 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
(scanner) => scanner.UsedByUserId === getUserId()
|
||||
)?.Name;
|
||||
|
||||
return scannerName === undefined ? "No scanner selected" : scannerName;
|
||||
return scannerName === undefined
|
||||
? t("sideMenu.adminArea.noScannerSelected")
|
||||
: scannerName;
|
||||
};
|
||||
|
||||
const getFirstMenuItems = () => {
|
||||
let items = [
|
||||
{
|
||||
label: "Dashboard",
|
||||
label: t("sideMenu.dashboard"),
|
||||
icon: <AppstoreOutlined />,
|
||||
key: "/",
|
||||
},
|
||||
];
|
||||
|
||||
let groupTasks = {
|
||||
label: "Group Tasks",
|
||||
label: t("sideMenu.groupTasks"),
|
||||
type: "group",
|
||||
children: [
|
||||
{
|
||||
label: "Overview",
|
||||
label: t("sideMenu.groupTasks.overview"),
|
||||
icon: <SnippetsOutlined />,
|
||||
key: "/group-tasks",
|
||||
},
|
||||
|
@ -70,7 +74,7 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
)
|
||||
) {
|
||||
groupTasks.children.push({
|
||||
label: "History",
|
||||
label: t("sideMenu.groupTasks.history"),
|
||||
icon: <HistoryOutlined />,
|
||||
key: "/group-tasks-history",
|
||||
});
|
||||
|
@ -93,7 +97,7 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
)
|
||||
) {
|
||||
let adminArea = {
|
||||
label: "Admin Area",
|
||||
label: t("sideMenu.adminArea"),
|
||||
icon: <SettingOutlined />,
|
||||
key: "/admin-area",
|
||||
children: [],
|
||||
|
@ -109,7 +113,7 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
)
|
||||
) {
|
||||
adminArea.children.push({
|
||||
label: "Roles",
|
||||
label: t("sideMenu.adminArea.roles"),
|
||||
icon: <UsergroupAddOutlined />,
|
||||
key: "/admin-area/roles",
|
||||
});
|
||||
|
@ -122,7 +126,7 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
)
|
||||
) {
|
||||
adminArea.children.push({
|
||||
label: "Logs",
|
||||
label: t("sideMenu.adminArea.logs"),
|
||||
icon: <FileTextOutlined />,
|
||||
key: "/admin-area/logs",
|
||||
});
|
||||
|
@ -157,9 +161,9 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
status={webSocketContext.ConnectionBadgeStatus}
|
||||
text={`${webSocketContext.ConnectedWebSocketUsersCount} ${
|
||||
webSocketContext.ConnectedWebSocketUsersCount === 1
|
||||
? "user"
|
||||
: "users"
|
||||
} connected`}
|
||||
? t("sideMenu.usersCount")
|
||||
: t("sideMenu.usersCount.multiple")
|
||||
}`}
|
||||
/>
|
||||
),
|
||||
key: "/users",
|
||||
|
@ -175,7 +179,7 @@ export default function SideMenu({ userSession, setUserSession }) {
|
|||
key: "/user-profile",
|
||||
},
|
||||
{
|
||||
label: "Logout",
|
||||
label: t("sideMenu.logout"),
|
||||
icon: <LogoutOutlined />,
|
||||
onClick: () => {
|
||||
setUserSession();
|
||||
|
|
|
@ -28,8 +28,10 @@ import {
|
|||
SaveOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function AdminAreaRoles() {
|
||||
const { t } = useTranslation();
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
@ -133,12 +135,13 @@ export default function AdminAreaRoles() {
|
|||
>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
okText="Create"
|
||||
title="Are you sure you want to create a new role?"
|
||||
okText={t("adminArea.createNewRole.popconfirm.okText")}
|
||||
cancelText={t("buttonCancel")}
|
||||
title={t("adminArea.createNewRole.popconfirm.title")}
|
||||
onConfirm={() => onCreateNewRoleClick()}
|
||||
>
|
||||
<Button shape="round" icon={<PlusOutlined />} size="large">
|
||||
Create new role
|
||||
{t("adminArea.createNewRole.button")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
|
@ -148,6 +151,7 @@ export default function AdminAreaRoles() {
|
|||
}
|
||||
|
||||
function Role({ treeData, role, webSocketContext, notificationApi }) {
|
||||
const { t } = useTranslation();
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [roleDisplayName, setRoleDisplayName] = useState("");
|
||||
const [roleDescription, setRoleDescription] = useState("");
|
||||
|
@ -169,7 +173,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
const [checkedTreeKeyPermissions, setCheckedTreeKeyPermissions] =
|
||||
useState(rolePermissions);
|
||||
|
||||
const onTreeCheck = (checkedKeys, info) =>
|
||||
const onTreeCheck = (checkedKeys) =>
|
||||
setCheckedTreeKeyPermissions(checkedKeys);
|
||||
|
||||
const getMasterPermissions = () => {
|
||||
|
@ -245,8 +249,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
changes.DisplayName.length < Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Display name must be greater than ${Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME}`,
|
||||
description: `Please enter a longer display name`,
|
||||
message: t(
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.message",
|
||||
{ MIN_ROLE_DISPLAY_NAME: Constants.GLOBALS.MIN_ROLE_DISPLAY_NAME }
|
||||
),
|
||||
description: t(
|
||||
"adminArea.roleUpdate.errorDisplayNameToShort.notification.description"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -254,8 +263,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
changes.DisplayName.length > Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Display name must be less than ${Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME}`,
|
||||
description: `Please enter a shorter display name`,
|
||||
message: t(
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.message",
|
||||
{ MAX_ROLE_DISPLAY_NAME: Constants.GLOBALS.MAX_ROLE_DISPLAY_NAME }
|
||||
),
|
||||
description: t(
|
||||
"adminArea.roleUpdate.errorDisplayNameToLong.notification.description"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -266,8 +280,13 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
changes.Description.length > Constants.GLOBALS.MAX_ROLE_DESCRIPTION
|
||||
) {
|
||||
notificationApi["error"]({
|
||||
message: `Description must be less than ${Constants.GLOBALS.MAX_ROLE_DESCRIPTION}`,
|
||||
description: `Please enter a shorter description`,
|
||||
message: t(
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.message",
|
||||
{ MAX_ROLE_DESCRIPTION: Constants.GLOBALS.MAX_ROLE_DESCRIPTION }
|
||||
),
|
||||
description: t(
|
||||
"adminArea.roleUpdate.errorDescriptionToLong.notification.description"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -381,12 +400,15 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
/>
|
||||
) : (
|
||||
<Popconfirm
|
||||
title="Delete role"
|
||||
description="Are you sure to delete this role?"
|
||||
title={t("adminArea.deleteRole.popconfirm.title")}
|
||||
description={t(
|
||||
"adminArea.deleteRole.popconfirm.description"
|
||||
)}
|
||||
icon={<QuestionCircleOutlined style={{ color: "red" }} />}
|
||||
cancelText={t("buttonCancel")}
|
||||
onConfirm={() => onDeleteClick()}
|
||||
>
|
||||
<Tooltip title="Delete">
|
||||
<Tooltip title={t("adminArea.deleteRole.tooltip.title")}>
|
||||
<DeleteOutlined />
|
||||
</Tooltip>
|
||||
</Popconfirm>
|
||||
|
@ -407,7 +429,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
}}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip title="Move role up">
|
||||
<Tooltip title={t("adminArea.moveRoleUp.tooltip.title")}>
|
||||
<ArrowUpOutlined onClick={() => onMoveUpClick()} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
@ -419,7 +441,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
}}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip title="Move role down">
|
||||
<Tooltip title={t("adminArea.moveRoleDown.tooltip.title")}>
|
||||
<ArrowDownOutlined onClick={() => onMoveDownClick()} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
@ -430,12 +452,12 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
webSocketContext.User.Permissions,
|
||||
Constants.PERMISSIONS.ADMIN_AREA.ROLES.UPDATE_ROLE
|
||||
) && (
|
||||
<Tooltip title="Save">
|
||||
<Tooltip title={t("adminArea.save.tooltip.title")}>
|
||||
<SaveOutlined onClick={() => onSaveClick()} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip title="Close">
|
||||
<Tooltip title={t("adminArea.close.tooltip.title")}>
|
||||
<CloseOutlined onClick={() => onCloseClick()} />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
|
@ -443,7 +465,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
<Space style={{ paddingLeft: 10 }} align="start">
|
||||
<UserAvatarsInRole />
|
||||
|
||||
<Tooltip title="Edit">
|
||||
<Tooltip title={t("adminArea.edit.tooltip.title")}>
|
||||
<EditOutlined onClick={() => onEditClick()} />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
|
@ -491,8 +513,7 @@ function Role({ treeData, role, webSocketContext, notificationApi }) {
|
|||
<>
|
||||
{role.Master && editMode && (
|
||||
<p style={{ fontStyle: "italic" }}>
|
||||
Rights cannot be edited, because this role is the master and
|
||||
has all rights.
|
||||
{t("adminArea.masterRoleRightsMessage")}
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ import {
|
|||
isEmailValid,
|
||||
} from "../../utils";
|
||||
import { useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
const [username, setUsername] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
@ -55,18 +57,19 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
|
|||
|
||||
return (
|
||||
<Modal
|
||||
title="Create a new user"
|
||||
title={t("allUsers.createUserModal.title")}
|
||||
open={isModalOpen}
|
||||
centered
|
||||
maskClosable={false}
|
||||
okText="Create user"
|
||||
okText={t("allUsers.createUserModal.okText")}
|
||||
cancelText={t("buttonCancel")}
|
||||
okButtonProps={{ disabled: !isCreateUserPossible() }}
|
||||
onCancel={() => setIsModalOpen(false)}
|
||||
onOk={() => onConfirmUserCreation()}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<Form.Item
|
||||
label="Username"
|
||||
label={t("allUsers.createUserModal.form.username")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
username.length !== 0 &&
|
||||
|
@ -75,7 +78,7 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
|
|||
}
|
||||
>
|
||||
<Input
|
||||
placeholder="Username"
|
||||
placeholder={t("allUsers.createUserModal.form.username")}
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
minLength={Constants.GLOBALS.MIN_USERNAME_LENGTH}
|
||||
|
@ -83,19 +86,19 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="E-Mail"
|
||||
label={t("allUsers.createUserModal.form.email")}
|
||||
hasFeedback
|
||||
validateStatus={email.length !== 0 && !isEmailValid(email) && "error"}
|
||||
>
|
||||
<Input
|
||||
placeholder="E-Mail"
|
||||
placeholder={t("allUsers.createUserModal.form.email")}
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
type="email"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Password"
|
||||
label={t("allUsers.createUserModal.form.password")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
password.length !== 0 &&
|
||||
|
@ -104,19 +107,19 @@ export default function CreateUserModal({ isModalOpen, setIsModalOpen }) {
|
|||
}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder="Password"
|
||||
placeholder={t("allUsers.createUserModal.form.password")}
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
minLength={Constants.GLOBALS.MIN_PASSWORD_LENGTH}
|
||||
maxLength={Constants.GLOBALS.MAX_PASSWORD_LENGTH}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="Role">
|
||||
<Form.Item label={t("allUsers.createUserModal.form.role")}>
|
||||
<Select
|
||||
getPopupContainer={(node) => node.parentNode}
|
||||
value={selectedRoleId}
|
||||
onChange={(e) => setSelectedRoleId(e)}
|
||||
placeholder="Select a role"
|
||||
placeholder={t("allUsers.createUserModal.form.role.placeholder")}
|
||||
>
|
||||
{webSocketContext.AllRoles.map((role) => (
|
||||
<Select.Option key={role.Id}>{role.DisplayName}</Select.Option>
|
||||
|
|
|
@ -21,9 +21,11 @@ import { useContext, useState } from "react";
|
|||
import { Link } from "react-router-dom";
|
||||
import { UserAddOutlined } from "@ant-design/icons";
|
||||
import CreateUserModal from "./CreateUserModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function AllUsers() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
const [selectedRoleId, setSelectedRoleId] = useState("");
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
@ -32,27 +34,27 @@ export default function AllUsers() {
|
|||
const getTableContent = () => {
|
||||
let items = [
|
||||
{
|
||||
title: "Avatar",
|
||||
title: t("allUsers.column.avatar"),
|
||||
dataIndex: "avatar",
|
||||
key: "avatar",
|
||||
},
|
||||
{
|
||||
title: "Username",
|
||||
title: t("allUsers.column.username"),
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
},
|
||||
{
|
||||
title: "Role",
|
||||
title: t("allUsers.column.role"),
|
||||
dataIndex: "role",
|
||||
key: "role",
|
||||
},
|
||||
{
|
||||
title: "Connection status",
|
||||
title: t("allUsers.column.connectionStatus"),
|
||||
dataIndex: "connectionStatus",
|
||||
key: "connectionStatus",
|
||||
},
|
||||
{
|
||||
title: "Last online",
|
||||
title: t("allUsers.column.lastOnline"),
|
||||
dataIndex: "lastOnline",
|
||||
key: "lastOnline",
|
||||
},
|
||||
|
@ -67,7 +69,7 @@ export default function AllUsers() {
|
|||
)
|
||||
) {
|
||||
items.push({
|
||||
title: "Action",
|
||||
title: t("allUsers.column.action"),
|
||||
key: "action",
|
||||
render: (_, record) => (
|
||||
<Space size="middle">
|
||||
|
@ -85,8 +87,13 @@ export default function AllUsers() {
|
|||
(role) => role.Id === webSocketContext.User.RoleId
|
||||
).Master) && (
|
||||
<Popconfirm
|
||||
title="Change role to"
|
||||
okText="Change"
|
||||
title={t(
|
||||
"allUsers.column.action.roleChange.popconfirm.title"
|
||||
)}
|
||||
cancelText={t("buttonCancel")}
|
||||
okText={t(
|
||||
"allUsers.column.action.roleChange.popconfirm.okText"
|
||||
)}
|
||||
onConfirm={() => onRoleChangeConfirm(record.key)}
|
||||
okButtonProps={{
|
||||
disabled:
|
||||
|
@ -138,7 +145,7 @@ export default function AllUsers() {
|
|||
);
|
||||
}}
|
||||
>
|
||||
Change role
|
||||
{t("allUsers.column.action.changeRole")}
|
||||
</Link>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
@ -158,11 +165,12 @@ export default function AllUsers() {
|
|||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
okText="Delete user"
|
||||
title="Are you sure you want to delete the user?"
|
||||
cancelText={t("buttonCancel")}
|
||||
okText={t("allUsers.column.action.delete.popconfirm.okText")}
|
||||
title={t("allUsers.column.action.delete.popconfirm.title")}
|
||||
onConfirm={() => onUserDeletionConfirm(record.key)}
|
||||
>
|
||||
<Link to="#">Delete</Link>
|
||||
<Link to="#">{t("allUsers.column.action.delete")}</Link>
|
||||
</Popconfirm>
|
||||
)}
|
||||
|
||||
|
@ -183,13 +191,18 @@ export default function AllUsers() {
|
|||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
okText="Deactivate user"
|
||||
title="Are you sure you want to deactivate the user?"
|
||||
okText={t(
|
||||
"allUsers.column.action.deactivate.popconfirm.okText"
|
||||
)}
|
||||
cancelText={t("buttonCancel")}
|
||||
title={t(
|
||||
"allUsers.column.action.deactivate.popconfirm.title"
|
||||
)}
|
||||
onConfirm={() =>
|
||||
onUserDeactivationConfirm(record.key, true)
|
||||
}
|
||||
>
|
||||
<Link to="#">Deactivate</Link>
|
||||
<Link to="#">{t("allUsers.column.action.deactivate")}</Link>
|
||||
</Popconfirm>
|
||||
)
|
||||
: hasPermission(
|
||||
|
@ -207,13 +220,18 @@ export default function AllUsers() {
|
|||
).Master) && (
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
okText="Activate user"
|
||||
title="Are you sure you want to activate the user?"
|
||||
okText={t(
|
||||
"allUsers.column.action.activate.popconfirm.okText"
|
||||
)}
|
||||
title={t(
|
||||
"allUsers.column.action.activate.popconfirm.title"
|
||||
)}
|
||||
cancelText={t("buttonCancel")}
|
||||
onConfirm={() =>
|
||||
onUserDeactivationConfirm(record.key, false)
|
||||
}
|
||||
>
|
||||
<Link to="#">Activate</Link>
|
||||
<Link to="#">{t("allUsers.column.action.activate")}</Link>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
|
@ -273,8 +291,8 @@ export default function AllUsers() {
|
|||
|
||||
if (existsRole === undefined) {
|
||||
notificationApi["error"]({
|
||||
message: `User role could not be changed`,
|
||||
description: `The role does not exist anymore`,
|
||||
message: t("allUsers.roleChangeError.notification.message"),
|
||||
description: t("allUsers.roleChangeError.notification.description"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -318,7 +336,7 @@ export default function AllUsers() {
|
|||
}}
|
||||
>
|
||||
<h1 style={{ fontWeight: "bold" }}>
|
||||
All users ({activatedUsers.length})
|
||||
{t("allUsers.header.allUsers")} ({activatedUsers.length})
|
||||
</h1>
|
||||
{hasPermission(
|
||||
webSocketContext.User.Permissions,
|
||||
|
@ -328,7 +346,7 @@ export default function AllUsers() {
|
|||
icon={<UserAddOutlined />}
|
||||
onClick={() => setIsCreateUserModalOpen(true)}
|
||||
>
|
||||
Create new user
|
||||
{t("allUsers.button.createNewUser")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
@ -345,7 +363,8 @@ export default function AllUsers() {
|
|||
deactivatedUsers.length > 0 && (
|
||||
<>
|
||||
<h1 style={{ fontWeight: "bold" }}>
|
||||
Deactivated users ({deactivatedUsers.length})
|
||||
{t("allUsers.header.deactivatedUsers")} ({deactivatedUsers.length}
|
||||
)
|
||||
</h1>
|
||||
<Table
|
||||
columns={getTableContent()}
|
||||
|
|
|
@ -21,20 +21,30 @@ import {
|
|||
hasXYPermission,
|
||||
} from "../../../utils";
|
||||
import { useContext } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const columns = [
|
||||
export default function GroupTaskTableList({
|
||||
categoryGroup,
|
||||
showGroupTypeSelectionModal,
|
||||
groupTasks,
|
||||
}) {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: "Creator",
|
||||
title: t("groupTasks.groupTasksTableList.column.creator"),
|
||||
dataIndex: "creator",
|
||||
key: "creator",
|
||||
},
|
||||
{
|
||||
title: "Group Name",
|
||||
title: t("groupTasks.groupTasksTableList.column.groupName"),
|
||||
dataIndex: "groupName",
|
||||
key: "groupName",
|
||||
},
|
||||
{
|
||||
title: "Description",
|
||||
title: t("groupTasks.groupTasksTableList.column.description"),
|
||||
dataIndex: "description",
|
||||
key: "description",
|
||||
ellipsis: {
|
||||
|
@ -47,63 +57,82 @@ const columns = [
|
|||
),
|
||||
},
|
||||
{
|
||||
title: "Step",
|
||||
title: t("groupTasks.groupTasksTableList.column.step"),
|
||||
dataIndex: "step",
|
||||
key: "step",
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
title: t("groupTasks.groupTasksTableList.column.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
},
|
||||
{
|
||||
title: "Started At",
|
||||
title: t("groupTasks.groupTasksTableList.column.startedAt"),
|
||||
dataIndex: "startedAt",
|
||||
key: "startedAt",
|
||||
},
|
||||
{
|
||||
title: "Ended At",
|
||||
title: t("groupTasks.groupTasksTableList.column.endedAt"),
|
||||
dataIndex: "endedAt",
|
||||
key: "endedAt",
|
||||
},
|
||||
{
|
||||
title: "Duration",
|
||||
title: t("groupTasks.groupTasksTableList.column.duration"),
|
||||
dataIndex: "duration",
|
||||
key: "duration",
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
title: t("groupTasks.groupTasksTableList.column.action"),
|
||||
dataIndex: "action",
|
||||
key: "action",
|
||||
render: (_, record) => (
|
||||
<Space size="middle">
|
||||
<Link to={Constants.ROUTE_PATHS.GROUP_TASKS_VIEW + record.key}>
|
||||
View
|
||||
{t("groupTasks.groupTasksTableList.column.action.view")}
|
||||
</Link>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export default function GroupTaskTableList({
|
||||
categoryGroup,
|
||||
showGroupTypeSelectionModal,
|
||||
groupTasks,
|
||||
}) {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
};
|
||||
|
||||
const getStatusBadge = (status) => {
|
||||
switch (status) {
|
||||
case Constants.GROUP_TASKS_STATUS.FINISHED:
|
||||
return <Badge status="success" text="Finished" />;
|
||||
return (
|
||||
<Badge
|
||||
status="success"
|
||||
text={t("groupTasks.groupTasksTableList.statusBadge.finished")}
|
||||
/>
|
||||
);
|
||||
case Constants.GROUP_TASKS_STATUS.RUNNING:
|
||||
return <Badge status="processing" text="Running" />;
|
||||
return (
|
||||
<Badge
|
||||
status="processing"
|
||||
text={t("groupTasks.groupTasksTableList.statusBadge.running")}
|
||||
/>
|
||||
);
|
||||
case Constants.GROUP_TASKS_STATUS.CANCELED:
|
||||
return <Badge status="warning" text="Canceled" />;
|
||||
return (
|
||||
<Badge
|
||||
status="warning"
|
||||
text={t("groupTasks.groupTasksTableList.statusBadge.canceled")}
|
||||
/>
|
||||
);
|
||||
case Constants.GROUP_TASKS_STATUS.FAILED:
|
||||
return <Badge status="error" text="Failed" />;
|
||||
return (
|
||||
<Badge
|
||||
status="error"
|
||||
text={t("groupTasks.groupTasksTableList.statusBadge.failed")}
|
||||
/>
|
||||
);
|
||||
case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED:
|
||||
return <Badge status="warning" text="Input required" />;
|
||||
return (
|
||||
<Badge
|
||||
status="warning"
|
||||
text={t("groupTasks.groupTasksTableList.statusBadge.inputRequired")}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <Badge status="error" text="Status not found" />;
|
||||
}
|
||||
|
@ -188,7 +217,7 @@ export default function GroupTaskTableList({
|
|||
icon={<PlusOutlined />}
|
||||
onClick={() => showGroupTypeSelectionModal(categoryGroup)}
|
||||
>
|
||||
New task
|
||||
{t("groupTasks.groupTasksTableList.button.newTask")}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
|
@ -199,17 +228,20 @@ export default function GroupTaskTableList({
|
|||
) && (
|
||||
<Popconfirm
|
||||
placement="left"
|
||||
title="Are you sure you want to reload the group configs?"
|
||||
okText="Yes"
|
||||
title={t("groupTasks.groupTasksTableList.popover.title")}
|
||||
cancelText={t("buttonCancel")}
|
||||
okText={t("groupTasks.groupTasksTableList.popover.buttonOk")}
|
||||
onConfirm={() => handleOnConfirm(categoryGroup.category)}
|
||||
>
|
||||
<Button icon={<ReloadOutlined />}>Reload</Button>
|
||||
<Button icon={<ReloadOutlined />}>
|
||||
{t("groupTasks.groupTasksTableList.button.reload")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Table columns={columns} dataSource={getTableItems()} />
|
||||
<Table columns={getTableColumns()} dataSource={getTableItems()} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import {
|
|||
} from "@ant-design/icons";
|
||||
import { StlViewer } from "react-stl-viewer";
|
||||
import TextArea from "antd/es/input/TextArea";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function GroupTasksViewModal({ isOpen }) {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
|
@ -40,6 +41,7 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
let { paramGroupTaskId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleCancel = () => navigate(Constants.ROUTE_PATHS.GROUP_TASKS);
|
||||
let currentGroupTask;
|
||||
|
@ -60,7 +62,10 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
onCancel={handleCancel}
|
||||
footer={<Button onClick={handleCancel}>Close</Button>}
|
||||
>
|
||||
<Result status="500" title="Group Task not found" />{" "}
|
||||
<Result
|
||||
status="500"
|
||||
title={t("groupTasks.groupTasksViewModal.groupTaskNotFound")}
|
||||
/>{" "}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -85,15 +90,17 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
const getAlertMessage = (status) => {
|
||||
switch (status) {
|
||||
case Constants.GROUP_TASKS_STATUS.FINISHED:
|
||||
return "Success";
|
||||
return t("groupTasks.groupTasksViewModal.alertMessage.successful");
|
||||
case Constants.GROUP_TASKS_STATUS.RUNNING:
|
||||
return "Task is running";
|
||||
return t("groupTasks.groupTasksViewModal.alertMessage.taskIsRunning");
|
||||
case Constants.GROUP_TASKS_STATUS.CANCELED:
|
||||
return "Task cancelled";
|
||||
return t("groupTasks.groupTasksViewModal.alertMessage.taskCanceled");
|
||||
case Constants.GROUP_TASKS_STATUS.FAILED:
|
||||
return "Task failed";
|
||||
return t("groupTasks.groupTasksViewModal.alertMessage.taskFailed");
|
||||
case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED:
|
||||
return "Input required";
|
||||
return t(
|
||||
"groupTasks.groupTasksViewModal.alertMessage.taskInputRequired"
|
||||
);
|
||||
default:
|
||||
return "Alert message not found";
|
||||
}
|
||||
|
@ -180,8 +187,12 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
|
||||
if (!canTaskContinued) {
|
||||
notificationApi["error"]({
|
||||
message: `Inputs cannot be empty`,
|
||||
description: `Please fill in all inputs`,
|
||||
message: t(
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.message"
|
||||
),
|
||||
description: t(
|
||||
"groupTasks.groupTasksViewModal.notification.inputsCannotBeEmpty.description"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -211,7 +222,7 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
handleTaskFailedTryAgainRunTaskStep(taskStepId, index + 1)
|
||||
}
|
||||
>
|
||||
Try again
|
||||
{t("groupTasks.groupTasksViewModal.button.tryAgain")}
|
||||
</Button>
|
||||
);
|
||||
case Constants.GROUP_TASKS_STATUS.INPUT_REQUIRED:
|
||||
|
@ -221,7 +232,7 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
disabled={taskLocked}
|
||||
onClick={() => handleTaskContinueTaskStep(taskStepId, index + 1)}
|
||||
>
|
||||
Continue
|
||||
{t("groupTasks.groupTasksViewModal.button.continue")}
|
||||
</Button>
|
||||
);
|
||||
default:
|
||||
|
@ -241,8 +252,6 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
|
||||
groupTaskSteps.sort((a, b) => a.Step - b.Step);
|
||||
|
||||
console.log("currentGroupTask", currentGroupTask.NumberOfSteps);
|
||||
|
||||
webSocketContext.CategoryGroups.forEach((categoryGroup) => {
|
||||
if (categoryGroup.category === currentGroupTask.Category) {
|
||||
categoryGroup.groups.forEach((group) => {
|
||||
|
@ -253,8 +262,6 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
}
|
||||
});
|
||||
|
||||
console.log("groupTasks", groupTasks, groupTaskSteps);
|
||||
|
||||
const getStepItem = (groupTask, index) => {
|
||||
return {
|
||||
key: index,
|
||||
|
@ -276,7 +283,9 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
color: Constants.COLORS.SECONDARY,
|
||||
}}
|
||||
>
|
||||
Specified Task Inputs
|
||||
{t(
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedTaskInputs"
|
||||
)}
|
||||
</h2>
|
||||
}
|
||||
content={
|
||||
|
@ -340,17 +349,17 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
groupTaskSteps[index] !== undefined ? (
|
||||
<>
|
||||
<p style={{ color: "#000" }}>
|
||||
<b>Id:</b> {groupTaskSteps[index].Id}
|
||||
<b>ID:</b> {groupTaskSteps[index].Id}
|
||||
<br />
|
||||
<b>Started at:</b>{" "}
|
||||
<b>{t("groupTasks.groupTasksViewModal.startedAt")}:</b>{" "}
|
||||
{FormatDatetime(groupTaskSteps[index].StartedAt)}
|
||||
<br />
|
||||
<b>Ended at:</b>{" "}
|
||||
<b>{t("groupTasks.groupTasksViewModal.endedAt")}:</b>{" "}
|
||||
{groupTaskSteps[index].EndedAt !== "0001-01-01T00:00:00Z"
|
||||
? FormatDatetime(groupTaskSteps[index].EndedAt)
|
||||
: Constants.TEXT_EMPTY_PLACEHOLDER}
|
||||
<br />
|
||||
<b>Duration:</b>{" "}
|
||||
<b>{t("groupTasks.groupTasksViewModal.duration")}:</b>{" "}
|
||||
{GetDuration(
|
||||
groupTaskSteps[index].StartedAt,
|
||||
groupTaskSteps[index].EndedAt
|
||||
|
@ -456,7 +465,7 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
width="70%"
|
||||
onCancel={handleCancel}
|
||||
maskClosable={false}
|
||||
footer={<Button onClick={handleCancel}>Close</Button>}
|
||||
footer={<Button onClick={handleCancel}>{t("buttonClose")}</Button>}
|
||||
>
|
||||
{notificationContextHolder}
|
||||
{webSocketContext.GroupTasks.map((groupTask) => {
|
||||
|
@ -482,7 +491,7 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
color: Constants.COLORS.SECONDARY,
|
||||
}}
|
||||
>
|
||||
Details
|
||||
{t("groupTasks.groupTasksViewModal.popover.details")}
|
||||
</h2>
|
||||
}
|
||||
content={
|
||||
|
@ -491,22 +500,22 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
<span style={{ fontWeight: "bold" }}>ID:</span>{" "}
|
||||
{paramGroupTaskId} <br />
|
||||
<span style={{ fontWeight: "bold" }}>
|
||||
Category:
|
||||
{t("groupTasks.groupTasksViewModal.category")}:
|
||||
</span>{" "}
|
||||
{currentGroupTask.Category}
|
||||
<br />
|
||||
<span style={{ fontWeight: "bold" }}>
|
||||
Started at:
|
||||
{t("groupTasks.groupTasksViewModal.startedAt")}:
|
||||
</span>{" "}
|
||||
{FormatDatetime(currentGroupTask.StartedAt)}
|
||||
<br />
|
||||
<span style={{ fontWeight: "bold" }}>
|
||||
Endet at:
|
||||
{t("groupTasks.groupTasksViewModal.endedAt")}:
|
||||
</span>{" "}
|
||||
{FormatDatetime(currentGroupTask.EndedAt)}
|
||||
<br />
|
||||
<span style={{ fontWeight: "bold" }}>
|
||||
Duration:
|
||||
{t("groupTasks.groupTasksViewModal.duration")}:
|
||||
</span>{" "}
|
||||
{GetDuration(
|
||||
currentGroupTask.StartedAt,
|
||||
|
@ -522,7 +531,9 @@ export default function GroupTasksViewModal({ isOpen }) {
|
|||
color: Constants.COLORS.SECONDARY,
|
||||
}}
|
||||
>
|
||||
Specified Global Inputs
|
||||
{t(
|
||||
"groupTasks.groupTasksViewModal.popover.specifiedGlobalInputs"
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<span>
|
||||
|
@ -610,6 +621,7 @@ function InputRequiredHandler({
|
|||
step,
|
||||
taskLockedByUserId,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [inputFields, setInputFields] = useState({});
|
||||
|
||||
const globalInputs = JSON.parse(currentGroupTask.GlobalInputs);
|
||||
|
@ -642,7 +654,7 @@ function InputRequiredHandler({
|
|||
<>
|
||||
{displayName}
|
||||
<Tag style={{ marginLeft: 6 }} color="purple">
|
||||
Global
|
||||
{t("groupTasks.tag.global")}
|
||||
</Tag>
|
||||
</>
|
||||
) : (
|
||||
|
@ -783,8 +795,16 @@ function InputRequiredHandler({
|
|||
);
|
||||
default:
|
||||
notificationApi["error"]({
|
||||
message: `Type ${groupTaskParameter.type} not implemented`,
|
||||
description: `Was specified in: ${groupTaskParameter.displayName}`,
|
||||
message: t(
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.message",
|
||||
{ groupTaskParameterType: groupTaskParameter.type }
|
||||
),
|
||||
description: t(
|
||||
"groupTasks.groupTasksViewModal.notification.groupTaskParameterNotImplemented.description",
|
||||
{
|
||||
groupTaskParameterDisplayName: groupTaskParameter.displayName,
|
||||
}
|
||||
),
|
||||
});
|
||||
return (
|
||||
<p>
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
import { useContext } from "react";
|
||||
import { InfoCircleOutlined } from "@ant-design/icons";
|
||||
import TextArea from "antd/es/input/TextArea";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function GroupTypeSelectionModal({
|
||||
isOpen,
|
||||
|
@ -29,6 +30,7 @@ export default function GroupTypeSelectionModal({
|
|||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
const handleCancel = () => setIsOpen(false);
|
||||
|
||||
const isStartTaskPossible = () => {
|
||||
|
@ -108,8 +110,12 @@ export default function GroupTypeSelectionModal({
|
|||
|
||||
if (!canTaskBeStarted) {
|
||||
notificationApi["error"]({
|
||||
message: `Global inputs cannot be empty`,
|
||||
description: `Please fill in all global inputs`,
|
||||
message: t(
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.message"
|
||||
),
|
||||
description: t(
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputsCannotBeEmpty.description"
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -144,7 +150,7 @@ export default function GroupTypeSelectionModal({
|
|||
|
||||
return (
|
||||
<Modal
|
||||
title="Select a group type"
|
||||
title={t("groupTasks.groupTypeSelectionModal.title")}
|
||||
open={isOpen}
|
||||
onCancel={handleCancel}
|
||||
centered
|
||||
|
@ -152,7 +158,7 @@ export default function GroupTypeSelectionModal({
|
|||
footer={[
|
||||
<Space key={0}>
|
||||
<Button key="back" onClick={handleCancel}>
|
||||
Cancel
|
||||
{t("buttonCancel")}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
|
@ -161,14 +167,14 @@ export default function GroupTypeSelectionModal({
|
|||
disabled={isStartTaskPossible()}
|
||||
onClick={handleStartTask}
|
||||
>
|
||||
Start task
|
||||
{t("groupTasks.groupTypeSelectionModal.button.startTask")}
|
||||
</Button>
|
||||
</Space>,
|
||||
]}
|
||||
>
|
||||
{notificationContextHolder}
|
||||
<Select
|
||||
placeholder="Choose a group type"
|
||||
placeholder={t("groupTasks.groupTypeSelectionModal.select.placeholder")}
|
||||
style={{ width: "100%" }}
|
||||
value={currentSelectedModalGroupType}
|
||||
onChange={(value) => setCurrentSelectedModalGroupType(value)}
|
||||
|
@ -188,10 +194,13 @@ export default function GroupTypeSelectionModal({
|
|||
<Form layout="vertical">
|
||||
<br />
|
||||
<Form.Item
|
||||
label="Description"
|
||||
label={t(
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.label"
|
||||
)}
|
||||
tooltip={{
|
||||
title:
|
||||
"This description helps to understand afterwards what this task was about",
|
||||
title: t(
|
||||
"groupTasks.groupTypeSelectionModal.form.item.groupTypeDescription.tooltip.title"
|
||||
),
|
||||
icon: <InfoCircleOutlined />,
|
||||
}}
|
||||
required
|
||||
|
@ -215,12 +224,14 @@ function GroupGlobalInputs({
|
|||
currentSelectedModalGroupType,
|
||||
notificationApi,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getLabel = (displayName) => {
|
||||
return (
|
||||
<>
|
||||
{displayName}
|
||||
<Tag style={{ marginLeft: 6 }} color="purple">
|
||||
Global
|
||||
{t("groupTasks.tag.global")}
|
||||
</Tag>
|
||||
</>
|
||||
);
|
||||
|
@ -275,8 +286,14 @@ function GroupGlobalInputs({
|
|||
break;
|
||||
default:
|
||||
notificationApi["error"]({
|
||||
message: `Type ${globalInput.type} not implemented`,
|
||||
description: `Was specified in: ${globalInput.displayName}`,
|
||||
message: t(
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.message",
|
||||
{ globalInputType: globalInput.type }
|
||||
),
|
||||
description: t(
|
||||
"groupTasks.groupTypeSelectionModal.notification.globalInputTypeNotImplemented.description",
|
||||
{ globalInputDisplayName: globalInput.displayName }
|
||||
),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -291,7 +308,9 @@ function GroupGlobalInputs({
|
|||
{elements.length > 0 ? (
|
||||
<div>
|
||||
<Divider />
|
||||
<h3 style={{ fontWeight: "bold" }}>Fill in the global values</h3>
|
||||
<h3 style={{ fontWeight: "bold" }}>
|
||||
{t("groupTasks.groupTypeSelectionModal.h3")}
|
||||
</h3>
|
||||
<Form
|
||||
layout="vertical"
|
||||
id="groupTypeSelectionUserSpecifiedGlobalInputForm"
|
||||
|
|
|
@ -4,6 +4,7 @@ import GroupTasksViewModal from "./GroupTasksViewModal";
|
|||
import GroupTypeSelectionModal from "./GroupTypeSelectionModal";
|
||||
import GroupTaskTableList from "./GroupTasksTableList";
|
||||
import { Constants, WebSocketContext, hasXYPermission } from "../../../utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function GroupTasks({ isGroupTasksViewModalOpen }) {
|
||||
const [isGroupTypeSelectionModalOpen, setIsGroupTypeSelectionModalOpen] =
|
||||
|
@ -12,6 +13,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
|
|||
const [currentSelectedModalGroupType, setCurrentSelectedModalGroupType] =
|
||||
useState();
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const showGroupTypeSelectionModal = (categoryGroup) => {
|
||||
setCurrentCategoryGroup(categoryGroup);
|
||||
|
@ -31,7 +33,7 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
|
|||
return (
|
||||
<>
|
||||
{webSocketContext.CategoryGroups.length === 0 ? (
|
||||
<Result status="404" title="No group tasks found" />
|
||||
<Result status="404" title={t("groupTasks.categoryGroups.length0")} />
|
||||
) : (
|
||||
<>
|
||||
{filteredCategoryGroups.length > 0 ? (
|
||||
|
@ -51,8 +53,8 @@ export default function GroupTasks({ isGroupTasksViewModalOpen }) {
|
|||
<Result
|
||||
key="result"
|
||||
status="403"
|
||||
title="You were not assigned to any group tasks"
|
||||
subTitle="Please contact an administrator"
|
||||
title={t("groupTasks.categoryGroups.assignedToNoTask.title")}
|
||||
subTitle={t("contactAdmin")}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
import { Button, Result } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function PageNotFound() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Result
|
||||
status="404"
|
||||
title="404"
|
||||
subTitle="Sorry, the page you visited does not exist."
|
||||
subTitle={t("pageNotFound.subTitle")}
|
||||
extra={
|
||||
<Link to="/">
|
||||
<Button type="primary">Back Home</Button>
|
||||
<Button type="primary">{t("pageNotFound.buttonBackHome")}</Button>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -9,39 +9,41 @@ import {
|
|||
import { useContext } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Constants } from "../../utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function Scanners() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: "Name",
|
||||
title: t("scanners.column.name"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
},
|
||||
{
|
||||
title: "Used by",
|
||||
title: t("scanners.column.usedBy"),
|
||||
dataIndex: "usedByUserId",
|
||||
key: "usedByUserId",
|
||||
},
|
||||
{
|
||||
title: "Last used",
|
||||
title: t("scanners.column.lastUsed"),
|
||||
dataIndex: "lastUsed",
|
||||
key: "lastUsed",
|
||||
},
|
||||
{
|
||||
title: "Registered at",
|
||||
title: t("scanners.column.registeredAt"),
|
||||
dataIndex: "registeredAt",
|
||||
key: "registeredAt",
|
||||
},
|
||||
{
|
||||
title: "User-Agent",
|
||||
title: t("scanners.column.userAgent"),
|
||||
dataIndex: "userAgent",
|
||||
key: "userAgent",
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
title: t("scanners.column.action"),
|
||||
dataIndex: "action",
|
||||
key: "action",
|
||||
render: (_, record) => (
|
||||
|
@ -49,8 +51,11 @@ export default function Scanners() {
|
|||
{record._usedByUserId === getUserId() ? (
|
||||
<Popconfirm
|
||||
placement="left"
|
||||
title="Are you sure you want to disconnect from this scanner?"
|
||||
okText="Disconnect"
|
||||
title={t("scanners.column.action.disconnect.popconfirm.title")}
|
||||
okText={t(
|
||||
"scanners.column.action.disconnect.popconfirm.okText"
|
||||
)}
|
||||
cancelText={t("buttonCancel")}
|
||||
onConfirm={() => {
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.ScannersDisconnectScanner,
|
||||
|
@ -60,14 +65,17 @@ export default function Scanners() {
|
|||
);
|
||||
}}
|
||||
>
|
||||
<Link to="#">Disconnect</Link>
|
||||
<Link to="#">{t("scanners.column.action.disconnect")}</Link>
|
||||
</Popconfirm>
|
||||
) : (
|
||||
<Popconfirm
|
||||
placement="left"
|
||||
title="Are you sure you want to use this scanner?"
|
||||
description="Users connected to this scanner will be disconnected"
|
||||
okText="Use"
|
||||
title={t("scanners.column.action.use.popconfirm.title")}
|
||||
description={t(
|
||||
"scanners.column.action.use.popconfirm.description"
|
||||
)}
|
||||
okText={t("scanners.column.action.use.popconfirm.okText")}
|
||||
cancelText={t("buttonCancel")}
|
||||
onConfirm={() => {
|
||||
webSocketContext.SendSocketMessage(
|
||||
SentMessagesCommands.ScannersUseScanners,
|
||||
|
@ -77,7 +85,7 @@ export default function Scanners() {
|
|||
);
|
||||
}}
|
||||
>
|
||||
<Link to="#">Use scanner</Link>
|
||||
<Link to="#">{t("scanners.column.action.use")}</Link>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
|
@ -121,7 +129,7 @@ export default function Scanners() {
|
|||
return (
|
||||
<>
|
||||
<h1 style={{ fontWeight: "bold", float: "left" }}>
|
||||
Scanners (
|
||||
{t("scanners.header.scanners")} (
|
||||
{webSocketContext.Scanners === null
|
||||
? "0"
|
||||
: webSocketContext.Scanners.length}
|
||||
|
@ -132,18 +140,3 @@ export default function Scanners() {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
<Popover
|
||||
title="Scan this on mobile"
|
||||
content={<QRCode value={"test"} bordered={false} />}
|
||||
>
|
||||
<Button
|
||||
style={{ float: "right" }}
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
Add scanner
|
||||
</Button>
|
||||
</Popover>
|
||||
*/
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Form,
|
||||
Input,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Upload,
|
||||
|
@ -22,30 +25,42 @@ import {
|
|||
isEmailValid,
|
||||
} from "../../utils";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const columns = [
|
||||
export default function UserProfile() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [repeatedNewPassword, setRepeatedNewPassword] = useState("");
|
||||
|
||||
const getTableColumns = () => {
|
||||
return [
|
||||
{
|
||||
title: "User-Agent",
|
||||
title: t("userProfile.column.userAgent"),
|
||||
dataIndex: "userAgent",
|
||||
key: "userAgent",
|
||||
},
|
||||
{
|
||||
title: "Connection status",
|
||||
title: t("userProfile.column.connectionStatus"),
|
||||
dataIndex: "connectionStatus",
|
||||
key: "connectionStatus",
|
||||
},
|
||||
{
|
||||
title: "Last used",
|
||||
title: t("userProfile.column.lastUsed"),
|
||||
dataIndex: "lastUsed",
|
||||
key: "lastUsed",
|
||||
},
|
||||
{
|
||||
title: "Expires at",
|
||||
title: t("userProfile.column.expiresAt"),
|
||||
dataIndex: "expiresAt",
|
||||
key: "expiresAt",
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
title: t("userProfile.column.action"),
|
||||
dataIndex: "action",
|
||||
key: "action",
|
||||
render: (_, record) => {
|
||||
|
@ -67,22 +82,14 @@ const columns = [
|
|||
});
|
||||
}}
|
||||
>
|
||||
Sign out
|
||||
{t("userProfile.column.action.signOut")}
|
||||
</Link>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default function UserProfile() {
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
||||
const [oldPassword, setOldPassword] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [repeatedNewPassword, setRepeatedNewPassword] = useState("");
|
||||
};
|
||||
|
||||
const getTableItems = () => {
|
||||
let items = [];
|
||||
|
@ -107,10 +114,11 @@ export default function UserProfile() {
|
|||
const beforeUpload = (file) => {
|
||||
if (file.size > Constants.MAX_AVATAR_SIZE) {
|
||||
notificationApi["error"]({
|
||||
message: `Your profile could not be changed`,
|
||||
description: `Avatar must be smaller than ${
|
||||
Constants.MAX_AVATAR_SIZE / 1024 / 1024
|
||||
} MB`,
|
||||
message: t("userProfile.changeAvatarError.notification.message"),
|
||||
description: t(
|
||||
"userProfile.changeAvatarError.notification.description",
|
||||
{ MAX_AVATAR_SIZE: Constants.MAX_AVATAR_SIZE / 1024 / 1024 }
|
||||
),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
@ -174,9 +182,14 @@ export default function UserProfile() {
|
|||
<>
|
||||
{notificationContextHolder}
|
||||
|
||||
<h1 style={{ fontWeight: "bold" }}>Your Profile</h1>
|
||||
<h1 style={{ fontWeight: "bold" }}>
|
||||
{t("userProfile.header.yourProfile")}
|
||||
</h1>
|
||||
|
||||
<Card>
|
||||
<Form layout="vertical">
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<Upload
|
||||
accept={Constants.ACCEPTED_FILE_TYPES.join(",")}
|
||||
action={Constants.API_ADDRESS + "/user/avatar"}
|
||||
|
@ -193,10 +206,31 @@ export default function UserProfile() {
|
|||
userId={webSocketContext.User.Id}
|
||||
/>
|
||||
</Upload>
|
||||
</Col>
|
||||
|
||||
<Col span={4} offset={16}>
|
||||
<Form.Item label={t("userProfile.form.language")}>
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
defaultValue={i18n.language}
|
||||
options={[
|
||||
{
|
||||
value: "en",
|
||||
label: "English",
|
||||
},
|
||||
{
|
||||
value: "de",
|
||||
label: "Deutsch",
|
||||
},
|
||||
]}
|
||||
onChange={(e) => i18n.changeLanguage(e)}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form layout="vertical">
|
||||
<Form.Item
|
||||
label="Username"
|
||||
label={t("userProfile.form.username")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
webSocketContext.UserProfileStateUsername.length <
|
||||
|
@ -213,7 +247,7 @@ export default function UserProfile() {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="E-Mail"
|
||||
label={t("userProfile.form.email")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
!isEmailValid(webSocketContext.UserProfileStateEmail) && "error"
|
||||
|
@ -228,7 +262,7 @@ export default function UserProfile() {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Old password"
|
||||
label={t("userProfile.form.oldPassword")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
oldPassword !== "" &&
|
||||
|
@ -244,7 +278,7 @@ export default function UserProfile() {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="New password"
|
||||
label={t("userProfile.form.newPassword")}
|
||||
hasFeedback
|
||||
validateStatus={
|
||||
newPassword !== "" &&
|
||||
|
@ -260,7 +294,7 @@ export default function UserProfile() {
|
|||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Repeat new password"
|
||||
label={t("userProfile.form.repeatNewPassword")}
|
||||
hasFeedback
|
||||
validateStatus={newPassword !== repeatedNewPassword && "error"}
|
||||
>
|
||||
|
@ -278,7 +312,7 @@ export default function UserProfile() {
|
|||
onClick={() => handleOnSubmit()}
|
||||
disabled={isButtonDisabled()}
|
||||
>
|
||||
Save
|
||||
{t("buttonSave")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
@ -287,10 +321,11 @@ export default function UserProfile() {
|
|||
<br />
|
||||
|
||||
<h1 style={{ fontWeight: "bold" }}>
|
||||
Your Sessions ({webSocketContext.User.Sessions.length})
|
||||
{t("userProfile.header.yourSessions")} (
|
||||
{webSocketContext.User.Sessions.length})
|
||||
</h1>
|
||||
|
||||
<Table columns={columns} dataSource={getTableItems()} />
|
||||
<Table columns={getTableColumns()} dataSource={getTableItems()} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
|
||||
// the translations
|
||||
// (tip move them in a JSON file and import them,
|
||||
// or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files)
|
||||
|
||||
i18n
|
||||
.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.use(LanguageDetector)
|
||||
.use(Backend)
|
||||
.init({
|
||||
debug: true,
|
||||
fallbackLng: "en",
|
||||
interpolation: {
|
||||
escapeValue: false, // react already safes from xss
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
|
@ -3,13 +3,16 @@ import ReactDOM from "react-dom/client";
|
|||
import "./index.css";
|
||||
import App from "./App";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import "./i18n";
|
||||
//import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
root.render(
|
||||
<React.Suspense fallback="loading">
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</React.Suspense>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
|
Loading…
Reference in New Issue