diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_de_DE.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_de_DE.json new file mode 100644 index 000000000000..9248c36119a3 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_de_DE.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Zugriffszertifikate", + "key_management_service_credential_identities": "Identitäten", + "key_management_service_credential_not_authorized": "Sie sind nicht berechtigt, auf diese Informationen zuzugreifen. Bitte wenden Sie sich an Ihren Administrator.", + "key_management_service_credential_create_title": "Zugriffszertifikat erstellen", + "key_management_service_credential_create_subtitle": "Erstellen Sie die Zugriffszertifikate, mit denen die Identitäten Ihrer Wahl auf Ihren KMS zugreifen können. Die Rechte für diese Identitäten müssen in einer IAM-Richtlinie konfiguriert werden.", + "key_management_service_credential_dashboard_tab_informations": "Informationen", + "key_management_service_credential_dashboard_tab_identities": "Identitäten", + "key_management_service_credential_headline": "Erstellen und verwalten Sie die Zugriffszertifikate, mit denen die Identitäten Ihrer Wahl auf Ihren KMS zugreifen können.", + "key_management_service_credential_cta_create": "Zugriffszertifikat erstellen", + "key_management_service_credential_status_creating": "Wird erstellt", + "key_management_service_credential_status_deleting": "Wird gelöscht", + "key_management_service_credential_status_error": "Fehler", + "key_management_service_credential_status_expired": "Abgelaufen", + "key_management_service_credential_status_ready": "Bereit", + "key_management_service_credential_list_column_name": "Name", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "Anzahl der Identitäten", + "key_management_service_credential_list_column_creation_date": "Erstellungsdatum", + "key_management_service_credential_list_column_expiration_date": "Ablaufdatum", + "key_management_service_credential_list_column_status": "Status", + "key_management_service_credential_create_general_information_title": "Allgemeine Informationen", + "key_management_service_credential_create_general_information_display_name_title": "Anzeigename", + "key_management_service_credential_create_general_information_display_name_subtitle": "Dieser Name wird verwendet, um die Identifizierung zu erleichtern.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Beschreibung (optional)", + "key_management_service_credential_create_general_information_validity_title": "Gültigkeit", + "key_management_service_credential_create_general_information_validity_subtitle": "Das Zertifikat wird am Ende der Gültigkeitsdauer automatisch deaktiviert.", + "key_management_service_credential_create_general_creation_method_title": "Erstellungsmethode", + "key_management_service_credential_create_general_information_creation_method_subtitle": "Die Erstellung des Zugriffszertifikats erfordert einen privaten Schlüssel.", + "key_management_service_credential_create_general_information_creation_method_no_key": "Ich habe keinen privaten Schlüssel.", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Das Zugriffszertifikat und der private Schlüssel werden von OVHcloud generiert.", + "key_management_service_credential_create_general_information_creation_method_key": "Ich habe bereits einen privaten Schlüssel.", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Certificate Signing Request (CSR) einreichen", + "key_management_service_credential_update_custom_csr_error_required": "Geben Sie dien Inhalt Ihrer CSR ein, um Identitäten hinzuzufügen.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Inhalt der CSR", + "key_management_service_credential_create_cta_cancel": "Abbrechen", + "key_management_service_credential_create_cta_add_identities": "Identitäten hinzufügen", + "key_management_service_credential_create_general_validity_period_day": "1 Tag", + "key_management_service_credential_create_general_validity_period_week": "1 Woche", + "key_management_service_credential_create_general_validity_period_month": "1 Monat", + "key_management_service_credential_create_general_validity_period_3months": "3 Monate", + "key_management_service_credential_create_general_validity_period_6months": "6 Monate", + "key_management_service_credential_create_general_validity_period_year": "1 Jahr", + "key_management_service_credential_create_general_validity_period_custom": "Personalisiert", + "key_management_service_credential_update_name_error_required": "Der Name muss zwischen 1 und 50 Zeichen lang sein.", + "key_management_service_credential_update_name_error_invalid_characters": "Ihre Eingabe ist ungültig.", + "key_management_service_credential_update_name_error_max": "Die zulässige Anzahl von Zeichen wurde überschritten. (maximal 50 Zeichen)", + "key_management_service_credential_update_description_error_invalid_characters": "Ihre Eingabe ist ungültig.", + "key_management_service_credential_update_description_error_max": "Die zulässige Anzahl von Zeichen wurde überschritten. (maximal 200 Zeichen)", + "key_management_service_credential_update_validity_error_min_period": "Die Mindestgültigkeitsdauer beträgt 1 Tag.", + "key_management_service_credential_update_validity_error_max_period": "Die maximale Gültigkeitsdauer beträgt 365 Tage.", + "key_management_service_credential_create_validity_custom_date_label": "Enddatum", + "key_management_service_credential_dashboard_backlink": "Zurück zur Zertifikatsliste", + "key_management_service_credential_dashboard_tile_general_informations": "Allgemeine Informationen", + "key_management_service_credential_dashboard_name": "Anzeigename", + "key_management_service_credential_dashboard_id": "Zugriffszertifikat-ID", + "key_management_service_credential_dashboard_description": "Beschreibung", + "key_management_service_credential_dashboard_status": "Status", + "key_management_service_credential_dashboard_creation": "Erstellungsdatum und -methode", + "key_management_service_credential_dashboard_expiration": "Ablaufdatum", + "key_management_service_credential_dashboard_actions": "Aktionen", + "key_management_service_credential_created_with_csr": "mit CSR erstellt", + "key_management_service_credential_created_without_csr": "ohne CSR erstellt", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "OVHcloud Accounts", + "key_management_service_credential_identities_account_column_account": "OVHcloud Account", + "key_management_service_credential_identities_user_title": "User", + "key_management_service_credential_identities_user_column_id": "Kennung", + "key_management_service_credential_identities_usergroup_title": "Nutzergruppen", + "key_management_service_credential_identities_usergroup_column_name": "Name", + "key_management_service_credential_identities_service_account_title": "Dienstkonten", + "key_management_service_credential_identities_service_account_column_id": "Kennung", + "key_management_service_credential_create_identities_title": "Identitäten hinzufügen", + "key_management_service_credential_create_identities_root_account_toggle_label": "Stammidentität des Accounts hinzufügen", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Die Zugriffsrechte werden nicht durch das IAM eingeschränkt.", + "key_management_service_credential_create_identities_max_label": "Die Gesamtzahl der Identitäten ist auf 25 beschränkt.", + "key_management_service_credential_create_identities_users_list_title": "User", + "key_management_service_credential_create_identities_users_list_button_add_label": "Nutzer hinzufügen", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Alles löschen", + "key_management_service_credential_identity_status_ok": "Aktiv", + "key_management_service_credential_identity_status_disabled": "Inaktiv", + "key_management_service_credential_identity_status_password_change_required": "Änderung des Passworts erforderlich", + "key_management_service_credential_user_list_column_name": "Name", + "key_management_service_credential_user_list_column_group": "Gruppe", + "key_management_service_credential_user_list_column_status": "Status", + "key_management_service_credential_create_identities_users_groups_title": "Nutzergruppen", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Nutzergruppen hinzufügen", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Alles löschen", + "key_management_service_credential_user_list_column_description": "Beschreibung", + "key_management_service_credential_create_identities_service_accounts_title": "Dienstkonto", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Dienstkonten hinzufügen", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Alles löschen", + "key_management_service_credential_create_identities_button_cancel_label": "Abbrechen", + "key_management_service_credential_create_identities_button_back_label": "Zurück", + "key_management_service_credential_create_identities_button_create_label": "Zugriffszertifikat erstellen", + "key_management_service_credentials_identity_modal_user_list_headline": "Nutzer hinzufügen", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Nach Name oder E-Mail suchen", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Nach Name suchen", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Nach Name oder Beschreibung suchen", + "key_management_service_credentials_identity_modal_user_list_cancel": "Abbrechen", + "key_management_service_credentials_identity_modal_user_list_add": "Hinzufügen", + "key_management_service_credentials_identity_modal_group_list_headline": "Gruppen hinzufügen", + "key_management_service_credentials_identity_modal_group_list_cancel": "Abbrechen", + "key_management_service_credentials_identity_modal_group_list_add": "Hinzufügen", + "key_management_service_credential_create_identities_list_button_no_result_label": "Keine Ergebnisse", + "key_management_service_credential_create_identities_group_tile_description_label": "Beschreibung", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identität", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Beschreibung", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identität", + "key_management_service_credential_create_identities_user_tile_email_label": "E-Mail", + "key_management_service_credential_create_identities_user_tile_group_label": "Gruppe", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identität", + "key_management_service_credential_create_success": "Ihr Zertifikat wird erstellt. Sie können den öffentlichen Schlüssel in einigen Minuten auf der Seite „Zugriffszertifikat“ Ihres KMS herunterladen.", + "key_management_service_credential_create_error": "Bei der Erstellung des Zertifikats sind Fehler aufgetreten.", + "key_management_service_credential_create_confirmation_details_title": "Zugriffszertifikat", + "key_management_service_credential_create_confirmation_details_id_label": "Zertifikat-ID", + "key_management_service_credential_create_confirmation_details_display-name_label": "Anzeigename", + "key_management_service_credential_create_confirmation_details_description_label": "Beschreibung", + "key_management_service_credential_create_confirmation_details_validity_label": "Gültigkeit", + "key_management_service_credential_create_confirmation_private-key_title": "Privater Schlüssel", + "key_management_service_credential_create_confirmation_private-key_warn": "Nach dem Beenden des Erstellungsassistenten haben Sie keinen Zugriff mehr auf diesen privaten Schlüssel. Denken Sie daran, diesen herunterzuladen und sicher zu speichern.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Privaten Schlüssel herunterladen", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Ich bestätige, dass ich den privaten Schlüssel heruntergeladen habe.", + "key_management_service_credential_create_confirmation_button_done_label": "Beenden", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} Tage", + "key_management_service_credential_download": "Herunterladen", + "key_management_service_credential_delete": "Löschen", + "key_management_service_credential_delete_modal_headline": "Mein Zertifikat löschen", + "key_management_service_credential_delete_modal_input_label": "Bitte geben Sie das Wort „TERMINATE“ ein, um die Löschung Ihres Zertifikats zu bestätigen.", + "key_management_service_credential_delete_success": "Das Zertifikat wurde erfolgreich gelöscht.", + "key_management_service_credential_delete_error": "Beim Löschen Ihres Zertifikats sind Fehler aufgetreten. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_en_GB.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_en_GB.json new file mode 100644 index 000000000000..72a925bec314 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_en_GB.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Access certificates", + "key_management_service_credential_identities": "User IDs", + "key_management_service_credential_not_authorized": "You don’t have the necessary permissions to access this information, please contact your administrator.", + "key_management_service_credential_create_title": "Generate an access certificate", + "key_management_service_credential_create_subtitle": "Generate access certificates to authorise selected user IDs to access your KMS. You need to configure an IAM policy to grant permissions to these user IDs.", + "key_management_service_credential_dashboard_tab_informations": "Information", + "key_management_service_credential_dashboard_tab_identities": "User IDs", + "key_management_service_credential_headline": "Generate and manage access certificates to grant selected user IDs access to your KMS.", + "key_management_service_credential_cta_create": "Generate an access certificate", + "key_management_service_credential_status_creating": "Creating...", + "key_management_service_credential_status_deleting": "Deleting...", + "key_management_service_credential_status_error": "Error", + "key_management_service_credential_status_expired": "Expired", + "key_management_service_credential_status_ready": "Ready", + "key_management_service_credential_list_column_name": "Name", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "No. of user IDs", + "key_management_service_credential_list_column_creation_date": "Created on", + "key_management_service_credential_list_column_expiration_date": "Expiry date", + "key_management_service_credential_list_column_status": "Status", + "key_management_service_credential_create_general_information_title": "General information", + "key_management_service_credential_create_general_information_display_name_title": "Display name", + "key_management_service_credential_create_general_information_display_name_subtitle": "This name will be used for easy identification.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Description (optional)", + "key_management_service_credential_create_general_information_validity_title": "Validity", + "key_management_service_credential_create_general_information_validity_subtitle": "The certificate is automatically disabled at the end of the validity period", + "key_management_service_credential_create_general_creation_method_title": "Certificate generation method", + "key_management_service_credential_create_general_information_creation_method_subtitle": "You need a private key to generate an access certificate", + "key_management_service_credential_create_general_information_creation_method_no_key": "I don’t have a private key", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Access certificate and private key are generated by OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "I already have a private key", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Submit a Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Please enter the content of your CSR to add user IDs.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request", + "key_management_service_credential_create_general_information_csr_subtitle": "CSR content", + "key_management_service_credential_create_cta_cancel": "Cancel", + "key_management_service_credential_create_cta_add_identities": "Add user IDs", + "key_management_service_credential_create_general_validity_period_day": "1 day", + "key_management_service_credential_create_general_validity_period_week": "1 week", + "key_management_service_credential_create_general_validity_period_month": "1 month", + "key_management_service_credential_create_general_validity_period_3months": "3 months", + "key_management_service_credential_create_general_validity_period_6months": "6 months", + "key_management_service_credential_create_general_validity_period_year": "1 year", + "key_management_service_credential_create_general_validity_period_custom": "Custom", + "key_management_service_credential_update_name_error_required": "The name must be between 1 and 50 characters long.", + "key_management_service_credential_update_name_error_invalid_characters": "Your input is not valid.", + "key_management_service_credential_update_name_error_max": "The maximum number of characters has been exceeded. (50 characters maximum)", + "key_management_service_credential_update_description_error_invalid_characters": "Your input is not valid.", + "key_management_service_credential_update_description_error_max": "The maximum number of characters has been exceeded. (200 characters maximum)", + "key_management_service_credential_update_validity_error_min_period": "The minimum validity period is 1 day.", + "key_management_service_credential_update_validity_error_max_period": "The maximum validity period is 365 days.", + "key_management_service_credential_create_validity_custom_date_label": "End date ", + "key_management_service_credential_dashboard_backlink": "Back to certificate list", + "key_management_service_credential_dashboard_tile_general_informations": "General information", + "key_management_service_credential_dashboard_name": "Display name", + "key_management_service_credential_dashboard_id": "Access certificate ID", + "key_management_service_credential_dashboard_description": "Description", + "key_management_service_credential_dashboard_status": "Status", + "key_management_service_credential_dashboard_creation": "Creation method and date", + "key_management_service_credential_dashboard_expiration": "Expiry", + "key_management_service_credential_dashboard_actions": "Actions", + "key_management_service_credential_created_with_csr": "created with CSR", + "key_management_service_credential_created_without_csr": "created without CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "OVHcloud accounts", + "key_management_service_credential_identities_account_column_account": "OVHcloud account", + "key_management_service_credential_identities_user_title": "Users", + "key_management_service_credential_identities_user_column_id": "Login", + "key_management_service_credential_identities_usergroup_title": "User groups", + "key_management_service_credential_identities_usergroup_column_name": "Name", + "key_management_service_credential_identities_service_account_title": "Service accounts", + "key_management_service_credential_identities_service_account_column_id": "Login", + "key_management_service_credential_create_identities_title": "Add user IDs", + "key_management_service_credential_create_identities_root_account_toggle_label": "Add account root identity", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Access rights will not be restricted by IAM", + "key_management_service_credential_create_identities_max_label": "Max limit: 25 users", + "key_management_service_credential_create_identities_users_list_title": "Users", + "key_management_service_credential_create_identities_users_list_button_add_label": "Add users", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Delete all", + "key_management_service_credential_identity_status_ok": "Active", + "key_management_service_credential_identity_status_disabled": "Disabled", + "key_management_service_credential_identity_status_password_change_required": "Password change required", + "key_management_service_credential_user_list_column_name": "Name", + "key_management_service_credential_user_list_column_group": "Group", + "key_management_service_credential_user_list_column_status": "Status", + "key_management_service_credential_create_identities_users_groups_title": "User groups", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Add user groups", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Delete all", + "key_management_service_credential_user_list_column_description": "Description", + "key_management_service_credential_create_identities_service_accounts_title": "Service account", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Add service accounts", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Delete all", + "key_management_service_credential_create_identities_button_cancel_label": "Cancel", + "key_management_service_credential_create_identities_button_back_label": "Previous", + "key_management_service_credential_create_identities_button_create_label": "Generate access certificate", + "key_management_service_credentials_identity_modal_user_list_headline": "Add users", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Search by name or email", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Search by name", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Search by name or description", + "key_management_service_credentials_identity_modal_user_list_cancel": "Cancel", + "key_management_service_credentials_identity_modal_user_list_add": "Add", + "key_management_service_credentials_identity_modal_group_list_headline": "Add groups", + "key_management_service_credentials_identity_modal_group_list_cancel": "Cancel", + "key_management_service_credentials_identity_modal_group_list_add": "Add", + "key_management_service_credential_create_identities_list_button_no_result_label": "No results", + "key_management_service_credential_create_identities_group_tile_description_label": "Description", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identity", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Description", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identity", + "key_management_service_credential_create_identities_user_tile_email_label": "Email address", + "key_management_service_credential_create_identities_user_tile_group_label": "Group", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identity", + "key_management_service_credential_create_success": "Generating certificate... You can download the public key from the KMS “Access certificate” page in just a few minutes.", + "key_management_service_credential_create_error": "An error has occurred generating certificate.", + "key_management_service_credential_create_confirmation_details_title": "Access certificate", + "key_management_service_credential_create_confirmation_details_id_label": "Certificate ID", + "key_management_service_credential_create_confirmation_details_display-name_label": "Display name", + "key_management_service_credential_create_confirmation_details_description_label": "Description", + "key_management_service_credential_create_confirmation_details_validity_label": "Validity", + "key_management_service_credential_create_confirmation_private-key_title": "Private key", + "key_management_service_credential_create_confirmation_private-key_warn": "Once you exit the creation wizard, you will lose access to this private key. Make sure you download and securely store it.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Download private key", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "I have downloaded the private key", + "key_management_service_credential_create_confirmation_button_done_label": "Finish", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} days", + "key_management_service_credential_download": "Download", + "key_management_service_credential_delete": "Delete", + "key_management_service_credential_delete_modal_headline": "Delete my certificate", + "key_management_service_credential_delete_modal_input_label": "Please enter the word “TERMINATE” to confirm the deletion of your certificate", + "key_management_service_credential_delete_success": "The certificate has been deleted", + "key_management_service_credential_delete_error": "An error has occurred deleting certificate. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_es_ES.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_es_ES.json new file mode 100644 index 000000000000..2a9614e76b65 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_es_ES.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certificados de acceso", + "key_management_service_credential_identities": "Identidades", + "key_management_service_credential_not_authorized": "Si no dispone de los permisos necesarios para acceder a esta información, póngase en contacto con su administrador.", + "key_management_service_credential_create_title": "Crear un certificado de acceso", + "key_management_service_credential_create_subtitle": "Cree los certificados de acceso necesarios para que las identidades que usted elija puedan acceder a su KMS. Los derechos de estas identidades deben configurarse en una política IAM.", + "key_management_service_credential_dashboard_tab_informations": "Información", + "key_management_service_credential_dashboard_tab_identities": "Identidades", + "key_management_service_credential_headline": "Cree y gestione los certificados de acceso necesarios para que las identidades que usted elija puedan acceder a su KMS.", + "key_management_service_credential_cta_create": "Crear un certificado de acceso", + "key_management_service_credential_status_creating": "Creando...", + "key_management_service_credential_status_deleting": "Eliminando...", + "key_management_service_credential_status_error": "Error", + "key_management_service_credential_status_expired": "Expirado", + "key_management_service_credential_status_ready": "Listo", + "key_management_service_credential_list_column_name": "Nombre", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "Nº de identidades", + "key_management_service_credential_list_column_creation_date": "Fecha de creación", + "key_management_service_credential_list_column_expiration_date": "Fecha de expiración", + "key_management_service_credential_list_column_status": "Estado", + "key_management_service_credential_create_general_information_title": "Información general", + "key_management_service_credential_create_general_information_display_name_title": "Nombre mostrado", + "key_management_service_credential_create_general_information_display_name_subtitle": "Este nombre se utilizará para facilitar su identificación.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Descripción (opcional)", + "key_management_service_credential_create_general_information_validity_title": "Validez", + "key_management_service_credential_create_general_information_validity_subtitle": "El certificado se desactivará automáticamente al final del período de validez", + "key_management_service_credential_create_general_creation_method_title": "Método de creación", + "key_management_service_credential_create_general_information_creation_method_subtitle": "La creación del certificado de acceso requiere una clave privada", + "key_management_service_credential_create_general_information_creation_method_no_key": "No tengo clave privada", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "OVHcloud generará el certificado de acceso y la clave privada.", + "key_management_service_credential_create_general_information_creation_method_key": "Ya tengo una clave privada", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Enviar una solicitud de firma de certificados (CSR en inglés)", + "key_management_service_credential_update_custom_csr_error_required": "Introduzca el contenido de su CSR para añadir identidades.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Contenido de la CSR", + "key_management_service_credential_create_cta_cancel": "Cancelar", + "key_management_service_credential_create_cta_add_identities": "Añadir identidades", + "key_management_service_credential_create_general_validity_period_day": "1 día", + "key_management_service_credential_create_general_validity_period_week": "1 semana", + "key_management_service_credential_create_general_validity_period_month": "1 mes", + "key_management_service_credential_create_general_validity_period_3months": "3 meses", + "key_management_service_credential_create_general_validity_period_6months": "6 meses", + "key_management_service_credential_create_general_validity_period_year": "1 año", + "key_management_service_credential_create_general_validity_period_custom": "Personalizado", + "key_management_service_credential_update_name_error_required": "El nombre debe tener entre 1 y 50 caracteres.", + "key_management_service_credential_update_name_error_invalid_characters": "El texto introducido no es válido.", + "key_management_service_credential_update_name_error_max": "El nombre supera el número de caracteres permitido. (50 caracteres máximo)", + "key_management_service_credential_update_description_error_invalid_characters": "El texto introducido no es válido.", + "key_management_service_credential_update_description_error_max": "El nombre supera el número de caracteres permitido. (200 caracteres máximo)", + "key_management_service_credential_update_validity_error_min_period": "La validez mínima es de 1 día.", + "key_management_service_credential_update_validity_error_max_period": "La validez máxima es de 365 días.", + "key_management_service_credential_create_validity_custom_date_label": "Fecha de finalización", + "key_management_service_credential_dashboard_backlink": "Volver a la lista de certificados", + "key_management_service_credential_dashboard_tile_general_informations": "Información general", + "key_management_service_credential_dashboard_name": "Nombre mostrado", + "key_management_service_credential_dashboard_id": "Id. de certificado de acceso", + "key_management_service_credential_dashboard_description": "Descripción", + "key_management_service_credential_dashboard_status": "Estado", + "key_management_service_credential_dashboard_creation": "Método y fecha de creación", + "key_management_service_credential_dashboard_expiration": "Expiración", + "key_management_service_credential_dashboard_actions": "Acciones", + "key_management_service_credential_created_with_csr": "creado con CSR", + "key_management_service_credential_created_without_csr": "creado sin CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Cuentas OVHcloud", + "key_management_service_credential_identities_account_column_account": "Cuenta OVHcloud", + "key_management_service_credential_identities_user_title": "Usuarios", + "key_management_service_credential_identities_user_column_id": "Identificador", + "key_management_service_credential_identities_usergroup_title": "Grupos de usuarios", + "key_management_service_credential_identities_usergroup_column_name": "Nombre", + "key_management_service_credential_identities_service_account_title": "Cuentas de servicio", + "key_management_service_credential_identities_service_account_column_id": "Identificador", + "key_management_service_credential_create_identities_title": "Añadir identidades", + "key_management_service_credential_create_identities_root_account_toggle_label": "Añadir la identidad raíz de la cuenta", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Los derechos de acceso no estarán restringidos por el IAM", + "key_management_service_credential_create_identities_max_label": "El número total de identidades está limitado a 25.", + "key_management_service_credential_create_identities_users_list_title": "Usuarios", + "key_management_service_credential_create_identities_users_list_button_add_label": "Añadir usuarios", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Eliminar todo", + "key_management_service_credential_identity_status_ok": "Activo", + "key_management_service_credential_identity_status_disabled": "Inactivo", + "key_management_service_credential_identity_status_password_change_required": "Es necesario cambiar la contraseña", + "key_management_service_credential_user_list_column_name": "Nombre", + "key_management_service_credential_user_list_column_group": "Grupo", + "key_management_service_credential_user_list_column_status": "Estado", + "key_management_service_credential_create_identities_users_groups_title": "Grupos de usuarios", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Añadir grupos de usuarios", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Eliminar todo", + "key_management_service_credential_user_list_column_description": "Descripción", + "key_management_service_credential_create_identities_service_accounts_title": "Cuenta de servicios", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Añadir cuentas de servicio", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Eliminar todo", + "key_management_service_credential_create_identities_button_cancel_label": "Cancelar", + "key_management_service_credential_create_identities_button_back_label": "Anterior", + "key_management_service_credential_create_identities_button_create_label": "Crear el certificado de acceso", + "key_management_service_credentials_identity_modal_user_list_headline": "Añadir usuarios", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Buscar por nombre o correo electrónico", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Buscar por nombre", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Buscar por nombre o descripción", + "key_management_service_credentials_identity_modal_user_list_cancel": "Cancelar", + "key_management_service_credentials_identity_modal_user_list_add": "Añadir", + "key_management_service_credentials_identity_modal_group_list_headline": "Añadir grupos", + "key_management_service_credentials_identity_modal_group_list_cancel": "Cancelar", + "key_management_service_credentials_identity_modal_group_list_add": "Añadir", + "key_management_service_credential_create_identities_list_button_no_result_label": "Sin resultados", + "key_management_service_credential_create_identities_group_tile_description_label": "Descripción", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identidad", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Descripción", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identidad", + "key_management_service_credential_create_identities_user_tile_email_label": "Email", + "key_management_service_credential_create_identities_user_tile_group_label": "Grupo", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identidad", + "key_management_service_credential_create_success": "Creando el certificado... En unos minutos podrá descargar la clave pública desde la página «Certificado de acceso» del KMS.", + "key_management_service_credential_create_error": "Se han producido errores al crear el certificado.", + "key_management_service_credential_create_confirmation_details_title": "Certificado de acceso", + "key_management_service_credential_create_confirmation_details_id_label": "Id. de certificado", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nombre mostrado", + "key_management_service_credential_create_confirmation_details_description_label": "Descripción", + "key_management_service_credential_create_confirmation_details_validity_label": "Validez", + "key_management_service_credential_create_confirmation_private-key_title": "Clave privada", + "key_management_service_credential_create_confirmation_private-key_warn": "Cuando salga del asistente de creación, ya no tendrá acceso a esta clave privada. Asegúrese de descargarla y almacenarla de forma segura.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Descargar la clave privada", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Confirmo que he descargado la clave privada", + "key_management_service_credential_create_confirmation_button_done_label": "Finalizar", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} días", + "key_management_service_credential_download": "Descargar", + "key_management_service_credential_delete": "Eliminar", + "key_management_service_credential_delete_modal_headline": "Eliminar mi certificado", + "key_management_service_credential_delete_modal_input_label": "Introduzca la palabra «TERMINATE» para confirmar la eliminación del certificado", + "key_management_service_credential_delete_success": "El certificado se ha eliminado correctamente", + "key_management_service_credential_delete_error": "Se han producido errores al eliminar el certificado. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_CA.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_CA.json new file mode 100644 index 000000000000..1c7943bafe55 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_CA.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certificats d'accès", + "key_management_service_credential_identities": "identités", + "key_management_service_credential_not_authorized": "Vous ne disposez pas des permissions nécessaires pour accéder à cette information, veuillez contacter votre administrateur.", + "key_management_service_credential_create_title": "Créer un certificat d’accès", + "key_management_service_credential_create_subtitle": "Créez les certificats d’accès qui permettront aux identités de votre choix d’accéder à votre KMS. Les droits de ces identités doivent être configurés dans une politique IAM.", + "key_management_service_credential_dashboard_tab_informations": "Informations", + "key_management_service_credential_dashboard_tab_identities": "Identités", + "key_management_service_credential_headline": "Créez et gérez les certificats d’accès qui permettront aux identités de votre choix d’accéder à votre KMS.", + "key_management_service_credential_cta_create": "Créer un certificat d'accès", + "key_management_service_credential_status_creating": "Création en cours", + "key_management_service_credential_status_deleting": "Suppression en cours", + "key_management_service_credential_status_error": "Erreur", + "key_management_service_credential_status_expired": "Expiré", + "key_management_service_credential_status_ready": "Prêt", + "key_management_service_credential_list_column_name": "Nom", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "Nb d'identités", + "key_management_service_credential_list_column_creation_date": "Date de création", + "key_management_service_credential_list_column_expiration_date": "Date d'expiration", + "key_management_service_credential_list_column_status": "Statut", + "key_management_service_credential_create_general_information_title": "Informations générales", + "key_management_service_credential_create_general_information_display_name_title": "Nom d'affichage", + "key_management_service_credential_create_general_information_display_name_subtitle": "Ce nom sera utilisé pour faciliter son identification.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Description (optionnelle)", + "key_management_service_credential_create_general_information_validity_title": "Validité", + "key_management_service_credential_create_general_information_validity_subtitle": "Le certificat sera automatiquement désactivé à la fin de la période de validité", + "key_management_service_credential_create_general_creation_method_title": "Méthode de création", + "key_management_service_credential_create_general_information_creation_method_subtitle": "La création du certificat d'accès nécessite une clé privée", + "key_management_service_credential_create_general_information_creation_method_no_key": "Je n’ai pas de clé privée", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Le certificat d’accès et la clé privée seront générés par OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "J'ai déjà une clé privée", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Soumettre une Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Veuillez renseigner le contenu de votre CSR afin d'ajouter des identités.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Contenu de la CSR", + "key_management_service_credential_create_cta_cancel": "Annuler", + "key_management_service_credential_create_cta_add_identities": "Ajouter des identités", + "key_management_service_credential_create_general_validity_period_day": "1 jour", + "key_management_service_credential_create_general_validity_period_week": "1 semaine", + "key_management_service_credential_create_general_validity_period_month": "1 mois", + "key_management_service_credential_create_general_validity_period_3months": "3 mois", + "key_management_service_credential_create_general_validity_period_6months": "6 mois", + "key_management_service_credential_create_general_validity_period_year": "1 an", + "key_management_service_credential_create_general_validity_period_custom": "Personnalisé", + "key_management_service_credential_update_name_error_required": "Le nom doit comporter entre 1 et 50 caractères.", + "key_management_service_credential_update_name_error_invalid_characters": "Votre saisie n'est pas valide.", + "key_management_service_credential_update_name_error_max": "Le nombre de caractères autorisé est dépassé. (50 caractères maximum)", + "key_management_service_credential_update_description_error_invalid_characters": "Votre saisie n'est pas valide.", + "key_management_service_credential_update_description_error_max": "Le nombre de caractères autorisé est dépassé. (200 caractères maximum)", + "key_management_service_credential_update_validity_error_min_period": "La durée de validité minimale est de 1 jour.", + "key_management_service_credential_update_validity_error_max_period": "La durée de validité maximale est de 365 jours.", + "key_management_service_credential_create_validity_custom_date_label": "Date de fin", + "key_management_service_credential_dashboard_backlink": "Retour à la liste des certificats", + "key_management_service_credential_dashboard_tile_general_informations": "Informations générales", + "key_management_service_credential_dashboard_name": "Nom d'affichage", + "key_management_service_credential_dashboard_id": "ID du certificat d'accès", + "key_management_service_credential_dashboard_description": "Description", + "key_management_service_credential_dashboard_status": "Statut", + "key_management_service_credential_dashboard_creation": "Méthode et date de création", + "key_management_service_credential_dashboard_expiration": "Expiration", + "key_management_service_credential_dashboard_actions": "Actions", + "key_management_service_credential_created_with_csr": "créé avec CSR", + "key_management_service_credential_created_without_csr": "créé sans CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Comptes OVH", + "key_management_service_credential_identities_account_column_account": "Compte OVH", + "key_management_service_credential_identities_user_title": "Utilisateurs", + "key_management_service_credential_identities_user_column_id": "Identifiant", + "key_management_service_credential_identities_usergroup_title": "Groupes d'utilisateur", + "key_management_service_credential_identities_usergroup_column_name": "Nom", + "key_management_service_credential_identities_service_account_title": "Comptes de service", + "key_management_service_credential_identities_service_account_column_id": "Identifiant", + "key_management_service_credential_create_identities_title": "Ajouter des identités", + "key_management_service_credential_create_identities_root_account_toggle_label": "Ajouter l'identité racine du compte", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Les droits d'accès ne seront pas restreints par l'IAM", + "key_management_service_credential_create_identities_max_label": "Le nombre total d'identités est limité à 25.", + "key_management_service_credential_create_identities_users_list_title": "Utilisateurs", + "key_management_service_credential_create_identities_users_list_button_add_label": "Ajouter des utilisateurs", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_identity_status_ok": "Actif", + "key_management_service_credential_identity_status_disabled": "Inactif", + "key_management_service_credential_identity_status_password_change_required": "Changement de mot de passe requis", + "key_management_service_credential_user_list_column_name": "Nom", + "key_management_service_credential_user_list_column_group": "Groupe", + "key_management_service_credential_user_list_column_status": "Statut", + "key_management_service_credential_create_identities_users_groups_title": "Groupes d'utilisateurs", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Ajouter des groupes d'utilisateurs", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_user_list_column_description": "Description", + "key_management_service_credential_create_identities_service_accounts_title": "Compte de services", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Ajouter des comptes de services", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_create_identities_button_cancel_label": "Annuler", + "key_management_service_credential_create_identities_button_back_label": "Précédent", + "key_management_service_credential_create_identities_button_create_label": "Créer le certificat d'accès", + "key_management_service_credentials_identity_modal_user_list_headline": "Ajouter des utilisateurs", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Rechercher par nom ou e-mail", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Rechercher par nom", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Rechercher par nom ou description", + "key_management_service_credentials_identity_modal_user_list_cancel": "Annuler", + "key_management_service_credentials_identity_modal_user_list_add": "Ajouter", + "key_management_service_credentials_identity_modal_group_list_headline": "Ajouter des groupes", + "key_management_service_credentials_identity_modal_group_list_cancel": "Annuler", + "key_management_service_credentials_identity_modal_group_list_add": "Ajouter", + "key_management_service_credential_create_identities_list_button_no_result_label": "Pas de résultats", + "key_management_service_credential_create_identities_group_tile_description_label": "Description", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identité", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Description", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identité", + "key_management_service_credential_create_identities_user_tile_email_label": "E-mail", + "key_management_service_credential_create_identities_user_tile_group_label": "Groupe", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identité", + "key_management_service_credential_create_success": "La création de votre certificat est en cours. Vous pourrez télécharger la clé publique depuis la page “Certificat d’accès” de votre KMS dans quelques minutes.", + "key_management_service_credential_create_error": "La création de votre certificat a rencontré des erreurs.", + "key_management_service_credential_create_confirmation_details_title": "Certificat d’accès", + "key_management_service_credential_create_confirmation_details_id_label": "ID du certificat", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nom d’affichage", + "key_management_service_credential_create_confirmation_details_description_label": "Description", + "key_management_service_credential_create_confirmation_details_validity_label": "Validité", + "key_management_service_credential_create_confirmation_private-key_title": "Clé privée", + "key_management_service_credential_create_confirmation_private-key_warn": "Vous n’aurez plus accès à cette clé privée lorsque vous quitterez l’assistant de création. Veillez à la télécharger et à la stocker de manière sécurisée.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Télécharger la clé privée", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Je confirme avoir téléchargé la clé privée", + "key_management_service_credential_create_confirmation_button_done_label": "Terminer", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} jours", + "key_management_service_credential_download": "Télécharger", + "key_management_service_credential_delete": "Supprimer", + "key_management_service_credential_delete_modal_headline": "Supprimer mon certificat", + "key_management_service_credential_delete_modal_input_label": "Veuillez entrer le mot « TERMINATE » pour confirmer la suppression de votre certificat", + "key_management_service_credential_delete_success": "Le certificat a été supprimé avec succès", + "key_management_service_credential_delete_error": "La suppression de votre certificat a rencontré des erreurs. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_FR.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_FR.json new file mode 100644 index 000000000000..1c7943bafe55 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_fr_FR.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certificats d'accès", + "key_management_service_credential_identities": "identités", + "key_management_service_credential_not_authorized": "Vous ne disposez pas des permissions nécessaires pour accéder à cette information, veuillez contacter votre administrateur.", + "key_management_service_credential_create_title": "Créer un certificat d’accès", + "key_management_service_credential_create_subtitle": "Créez les certificats d’accès qui permettront aux identités de votre choix d’accéder à votre KMS. Les droits de ces identités doivent être configurés dans une politique IAM.", + "key_management_service_credential_dashboard_tab_informations": "Informations", + "key_management_service_credential_dashboard_tab_identities": "Identités", + "key_management_service_credential_headline": "Créez et gérez les certificats d’accès qui permettront aux identités de votre choix d’accéder à votre KMS.", + "key_management_service_credential_cta_create": "Créer un certificat d'accès", + "key_management_service_credential_status_creating": "Création en cours", + "key_management_service_credential_status_deleting": "Suppression en cours", + "key_management_service_credential_status_error": "Erreur", + "key_management_service_credential_status_expired": "Expiré", + "key_management_service_credential_status_ready": "Prêt", + "key_management_service_credential_list_column_name": "Nom", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "Nb d'identités", + "key_management_service_credential_list_column_creation_date": "Date de création", + "key_management_service_credential_list_column_expiration_date": "Date d'expiration", + "key_management_service_credential_list_column_status": "Statut", + "key_management_service_credential_create_general_information_title": "Informations générales", + "key_management_service_credential_create_general_information_display_name_title": "Nom d'affichage", + "key_management_service_credential_create_general_information_display_name_subtitle": "Ce nom sera utilisé pour faciliter son identification.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Description (optionnelle)", + "key_management_service_credential_create_general_information_validity_title": "Validité", + "key_management_service_credential_create_general_information_validity_subtitle": "Le certificat sera automatiquement désactivé à la fin de la période de validité", + "key_management_service_credential_create_general_creation_method_title": "Méthode de création", + "key_management_service_credential_create_general_information_creation_method_subtitle": "La création du certificat d'accès nécessite une clé privée", + "key_management_service_credential_create_general_information_creation_method_no_key": "Je n’ai pas de clé privée", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Le certificat d’accès et la clé privée seront générés par OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "J'ai déjà une clé privée", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Soumettre une Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Veuillez renseigner le contenu de votre CSR afin d'ajouter des identités.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Contenu de la CSR", + "key_management_service_credential_create_cta_cancel": "Annuler", + "key_management_service_credential_create_cta_add_identities": "Ajouter des identités", + "key_management_service_credential_create_general_validity_period_day": "1 jour", + "key_management_service_credential_create_general_validity_period_week": "1 semaine", + "key_management_service_credential_create_general_validity_period_month": "1 mois", + "key_management_service_credential_create_general_validity_period_3months": "3 mois", + "key_management_service_credential_create_general_validity_period_6months": "6 mois", + "key_management_service_credential_create_general_validity_period_year": "1 an", + "key_management_service_credential_create_general_validity_period_custom": "Personnalisé", + "key_management_service_credential_update_name_error_required": "Le nom doit comporter entre 1 et 50 caractères.", + "key_management_service_credential_update_name_error_invalid_characters": "Votre saisie n'est pas valide.", + "key_management_service_credential_update_name_error_max": "Le nombre de caractères autorisé est dépassé. (50 caractères maximum)", + "key_management_service_credential_update_description_error_invalid_characters": "Votre saisie n'est pas valide.", + "key_management_service_credential_update_description_error_max": "Le nombre de caractères autorisé est dépassé. (200 caractères maximum)", + "key_management_service_credential_update_validity_error_min_period": "La durée de validité minimale est de 1 jour.", + "key_management_service_credential_update_validity_error_max_period": "La durée de validité maximale est de 365 jours.", + "key_management_service_credential_create_validity_custom_date_label": "Date de fin", + "key_management_service_credential_dashboard_backlink": "Retour à la liste des certificats", + "key_management_service_credential_dashboard_tile_general_informations": "Informations générales", + "key_management_service_credential_dashboard_name": "Nom d'affichage", + "key_management_service_credential_dashboard_id": "ID du certificat d'accès", + "key_management_service_credential_dashboard_description": "Description", + "key_management_service_credential_dashboard_status": "Statut", + "key_management_service_credential_dashboard_creation": "Méthode et date de création", + "key_management_service_credential_dashboard_expiration": "Expiration", + "key_management_service_credential_dashboard_actions": "Actions", + "key_management_service_credential_created_with_csr": "créé avec CSR", + "key_management_service_credential_created_without_csr": "créé sans CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Comptes OVH", + "key_management_service_credential_identities_account_column_account": "Compte OVH", + "key_management_service_credential_identities_user_title": "Utilisateurs", + "key_management_service_credential_identities_user_column_id": "Identifiant", + "key_management_service_credential_identities_usergroup_title": "Groupes d'utilisateur", + "key_management_service_credential_identities_usergroup_column_name": "Nom", + "key_management_service_credential_identities_service_account_title": "Comptes de service", + "key_management_service_credential_identities_service_account_column_id": "Identifiant", + "key_management_service_credential_create_identities_title": "Ajouter des identités", + "key_management_service_credential_create_identities_root_account_toggle_label": "Ajouter l'identité racine du compte", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Les droits d'accès ne seront pas restreints par l'IAM", + "key_management_service_credential_create_identities_max_label": "Le nombre total d'identités est limité à 25.", + "key_management_service_credential_create_identities_users_list_title": "Utilisateurs", + "key_management_service_credential_create_identities_users_list_button_add_label": "Ajouter des utilisateurs", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_identity_status_ok": "Actif", + "key_management_service_credential_identity_status_disabled": "Inactif", + "key_management_service_credential_identity_status_password_change_required": "Changement de mot de passe requis", + "key_management_service_credential_user_list_column_name": "Nom", + "key_management_service_credential_user_list_column_group": "Groupe", + "key_management_service_credential_user_list_column_status": "Statut", + "key_management_service_credential_create_identities_users_groups_title": "Groupes d'utilisateurs", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Ajouter des groupes d'utilisateurs", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_user_list_column_description": "Description", + "key_management_service_credential_create_identities_service_accounts_title": "Compte de services", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Ajouter des comptes de services", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Supprimer tout", + "key_management_service_credential_create_identities_button_cancel_label": "Annuler", + "key_management_service_credential_create_identities_button_back_label": "Précédent", + "key_management_service_credential_create_identities_button_create_label": "Créer le certificat d'accès", + "key_management_service_credentials_identity_modal_user_list_headline": "Ajouter des utilisateurs", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Rechercher par nom ou e-mail", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Rechercher par nom", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Rechercher par nom ou description", + "key_management_service_credentials_identity_modal_user_list_cancel": "Annuler", + "key_management_service_credentials_identity_modal_user_list_add": "Ajouter", + "key_management_service_credentials_identity_modal_group_list_headline": "Ajouter des groupes", + "key_management_service_credentials_identity_modal_group_list_cancel": "Annuler", + "key_management_service_credentials_identity_modal_group_list_add": "Ajouter", + "key_management_service_credential_create_identities_list_button_no_result_label": "Pas de résultats", + "key_management_service_credential_create_identities_group_tile_description_label": "Description", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identité", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Description", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identité", + "key_management_service_credential_create_identities_user_tile_email_label": "E-mail", + "key_management_service_credential_create_identities_user_tile_group_label": "Groupe", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identité", + "key_management_service_credential_create_success": "La création de votre certificat est en cours. Vous pourrez télécharger la clé publique depuis la page “Certificat d’accès” de votre KMS dans quelques minutes.", + "key_management_service_credential_create_error": "La création de votre certificat a rencontré des erreurs.", + "key_management_service_credential_create_confirmation_details_title": "Certificat d’accès", + "key_management_service_credential_create_confirmation_details_id_label": "ID du certificat", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nom d’affichage", + "key_management_service_credential_create_confirmation_details_description_label": "Description", + "key_management_service_credential_create_confirmation_details_validity_label": "Validité", + "key_management_service_credential_create_confirmation_private-key_title": "Clé privée", + "key_management_service_credential_create_confirmation_private-key_warn": "Vous n’aurez plus accès à cette clé privée lorsque vous quitterez l’assistant de création. Veillez à la télécharger et à la stocker de manière sécurisée.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Télécharger la clé privée", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Je confirme avoir téléchargé la clé privée", + "key_management_service_credential_create_confirmation_button_done_label": "Terminer", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} jours", + "key_management_service_credential_download": "Télécharger", + "key_management_service_credential_delete": "Supprimer", + "key_management_service_credential_delete_modal_headline": "Supprimer mon certificat", + "key_management_service_credential_delete_modal_input_label": "Veuillez entrer le mot « TERMINATE » pour confirmer la suppression de votre certificat", + "key_management_service_credential_delete_success": "Le certificat a été supprimé avec succès", + "key_management_service_credential_delete_error": "La suppression de votre certificat a rencontré des erreurs. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_it_IT.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_it_IT.json new file mode 100644 index 000000000000..65e8e2e7060b --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_it_IT.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certificati di accesso", + "key_management_service_credential_identities": "Identità", + "key_management_service_credential_not_authorized": "Non disponi dei permessi necessari per accedere a queste informazioni, contatta il tuo amministratore.", + "key_management_service_credential_create_title": "Creare un certificato di accesso", + "key_management_service_credential_create_subtitle": "Crea i certificati di accesso che permetteranno alle identità scelte di accedere al tuo KMS. I diritti di queste identità devono essere configurati in una politica IAM.", + "key_management_service_credential_dashboard_tab_informations": "Informazioni", + "key_management_service_credential_dashboard_tab_identities": "Identità", + "key_management_service_credential_headline": "Crea e gestisci i certificati di accesso che permetteranno alle identità scelte di accedere al tuo KMS.", + "key_management_service_credential_cta_create": "Creare un certificato di accesso", + "key_management_service_credential_status_creating": "Creazione in corso...", + "key_management_service_credential_status_deleting": "Eliminazione in corso...", + "key_management_service_credential_status_error": "Errore", + "key_management_service_credential_status_expired": "Scaduto", + "key_management_service_credential_status_ready": "Pronto", + "key_management_service_credential_list_column_name": "Cognome", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "N° di identità", + "key_management_service_credential_list_column_creation_date": "Data di creazione", + "key_management_service_credential_list_column_expiration_date": "Data di scadenza", + "key_management_service_credential_list_column_status": "Stato", + "key_management_service_credential_create_general_information_title": "Informazioni generali", + "key_management_service_credential_create_general_information_display_name_title": "Nome visualizzato", + "key_management_service_credential_create_general_information_display_name_subtitle": "Questo nome verrà utilizzato per facilitare la sua identificazione.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Descrizione (opzionale)", + "key_management_service_credential_create_general_information_validity_title": "Validità", + "key_management_service_credential_create_general_information_validity_subtitle": "Il certificato sarà disattivato automaticamente alla fine del periodo di validità", + "key_management_service_credential_create_general_creation_method_title": "Metodo di creazione", + "key_management_service_credential_create_general_information_creation_method_subtitle": "La creazione del certificato di accesso richiede una chiave privata", + "key_management_service_credential_create_general_information_creation_method_no_key": "Non ho una chiave privata", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Il certificato di accesso e la chiave privata saranno generati da OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "Ho già una chiave privata", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Inviare un Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Inserisci il contenuto del tuo CSR per aggiungere le identità.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Contenuto della CSR", + "key_management_service_credential_create_cta_cancel": "Annullare", + "key_management_service_credential_create_cta_add_identities": "Aggiungere identità", + "key_management_service_credential_create_general_validity_period_day": "1 giorno", + "key_management_service_credential_create_general_validity_period_week": "1 settimana", + "key_management_service_credential_create_general_validity_period_month": "1 mese", + "key_management_service_credential_create_general_validity_period_3months": "3 mesi", + "key_management_service_credential_create_general_validity_period_6months": "6 mesi", + "key_management_service_credential_create_general_validity_period_year": "1 anno", + "key_management_service_credential_create_general_validity_period_custom": "Personalizzato", + "key_management_service_credential_update_name_error_required": "Il nome deve contenere da 1 a 50 caratteri.", + "key_management_service_credential_update_name_error_invalid_characters": "Il testo inserito non è valido.", + "key_management_service_credential_update_name_error_max": "È stato superato il numero di caratteri consentito (massimo 50 caratteri)", + "key_management_service_credential_update_description_error_invalid_characters": "Il testo inserito non è valido.", + "key_management_service_credential_update_description_error_max": "È stato superato il numero di caratteri consentito (massimo 200 caratteri)", + "key_management_service_credential_update_validity_error_min_period": "La durata di validità minima è di 1 giorno.", + "key_management_service_credential_update_validity_error_max_period": "La durata di validità massima è di 365 giorni.", + "key_management_service_credential_create_validity_custom_date_label": "Data di fine", + "key_management_service_credential_dashboard_backlink": "Ritorna alla lista dei certificati", + "key_management_service_credential_dashboard_tile_general_informations": "Informazioni generali", + "key_management_service_credential_dashboard_name": "Nome visualizzato", + "key_management_service_credential_dashboard_id": "ID del certificato di accesso", + "key_management_service_credential_dashboard_description": "Descrizione", + "key_management_service_credential_dashboard_status": "Stato", + "key_management_service_credential_dashboard_creation": "Metodo e data di creazione", + "key_management_service_credential_dashboard_expiration": "Scadenza", + "key_management_service_credential_dashboard_actions": "Azioni", + "key_management_service_credential_created_with_csr": "creato con CSR", + "key_management_service_credential_created_without_csr": "creato senza CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Account OVHcloud", + "key_management_service_credential_identities_account_column_account": "Account OVHcloud", + "key_management_service_credential_identities_user_title": "Utenti", + "key_management_service_credential_identities_user_column_id": "Identificativo", + "key_management_service_credential_identities_usergroup_title": "Gruppi di utenti", + "key_management_service_credential_identities_usergroup_column_name": "Cognome", + "key_management_service_credential_identities_service_account_title": "Account di servizio", + "key_management_service_credential_identities_service_account_column_id": "Identificativo", + "key_management_service_credential_create_identities_title": "Aggiungere identità", + "key_management_service_credential_create_identities_root_account_toggle_label": "Aggiungere l'identità principale dell'account", + "key_management_service_credential_create_identities_root_account_toggle_helper": "I diritti di accesso non saranno limitati dall'IAM", + "key_management_service_credential_create_identities_max_label": "Il numero totale di identità è limitato a 25.", + "key_management_service_credential_create_identities_users_list_title": "Utenti", + "key_management_service_credential_create_identities_users_list_button_add_label": "Aggiungere utenti", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Elimina tutto", + "key_management_service_credential_identity_status_ok": "Attivo", + "key_management_service_credential_identity_status_disabled": "Disattivo", + "key_management_service_credential_identity_status_password_change_required": "Modifica della password necessaria", + "key_management_service_credential_user_list_column_name": "Cognome", + "key_management_service_credential_user_list_column_group": "Gruppo", + "key_management_service_credential_user_list_column_status": "Stato", + "key_management_service_credential_create_identities_users_groups_title": "Gruppi di utenti", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Aggiungi gruppi di utenti", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Elimina tutto", + "key_management_service_credential_user_list_column_description": "Descrizione", + "key_management_service_credential_create_identities_service_accounts_title": "Account di servizi", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Aggiungere account di servizi", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Elimina tutto", + "key_management_service_credential_create_identities_button_cancel_label": "Annullare", + "key_management_service_credential_create_identities_button_back_label": "Indietro", + "key_management_service_credential_create_identities_button_create_label": "Creare il certificato di accesso", + "key_management_service_credentials_identity_modal_user_list_headline": "Aggiungere utenti", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Cercare per nome o email", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Cercare per nome", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Cercare per nome o descrizione", + "key_management_service_credentials_identity_modal_user_list_cancel": "Annullare", + "key_management_service_credentials_identity_modal_user_list_add": "Aggiungere", + "key_management_service_credentials_identity_modal_group_list_headline": "Aggiungere gruppi", + "key_management_service_credentials_identity_modal_group_list_cancel": "Annullare", + "key_management_service_credentials_identity_modal_group_list_add": "Aggiungere", + "key_management_service_credential_create_identities_list_button_no_result_label": "Nessun risultato", + "key_management_service_credential_create_identities_group_tile_description_label": "Descrizione", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identità", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Descrizione", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identità", + "key_management_service_credential_create_identities_user_tile_email_label": "Email", + "key_management_service_credential_create_identities_user_tile_group_label": "Gruppo", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identità", + "key_management_service_credential_create_success": "Creazione del certificato in corso... Potrai scaricare la chiave pubblica dalla pagina \"Certificato di accesso\" del tuo KMS in pochi minuti.", + "key_management_service_credential_create_error": "Si sono verificati errori durante la creazione del tuo certificato.", + "key_management_service_credential_create_confirmation_details_title": "Certificato di accesso", + "key_management_service_credential_create_confirmation_details_id_label": "ID del certificato", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nome visualizzato", + "key_management_service_credential_create_confirmation_details_description_label": "Descrizione", + "key_management_service_credential_create_confirmation_details_validity_label": "Validità", + "key_management_service_credential_create_confirmation_private-key_title": "Chiave privata", + "key_management_service_credential_create_confirmation_private-key_warn": "Se esci dalla procedura guidata non sarà più possibile accedere alla chiave privata. Scaricala e salvala in modo sicuro.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Scaricare la chiave privata", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Confermo di aver scaricato la chiave privata", + "key_management_service_credential_create_confirmation_button_done_label": "Terminare", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} giorni", + "key_management_service_credential_download": "Scarica", + "key_management_service_credential_delete": "Eliminare", + "key_management_service_credential_delete_modal_headline": "Eliminare il tuo certificato", + "key_management_service_credential_delete_modal_input_label": "Inserisci la parola \"TERMINATE\" per confermare l'eliminazione del tuo certificato.", + "key_management_service_credential_delete_success": "Il certificato è stato eliminato correttamente.", + "key_management_service_credential_delete_error": "Si sono verificati errori durante l’eliminazione del tuo certificato: {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pl_PL.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pl_PL.json new file mode 100644 index 000000000000..51606b9a81f4 --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pl_PL.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certyfikaty dostępu", + "key_management_service_credential_identities": "Tożsamości", + "key_management_service_credential_not_authorized": "Nie masz wystarczających uprawnień, aby uzyskać dostęp do tych informacji. Skontaktuj się z administratorem.", + "key_management_service_credential_create_title": "Utwórz certyfikat dostępu", + "key_management_service_credential_create_subtitle": "Twórz certyfikaty dostępu, które pozwolą na dostęp do serwera KMS wybranym tożsamościom. Uprawnienia tych tożsamości muszą być skonfigurowane w polityce IAM.", + "key_management_service_credential_dashboard_tab_informations": "Informacje", + "key_management_service_credential_dashboard_tab_identities": "Tożsamości", + "key_management_service_credential_headline": "Twórz i zarządzaj certyfikatami dostępu, które umożliwią wybranym tożsamościom dostęp do Twojego serwera KMS.", + "key_management_service_credential_cta_create": "Utwórz certyfikat dostępu", + "key_management_service_credential_status_creating": "Trwa tworzenie", + "key_management_service_credential_status_deleting": "Trwa usuwanie", + "key_management_service_credential_status_error": "Błąd", + "key_management_service_credential_status_expired": "Wygasły", + "key_management_service_credential_status_ready": "Gotowe", + "key_management_service_credential_list_column_name": "Nazwa", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "Liczba tożsamości", + "key_management_service_credential_list_column_creation_date": "Data utworzenia", + "key_management_service_credential_list_column_expiration_date": "Data wygasania", + "key_management_service_credential_list_column_status": "Status", + "key_management_service_credential_create_general_information_title": "Informacje ogólne", + "key_management_service_credential_create_general_information_display_name_title": "Nazwa wyświetlana", + "key_management_service_credential_create_general_information_display_name_subtitle": "Ta nazwa ułatwi jego identyfikację.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Opis (opcjonalnie)", + "key_management_service_credential_create_general_information_validity_title": "Ważność", + "key_management_service_credential_create_general_information_validity_subtitle": "Certyfikat zostanie automatycznie wyłączony po zakończeniu okresu ważności", + "key_management_service_credential_create_general_creation_method_title": "Metoda tworzenia", + "key_management_service_credential_create_general_information_creation_method_subtitle": "Utworzenie certyfikatu dostępu wymaga klucza prywatnego", + "key_management_service_credential_create_general_information_creation_method_no_key": "Nie mam klucza prywatnego", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "Certyfikat dostępu i klucz prywatny zostaną wygenerowane przez OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "Mam już klucz prywatny", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Prześlij Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Wpisz treść CSR, aby dodać tożsamości.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Treść CSR", + "key_management_service_credential_create_cta_cancel": "Anuluj", + "key_management_service_credential_create_cta_add_identities": "Dodaj tożsamości", + "key_management_service_credential_create_general_validity_period_day": "1 dzień", + "key_management_service_credential_create_general_validity_period_week": "1 tydzień", + "key_management_service_credential_create_general_validity_period_month": "1 miesiąc", + "key_management_service_credential_create_general_validity_period_3months": "3 miesiące", + "key_management_service_credential_create_general_validity_period_6months": "6 miesięcy", + "key_management_service_credential_create_general_validity_period_year": "1 rok", + "key_management_service_credential_create_general_validity_period_custom": "Spersonalizowany", + "key_management_service_credential_update_name_error_required": "Nazwa musi zawierać od 1 do 50 znaków.", + "key_management_service_credential_update_name_error_invalid_characters": "Wprowadzone dane są nieprawidłowe.", + "key_management_service_credential_update_name_error_max": "Przekroczono dozwoloną liczbę znaków. (maksymalnie 50 znaków)", + "key_management_service_credential_update_description_error_invalid_characters": "Wprowadzone dane są nieprawidłowe.", + "key_management_service_credential_update_description_error_max": "Przekroczono dozwoloną liczbę znaków. (maksymalnie 200 znaków)", + "key_management_service_credential_update_validity_error_min_period": "Minimalny okres ważności wynosi 1 dzień.", + "key_management_service_credential_update_validity_error_max_period": "Maksymalny okres ważności wynosi 365 dni.", + "key_management_service_credential_create_validity_custom_date_label": "Data zakończenia", + "key_management_service_credential_dashboard_backlink": "Powrót do listy certyfikatów", + "key_management_service_credential_dashboard_tile_general_informations": "Informacje ogólne", + "key_management_service_credential_dashboard_name": "Nazwa wyświetlana", + "key_management_service_credential_dashboard_id": "Identyfikator certyfikatu dostępu", + "key_management_service_credential_dashboard_description": "Opis", + "key_management_service_credential_dashboard_status": "Status", + "key_management_service_credential_dashboard_creation": "Metoda i data utworzenia", + "key_management_service_credential_dashboard_expiration": "Data ważności", + "key_management_service_credential_dashboard_actions": "Operacje", + "key_management_service_credential_created_with_csr": "utworzony z CSR", + "key_management_service_credential_created_without_csr": "utworzony bez CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Konta OVHcloud", + "key_management_service_credential_identities_account_column_account": "Konto OVHcloud", + "key_management_service_credential_identities_user_title": "Użytkownicy", + "key_management_service_credential_identities_user_column_id": "Identyfikator", + "key_management_service_credential_identities_usergroup_title": "Grupy użytkowników", + "key_management_service_credential_identities_usergroup_column_name": "Nazwa", + "key_management_service_credential_identities_service_account_title": "Konta serwisowe", + "key_management_service_credential_identities_service_account_column_id": "Identyfikator", + "key_management_service_credential_create_identities_title": "Dodaj tożsamości", + "key_management_service_credential_create_identities_root_account_toggle_label": "Dodaj tożsamość główną konta", + "key_management_service_credential_create_identities_root_account_toggle_helper": "Prawa dostępu nie będą ograniczone przez IAM", + "key_management_service_credential_create_identities_max_label": "Całkowita liczba tożsamości jest ograniczona do 25.", + "key_management_service_credential_create_identities_users_list_title": "Użytkownicy", + "key_management_service_credential_create_identities_users_list_button_add_label": "Dodaj użytkowników", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Usuń wszystko", + "key_management_service_credential_identity_status_ok": "Aktywny", + "key_management_service_credential_identity_status_disabled": "Nieaktywny", + "key_management_service_credential_identity_status_password_change_required": "Wymagana zmiana hasła", + "key_management_service_credential_user_list_column_name": "Nazwa", + "key_management_service_credential_user_list_column_group": "Grupa", + "key_management_service_credential_user_list_column_status": "Status", + "key_management_service_credential_create_identities_users_groups_title": "Grupy użytkowników", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Dodaj grupy użytkowników", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Usuń wszystko", + "key_management_service_credential_user_list_column_description": "Opis", + "key_management_service_credential_create_identities_service_accounts_title": "Konto usług", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Dodaj konta usług", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Usuń wszystko", + "key_management_service_credential_create_identities_button_cancel_label": "Anuluj", + "key_management_service_credential_create_identities_button_back_label": "Wstecz", + "key_management_service_credential_create_identities_button_create_label": "Utwórz certyfikat dostępu", + "key_management_service_credentials_identity_modal_user_list_headline": "Dodaj użytkowników", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Wyszukaj według nazwy lub e-maila", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Wyszukaj według nazwy", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Wyszukaj według nazwy lub opisu", + "key_management_service_credentials_identity_modal_user_list_cancel": "Anuluj", + "key_management_service_credentials_identity_modal_user_list_add": "Dodaj", + "key_management_service_credentials_identity_modal_group_list_headline": "Dodaj grupy", + "key_management_service_credentials_identity_modal_group_list_cancel": "Anuluj", + "key_management_service_credentials_identity_modal_group_list_add": "Dodaj", + "key_management_service_credential_create_identities_list_button_no_result_label": "Brak wyników", + "key_management_service_credential_create_identities_group_tile_description_label": "Opis", + "key_management_service_credential_create_identities_group_tile_identity_label": "Tożsamość", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Opis", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Tożsamość", + "key_management_service_credential_create_identities_user_tile_email_label": "Adres e-mail", + "key_management_service_credential_create_identities_user_tile_group_label": "Grupa", + "key_management_service_credential_create_identities_user_tile_identity_label": "Tożsamość", + "key_management_service_credential_create_success": "Trwa tworzenie certyfikatu. Klucz publiczny możesz pobrać ze strony „Certyfikat dostępu” serwera KMS w ciągu kilku minut.", + "key_management_service_credential_create_error": "Wystąpił błąd podczas tworzenia certyfikatu.", + "key_management_service_credential_create_confirmation_details_title": "Certyfikat dostępu", + "key_management_service_credential_create_confirmation_details_id_label": "ID certyfikatu", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nazwa wyświetlana", + "key_management_service_credential_create_confirmation_details_description_label": "Opis", + "key_management_service_credential_create_confirmation_details_validity_label": "Ważność", + "key_management_service_credential_create_confirmation_private-key_title": "Klucz prywatny", + "key_management_service_credential_create_confirmation_private-key_warn": "Po zamknięciu asystenta aktywacji nie będziesz mieć dostępu do tego klucza prywatnego. Pobierz go i przechowuj w bezpieczny sposób.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Pobierz klucz prywatny", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Potwierdzam pobranie klucza prywatnego", + "key_management_service_credential_create_confirmation_button_done_label": "Zakończ", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} dni", + "key_management_service_credential_download": "Pobierz", + "key_management_service_credential_delete": "Usuń", + "key_management_service_credential_delete_modal_headline": "Usuń certyfikat", + "key_management_service_credential_delete_modal_input_label": "Wpisz słowo „TERMINATE”, aby potwierdzić usunięcie certyfikatu", + "key_management_service_credential_delete_success": "Certyfikat został usunięty", + "key_management_service_credential_delete_error": "Podczas usuwania certyfikatu wystąpiły błędy. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pt_PT.json b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pt_PT.json new file mode 100644 index 000000000000..f58654bc3a2f --- /dev/null +++ b/packages/manager/apps/key-management-service/public/translations/key-management-service/credential/Messages_pt_PT.json @@ -0,0 +1,134 @@ +{ + "key_management_service_credential": "Certificados de acesso", + "key_management_service_credential_identities": "Identidades", + "key_management_service_credential_not_authorized": "Não dispõe das permissões necessárias para aceder a esta informação. Contacte o seu administrador.", + "key_management_service_credential_create_title": "Criar um certificado de acesso", + "key_management_service_credential_create_subtitle": "Crie os certificados de acesso que permitirão que as identidades da sua escolha acedam ao seu KMS. As permissões destas identidades devem ser configuradas numa política IAM.", + "key_management_service_credential_dashboard_tab_informations": "Informações", + "key_management_service_credential_dashboard_tab_identities": "Identidades", + "key_management_service_credential_headline": "Crie e faça a gestão dos certificados de acesso que permitirão que as identidades da sua escolha acedam ao seu KMS.", + "key_management_service_credential_cta_create": "Criar um certificado de acesso", + "key_management_service_credential_status_creating": "Criação em curso", + "key_management_service_credential_status_deleting": "Eliminação em curso", + "key_management_service_credential_status_error": "Erro", + "key_management_service_credential_status_expired": "Expirado", + "key_management_service_credential_status_ready": "Pronto", + "key_management_service_credential_list_column_name": "Nome", + "key_management_service_credential_list_column_id": "ID", + "key_management_service_credential_list_column_identities": "N.º de identidades", + "key_management_service_credential_list_column_creation_date": "Data de criação", + "key_management_service_credential_list_column_expiration_date": "Data de expiração", + "key_management_service_credential_list_column_status": "Estado", + "key_management_service_credential_create_general_information_title": "Informações gerais", + "key_management_service_credential_create_general_information_display_name_title": "Nome a ser apresentado", + "key_management_service_credential_create_general_information_display_name_subtitle": "Este nome será utilizado para facilitar a sua identificação.", + "key_management_service_credential_create_general_information_display_name_placeholder": "", + "key_management_service_credential_create_general_information_description_title": "Descrição (opcional)", + "key_management_service_credential_create_general_information_validity_title": "Validade", + "key_management_service_credential_create_general_information_validity_subtitle": "O certificado será automaticamente desativado ao fim do período de validade", + "key_management_service_credential_create_general_creation_method_title": "Método de criação", + "key_management_service_credential_create_general_information_creation_method_subtitle": "A criação do certificado de acesso requer uma chave privada", + "key_management_service_credential_create_general_information_creation_method_no_key": "Não tenho uma chave privada", + "key_management_service_credential_create_general_information_creation_method_no_key_desc": "O certificado de acesso e a chave privada serão gerados pela OVHcloud.", + "key_management_service_credential_create_general_information_creation_method_key": "Já tenho uma chave privada", + "key_management_service_credential_create_general_information_creation_method_key_desc": "Submeter um Certificate Signing Request (CSR)", + "key_management_service_credential_update_custom_csr_error_required": "Introduza o conteúdo do seu CSR para adicionar identidades.", + "key_management_service_credential_create_general_information_csr_title": "Certificate Signing Request (CSR)", + "key_management_service_credential_create_general_information_csr_subtitle": "Conteúdo do CSR", + "key_management_service_credential_create_cta_cancel": "Anular", + "key_management_service_credential_create_cta_add_identities": "Adicionar identidades", + "key_management_service_credential_create_general_validity_period_day": "1 dia", + "key_management_service_credential_create_general_validity_period_week": "1 semana", + "key_management_service_credential_create_general_validity_period_month": "1 mês", + "key_management_service_credential_create_general_validity_period_3months": "3 meses", + "key_management_service_credential_create_general_validity_period_6months": "6 meses", + "key_management_service_credential_create_general_validity_period_year": "1 ano", + "key_management_service_credential_create_general_validity_period_custom": "Personalizado", + "key_management_service_credential_update_name_error_required": "O nome deve ter entre 1 e 50 caracteres.", + "key_management_service_credential_update_name_error_invalid_characters": "Os seus dados não são válidos.", + "key_management_service_credential_update_name_error_max": "Foi excedido o número de caracteres permitido. (Máximo de 50 caracteres)", + "key_management_service_credential_update_description_error_invalid_characters": "Os seus dados não são válidos.", + "key_management_service_credential_update_description_error_max": "Foi excedido o número de caracteres permitido. (Máximo de 200 caracteres)", + "key_management_service_credential_update_validity_error_min_period": "O período mínimo de validade é de um dia.", + "key_management_service_credential_update_validity_error_max_period": "O período máximo de validade é de 365 dias.", + "key_management_service_credential_create_validity_custom_date_label": "Data de fim", + "key_management_service_credential_dashboard_backlink": "Voltar à lista dos certificados", + "key_management_service_credential_dashboard_tile_general_informations": "Informações gerais", + "key_management_service_credential_dashboard_name": "Nome a ser apresentado", + "key_management_service_credential_dashboard_id": "ID do certificado de acesso", + "key_management_service_credential_dashboard_description": "Descrição", + "key_management_service_credential_dashboard_status": "Estado", + "key_management_service_credential_dashboard_creation": "Método e data de criação", + "key_management_service_credential_dashboard_expiration": "Expiração", + "key_management_service_credential_dashboard_actions": "Ações", + "key_management_service_credential_created_with_csr": "criado com CSR", + "key_management_service_credential_created_without_csr": "criado sem CSR", + "key_management_service_credential_identities_column_urn": "URN", + "key_management_service_credential_identities_account_title": "Contas OVH", + "key_management_service_credential_identities_account_column_account": "Conta OVH", + "key_management_service_credential_identities_user_title": "Utilizadores", + "key_management_service_credential_identities_user_column_id": "ID de utilizador", + "key_management_service_credential_identities_usergroup_title": "Grupos de utilizadores", + "key_management_service_credential_identities_usergroup_column_name": "Nome", + "key_management_service_credential_identities_service_account_title": "Contas de serviço", + "key_management_service_credential_identities_service_account_column_id": "ID de utilizador", + "key_management_service_credential_create_identities_title": "Adicionar identidades", + "key_management_service_credential_create_identities_root_account_toggle_label": "Adicionar a identidade-raiz da conta", + "key_management_service_credential_create_identities_root_account_toggle_helper": "As permissões de acesso não serão restringidas pelo IAM", + "key_management_service_credential_create_identities_max_label": "O número total de identidades está limitado a 25.", + "key_management_service_credential_create_identities_users_list_title": "Utilizadores", + "key_management_service_credential_create_identities_users_list_button_add_label": "Adicionar utilizadores", + "key_management_service_credential_create_identities_users_list_button_delete_all_label": "Eliminar tudo", + "key_management_service_credential_identity_status_ok": "Ativo", + "key_management_service_credential_identity_status_disabled": "Inativo", + "key_management_service_credential_identity_status_password_change_required": "Alteração de palavra-passe necessária", + "key_management_service_credential_user_list_column_name": "Nome", + "key_management_service_credential_user_list_column_group": "Grupo", + "key_management_service_credential_user_list_column_status": "Estado", + "key_management_service_credential_create_identities_users_groups_title": "Grupos de utilizadores", + "key_management_service_credential_create_identities_users_groups_button_add_label": "Adicionar grupos de utilizadores", + "key_management_service_credential_create_identities_users_groups_button_delete_all_label": "Eliminar tudo", + "key_management_service_credential_user_list_column_description": "Descrição", + "key_management_service_credential_create_identities_service_accounts_title": "Conta de serviços", + "key_management_service_credential_create_identities_service_accounts_button_add_label": "Adicionar contas de serviços", + "key_management_service_credential_create_identities_service_accounts_button_delete_all_label": "Eliminar tudo", + "key_management_service_credential_create_identities_button_cancel_label": "Anular", + "key_management_service_credential_create_identities_button_back_label": "Anterior", + "key_management_service_credential_create_identities_button_create_label": "Criar o certificado de acesso", + "key_management_service_credentials_identity_modal_user_list_headline": "Adicionar utilizadores", + "key_management_service_credential_create_identities_user_list_search_placeholder": "Pesquisar por nome ou e-mail", + "key_management_service_credential_create_identities_group_list_search_placeholder": "Procurar por nome", + "key_management_service_credential_create_identities_service-account_list_search_placeholder": "Procurar por nome ou descrição", + "key_management_service_credentials_identity_modal_user_list_cancel": "Anular", + "key_management_service_credentials_identity_modal_user_list_add": "Adicionar", + "key_management_service_credentials_identity_modal_group_list_headline": "Adicionar grupos", + "key_management_service_credentials_identity_modal_group_list_cancel": "Anular", + "key_management_service_credentials_identity_modal_group_list_add": "Adicionar", + "key_management_service_credential_create_identities_list_button_no_result_label": "Sem resultados", + "key_management_service_credential_create_identities_group_tile_description_label": "Descrição", + "key_management_service_credential_create_identities_group_tile_identity_label": "Identidade", + "key_management_service_credential_create_identities_service-account_tile_description_label": "Descrição", + "key_management_service_credential_create_identities_service-account_tile_identity_label": "Identidade", + "key_management_service_credential_create_identities_user_tile_email_label": "E-mail", + "key_management_service_credential_create_identities_user_tile_group_label": "Grupo", + "key_management_service_credential_create_identities_user_tile_identity_label": "Identidade", + "key_management_service_credential_create_success": "A criação do seu certificado está em curso. Dentro de alguns minutos poderá descarregar a chave pública a partir da página «Certificado de acesso» do seu KMS.", + "key_management_service_credential_create_error": "A criação do certificado não foi bem-sucedida.", + "key_management_service_credential_create_confirmation_details_title": "Certificado de acesso", + "key_management_service_credential_create_confirmation_details_id_label": "ID do certificado", + "key_management_service_credential_create_confirmation_details_display-name_label": "Nome a ser apresentado", + "key_management_service_credential_create_confirmation_details_description_label": "Descrição", + "key_management_service_credential_create_confirmation_details_validity_label": "Validade", + "key_management_service_credential_create_confirmation_private-key_title": "Chave privada", + "key_management_service_credential_create_confirmation_private-key_warn": "Deixará de ter acesso a esta chave privada quando sair do assistente de criação. Certifique-se de que a descarrega e armazena de forma segura.", + "key_management_service_credential_create_confirmation_private-key_download_label": "Descarregar a chave privada", + "key_management_service_credential_create_confirmation_private-key_checkbox_label": "Confirmo ter descarregado a chave privada", + "key_management_service_credential_create_confirmation_button_done_label": "Concluir", + "key_management_service_credential_create_confirmation_details_validity_suffix": "{{days}} dias", + "key_management_service_credential_download": "Transferir", + "key_management_service_credential_delete": "Eliminar", + "key_management_service_credential_delete_modal_headline": "Eliminar o meu certificado", + "key_management_service_credential_delete_modal_input_label": "Introduza a palavra «TERMINATE» para confirmar a eliminação do seu certificado", + "key_management_service_credential_delete_success": "O certificado foi eliminado com sucesso", + "key_management_service_credential_delete_error": "A eliminação do certificado não foi bem-sucedida. {{error}}" +} diff --git a/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityGroupListModal.component.tsx b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityGroupListModal.component.tsx new file mode 100644 index 000000000000..dc7869a95d57 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityGroupListModal.component.tsx @@ -0,0 +1,88 @@ +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_TYPE, + ODS_BUTTON_VARIANT, + ODS_SPINNER_SIZE, +} from '@ovhcloud/ods-components'; +import { + OsdsButton, + OsdsModal, + OsdsSpinner, +} from '@ovhcloud/ods-components/react'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { IdentityGroup } from '@/types/identity.type'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { useIdentityGroupList } from '@/data/hooks/useIdentity'; +import IdentitiesGroupList from '@/pages/credential/create/identities/list/IdentitiesGroupList.component'; + +type IdentityGroupListModalProps = { + closeModal: () => void; +}; + +const IdentityGroupListModal = ({ + closeModal, +}: IdentityGroupListModalProps) => { + const { t } = useTranslation('key-management-service/credential'); + const { combinedData, isLoading } = useIdentityGroupList(); + const { groupList, setGroupList } = useIdentityData(); + const [selectedGroupList, setSelectedGroupList] = useState( + groupList, + ); + + const close = () => { + closeModal(); + }; + + return ( + +
+ {isLoading ? ( +
+ +
+ ) : ( + + )} +
+ + {t( + 'key_management_service_credentials_identity_modal_group_list_cancel', + )} + + { + setGroupList(selectedGroupList); + close(); + }} + > + {t('key_management_service_credentials_identity_modal_group_list_add')} + +
+ ); +}; + +export default IdentityGroupListModal; diff --git a/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityServiceAccountListModal.component.tsx b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityServiceAccountListModal.component.tsx new file mode 100644 index 000000000000..f5ed6614b86e --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityServiceAccountListModal.component.tsx @@ -0,0 +1,88 @@ +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_TYPE, + ODS_BUTTON_VARIANT, + ODS_SPINNER_SIZE, +} from '@ovhcloud/ods-components'; +import { + OsdsButton, + OsdsModal, + OsdsSpinner, +} from '@ovhcloud/ods-components/react'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { IdentityOauthClient } from '@/types/identity.type'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { useIdentityServiceAccountList } from '@/data/hooks/useIdentity'; +import IdentitiesServiceAccountList from '@/pages/credential/create/identities/list/IdentitiesServiceAccountList.component'; + +type IdentityServiceAccountListModalProps = { + closeModal: () => void; +}; + +const IdentityServiceAccountListModal = ({ + closeModal, +}: IdentityServiceAccountListModalProps) => { + const { t } = useTranslation('key-management-service/credential'); + const { combinedData, isLoading } = useIdentityServiceAccountList(); + const { serviceAccountList, setServiceAccountList } = useIdentityData(); + const [selectedServiceAccountList, setSelectedServiceAccountList] = useState< + IdentityOauthClient[] + >(serviceAccountList); + + const close = () => { + closeModal(); + }; + + return ( + +
+ {isLoading ? ( +
+ +
+ ) : ( + + )} +
+ + {t( + 'key_management_service_credentials_identity_modal_user_list_cancel', + )} + + { + setServiceAccountList(selectedServiceAccountList); + close(); + }} + > + {t('key_management_service_credentials_identity_modal_user_list_add')} + +
+ ); +}; + +export default IdentityServiceAccountListModal; diff --git a/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityUserListModal.component.tsx b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityUserListModal.component.tsx new file mode 100644 index 000000000000..7b873260b3c7 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/Modal/credential/identities/IdentityUserListModal.component.tsx @@ -0,0 +1,90 @@ +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_TYPE, + ODS_BUTTON_VARIANT, + ODS_SPINNER_SIZE, +} from '@ovhcloud/ods-components'; +import { + OsdsButton, + OsdsModal, + OsdsSpinner, +} from '@ovhcloud/ods-components/react'; +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { IdentityUser } from '@/types/identity.type'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { useIdentityUserList } from '@/data/hooks/useIdentity'; +import IdentitiesUserList from '@/pages/credential/create/identities/list/IdentitiesUserList.component'; + +type IdentityUserListModalProps = { + closeModal: () => void; +}; + +const IdentityUserListModal = ({ closeModal }: IdentityUserListModalProps) => { + const { t } = useTranslation('key-management-service/credential'); + const { combinedData, isLoading } = useIdentityUserList(); + const { userList, setUserList } = useIdentityData(); + const [selectedUserList, setSelectedUserList] = useState( + userList, + ); + + const close = () => { + closeModal(); + }; + + useEffect(() => { + console.log(selectedUserList); + }, [selectedUserList]); + + return ( + +
+ {isLoading ? ( +
+ +
+ ) : ( + + )} +
+ + {t( + 'key_management_service_credentials_identity_modal_user_list_cancel', + )} + + { + setUserList(selectedUserList); + close(); + }} + > + {t('key_management_service_credentials_identity_modal_user_list_add')} + +
+ ); +}; + +export default IdentityUserListModal; diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.component.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.component.tsx new file mode 100644 index 000000000000..11203df10cc1 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.component.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { TileValue } from '@/components/dashboard/tile-value/tileValue.component'; +import { OkmsCredential } from '@/types/okmsCredential.type'; + +type TCredentialCreationMethod = Pick; + +const CredentialCreationMethod = ({ fromCSR }: TCredentialCreationMethod) => { + const { t } = useTranslation('key-management-service/credential'); + + return ( + + ); +}; + +export default CredentialCreationMethod; diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.spec.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.spec.tsx new file mode 100644 index 000000000000..e49c863ee0bf --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialCreationMethod/credentialCreationMethod.spec.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import CredentialCreationMethod from './credentialCreationMethod.component'; + +describe('CredentialStatus component test suite', () => { + const useCases: { + fromCSR: boolean; + expectedLabel: string; + otherLabel: string; + }[] = [ + { + fromCSR: true, + expectedLabel: 'key_management_service_credential_created_with_csr', + otherLabel: 'key_management_service_credential_created_without_csr', + }, + { + fromCSR: false, + expectedLabel: 'key_management_service_credential_created_without_csr', + otherLabel: 'key_management_service_credential_created_with_csr', + }, + ]; + + test.each(useCases)( + 'should return the right translation text for `fromCSR===$fromCSR`', + ({ fromCSR, expectedLabel, otherLabel }) => { + // given fromCSR + + // when + const { getByText, queryByText } = render( + , + ); + + // then + expect(getByText(expectedLabel)).toBeInTheDocument(); + expect(queryByText(otherLabel)).not.toBeInTheDocument(); + }, + ); +}); diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagrid.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagrid.tsx new file mode 100644 index 000000000000..af1e89646988 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagrid.tsx @@ -0,0 +1,108 @@ +import { + Datagrid, + DatagridColumn, + ErrorBanner, +} from '@ovh-ux/manager-react-components'; +import { queryClient } from '@ovh-ux/manager-react-core-application'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { + getOkmsCredentialsQueryKey, + useOkmsCredentials, +} from '@/data/hooks/useOkmsCredential'; +import { + DatagridCredentialCellActions, + DatagridCredentialCellCreationDate, + DatagridCredentialCellExpirationDate, + DatagridCredentialCellId, + DatagridCredentialCellIdentities, + DatagridCredentialCellName, + DatagridCredentialCellStatus, +} from '@/components/credential/credentialDatagrid/CredentialDatagridCells'; +import Loading from '@/components/Loading/Loading'; +import { OkmsCredential } from '@/types/okmsCredential.type'; + +const CredentialDatagrid = () => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const { okmsId } = useParams(); + + const { + data: credentials, + isLoading: isLoadingCredentials, + error: credentialsError, + } = useOkmsCredentials(okmsId); + + if (isLoadingCredentials) return ; + + if (credentialsError) + return ( + navigate(ROUTES_URLS.listing)} + onReloadPage={() => + queryClient.refetchQueries({ + queryKey: getOkmsCredentialsQueryKey(okmsId), + }) + } + /> + ); + + const columns: DatagridColumn[] = [ + { + id: 'name', + cell: DatagridCredentialCellName, + label: t('key_management_service_credential_list_column_name'), + isSortable: false, + }, + { + id: 'id', + cell: DatagridCredentialCellId, + label: t('key_management_service_credential_list_column_id'), + isSortable: false, + }, + { + id: 'identities', + cell: DatagridCredentialCellIdentities, + label: t('key_management_service_credential_list_column_identities'), + isSortable: false, + }, + { + id: 'creation_date', + cell: DatagridCredentialCellCreationDate, + label: t('key_management_service_credential_list_column_creation_date'), + isSortable: false, + }, + { + id: 'expiration_date', + cell: DatagridCredentialCellExpirationDate, + label: t('key_management_service_credential_list_column_expiration_date'), + isSortable: false, + }, + { + id: 'status', + cell: DatagridCredentialCellStatus, + label: t('key_management_service_credential_list_column_status'), + isSortable: false, + }, + { + id: 'actions', + cell: DatagridCredentialCellActions, + label: '', + isSortable: false, + }, + ]; + + return ( + + ); +}; + +export default CredentialDatagrid; diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagridCells.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagridCells.tsx new file mode 100644 index 000000000000..2ee6935fecaa --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialDatagrid/CredentialDatagridCells.tsx @@ -0,0 +1,113 @@ +import React, { useContext } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + ActionMenu, + ActionMenuItem, + DataGridClipboardCell, + DataGridTextCell, + Links, +} from '@ovh-ux/manager-react-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OkmsCredential } from '@/types/okmsCredential.type'; +import { useFormattedDate } from '@/hooks/useFormattedDate'; +import { CredentialStatus } from '../credentialStatus/CredentialStatus.component'; +import { getDownloadCredentialParameters } from '@/utils/credential/credentialDownload'; +import { OkmsContext } from '@/pages/dashboard'; +import { ROUTES_URLS } from '@/routes/routes.constants'; + +export const DatagridCredentialCellName = (credential: OkmsCredential) => { + const navigate = useNavigate(); + return ( +
+ { + navigate(`${credential.id}`); + }} + label={credential.name} + /> +
+ ); +}; + +export const DatagridCredentialCellId = (credential: OkmsCredential) => { + return ; +}; + +export const DatagridCredentialCellIdentities = ( + credential: OkmsCredential, +) => { + const identities = credential.identityURNs.length; + return {identities}; +}; + +const dateFormatOptions: Intl.DateTimeFormatOptions = { + hour12: false, + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', +}; + +export const DatagridCredentialCellCreationDate = ( + credential: OkmsCredential, +) => { + const date = new Date(Date.parse(credential.createdAt)); + + const formattedDate = useFormattedDate({ + date, + options: dateFormatOptions, + }); + + return {formattedDate}; +}; + +export const DatagridCredentialCellExpirationDate = ( + credential: OkmsCredential, +) => { + const date = new Date(Date.parse(credential.expiredAt)); + + const formattedDate = useFormattedDate({ + date, + options: dateFormatOptions, + }); + + return {formattedDate}; +}; + +export const DatagridCredentialCellStatus = (credential: OkmsCredential) => { + return ; +}; + +export const DatagridCredentialCellActions = (credential: OkmsCredential) => { + const { t } = useTranslation('key-management-service/credential'); + const okms = useContext(OkmsContext); + const navigate = useNavigate(); + + const { filename, href, isDisabled } = getDownloadCredentialParameters( + credential, + ); + + const items: ActionMenuItem[] = [ + { + id: 1, + label: t('key_management_service_credential_download'), + href, + download: filename, + disabled: isDisabled, + }, + { + id: 2, + label: t('key_management_service_credential_delete'), + color: ODS_THEME_COLOR_INTENT.error, + iamActions: ['okms:apiovh:resource/credential/delete'], + urn: okms.iam.urn, + onClick: () => + navigate(`${ROUTES_URLS.credentialDelete}/${credential.id}`), + }, + ]; + + return ; +}; diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.component.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.component.tsx new file mode 100644 index 000000000000..181df57a8ef8 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.component.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + ODS_CHIP_SIZE, + ODS_TEXT_COLOR_INTENT, + OdsChipAttribute, +} from '@ovhcloud/ods-components'; +import { OsdsChip } from '@ovhcloud/ods-components/react'; +import { OkmsCredentialStatus } from '@/types/okmsCredential.type'; + +export type KeyStatusProps = Omit & { + state: OkmsCredentialStatus; +}; + +export const CredentialStatus = ({ + state, + size = ODS_CHIP_SIZE.md, + ...otherProps +}: KeyStatusProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const chipPropsByState: { + [key in OkmsCredentialStatus]: { + translationKey: string; + color: ODS_TEXT_COLOR_INTENT; + }; + } = { + [OkmsCredentialStatus.creating]: { + translationKey: 'key_management_service_credential_status_creating', + color: ODS_TEXT_COLOR_INTENT.primary, + }, + [OkmsCredentialStatus.deleting]: { + translationKey: 'key_management_service_credential_status_deleting', + color: ODS_TEXT_COLOR_INTENT.warning, + }, + [OkmsCredentialStatus.error]: { + translationKey: 'key_management_service_credential_status_error', + color: ODS_TEXT_COLOR_INTENT.error, + }, + [OkmsCredentialStatus.expired]: { + translationKey: 'key_management_service_credential_status_expired', + color: ODS_TEXT_COLOR_INTENT.default, + }, + [OkmsCredentialStatus.ready]: { + translationKey: 'key_management_service_credential_status_ready', + color: ODS_TEXT_COLOR_INTENT.success, + }, + }; + + const props = chipPropsByState[state]; + + return ( + + {props ? t(props.translationKey) : state} + + ); +}; diff --git a/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.spec.tsx b/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.spec.tsx new file mode 100644 index 000000000000..7cef51fbbbee --- /dev/null +++ b/packages/manager/apps/key-management-service/src/components/credential/credentialStatus/CredentialStatus.spec.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { + ODS_TEXT_COLOR_INTENT, + OdsChipAttribute, +} from '@ovhcloud/ods-components'; +import { render } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { OkmsCredentialStatus } from '@/types/okmsCredential.type'; +import { CredentialStatus } from './CredentialStatus.component'; + +describe('CredentialStatus component test suite', () => { + const useCases: { + state: OkmsCredentialStatus; + label: string; + colorValue: OdsChipAttribute['color']; + }[] = [ + { + state: OkmsCredentialStatus.creating, + label: 'key_management_service_credential_status_creating', + colorValue: ODS_TEXT_COLOR_INTENT.primary, + }, + { + state: OkmsCredentialStatus.deleting, + label: 'key_management_service_credential_status_deleting', + colorValue: ODS_TEXT_COLOR_INTENT.warning, + }, + { + state: OkmsCredentialStatus.error, + label: 'key_management_service_credential_status_error', + colorValue: ODS_TEXT_COLOR_INTENT.error, + }, + { + state: OkmsCredentialStatus.expired, + label: 'key_management_service_credential_status_expired', + colorValue: ODS_TEXT_COLOR_INTENT.default, + }, + { + state: OkmsCredentialStatus.ready, + label: 'key_management_service_credential_status_ready', + colorValue: ODS_TEXT_COLOR_INTENT.success, + }, + ]; + + test.each(useCases)( + 'should return the right configuration for $state state', + ({ state, colorValue, label }) => { + // given state, colorValue and label + + // when + const { getByTestId } = render( + , + ); + const component = getByTestId('test'); + + // then + expect(component).toHaveTextContent(label); + expect(component).toHaveProperty('color', colorValue); + }, + ); + + it('should return default configuration for unexpected state', () => { + // given + const serviceKeyState = 'AAA' as OkmsCredentialStatus; + + // when + const { getByTestId } = render( + , + ); + const component = getByTestId('test'); + + // then + expect(component).toHaveTextContent(serviceKeyState); + expect(component).toHaveProperty('color', ODS_TEXT_COLOR_INTENT.default); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/data/api/identity.ts b/packages/manager/apps/key-management-service/src/data/api/identity.ts new file mode 100644 index 000000000000..fb86004209d8 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/api/identity.ts @@ -0,0 +1,87 @@ +import apiClient, { ApiResponse } from '@ovh-ux/manager-core-api'; +import { + IdentityUser, + IdentityGroup, + IdentityOauthClient, +} from '@/types/identity.type'; + +/** + * Retrieve all IAM users of this account + */ + +export const getIdentityUsersIds = async (): Promise> => { + return apiClient.v6.get(`me/identity/user`); +}; + +export const getIdentityUsersIdsQueryKey = () => [`get/me/identity/user`]; + +/** + * Retrieve user by ID + */ + +export const getIdentityUser = async ( + userId: string, +): Promise> => { + return apiClient.v6.get(`me/identity/user/${userId}`); +}; + +export const getIdentityUserQueryKey = (userId: string) => [ + 'get/me/identity/user/', + userId, +]; + +/** + * Retrieve all IAM groups of this account + */ + +export const getIdentityGroupsIds = async (): Promise> => { + return apiClient.v6.get(`me/identity/group`); +}; + +export const getIdentityGroupsIdsQueryKey = () => [`get/me/identity/group`]; + +/** + * Retrieve group by ID + */ + +export const getIdentityGroup = async ( + groupId: string, +): Promise> => { + return apiClient.v6.get(`me/identity/group/${groupId}`); +}; + +export const getIdentityGroupQueryKey = (groupId: string) => [ + 'get/me/identity/group/', + groupId, +]; + +/** + * Retrieve all oAuth2 clients (Service Account) + */ + +export const getIdentityServiceAccountsIds = async (): Promise> => { + return apiClient.v6.get(`me/api/oauth2/client`); +}; + +export const getIdentityServiceAccountsIdsQueryKey = () => [ + `get/me/api/oauth2/client`, +]; + +/** + * Retrieve service account by ID + */ + +export const getIdentityServiceAccount = async ( + serviceAccountId: string, +): Promise> => { + return apiClient.v6.get(`me/api/oauth2/client/${serviceAccountId}`); +}; + +export const getIdentityServiceAccountQueryKey = (serviceAccountId: string) => [ + 'get/me/identity/service-account/', + serviceAccountId, +]; diff --git a/packages/manager/apps/key-management-service/src/data/api/okmsCredential.ts b/packages/manager/apps/key-management-service/src/data/api/okmsCredential.ts new file mode 100644 index 000000000000..dd22ce669369 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/api/okmsCredential.ts @@ -0,0 +1,76 @@ +import apiClient, { ApiResponse } from '@ovh-ux/manager-core-api'; +import { + OkmsCredential, + OkmsCredentialCreation, +} from '@/types/okmsCredential.type'; + +/** + * Get okms Credential list + */ + +export const getOkmsCredentials = async ( + okmsId: string, +): Promise> => { + return apiClient.v2.get(`okms/resource/${okmsId}/credential`); +}; + +/** + * Get okms Credential + */ + +export const getOkmsCredential = async ({ + okmsId, + credentialId, +}: { + okmsId: string; + credentialId: string; +}): Promise> => { + return apiClient.v2.get(`okms/resource/${okmsId}/credential/${credentialId}`); +}; + +/** + * create okms Credential + */ + +export const createOkmsCredential = async ({ + okmsId, + data, +}: { + okmsId: string; + data: OkmsCredentialCreation; +}) => { + return apiClient.v2.post( + `okms/resource/${okmsId}/credential`, + data, + ); +}; + +export const createOkmsCredentialQueryKey = ({ + okmsId, +}: { + okmsId: string; +}) => [`post/okms/resource/${okmsId}/credential/create`]; + +/** + * delete okms Credential + */ + +export const deleteOkmsCredential = async ({ + okmsId, + credentialId, +}: { + okmsId: string; + credentialId: string; +}) => { + return apiClient.v2.delete( + `okms/resource/${okmsId}/credential/${credentialId}`, + ); +}; + +export const deleteOkmsCredentialQueryKey = ({ + okmsId, + credentialId, +}: { + okmsId: string; + credentialId: string; +}) => [`/okms/resource/${okmsId}/credential/${credentialId}`]; diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useCreateOkmsCredential.ts b/packages/manager/apps/key-management-service/src/data/hooks/useCreateOkmsCredential.ts new file mode 100644 index 000000000000..42061cf963ab --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/hooks/useCreateOkmsCredential.ts @@ -0,0 +1,55 @@ +import { ApiError } from '@ovh-ux/manager-core-api'; +import { useTranslation } from 'react-i18next'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { + OkmsCredential, + OkmsCredentialCreation, +} from '@/types/okmsCredential.type'; +import { createOkmsCredential } from '../api/okmsCredential'; +import { getOkmsCredentialsQueryKey } from './useOkmsCredential'; + +export type CreateOkmsCredentialParams = { + okmsId: string; + onSuccess: (credential: OkmsCredential) => void; + onError: () => void; +}; + +export const useCreateOkmsCredential = ({ + okmsId, + onSuccess, + onError, +}: CreateOkmsCredentialParams) => { + const queryClient = useQueryClient(); + const { addError, addSuccess } = useNotifications(); + + const { t } = useTranslation('key-management-service/credential'); + + const { mutate: createKmsCredential, isPending } = useMutation({ + mutationFn: async (data: OkmsCredentialCreation) => { + const okmsCredential = await createOkmsCredential({ okmsId, data }); + return okmsCredential.data; + }, + onSuccess: async (credential: OkmsCredential) => { + await queryClient.invalidateQueries({ + queryKey: getOkmsCredentialsQueryKey(okmsId), + }); + addSuccess(t('key_management_service_credential_create_success'), true); + onSuccess?.(credential); + }, + onError: (result: ApiError) => { + addError( + t('key_management_service_credential_create_error', { + error: result.message, + }), + true, + ); + onError?.(); + }, + }); + + return { + createKmsCredential, + isPending, + }; +}; diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useDeleteOkmsCredential.ts b/packages/manager/apps/key-management-service/src/data/hooks/useDeleteOkmsCredential.ts new file mode 100644 index 000000000000..81d86113ea6e --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/hooks/useDeleteOkmsCredential.ts @@ -0,0 +1,56 @@ +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { ApiError } from '@ovh-ux/manager-core-api'; +import { useTranslation } from 'react-i18next'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { + deleteOkmsCredential, + deleteOkmsCredentialQueryKey, +} from '../api/okmsCredential'; +import { getOkmsCredentialsQueryKey } from './useOkmsCredential'; + +export interface IUseDeleteOkmsCredential { + okmsId: string; + credentialId: string; + onSuccess: () => void; + onError: () => void; +} + +export const useDeleteOkmsCredential = ({ + okmsId, + credentialId, + onSuccess, + onError, +}: IUseDeleteOkmsCredential) => { + const queryClient = useQueryClient(); + const { addError, addSuccess } = useNotifications(); + const { t } = useTranslation('key-management-service/credential'); + + const { mutate, isPending } = useMutation({ + mutationKey: deleteOkmsCredentialQueryKey({ okmsId, credentialId }), + mutationFn: async () => { + return deleteOkmsCredential({ okmsId, credentialId }); + }, + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: getOkmsCredentialsQueryKey(okmsId), + }); + + addSuccess(t('key_management_service_credential_delete_success'), true); + onSuccess(); + }, + onError: (result: ApiError) => { + addError( + t('key_management_service_credential_delete_error', { + error: result.message, + }), + true, + ); + onError(); + }, + }); + + return { + mutate, + isPending, + }; +}; diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useIdentity.ts b/packages/manager/apps/key-management-service/src/data/hooks/useIdentity.ts new file mode 100644 index 000000000000..d7a2a414e28e --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/hooks/useIdentity.ts @@ -0,0 +1,101 @@ +import { UseQueryOptions, useQueries, useQuery } from '@tanstack/react-query'; +import { ApiError, ApiResponse } from '@ovh-ux/manager-core-api'; +import { + getIdentityUsersIdsQueryKey, + getIdentityUsersIds, + getIdentityUserQueryKey, + getIdentityUser, + getIdentityGroupsIdsQueryKey, + getIdentityGroupsIds, + getIdentityGroup, + getIdentityGroupQueryKey, + getIdentityServiceAccountQueryKey, + getIdentityServiceAccount, + getIdentityServiceAccountsIdsQueryKey, + getIdentityServiceAccountsIds, +} from '../api/identity'; +import { + IdentityUser, + IdentityGroup, + IdentityOauthClient, +} from '@/types/identity.type'; + +const useIdentityList = ( + idsQueryKeyFn: () => unknown[], + idsQueryFn: () => Promise>, + detailsQueryKeyFn: (id: string) => unknown[], + detailsQueryFn: (id: string) => Promise>, +) => { + const { + data: listData, + isLoading: isListLoading, + isError: isListError, + error: listError, + isFetched, + } = useQuery, ApiError>({ + queryKey: idsQueryKeyFn(), + queryFn: idsQueryFn, + }); + + const detailsQueries = useQueries({ + queries: + isFetched && listData?.data.length > 0 + ? listData.data.map( + (id): UseQueryOptions, ApiError> => ({ + retry: false, + queryKey: detailsQueryKeyFn(id), + queryFn: () => detailsQueryFn(id), + }), + ) + : [], + }); + + const resultStatus = { + isLoading: + isListLoading || detailsQueries.some(({ isLoading }) => isLoading), + isError: isListError || detailsQueries.some(({ isError }) => isError), + error: listError || detailsQueries.find(({ error }) => error)?.error, + identitiesInError: detailsQueries + .map(({ isError }, index) => (isError ? listData?.data?.[index] : null)) + .filter(Boolean), + }; + + const combinedData: T[] = + !resultStatus.isLoading && !resultStatus.isError + ? detailsQueries.reduce((acc, { data }) => { + if (data) { + return acc.concat(data?.data); + } + return acc; + }, [] as T[]) + : []; + + return { + combinedData, + ...resultStatus, + }; +}; + +export const useIdentityUserList = () => + useIdentityList( + getIdentityUsersIdsQueryKey, + getIdentityUsersIds, + getIdentityUserQueryKey, + getIdentityUser, + ); + +export const useIdentityGroupList = () => + useIdentityList( + getIdentityGroupsIdsQueryKey, + getIdentityGroupsIds, + getIdentityGroupQueryKey, + getIdentityGroup, + ); + +export const useIdentityServiceAccountList = () => + useIdentityList( + getIdentityServiceAccountsIdsQueryKey, + getIdentityServiceAccountsIds, + getIdentityServiceAccountQueryKey, + getIdentityServiceAccount, + ); diff --git a/packages/manager/apps/key-management-service/src/data/hooks/useOkmsCredential.ts b/packages/manager/apps/key-management-service/src/data/hooks/useOkmsCredential.ts new file mode 100644 index 000000000000..34f095ce565f --- /dev/null +++ b/packages/manager/apps/key-management-service/src/data/hooks/useOkmsCredential.ts @@ -0,0 +1,49 @@ +import { useQuery } from '@tanstack/react-query'; +import { ApiError } from '@ovh-ux/manager-core-api'; +import { OkmsCredential } from '@/types/okmsCredential.type'; +import { getOkmsCredential, getOkmsCredentials } from '../api/okmsCredential'; +import { ErrorResponse } from '@/types/api.type'; + +/* Credential List */ + +export const getOkmsCredentialsQueryKey = (okmsId: string) => [ + `get/okms/resource/${okmsId}/credential`, +]; + +export const useOkmsCredentials = (okmsId: string) => { + return useQuery<{ data: OkmsCredential[] }, ApiError>({ + queryKey: getOkmsCredentialsQueryKey(okmsId), + queryFn: () => getOkmsCredentials(okmsId), + retry: false, + ...{ + keepPreviousData: true, + }, + }); +}; + +/* Credential */ + +export const getOkmsCredentialQueryKey = ({ + okmsId, + credentialId, +}: { + okmsId: string; + credentialId: string; +}) => [`get/okms/resource/${okmsId}/credential/${credentialId}`]; + +export const useOkmsCredentialById = ({ + okmsId, + credentialId, +}: { + okmsId: string; + credentialId: string; +}) => { + return useQuery<{ data: OkmsCredential }, ErrorResponse>({ + queryKey: getOkmsCredentialQueryKey({ okmsId, credentialId }), + queryFn: () => getOkmsCredential({ okmsId, credentialId }), + retry: false, + ...{ + keepPreviousData: true, + }, + }); +}; diff --git a/packages/manager/apps/key-management-service/src/hooks/credential/useIdentityData.tsx b/packages/manager/apps/key-management-service/src/hooks/credential/useIdentityData.tsx new file mode 100644 index 000000000000..69acffbe547e --- /dev/null +++ b/packages/manager/apps/key-management-service/src/hooks/credential/useIdentityData.tsx @@ -0,0 +1,59 @@ +import React, { + createContext, + useContext, + useState, + ReactNode, + useMemo, +} from 'react'; +import { + IdentityUser, + IdentityGroup, + IdentityOauthClient, +} from '@/types/identity.type'; + +interface IdentityDataContextType { + userList: IdentityUser[]; + setUserList: React.Dispatch>; + groupList: IdentityGroup[]; + setGroupList: React.Dispatch>; + serviceAccountList: IdentityOauthClient[]; + setServiceAccountList: React.Dispatch< + React.SetStateAction + >; +} + +const IdentityDataContext = createContext(null); + +export const useIdentityData = () => { + const context = useContext(IdentityDataContext); + if (!context) { + throw new Error('useAppData must be used within an IdentityDataProvider'); + } + return context; +}; + +export const IdentityDataProvider = ({ children }: { children: ReactNode }) => { + const [userList, setUserList] = useState([]); + const [groupList, setGroupList] = useState([]); + const [serviceAccountList, setServiceAccountList] = useState< + IdentityOauthClient[] + >([]); + + return ( + ({ + userList, + setUserList, + groupList, + setGroupList, + serviceAccountList, + setServiceAccountList, + }), + [userList, groupList, serviceAccountList], + )} + > + {children} + + ); +}; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/Credential.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/Credential.page.tsx new file mode 100644 index 000000000000..b3347561389d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/Credential.page.tsx @@ -0,0 +1,163 @@ +import React, { Suspense, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + NavLink, + Outlet, + useLocation, + useNavigate, + useOutletContext, + useParams, +} from 'react-router-dom'; +import { + BaseLayout, + ErrorBanner, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { queryClient } from '@ovh-ux/manager-react-core-application'; +import { + OsdsTabBar, + OsdsTabBarItem, + OsdsTabs, +} from '@ovhcloud/ods-components/react'; +import { + getOkmsCredentialQueryKey, + useOkmsCredentialById, +} from '@/data/hooks/useOkmsCredential'; +import Loading from '@/components/Loading/Loading'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import Breadcrumb from '@/components/Breadcrumb/Breadcrumb'; +import KmsGuidesHeader from '@/components/Guide/KmsGuidesHeader'; +import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; +import { useOKMSById } from '@/data/hooks/useOKMS'; +import { OKMS } from '@/types/okms.type'; +import { OkmsCredential } from '@/types/okmsCredential.type'; + +export type CredentialContextType = { + okms: OKMS; + credential: OkmsCredential; +}; + +export function useOutletCredential() { + return useOutletContext(); +} + +const CredentialDashboard = () => { + const navigate = useNavigate(); + const { t } = useTranslation('key-management-service/credential'); + const [activePanel, setActivePanel] = useState(''); + const location = useLocation(); + const { okmsId, credentialId } = useParams(); + + const { data: okms, isLoading: isLoadingKms, error: errorKms } = useOKMSById( + okmsId, + ); + + const { + data, + isLoading: isLoadingCredential, + error: errorCredential, + } = useOkmsCredentialById({ + okmsId, + credentialId, + }); + + useEffect(() => { + setActivePanel(location.pathname); + }, [location]); + + if (isLoadingCredential || isLoadingKms) return ; + + if (errorCredential || errorKms) { + return ( + navigate(ROUTES_URLS.listing)} + onReloadPage={() => + queryClient.refetchQueries({ + queryKey: getOkmsCredentialQueryKey({ okmsId, credentialId }), + }) + } + /> + ); + } + + const credential = data.data; + + const breadcrumbItems: BreadcrumbItem[] = [ + { + id: okmsId, + label: okms.data.iam.displayName, + navigateTo: `/${okmsId}`, + }, + { + id: ROUTES_URLS.credentials, + label: t('key_management_service_credential'), + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}`, + }, + { + id: credentialId, + label: credential.name, + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}/${credentialId}`, + }, + { + id: ROUTES_URLS.credentialIdentities, + label: t('key_management_service_credential_identities'), + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}/${credentialId}/${ROUTES_URLS.credentialIdentities}`, + }, + ]; + + return ( + }> + } + header={{ + title: credential.name || credential.id, + headerButton: , + }} + backLinkLabel={t( + 'key_management_service_credential_dashboard_backlink', + )} + message={} + onClickReturn={() => navigate(`/${okmsId}/${ROUTES_URLS.credentials}`)} + tabs={ + + + + + {t( + 'key_management_service_credential_dashboard_tab_informations', + )} + + + + + {t( + 'key_management_service_credential_dashboard_tab_identities', + )} + + + + + } + > + + + + ); +}; + +export default CredentialDashboard; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx new file mode 100644 index 000000000000..820c776c97b0 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateAddIdentities.component.tsx @@ -0,0 +1,136 @@ +import { Subtitle } from '@ovh-ux/manager-react-components'; +import React, { + Dispatch, + SetStateAction, + useContext, + useEffect, + useState, +} from 'react'; +import { useTranslation } from 'react-i18next'; +import { OsdsButton, OsdsIcon, OsdsText } from '@ovhcloud/ods-components/react'; +import { + ODS_BUTTON_SIZE, + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import IdentitiesRootAccount from './identities/IdentitiesRootAccount.component'; +import IdentitiesSelectedUsersList from './identities/IdentitiesSelectedUsersList.component'; +import IdentitiesSelectedGroups from './identities/IdentitiesSelectedGroups.component'; +import IdentitiesSelectedServiceAccounts from './identities/IdentitiesSelectedServiceAccounts.component'; + +type CreateAddIdentitiesProps = { + identityURNs: string[]; + setIdentityURNs: Dispatch>; + prevStep: () => void; + nextStep: () => void; +}; + +const CreateAddIdentities = ({ + identityURNs, + setIdentityURNs, + prevStep, + nextStep, +}: CreateAddIdentitiesProps) => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const { okmsId } = useParams(); + const [isRootAccount, setIsRootAccount] = useState(false); + const { userList, groupList, serviceAccountList } = useIdentityData(); + const { nichandle } = useContext(ShellContext).environment.getUser(); + + useEffect(() => { + if (isRootAccount) { + setIdentityURNs([`urn:v1:eu:identity:account:${nichandle}`]); + return; + } + const userURNs = userList.map((user) => user.urn); + const groupURNs = groupList.map((group) => group.urn); + const serviceAccountURNs = serviceAccountList.map( + (serviceAccount) => serviceAccount.identity, + ); + setIdentityURNs([...userURNs, ...groupURNs, ...serviceAccountURNs]); + }, [userList, groupList, serviceAccountList, isRootAccount]); + + return ( +
+
+
+ + {t('key_management_service_credential_create_identities_title')} + + + + {!isRootAccount && ( + <> +
+ + + {t( + 'key_management_service_credential_create_identities_max_label', + )} + +
+ + + + + )} +
+
+ { + navigate(`/${okmsId}/${ROUTES_URLS.credentials}`); + }} + > + {t( + 'key_management_service_credential_create_identities_button_cancel_label', + )} + + + {t( + 'key_management_service_credential_create_identities_button_back_label', + )} + + 25 || identityURNs.length === 0 || undefined + } + > + {t( + 'key_management_service_credential_create_identities_button_create_label', + )} + +
+
+
+ ); +}; + +export default CreateAddIdentities; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateCredential.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateCredential.page.tsx new file mode 100644 index 000000000000..bdd13278305b --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateCredential.page.tsx @@ -0,0 +1,140 @@ +import React, { Suspense, useEffect, useState } from 'react'; +import { + BaseLayout, + ErrorBanner, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { Outlet, useNavigate, useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import Breadcrumb from '@/components/Breadcrumb/Breadcrumb'; +import KmsGuidesHeader from '@/components/Guide/KmsGuidesHeader'; +import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { useOKMSById } from '@/data/hooks/useOKMS'; +import Loading from '@/components/Loading/Loading'; +import { IdentityDataProvider } from '@/hooks/credential/useIdentityData'; +import { useCreateOkmsCredential } from '@/data/hooks/useCreateOkmsCredential'; +import CreateGeneralInformations from '@/pages/credential/create/CreateGeneralInformations.component'; +import CreateAddIdentities from '@/pages/credential/create/CreateAddIdentities.component'; +import CreateCredentialConfirmation from '@/pages/credential/create/confirmation/CreateCredentialConfirmation.component'; +import { OkmsCredential } from '@/types/okmsCredential.type'; + +const CreateCredential = () => { + const navigate = useNavigate(); + const { okmsId } = useParams(); + const { data: okms, isLoading, error } = useOKMSById(okmsId); + const { t } = useTranslation('key-management-service/credential'); + const [step, setStep] = useState(1); + const [name, setName] = useState(''); + const [validity, setValidity] = useState(30); + const [description, setDescription] = useState(); + const [csr, setCsr] = useState(null); + const [identityURNs, setIdentityURNs] = useState([]); + const [okmsCredential, setOkmsCredential] = useState(); + const [isCustomCsr, setIsCustomCsr] = useState(false); + const { createKmsCredential } = useCreateOkmsCredential({ + okmsId, + onSuccess: (credential) => { + setOkmsCredential(credential); + }, + onError: () => {}, + }); + + const breadcrumbItems: BreadcrumbItem[] = [ + { + id: okmsId, + label: okms?.data?.iam?.displayName, + navigateTo: `/${okmsId}`, + }, + { + id: ROUTES_URLS.credentials, + label: t('key_management_service_credential'), + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}`, + }, + { + id: ROUTES_URLS.createKmsServiceKey, + label: t('key_management_service_credential_create_title'), + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}/${ROUTES_URLS.createCredential}`, + }, + ]; + + useEffect(() => { + if (okmsCredential) { + if (!okmsCredential.fromCSR) { + setStep(3); + } else { + navigate(`/${okmsId}/${ROUTES_URLS.credentials}`); + } + } + }, [okmsCredential]); + + if (isLoading) return ; + + if (error) + return ( + navigate(ROUTES_URLS.listing)} + /> + ); + + return ( + }> + } + header={{ + title: t('key_management_service_credential_create_title'), + description: t('key_management_service_credential_create_subtitle'), + headerButton: , + }} + > + +
+
+ +
+ {step === 1 && ( + setStep(2)} + /> + )} + {step === 2 && ( + { + setStep(1); + }} + nextStep={() => { + createKmsCredential({ + name, + identityURNs, + description, + validity, + ...(csr ? { csr } : {}), + }); + }} + > + )} + {step === 3 && ( + + )} +
+ +
+
+
+ ); +}; + +export default CreateCredential; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.component.tsx new file mode 100644 index 000000000000..2ccfe170541c --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.component.tsx @@ -0,0 +1,130 @@ +import React, { Dispatch, SetStateAction, useEffect } from 'react'; +import { Subtitle } from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { useNavigate, useParams } from 'react-router-dom'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { validateCredentialName } from '@/utils/credential/validateCredentialName'; +import { validateCredentialDescription } from '@/utils/credential/validateCredentialDescription'; + +import { validateValidityDate } from '@/utils/credential/validateValidityDate'; +import CreateGeneralInformationsName from './generalInformations/CreateGeneralInformationsName.component'; +import CreateGeneralInformationsDescription from './generalInformations/CreateGeneralInformationsDescription'; +import CreateGeneralInformationsValidity from './generalInformations/CreateGeneralInformationsValidity'; +import CreateGeneralInformationsCreationMethod from './generalInformations/CreateGeneralInformationsCreationMethod.component'; +import { validateCredentialCreationMethod } from '@/utils/credential/validateCredentialCreationMethod'; + +type CreateGeneralInformationsProps = { + name: string; + setName: Dispatch>; + validity: number; + setValidity: Dispatch>; + description: string | null; + setDescription: Dispatch>; + csr: string | null; + setCsr: Dispatch>; + isCustomCsr: boolean; + setIsCustomCsr: Dispatch>; + nextStep: () => void; +}; + +const CreateGeneralInformations = ({ + name, + setName, + validity, + setValidity, + description, + setDescription, + csr, + setCsr, + isCustomCsr, + setIsCustomCsr, + nextStep, +}: CreateGeneralInformationsProps) => { + const { t } = useTranslation('key-management-service/credential'); + const { okmsId } = useParams(); + const navigate = useNavigate(); + const credentialNameError = validateCredentialName(name); + const credentialDescriptionError = validateCredentialDescription(description); + const credentialValidityError = validateValidityDate(validity); + const credentialCreationMethodError = validateCredentialCreationMethod(csr); + + useEffect(() => { + if (!isCustomCsr) { + setCsr(null); + } + }, [isCustomCsr]); + + return ( +
+
+
+ + {t( + 'key_management_service_credential_create_general_information_title', + )} + + + + + + {t( + 'key_management_service_credential_create_general_creation_method_title', + )} + + +
+ { + navigate(`/${okmsId}/${ROUTES_URLS.credentials}`); + }} + > + {t('key_management_service_credential_create_cta_cancel')} + + + {t('key_management_service_credential_create_cta_add_identities')} + +
+
+
+
+ ); +}; + +export default CreateGeneralInformations; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.constants.ts b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.constants.ts new file mode 100644 index 000000000000..b34fa3593297 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/CreateGeneralInformations.constants.ts @@ -0,0 +1,40 @@ +export const VALIDITY_PERIOD_PRESET = [ + { + label: + 'key_management_service_credential_create_general_validity_period_day', + days: 1, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_week', + days: 7, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_month', + days: 30, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_3months', + days: 90, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_6months', + days: 183, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_year', + days: 365, + }, + { + label: + 'key_management_service_credential_create_general_validity_period_custom', + days: -1, + }, +]; + +export const CSR_PLACEHOLDER = + '-----BEGIN CERTIFICATE REQUEST-----\nMIICvTCCAaUCAQAwNTELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEJyaXR0YW55MRMwEQYDVQQHDApDb25jYXJuZWF1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsuDwq/fuIwOzfbilAxBveL4RyXTHPP................ \n-----END CERTIFICATE REQUEST-----'; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/addGroups/CreateCredentialIdentityGroupList.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/addGroups/CreateCredentialIdentityGroupList.page.tsx new file mode 100644 index 000000000000..dd579bc61fa7 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/addGroups/CreateCredentialIdentityGroupList.page.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import IdentityGroupListModal from '@/components/Modal/credential/identities/IdentityGroupListModal.component'; + +const CreateCredentialIdentityGroupList = () => { + const navigate = useNavigate(); + + const closeModal = () => { + navigate('..'); + }; + + return ; +}; + +export default CreateCredentialIdentityGroupList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/addServiceAccount/CreateCredentialIdentityServiceAccountList.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/addServiceAccount/CreateCredentialIdentityServiceAccountList.page.tsx new file mode 100644 index 000000000000..737f71eb41e1 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/addServiceAccount/CreateCredentialIdentityServiceAccountList.page.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import IdentityServiceAccountListModal from '@/components/Modal/credential/identities/IdentityServiceAccountListModal.component'; + +const CreateCredentialIdentityServiceAccountList = () => { + const navigate = useNavigate(); + + const closeModal = () => { + navigate('..'); + }; + + return ; +}; + +export default CreateCredentialIdentityServiceAccountList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/addUsers/CreateCredentialIdentityUserList.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/addUsers/CreateCredentialIdentityUserList.page.tsx new file mode 100644 index 000000000000..df1cbef2b3f2 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/addUsers/CreateCredentialIdentityUserList.page.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import IdentityUserListModal from '@/components/Modal/credential/identities/IdentityUserListModal.component'; + +const CreateCredentialIdentityUserList = () => { + const navigate = useNavigate(); + + const closeModal = () => { + navigate('..'); + }; + + return ; +}; + +export default CreateCredentialIdentityUserList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmation.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmation.component.tsx new file mode 100644 index 000000000000..fb67de5d8095 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmation.component.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import CreateCredentialConfirmationDetails from './CreateCredentialConfirmationDetails.component'; +import CreateCredentialConfirmationPrivateKey from './CreateCredentialConfirmationPrivateKey.component'; +import { OkmsCredential } from '@/types/okmsCredential.type'; +import { ROUTES_URLS } from '@/routes/routes.constants'; + +type CreateCredentialConfirmationProps = { + okmsCredential: OkmsCredential; +}; + +const CreateCredentialConfirmation = ({ + okmsCredential, +}: CreateCredentialConfirmationProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [isKeyDownloaded, setIsKeyDownloaded] = useState(false); + const { okmsId } = useParams(); + const navigate = useNavigate(); + + return ( +
+ + + + navigate(`/${okmsId}/${ROUTES_URLS.credentials}`)} + inline + > + {t( + 'key_management_service_credential_create_confirmation_button_done_label', + )} + + +
+ ); +}; + +export default CreateCredentialConfirmation; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetails.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetails.component.tsx new file mode 100644 index 000000000000..19b61ed37fd7 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetails.component.tsx @@ -0,0 +1,58 @@ +import { Subtitle } from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { OsdsTile } from '@ovhcloud/ods-components/react'; +import CreateCredentialConfirmationDetailsText from './CreateCredentialConfirmationDetailsText.component'; +import { OkmsCredential } from '@/types/okmsCredential.type'; +import { getDaysFromDate } from '@/utils/credential/validityDateUtils'; + +type CreateCredentialConfirmationDetailsProps = { + okmsCredential: OkmsCredential; +}; + +const CreateCredentialConfirmationDetails = ({ + okmsCredential, +}: CreateCredentialConfirmationDetailsProps) => { + const { t } = useTranslation('key-management-service/credential'); + + return ( + +
+ + {t( + 'key_management_service_credential_create_confirmation_details_title', + )} + + + + + +
+
+ ); +}; + +export default CreateCredentialConfirmationDetails; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetailsText.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetailsText.component.tsx new file mode 100644 index 000000000000..3b132655cc8d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationDetailsText.component.tsx @@ -0,0 +1,20 @@ +import { Description } from '@ovh-ux/manager-react-components'; +import React from 'react'; + +type CreateCredentialConfirmationDetailsTextProps = { + label: string; + value: string; +}; + +const CreateCredentialConfirmationDetailsText = ({ + label, + value, +}: CreateCredentialConfirmationDetailsTextProps) => { + return ( +
+ {`${label}:`} + {value} +
+ ); +}; +export default CreateCredentialConfirmationDetailsText; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationPrivateKey.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationPrivateKey.component.tsx new file mode 100644 index 000000000000..3254397e3974 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/confirmation/CreateCredentialConfirmationPrivateKey.component.tsx @@ -0,0 +1,84 @@ +import { Subtitle } from '@ovh-ux/manager-react-components'; +import { + ODS_BUTTON_SIZE, + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, +} from '@ovhcloud/ods-components'; +import { + OsdsButton, + OsdsCheckbox, + OsdsCheckboxButton, + OsdsMessage, + OsdsText, + OsdsTile, +} from '@ovhcloud/ods-components/react'; +import React, { Dispatch, SetStateAction } from 'react'; +import { useTranslation } from 'react-i18next'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; + +type CreateCredentialConfirmationPrivateKeyProps = { + privateKey: string; + credentialId: string; + isKeyDownloaded: boolean; + setIsKeyDownloaded: Dispatch>; +}; + +const CreateCredentialConfirmationPrivateKey = ({ + privateKey, + credentialId, + isKeyDownloaded, + setIsKeyDownloaded, +}: CreateCredentialConfirmationPrivateKeyProps) => { + const { t } = useTranslation('key-management-service/credential'); + return ( + +
+ + {t( + 'key_management_service_credential_create_confirmation_private-key_title', + )} + + + {t( + 'key_management_service_credential_create_confirmation_private-key_warn', + )} + + + + {t( + 'key_management_service_credential_create_confirmation_private-key_download_label', + )} + + + setIsKeyDownloaded(!isKeyDownloaded)} + > + + + + {t( + 'key_management_service_credential_create_confirmation_private-key_checkbox_label', + )} + + + + +
+
+ ); +}; + +export default CreateCredentialConfirmationPrivateKey; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsCreationMethod.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsCreationMethod.component.tsx new file mode 100644 index 000000000000..10533a5c089f --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsCreationMethod.component.tsx @@ -0,0 +1,144 @@ +import { + CommonTitle, + Description, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { + ODS_THEME_TYPOGRAPHY_SIZE, + ODS_THEME_COLOR_INTENT, +} from '@ovhcloud/ods-common-theming'; +import { + ODS_RADIO_BUTTON_SIZE, + OdsTextAreaValueChangeEvent, + OsdsTextareaCustomEvent, +} from '@ovhcloud/ods-components'; +import { + OsdsFormField, + OsdsRadio, + OsdsRadioButton, + OsdsRadioGroup, + OsdsText, + OsdsTextarea, +} from '@ovhcloud/ods-components/react'; +import React, { Dispatch, SetStateAction } from 'react'; +import { useTranslation } from 'react-i18next'; +import { CSR_PLACEHOLDER } from '../CreateGeneralInformations.constants'; +import { CredentialCreationMethodErrorsType } from '@/utils/credential/validateCredentialCreationMethod'; + +type CreateGeneralInformationsCreationMethodProps = { + csr: string | null; + setCsr: Dispatch>; + isCustomCsr: boolean; + setIsCustomCsr: Dispatch>; + credentialCreationMethodError: CredentialCreationMethodErrorsType | undefined; +}; + +const CreateGeneralInformationsCreationMethod = ({ + csr, + setCsr, + isCustomCsr, + setIsCustomCsr, + credentialCreationMethodError, +}: CreateGeneralInformationsCreationMethodProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const getCreationMethodErrorMessage = ( + error: CredentialCreationMethodErrorsType, + ) => { + if (error === 'REQUIRED') { + return t( + 'key_management_service_credential_update_custom_csr_error_required', + ); + } + return null; + }; + + return ( +
+ + {t( + 'key_management_service_credential_create_general_information_creation_method_subtitle', + )} + + + + setIsCustomCsr(false)} + > + + + {t( + 'key_management_service_credential_create_general_information_creation_method_no_key', + )} + + + {t( + `key_management_service_credential_create_general_information_creation_method_no_key_desc`, + )} + + + + + + setIsCustomCsr(true)} + > + + + {t( + 'key_management_service_credential_create_general_information_creation_method_key', + )} + + + {t( + `key_management_service_credential_create_general_information_creation_method_key_desc`, + )} + + + + + + {isCustomCsr && ( + <> + + {t( + 'key_management_service_credential_create_general_information_csr_title', + )} + + + {t( + 'key_management_service_credential_create_general_information_csr_subtitle', + )} + + + , + ) => { + return setCsr(e.detail.value); + }} + > + + + )} +
+ ); +}; + +export default CreateGeneralInformationsCreationMethod; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsDescription.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsDescription.tsx new file mode 100644 index 000000000000..1eda24c086a3 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsDescription.tsx @@ -0,0 +1,83 @@ +import React, { Dispatch, SetStateAction } from 'react'; +import { CommonTitle } from '@ovh-ux/manager-react-components'; +import { + OsdsFormField, + OsdsText, + OsdsTextarea, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { + ODS_TEXT_LEVEL, + OdsTextAreaValueChangeEvent, + OsdsTextareaCustomEvent, +} from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + CredentialDescriptionErrorsType, + CredentialDescriptionMaxCharacters, +} from '@/utils/credential/validateCredentialDescription'; + +type CreateGeneralInformationsDescriptionProps = { + description: string | null; + setDescription: Dispatch>; + credentialDescriptionError: CredentialDescriptionErrorsType | undefined; +}; + +const CreateGeneralInformationsDescription = ({ + description, + setDescription, + credentialDescriptionError, +}: CreateGeneralInformationsDescriptionProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const getDescriptionErrorMessage = ( + error: CredentialDescriptionErrorsType, + ) => { + switch (error) { + case 'INVALID_CHARACTERS': + return t( + 'key_management_service_credential_update_description_error_invalid_characters', + ); + case 'TOO_MANY_CHARACTERS': + return t( + 'key_management_service_credential_update_description_error_max', + ); + + default: + return null; + } + }; + + return ( +
+ + {t( + 'key_management_service_credential_create_general_information_description_title', + )} + + + , + ) => { + return setDescription(e.detail.value); + }} + > + + {description?.length || 0}/{CredentialDescriptionMaxCharacters} + + +
+ ); +}; + +export default CreateGeneralInformationsDescription; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsName.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsName.component.tsx new file mode 100644 index 000000000000..d27f7fc49c8f --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsName.component.tsx @@ -0,0 +1,75 @@ +import { CommonTitle, Description } from '@ovh-ux/manager-react-components'; +import { + ODS_INPUT_TYPE, + OdsInputValueChangeEventDetail, + OsdsInputCustomEvent, +} from '@ovhcloud/ods-components'; +import { OsdsFormField, OsdsInput } from '@ovhcloud/ods-components/react'; +import React, { Dispatch, SetStateAction } from 'react'; +import { useTranslation } from 'react-i18next'; +import { CredentialNameErrorsType } from '@/utils/credential/validateCredentialName'; + +type CreateGeneralInformationsNameProps = { + name: string; + setName: Dispatch>; + credentialNameError: CredentialNameErrorsType | undefined; +}; + +const CreateGeneralInformationsName = ({ + name, + setName, + credentialNameError, +}: CreateGeneralInformationsNameProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const getNameErrorMessage = (error: CredentialNameErrorsType) => { + switch (error) { + case 'REQUIRED': + return t( + 'key_management_service_credential_update_name_error_required', + ); + case 'INVALID_CHARACTERS': + return t( + 'key_management_service_credential_update_name_error_invalid_characters', + ); + case 'TOO_MANY_CHARACTERS': + return t('key_management_service_credential_update_name_error_max'); + + default: + return null; + } + }; + return ( +
+ + {t( + 'key_management_service_credential_create_general_information_display_name_title', + )} + + + {t( + 'key_management_service_credential_create_general_information_display_name_subtitle', + )} + + + , + ) => { + return setName(e.detail.value); + }} + /> + +
+ ); +}; + +export default CreateGeneralInformationsName; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsValidity.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsValidity.tsx new file mode 100644 index 000000000000..2211f6c9d882 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/generalInformations/CreateGeneralInformationsValidity.tsx @@ -0,0 +1,124 @@ +import { CommonTitle, Description } from '@ovh-ux/manager-react-components'; +import { + OsdsDatepicker, + OsdsFormField, + OsdsSelect, + OsdsSelectOption, + OsdsText, +} from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_TEXT_LEVEL } from '@ovhcloud/ods-components'; +import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { VALIDITY_PERIOD_PRESET } from '../CreateGeneralInformations.constants'; +import { ValidityPeriodErrorsType } from '@/utils/credential/validateValidityDate'; +import { + addDaysToDate, + getDateFromDays, + getDaysFromDate, +} from '@/utils/credential/validityDateUtils'; + +type CreateGeneralInformationsValidityProps = { + validity: number; + setValidity: Dispatch>; + credentialValidityError: ValidityPeriodErrorsType | undefined; +}; + +const CreateGeneralInformationsValidity = ({ + validity, + setValidity, + credentialValidityError, +}: CreateGeneralInformationsValidityProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const getPresetForDays = (days: number): number => + VALIDITY_PERIOD_PRESET.find((preset) => preset.days === days)?.days ?? -1; + + const [validityPresetPeriod, setValidityPresetPeriod] = useState( + getPresetForDays(validity), + ); + const [validityDatepicker, setValidityDatepicker] = useState( + getDateFromDays(validity), + ); + + const getValidityErrorMessage = (error: ValidityPeriodErrorsType) => { + switch (error) { + case 'MIN_PERIOD': + return t( + 'key_management_service_credential_update_validity_error_min_period', + ); + case 'MAX_PERIOD': + return t( + 'key_management_service_credential_update_validity_error_max_period', + ); + + default: + return null; + } + }; + + useEffect(() => { + if (validityPresetPeriod !== -1) { + setValidity(validityPresetPeriod); + } else { + if (!validityDatepicker) return; + setValidity(getDaysFromDate(validityDatepicker)); + } + }, [validityPresetPeriod, validityDatepicker]); + + return ( +
+ + {t( + 'key_management_service_credential_create_general_information_validity_title', + )} + + + {t( + 'key_management_service_credential_create_general_information_validity_subtitle', + )} + + { + return setValidityPresetPeriod(Number(v.detail.value)); + }} + > + {VALIDITY_PERIOD_PRESET.map((validityEntry) => ( + + {t(validityEntry.label)} + + ))} + + {validityPresetPeriod === -1 && ( + + { + setValidityDatepicker(v.detail.value); + }} + maxDate={addDaysToDate(365)} + minDate={addDaysToDate(1)} + > + + {t( + 'key_management_service_credential_create_validity_custom_date_label', + )} + + + {t( + 'key_management_service_credential_update_validity_error_max_period', + )} + + + )} +
+ ); +}; + +export default CreateGeneralInformationsValidity; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesRootAccount.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesRootAccount.component.tsx new file mode 100644 index 000000000000..8429abd96810 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesRootAccount.component.tsx @@ -0,0 +1,55 @@ +import React, { Dispatch, SetStateAction } from 'react'; +import { + OsdsToggle, + OsdsText, + OsdsFormField, + OsdsCheckbox, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; + +type IdentitiesRootAccountProps = { + isRootAccount: boolean; + setIsRootAccount: Dispatch>; +}; + +const IdentitiesRootAccount = ({ + isRootAccount, + setIsRootAccount, +}: IdentitiesRootAccountProps) => { + const { t } = useTranslation('key-management-service/credential'); + + return ( + + { + setIsRootAccount(!isRootAccount); + }} + > + + + {t( + 'key_management_service_credential_create_identities_root_account_toggle_label', + )} + + + + + {t( + 'key_management_service_credential_create_identities_root_account_toggle_helper', + )} + + + ); +}; + +export default IdentitiesRootAccount; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx new file mode 100644 index 000000000000..762edddd6777 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedBase.component.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { + CommonTitle, + Datagrid, + DatagridColumn, +} from '@ovh-ux/manager-react-components'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { useTranslation } from 'react-i18next'; + +type IdentitiesSelectedBaseProps = { + title: string; + addCallback: () => void; + addButtonLabel: string; + deleteCallback: () => void; + datagridColumns: DatagridColumn[]; + items: any[]; +}; + +const IdentitiesSelectedBase = ({ + title, + addCallback, + addButtonLabel, + deleteCallback, + datagridColumns, + items, +}: IdentitiesSelectedBaseProps) => { + const { t } = useTranslation('key-management-service/credential'); + return ( + <> + {title} +
+ + {addButtonLabel} + + + {t( + 'key_management_service_credential_create_identities_users_list_button_delete_all_label', + )} + +
+ + + ); +}; + +export default IdentitiesSelectedBase; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx new file mode 100644 index 000000000000..0d6180275fae --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedGroups.component.tsx @@ -0,0 +1,56 @@ +import { DatagridColumn } from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { IdentityGroup } from '@/types/identity.type'; +import IdentitiesSelectedBase from './IdentitiesSelectedBase.component'; +import IdentityGroupNameCell from './cell/group/IdentityGroupNameCell.component'; +import IdentityGroupDescriptionCell from './cell/group/IdentityGroupDescriptionCell.component'; +import IdentityGroupDeleteActionCell from './cell/group/IdentityGroupDeleteActionCell'; + +const IdentitiesSelectedGroups = () => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const { groupList, setGroupList } = useIdentityData(); + + const columns: DatagridColumn[] = [ + { + id: 'name', + cell: IdentityGroupNameCell, + label: t('key_management_service_credential_user_list_column_name'), + isSortable: false, + }, + { + id: 'description', + cell: IdentityGroupDescriptionCell, + label: t( + 'key_management_service_credential_user_list_column_description', + ), + isSortable: false, + }, + { + id: 'action', + cell: IdentityGroupDeleteActionCell, + label: '', + isSortable: false, + }, + ]; + return ( + navigate(ROUTES_URLS.createCredentialAddGroupsModal)} + addButtonLabel={t( + 'key_management_service_credential_create_identities_users_groups_button_add_label', + )} + deleteCallback={() => setGroupList([])} + datagridColumns={columns} + items={groupList} + > + ); +}; + +export default IdentitiesSelectedGroups; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx new file mode 100644 index 000000000000..ace116814196 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedServiceAccounts.component.tsx @@ -0,0 +1,58 @@ +import { DatagridColumn } from '@ovh-ux/manager-react-components'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { IdentityOauthClient } from '@/types/identity.type'; +import IdentitiesSelectedBase from './IdentitiesSelectedBase.component'; +import IdentityServiceAccountDescriptionCell from './cell/service-account/IdentityServiceAccountDescriptionCell.component'; +import IdentityServiceAccountNameCell from './cell/service-account/IdentityServiceAccountNameCell.component'; +import IdentityServiceAccountDeleteActionCell from './cell/service-account/IdentityServiceAccountDeleteActionCell'; + +const IdentitiesSelectedServiceAccounts = () => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const { serviceAccountList, setServiceAccountList } = useIdentityData(); + + const columns: DatagridColumn[] = [ + { + id: 'name', + cell: IdentityServiceAccountNameCell, + label: t('key_management_service_credential_user_list_column_name'), + isSortable: false, + }, + { + id: 'description', + cell: IdentityServiceAccountDescriptionCell, + label: t( + 'key_management_service_credential_user_list_column_description', + ), + isSortable: false, + }, + { + id: 'action', + cell: IdentityServiceAccountDeleteActionCell, + label: '', + isSortable: false, + }, + ]; + return ( + + navigate(ROUTES_URLS.createCredentialAddServiceAccountModal) + } + addButtonLabel={t( + 'key_management_service_credential_create_identities_service_accounts_button_add_label', + )} + deleteCallback={() => setServiceAccountList([])} + datagridColumns={columns} + items={serviceAccountList} + > + ); +}; + +export default IdentitiesSelectedServiceAccounts; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx new file mode 100644 index 000000000000..79e1b2a89943 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/IdentitiesSelectedUsersList.component.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { DatagridColumn } from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { IdentityUser } from '@/types/identity.type'; +import IdentitiesSelectedBase from './IdentitiesSelectedBase.component'; +import IdentityUserLoginCell from './cell/user/IdentityUserLoginCell.component'; +import IdentityUserGroupCell from './cell/user/IdentityUserGroupCell.component'; +import IdentityUserStatusCell from './cell/user/IdentityUserStatusCell.component'; +import IdentityUserDeleteActionCell from './cell/user/IdentityUserDeleteActionCell'; + +const IdentitiesSelectedUsersList = () => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const { userList, setUserList } = useIdentityData(); + + const columns: DatagridColumn[] = [ + { + id: 'login', + cell: IdentityUserLoginCell, + label: t('key_management_service_credential_user_list_column_name'), + isSortable: false, + }, + { + id: 'group', + cell: IdentityUserGroupCell, + label: t('key_management_service_credential_user_list_column_group'), + isSortable: false, + }, + { + id: 'status', + cell: IdentityUserStatusCell, + label: t('key_management_service_credential_user_list_column_status'), + isSortable: false, + }, + { + id: 'action', + cell: IdentityUserDeleteActionCell, + label: '', + isSortable: false, + }, + ]; + + return ( + { + return navigate(ROUTES_URLS.createCredentialAddUserModal); + }} + addButtonLabel={t( + 'key_management_service_credential_create_identities_users_list_button_add_label', + )} + deleteCallback={() => { + setUserList([]); + }} + datagridColumns={columns} + items={userList} + > + ); +}; + +export default IdentitiesSelectedUsersList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/badge/IdentitiesStatusBadge.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/badge/IdentitiesStatusBadge.component.tsx new file mode 100644 index 000000000000..309ce87ae2ba --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/badge/IdentitiesStatusBadge.component.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { OsdsChip } from '@ovhcloud/ods-components/react'; +import { + ODS_CHIP_SIZE, + ODS_TEXT_COLOR_INTENT, + OdsChipAttribute, +} from '@ovhcloud/ods-components'; +import { useTranslation } from 'react-i18next'; +import { IdentityStatus } from '@/types/identity.type'; + +type IdentitiesStatusBadgeProps = Omit & { + status: IdentityStatus; +}; + +const IdentitiesStatusBadge = ({ + status, + size = ODS_CHIP_SIZE.md, + ...otherProps +}: IdentitiesStatusBadgeProps) => { + const { t } = useTranslation('key-management-service/credential'); + + const chipPropsByStatus: { + [key in IdentityStatus]: { + translationKey: string; + color: ODS_TEXT_COLOR_INTENT; + }; + } = { + [IdentityStatus.password_change_required]: { + translationKey: + 'key_management_service_credential_identity_status_password_change_required', + color: ODS_TEXT_COLOR_INTENT.warning, + }, + [IdentityStatus.disabled]: { + translationKey: + 'key_management_service_credential_identity_status_disabled', + color: ODS_TEXT_COLOR_INTENT.error, + }, + [IdentityStatus.ok]: { + translationKey: 'key_management_service_credential_identity_status_ok', + color: ODS_TEXT_COLOR_INTENT.success, + }, + }; + + const props = chipPropsByStatus[status]; + + return ( + + {props ? t(props.translationKey) : status} + + ); +}; + +export default IdentitiesStatusBadge; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDeleteActionCell.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDeleteActionCell.tsx new file mode 100644 index 000000000000..f445efca56e7 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDeleteActionCell.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import { OsdsButton, OsdsIcon } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; +import { IdentityGroup } from '@/types/identity.type'; + +const IdentityGroupDeleteActionCell = (group: IdentityGroup) => { + const { setGroupList } = useIdentityData(); + + return ( + { + setGroupList((prevGroupList) => + prevGroupList.filter((groupInList) => groupInList.urn !== group.urn), + ); + }} + > + + + ); +}; + +export default IdentityGroupDeleteActionCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDescriptionCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDescriptionCell.component.tsx new file mode 100644 index 000000000000..248669777829 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupDescriptionCell.component.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityGroup } from '@/types/identity.type'; + +const IdentityGroupDescriptionCell = (group: IdentityGroup) => { + return {group.description}; +}; + +export default IdentityGroupDescriptionCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupIdentityCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupIdentityCell.component.tsx new file mode 100644 index 000000000000..0901de9bb2ab --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupIdentityCell.component.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityGroup } from '@/types/identity.type'; + +const IdentityGroupIdentityCell = (group: IdentityGroup) => { + return {group.urn}; +}; + +export default IdentityGroupIdentityCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupNameCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupNameCell.component.tsx new file mode 100644 index 000000000000..2585aa0e939b --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/group/IdentityGroupNameCell.component.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityGroup } from '@/types/identity.type'; + +const IdentityGroupNameCell = (group: IdentityGroup) => { + return {group.name}; +}; + +export default IdentityGroupNameCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDeleteActionCell.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDeleteActionCell.tsx new file mode 100644 index 000000000000..35deb6f46254 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDeleteActionCell.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import { OsdsButton, OsdsIcon } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { IdentityOauthClient } from '@/types/identity.type'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; + +const IdentityServiceAccountDeleteActionCell = ( + serviceAccount: IdentityOauthClient, +) => { + const { setServiceAccountList } = useIdentityData(); + + return ( + { + setServiceAccountList((prevServiceAccountList) => + prevServiceAccountList.filter( + (serviceAccountInList) => + serviceAccountInList.identity !== serviceAccount.identity, + ), + ); + }} + > + + + ); +}; + +export default IdentityServiceAccountDeleteActionCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx new file mode 100644 index 000000000000..14ccda07496b --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountDescriptionCell.component.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityOauthClient } from '@/types/identity.type'; + +const IdentityServiceAccountDescriptionCell = ( + serviceAccount: IdentityOauthClient, +) => { + return {serviceAccount.description}; +}; + +export default IdentityServiceAccountDescriptionCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountNameCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountNameCell.component.tsx new file mode 100644 index 000000000000..881f6b2c6f65 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/service-account/IdentityServiceAccountNameCell.component.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityOauthClient } from '@/types/identity.type'; + +const IdentityServiceAccountNameCell = ( + serviceAccount: IdentityOauthClient, +) => { + return {serviceAccount.name}; +}; + +export default IdentityServiceAccountNameCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserDeleteActionCell.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserDeleteActionCell.tsx new file mode 100644 index 000000000000..d152cfcc6030 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserDeleteActionCell.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import { OsdsButton, OsdsIcon } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { IdentityUser } from '@/types/identity.type'; +import { useIdentityData } from '@/hooks/credential/useIdentityData'; + +const IdentityUserDeleteActionCell = (user: IdentityUser) => { + const { setUserList } = useIdentityData(); + + return ( + { + setUserList((prevUserList) => + prevUserList.filter((userInList) => userInList.urn !== user.urn), + ); + }} + > + + + ); +}; + +export default IdentityUserDeleteActionCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserGroupCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserGroupCell.component.tsx new file mode 100644 index 000000000000..ecdc4d275c68 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserGroupCell.component.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityUser } from '@/types/identity.type'; + +const IdentityUserGroupCell = (user: IdentityUser) => { + return {user.group}; +}; + +export default IdentityUserGroupCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserLoginCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserLoginCell.component.tsx new file mode 100644 index 000000000000..5c325c8adfb8 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserLoginCell.component.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityUser } from '@/types/identity.type'; + +const IdentityUserLoginCell = (user: IdentityUser) => { + return {user.login}; +}; + +export default IdentityUserLoginCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserStatusCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserStatusCell.component.tsx new file mode 100644 index 000000000000..3245a03ef87d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/cell/user/IdentityUserStatusCell.component.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { IdentityUser } from '@/types/identity.type'; +import IdentitiesStatusBadge from '../../badge/IdentitiesStatusBadge.component'; + +const IdentityUserStatusCell = (user: IdentityUser) => { + return ( + + + + ); +}; + +export default IdentityUserStatusCell; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesGroupList.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesGroupList.component.tsx new file mode 100644 index 000000000000..c4d5beca970c --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesGroupList.component.tsx @@ -0,0 +1,60 @@ +import React, { Dispatch, SetStateAction, useState } from 'react'; +import { OsdsSearchBar, OsdsDivider } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { IdentityGroup } from '@/types/identity.type'; +import IdentitiesGroupTile from '../tile/IdentitiesGroupTile.component'; +import identityListSortAndFilter from '@/utils/credential/identityListSortAndFilter'; + +type IdentitiesGroupListProps = { + groupList: IdentityGroup[]; + selectedGroupList: IdentityGroup[]; + setSelectedGroupList: Dispatch>; +}; + +const IdentitiesGroupList = ({ + groupList, + selectedGroupList, + setSelectedGroupList, +}: IdentitiesGroupListProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [sortedFilteredGroups, setSortedFilteredGroups] = useState< + IdentityGroup[] + >(identityListSortAndFilter(groupList, 'name')); + + const filterTerms = (searchTerm: string) => { + setSortedFilteredGroups( + identityListSortAndFilter(groupList, 'name', searchTerm, [ + 'name', + ]), + ); + }; + + return ( + <> + { + return filterTerms(searchText.detail.value); + }} + onOdsSearchSubmit={(searchText) => { + return filterTerms(searchText.detail.inputValue); + }} + placeholder={t( + 'key_management_service_credential_create_identities_group_list_search_placeholder', + )} + /> + +
+ {sortedFilteredGroups.map((group) => ( + + ))} +
+ + ); +}; + +export default IdentitiesGroupList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesServiceAccountList.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesServiceAccountList.component.tsx new file mode 100644 index 000000000000..2c056d6c26fa --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesServiceAccountList.component.tsx @@ -0,0 +1,65 @@ +import React, { Dispatch, SetStateAction, useState } from 'react'; +import { OsdsSearchBar, OsdsDivider } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { IdentityOauthClient } from '@/types/identity.type'; +import IdentitiesServiceAccountTile from '../tile/IdentitiesServiceAccountTile.component'; +import identityListSortAndFilter from '@/utils/credential/identityListSortAndFilter'; + +type IdentitiesServiceAccountProps = { + serviceAccountList: IdentityOauthClient[]; + selectedServiceAccounts: IdentityOauthClient[]; + setSelectedServiceAccounts: Dispatch>; +}; + +const IdentitiesServiceAccountList = ({ + serviceAccountList, + selectedServiceAccounts, + setSelectedServiceAccounts, +}: IdentitiesServiceAccountProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [ + sortedFilteredServiceAccount, + setSortedFilteredServiceAccount, + ] = useState( + identityListSortAndFilter(serviceAccountList, 'name'), + ); + + const filterTerms = (searchTerm: string) => { + setSortedFilteredServiceAccount( + identityListSortAndFilter( + serviceAccountList, + 'name', + searchTerm, + ['name', 'description'], + ), + ); + }; + return ( + <> + { + return filterTerms(searchText.detail.value); + }} + onOdsSearchSubmit={(searchText) => { + return filterTerms(searchText.detail.inputValue); + }} + placeholder={t( + 'key_management_service_credential_create_identities_service-account_list_search_placeholder', + )} + /> + +
+ {sortedFilteredServiceAccount.map((serviceAccount) => ( + + ))} +
+ + ); +}; + +export default IdentitiesServiceAccountList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesUserList.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesUserList.component.tsx new file mode 100644 index 000000000000..326c6a768c2c --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/list/IdentitiesUserList.component.tsx @@ -0,0 +1,61 @@ +import React, { Dispatch, SetStateAction, useState } from 'react'; +import { OsdsSearchBar, OsdsDivider } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import IdentitiesUserTile from '../tile/IdentitiesUserTile.component'; +import { IdentityUser } from '@/types/identity.type'; +import identityListSortAndFilter from '@/utils/credential/identityListSortAndFilter'; + +type IdentitiesUserListProps = { + userList: IdentityUser[]; + selectedUserList: IdentityUser[]; + setSelectedUserList: Dispatch>; +}; + +const IdentitiesUserList = ({ + userList, + selectedUserList, + setSelectedUserList, +}: IdentitiesUserListProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [sortedFilteredUsers, setSortedFilteredUsers] = useState< + IdentityUser[] + >(identityListSortAndFilter(userList, 'login')); + + const filterTerms = (searchTerm: string) => { + setSortedFilteredUsers( + identityListSortAndFilter(userList, 'login', searchTerm, [ + 'login', + 'email', + ]), + ); + }; + + return ( + <> + { + return filterTerms(searchText.detail.value); + }} + onOdsSearchSubmit={(searchText) => { + return filterTerms(searchText.detail.inputValue); + }} + placeholder={t( + 'key_management_service_credential_create_identities_user_list_search_placeholder', + )} + /> + +
+ {sortedFilteredUsers.map((user) => ( + + ))} +
+ + ); +}; + +export default IdentitiesUserList; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesBaseTile.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesBaseTile.component.tsx new file mode 100644 index 000000000000..efe56bb99ac6 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesBaseTile.component.tsx @@ -0,0 +1,55 @@ +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; +import { + OsdsCheckbox, + OsdsText, + OsdsTile, +} from '@ovhcloud/ods-components/react'; +import React, { Dispatch, ReactNode, SetStateAction } from 'react'; + +type IdentitiesBaseTileProps = { + title: string; + urn: string; + updateCallback: (isSelected: boolean) => void; + isChecked: boolean; + setIsChecked: Dispatch>; + children: ReactNode; +}; + +const IdentitiesBaseTile = ({ + title, + urn, + updateCallback, + isChecked, + setIsChecked, + children, +}: IdentitiesBaseTileProps) => { + return ( + { + setIsChecked(!isChecked); + updateCallback(!isChecked); + }} + > + +
+ + {title} + +
{children}
+
+
+
+ ); +}; + +export default IdentitiesBaseTile; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesGroupTile.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesGroupTile.component.tsx new file mode 100644 index 000000000000..89bc469562ed --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesGroupTile.component.tsx @@ -0,0 +1,68 @@ +import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { OsdsText } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { ODS_TEXT_COLOR_INTENT } from '@ovhcloud/ods-components'; +import { IdentityGroup } from '@/types/identity.type'; +import IdentitiesBaseTile from './IdentitiesBaseTile.component'; +import IdentitiesTileText from './IdentitiesTileText.component'; + +type IdentitiesGroupTileProps = { + group: IdentityGroup; + selectedGroupList: IdentityGroup[]; + setSelectedGroupList: Dispatch>; +}; +const IdentitiesGroupTile = ({ + group, + selectedGroupList, + setSelectedGroupList, +}: IdentitiesGroupTileProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [isChecked, setIsChecked] = useState(false); + + useEffect(() => { + if ( + selectedGroupList.some((groupInList) => groupInList.urn === group.urn) + ) { + setIsChecked(true); + } + }, [selectedGroupList, group]); + + const updateGroupInList = (isGroupInList: boolean) => { + setSelectedGroupList((prevGroupList) => + isGroupInList + ? prevGroupList.concat(group) + : prevGroupList.filter((groupInList) => groupInList.urn !== group.urn), + ); + }; + + return ( + + + + {t( + 'key_management_service_credential_create_identities_group_tile_description_label', + )} + : + + {group.description} + + + + {t( + 'key_management_service_credential_create_identities_group_tile_identity_label', + )} + : + + {group.urn} + + + ); +}; + +export default IdentitiesGroupTile; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesServiceAccountTile.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesServiceAccountTile.component.tsx new file mode 100644 index 000000000000..8d6d5f8cc303 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesServiceAccountTile.component.tsx @@ -0,0 +1,81 @@ +import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { OsdsText } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { ODS_TEXT_COLOR_INTENT } from '@ovhcloud/ods-components'; +import { IdentityOauthClient } from '@/types/identity.type'; +import IdentitiesBaseTile from './IdentitiesBaseTile.component'; +import IdentitiesTileText from './IdentitiesTileText.component'; + +type IdentitiesServiceAccountTileProps = { + serviceAccount: IdentityOauthClient; + selectedServiceAccountList: IdentityOauthClient[]; + setSelectedServiceAccountList: Dispatch< + SetStateAction + >; +}; +const IdentitiesServiceAccountTile = ({ + serviceAccount, + selectedServiceAccountList, + setSelectedServiceAccountList, +}: IdentitiesServiceAccountTileProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [isChecked, setIsChecked] = useState(false); + + useEffect(() => { + if ( + selectedServiceAccountList.some( + (serviceAccountInList) => + serviceAccountInList.identity === serviceAccount.identity, + ) + ) { + setIsChecked(true); + } + }, [selectedServiceAccountList, serviceAccount]); + + const updateServiceAccountInList = (isServiceAccountInList: boolean) => { + if (isServiceAccountInList) { + setSelectedServiceAccountList((prevServiceAccountList) => [ + ...prevServiceAccountList, + serviceAccount, + ]); + } else { + setSelectedServiceAccountList((prevServiceAccountList) => + prevServiceAccountList.filter( + (serviceAccountInList) => + serviceAccountInList.identity !== serviceAccount.identity, + ), + ); + } + }; + + return ( + + + + {t( + 'key_management_service_credential_create_identities_service-account_tile_description_label', + )} + : + + {serviceAccount.description} + + + + {t( + 'key_management_service_credential_create_identities_service-account_tile_identity_label', + )} + : + + {serviceAccount.identity} + + + ); +}; + +export default IdentitiesServiceAccountTile; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesTileText.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesTileText.component.tsx new file mode 100644 index 000000000000..cc145b84cb9f --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesTileText.component.tsx @@ -0,0 +1,26 @@ +import { + ODS_TEXT_COLOR_INTENT, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, +} from '@ovhcloud/ods-components'; +import { OsdsText } from '@ovhcloud/ods-components/react'; +import React, { ReactNode } from 'react'; + +type IdentitiesTileTextProps = { + children: ReactNode; +}; + +const IdentitiesTileText = ({ children }: IdentitiesTileTextProps) => { + return ( + + {children} + + ); +}; + +export default IdentitiesTileText; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesUserTile.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesUserTile.component.tsx new file mode 100644 index 000000000000..e9bde0714934 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/create/identities/tile/IdentitiesUserTile.component.tsx @@ -0,0 +1,86 @@ +import React, { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { OsdsText } from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { ODS_CHIP_SIZE, ODS_TEXT_COLOR_INTENT } from '@ovhcloud/ods-components'; +import { IdentityUser } from '@/types/identity.type'; +import IdentitiesTileText from './IdentitiesTileText.component'; +import IdentitiesBaseTile from './IdentitiesBaseTile.component'; +import IdentitiesStatusBadge from '../badge/IdentitiesStatusBadge.component'; + +type IdentitiesUserTileProps = { + user: IdentityUser; + selectedUserList: IdentityUser[]; + setSelectedUserList: Dispatch>; +}; + +const IdentitiesUserTile = ({ + user, + selectedUserList, + setSelectedUserList, +}: IdentitiesUserTileProps) => { + const { t } = useTranslation('key-management-service/credential'); + const [isChecked, setIsChecked] = useState(false); + + useEffect(() => { + if (selectedUserList.find((userInList) => userInList.urn === user.urn)) { + setIsChecked(true); + } + }, [selectedUserList, user]); + + const updateUserInList = (isInList: boolean) => { + if (isInList) { + setSelectedUserList((prevUserList) => [...prevUserList, user]); + } else { + setSelectedUserList((prevUserList) => + prevUserList.filter((userInList) => userInList.urn !== user.urn), + ); + } + }; + + return ( + + + + {t( + 'key_management_service_credential_create_identities_user_tile_email_label', + )} + : + + {user.email} + + + + {t( + 'key_management_service_credential_create_identities_user_tile_group_label', + )} + : + + {user.group} + + + + {t( + 'key_management_service_credential_create_identities_user_tile_identity_label', + )} + : + + {user.urn} + + + + + + ); +}; + +export default IdentitiesUserTile; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/delete/DeleteCredentialModal.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/delete/DeleteCredentialModal.page.tsx new file mode 100644 index 000000000000..edbace35ce5b --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/delete/DeleteCredentialModal.page.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { DeleteModal } from '@ovh-ux/manager-react-components'; +import { useDeleteOkmsCredential } from '@/data/hooks/useDeleteOkmsCredential'; +import { ROUTES_URLS } from '@/routes/routes.constants'; + +const DeleteCredentialPage = () => { + const navigate = useNavigate(); + const { okmsId, credentialId } = useParams(); + const { t } = useTranslation('key-management-service/credential'); + + const { mutate, isPending } = useDeleteOkmsCredential({ + okmsId, + credentialId, + onError: () => navigate('..'), + onSuccess: () => navigate(`/${okmsId}/${ROUTES_URLS.credentials}`), + }); + + const onClose = () => { + navigate('..'); + }; + + const onConfirm = () => { + mutate(); + }; + + return ( + + ); +}; + +export default DeleteCredentialPage; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/generalInformations.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/generalInformations.page.tsx new file mode 100644 index 000000000000..1ad9c998fa7a --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/generalInformations/generalInformations.page.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Outlet, useNavigate } from 'react-router-dom'; +import { OsdsButton } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_BUTTON_SIZE, ODS_BUTTON_VARIANT } from '@ovhcloud/ods-components'; +import { + Clipboard, + DashboardTile, + DashboardTileBlockItem, + ManagerButton, +} from '@ovh-ux/manager-react-components'; +import { CredentialStatus } from '@/components/credential/credentialStatus/CredentialStatus.component'; +import { TileValueDate } from '@/components/dashboard/tile-value-date/tileValueDate.component'; +import CredentialCreationMethod from '@/components/credential/credentialCreationMethod/credentialCreationMethod.component'; +import { getDownloadCredentialParameters } from '@/utils/credential/credentialDownload'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { useOutletCredential } from '../Credential.page'; + +const dateFormat: Intl.DateTimeFormatOptions = { + hour12: false, + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', +}; + +const CredentialGeneralInformations = () => { + const { okms, credential } = useOutletCredential(); + const navigate = useNavigate(); + const { t } = useTranslation('key-management-service/credential'); + + const { filename, href, isDisabled } = getDownloadCredentialParameters( + credential, + ); + + const items: DashboardTileBlockItem[] = [ + { + id: 'name', + label: t('key_management_service_credential_dashboard_name'), + value: credential.name || credential.id, + }, + { + id: 'id', + label: t('key_management_service_credential_dashboard_id'), + value: , + }, + { + id: 'description', + label: t('key_management_service_credential_dashboard_description'), + value: credential.description || '', + }, + { + id: 'status', + label: t('key_management_service_credential_dashboard_status'), + value: , + }, + { + id: 'creation', + label: t('key_management_service_credential_dashboard_creation'), + value: ( +
+ + +
+ ), + }, + { + id: 'expiration', + label: t('key_management_service_credential_dashboard_expiration'), + value: ( + + ), + }, + { + id: 'actions', + label: t('key_management_service_credential_dashboard_actions'), + value: ( +
+ + {t('key_management_service_credential_download')} + + navigate(ROUTES_URLS.credentialDelete)} + iamActions={['okms:apiovh:resource/credential/delete']} + urn={okms.iam.urn} + > + {t('key_management_service_credential_delete')} + +
+ ), + }, + ]; + + return ( +
+ + +
+ ); +}; + +export default CredentialGeneralInformations; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/cell/identityCell.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/cell/identityCell.component.tsx new file mode 100644 index 000000000000..3a3fd224fe8d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/cell/identityCell.component.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { DataGridTextCell } from '@ovh-ux/manager-react-components'; +import { IdentityObject } from '@/types/identity.type'; + +export const IdentityIdCell = (identity: IdentityObject) => { + return {identity.id}; +}; + +export const IdentityUrnCell = (identity: IdentityObject) => { + return {identity.urn}; +}; + +export const IdentityAccountCell = (identity: IdentityObject) => { + return {identity.account}; +}; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/identities.page.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/identities.page.tsx new file mode 100644 index 000000000000..5ce48c477e4a --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/identities.page.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import Users from './users.component'; +import UserGroups from './userGroups.component'; +import ServiceAccounts from './serviceAccounts.component'; +import OVHAccounts from './ovhAccounts.component'; +import { filterIdentities } from '@/utils/credential/filterIdentities'; +import { useOutletCredential } from '../Credential.page'; + +const Identities = () => { + const { + credential: { identityURNs }, + } = useOutletCredential(); + + const userIdentities = filterIdentities({ + identities: identityURNs, + type: 'user', + }); + + const groupsIdentities = filterIdentities({ + identities: identityURNs, + type: 'group', + }); + + const serviceAccountsIdentities = filterIdentities({ + identities: identityURNs, + type: 'credential', + }); + + const OVHAccountsIdentities = filterIdentities({ + identities: identityURNs, + type: 'account', + }); + + return ( +
+ + + + +
+ ); +}; + +export default Identities; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/ovhAccounts.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/ovhAccounts.component.tsx new file mode 100644 index 000000000000..da4a24ba2979 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/ovhAccounts.component.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + Datagrid, + DatagridColumn, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { IdentityObject } from '@/types/identity.type'; +import { + IdentityAccountCell, + IdentityUrnCell, +} from './cell/identityCell.component'; + +interface IOVHAccounts { + identities: IdentityObject[]; +} + +const OVHAccounts = ({ identities }: IOVHAccounts) => { + const { t } = useTranslation('key-management-service/credential'); + + const columns: DatagridColumn[] = [ + { + id: 'Account', + label: t( + 'key_management_service_credential_identities_account_column_account', + ), + cell: IdentityAccountCell, + }, + { + id: 'urn', + label: t('key_management_service_credential_identities_column_urn'), + cell: IdentityUrnCell, + }, + ]; + + return ( +
+ + {t('key_management_service_credential_identities_account_title')} + + +
+ ); +}; + +export default OVHAccounts; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/serviceAccounts.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/serviceAccounts.component.tsx new file mode 100644 index 000000000000..4aa4dde392a8 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/serviceAccounts.component.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + Datagrid, + DatagridColumn, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { IdentityObject } from '@/types/identity.type'; +import { IdentityIdCell, IdentityUrnCell } from './cell/identityCell.component'; + +interface IServiceAccounts { + identities: IdentityObject[]; +} + +const ServiceAccounts = ({ identities }: IServiceAccounts) => { + const { t } = useTranslation('key-management-service/credential'); + + const columns: DatagridColumn[] = [ + { + id: 'id', + label: t( + 'key_management_service_credential_identities_service_account_column_id', + ), + cell: IdentityIdCell, + }, + { + id: 'urn', + label: t('key_management_service_credential_identities_column_urn'), + cell: IdentityUrnCell, + }, + ]; + + return ( +
+ + {t( + 'key_management_service_credential_identities_service_account_title', + )} + + +
+ ); +}; + +export default ServiceAccounts; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/userGroups.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/userGroups.component.tsx new file mode 100644 index 000000000000..d9bf7759c4ac --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/userGroups.component.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + Datagrid, + DatagridColumn, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { IdentityObject } from '@/types/identity.type'; +import { IdentityIdCell, IdentityUrnCell } from './cell/identityCell.component'; + +interface IUserGroups { + identities: IdentityObject[]; +} + +const UserGroups = ({ identities }: IUserGroups) => { + const { t } = useTranslation('key-management-service/credential'); + + const columns: DatagridColumn[] = [ + { + id: 'name', + label: t( + 'key_management_service_credential_identities_usergroup_column_name', + ), + cell: IdentityIdCell, + }, + { + id: 'urn', + label: t('key_management_service_credential_identities_column_urn'), + cell: IdentityUrnCell, + }, + ]; + + return ( +
+ + {t('key_management_service_credential_identities_usergroup_title')} + + +
+ ); +}; + +export default UserGroups; diff --git a/packages/manager/apps/key-management-service/src/pages/credential/identities/users.component.tsx b/packages/manager/apps/key-management-service/src/pages/credential/identities/users.component.tsx new file mode 100644 index 000000000000..5760e09e7542 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/credential/identities/users.component.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { + Datagrid, + DatagridColumn, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { IdentityObject } from '@/types/identity.type'; +import { IdentityIdCell, IdentityUrnCell } from './cell/identityCell.component'; + +interface IUsers { + identities: IdentityObject[]; +} + +const Users = ({ identities }: IUsers) => { + const { t } = useTranslation('key-management-service/credential'); + + const columns: DatagridColumn[] = [ + { + id: 'id', + label: t('key_management_service_credential_identities_user_column_id'), + cell: IdentityIdCell, + }, + { + id: 'urn', + label: t('key_management_service_credential_identities_column_urn'), + cell: IdentityUrnCell, + }, + ]; + + return ( +
+ + {t('key_management_service_credential_identities_user_title')} + + +
+ ); +}; + +export default Users; diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/CredentialList.page.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/CredentialList.page.tsx new file mode 100644 index 000000000000..c4e7227ea957 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/CredentialList.page.tsx @@ -0,0 +1,72 @@ +import React, { useContext } from 'react'; +import { Outlet, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OsdsIcon } from '@ovhcloud/ods-components/react'; +import { useAuthorizationIam } from '@ovh-ux/manager-react-components/src/hooks/iam'; +import { + Description, + ManagerButton, +} from '@ovh-ux/manager-react-components/src/components'; +import { + ODS_BUTTON_SIZE, + ODS_BUTTON_VARIANT, + ODS_ICON_NAME, + ODS_ICON_SIZE, +} from '@ovhcloud/ods-components'; +import Loading from '@/components/Loading/Loading'; +import CredentialDatagrid from '../../../components/credential/credentialDatagrid/CredentialDatagrid'; +import { ROUTES_URLS } from '@/routes/routes.constants'; +import { OkmsContext } from '..'; + +const CredentialList = () => { + const { t } = useTranslation('key-management-service/credential'); + const navigate = useNavigate(); + const okms = useContext(OkmsContext); + + const { isAuthorized, isLoading: isLoadingIam } = useAuthorizationIam( + ['okms:apiovh:resource/credential/get'], + okms.iam.urn, + ); + + if (isLoadingIam) return ; + + return ( +
+ + {t('key_management_service_credential_headline')} + + { + navigate(ROUTES_URLS.createCredential); + }} + iamActions={['okms:apiovh:resource/credential/create']} + urn={okms.iam.urn} + > + + + + {t('key_management_service_credential_cta_create')} + + {isAuthorized ? ( + + ) : ( + + {t('key_management_service_credential_not_authorized')} + + )} + +
+ ); +}; + +export default CredentialList; diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/delete/DeleteCredentialModal.page.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/delete/DeleteCredentialModal.page.tsx new file mode 100644 index 000000000000..23470905d773 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/pages/dashboard/credentialList/delete/DeleteCredentialModal.page.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { DeleteModal } from '@ovh-ux/manager-react-components'; +import { useDeleteOkmsCredential } from '@/data/hooks/useDeleteOkmsCredential'; + +const DeleteCredentialPage = () => { + const navigate = useNavigate(); + const { okmsId, credentialId } = useParams(); + const { t } = useTranslation('key-management-service/credential'); + + const { mutate, isPending } = useDeleteOkmsCredential({ + okmsId, + credentialId, + onError: () => navigate('..'), + onSuccess: () => navigate('..'), + }); + + const onClose = () => { + navigate('..'); + }; + + const onConfirm = () => { + mutate(); + }; + + return ( + + ); +}; + +export default DeleteCredentialPage; diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx index 5812a8f01ea9..862b081ac235 100644 --- a/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx +++ b/packages/manager/apps/key-management-service/src/pages/dashboard/index.tsx @@ -1,11 +1,13 @@ -import React, { Suspense } from 'react'; +import React, { createContext, Suspense } from 'react'; import { useTranslation } from 'react-i18next'; import { Outlet, useNavigate, useParams } from 'react-router-dom'; import { Notifications, BaseLayout, + ErrorBanner, HeadersProps, } from '@ovh-ux/manager-react-components'; +import { queryClient } from '@ovh-ux/manager-react-core-application'; import KmsGuidesHeader from '@/components/Guide/KmsGuidesHeader'; import Dashboard, { DashboardTabItemProps, @@ -15,16 +17,37 @@ import { useOKMSById } from '@/data/hooks/useOKMS'; import Breadcrumb from '@/components/Breadcrumb/Breadcrumb'; import { ROUTES_URLS } from '@/routes/routes.constants'; import { BreadcrumbItem } from '@/hooks/breadcrumb/useBreadcrumb'; +import { getOkmsResourceQueryKey } from '@/data/api/okms'; +import { OKMS } from '@/types/okms.type'; + +export const OkmsContext = createContext(null); export default function DashboardPage() { const { t: tDashboard } = useTranslation('key-management-service/dashboard'); + const navigate = useNavigate(); const { t: tServiceKeys } = useTranslation( 'key-management-service/serviceKeys', ); + const { t: tCredentials } = useTranslation( + 'key-management-service/credential', + ); const { okmsId } = useParams(); - const { data: okms } = useOKMSById(okmsId); - const displayName = okms?.data?.iam?.displayName; - const navigate = useNavigate(); + const { data: okms, isLoading, error } = useOKMSById(okmsId); + + if (isLoading) return ; + + if (error) + return ( + navigate(ROUTES_URLS.listing)} + onReloadPage={() => + queryClient.refetchQueries({ + queryKey: getOkmsResourceQueryKey(okmsId), + }) + } + /> + ); const tabsList: DashboardTabItemProps[] = [ { @@ -36,16 +59,15 @@ export default function DashboardPage() { title: tDashboard('encrypted_keys'), }, { - url: ROUTES_URLS.certificates, + url: ROUTES_URLS.credentials, title: tDashboard('access_certificates'), - disabled: true, }, ]; const breadcrumbItems: BreadcrumbItem[] = [ { id: okmsId, - label: displayName, + label: okms.data.iam.displayName, navigateTo: `/${okmsId}`, }, { @@ -53,27 +75,34 @@ export default function DashboardPage() { label: tServiceKeys('key_management_service_service_keys'), navigateTo: `/${okmsId}/${ROUTES_URLS.keys}`, }, + { + id: ROUTES_URLS.credentials, + label: tCredentials('key_management_service_credential'), + navigateTo: `/${okmsId}/${ROUTES_URLS.credentials}`, + }, ]; const headerProps: HeadersProps = { - title: displayName, + title: okms.data.iam.displayName, headerButton: , }; return ( - { - navigate(ROUTES_URLS.root); - }} - backLinkLabel={tDashboard('key_management_service_dashboard_back_link')} - breadcrumb={} - message={} - tabs={} - > - }> - - - + }> + { + navigate(ROUTES_URLS.root); + }} + backLinkLabel={tDashboard('key_management_service_dashboard_back_link')} + breadcrumb={} + message={} + tabs={} + > + + + + + ); } diff --git a/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/serviceKeyList.page.tsx b/packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx similarity index 100% rename from packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/serviceKeyList.page.tsx rename to packages/manager/apps/key-management-service/src/pages/dashboard/serviceKeyList/ServiceKeyList.page.tsx diff --git a/packages/manager/apps/key-management-service/src/pages/serviceKey/createKey.page.tsx b/packages/manager/apps/key-management-service/src/pages/serviceKey/CreateKey.page.tsx similarity index 100% rename from packages/manager/apps/key-management-service/src/pages/serviceKey/createKey.page.tsx rename to packages/manager/apps/key-management-service/src/pages/serviceKey/CreateKey.page.tsx diff --git a/packages/manager/apps/key-management-service/src/pages/serviceKey/serviceKey.page.tsx b/packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx similarity index 100% rename from packages/manager/apps/key-management-service/src/pages/serviceKey/serviceKey.page.tsx rename to packages/manager/apps/key-management-service/src/pages/serviceKey/ServiceKey.page.tsx diff --git a/packages/manager/apps/key-management-service/src/pages/serviceKey/deactivateServiceKeyModal/deactivateServiceKeyModal.page.tsx b/packages/manager/apps/key-management-service/src/pages/serviceKey/deactivateServiceKeyModal/DeactivateServiceKeyModal.page.tsx similarity index 100% rename from packages/manager/apps/key-management-service/src/pages/serviceKey/deactivateServiceKeyModal/deactivateServiceKeyModal.page.tsx rename to packages/manager/apps/key-management-service/src/pages/serviceKey/deactivateServiceKeyModal/DeactivateServiceKeyModal.page.tsx diff --git a/packages/manager/apps/key-management-service/src/pages/serviceKey/editServiceKeyNameModal/editServiceKeyNameModal.page.tsx b/packages/manager/apps/key-management-service/src/pages/serviceKey/editServiceKeyNameModal/EditServiceKeyNameModal.page.tsx similarity index 100% rename from packages/manager/apps/key-management-service/src/pages/serviceKey/editServiceKeyNameModal/editServiceKeyNameModal.page.tsx rename to packages/manager/apps/key-management-service/src/pages/serviceKey/editServiceKeyNameModal/EditServiceKeyNameModal.page.tsx diff --git a/packages/manager/apps/key-management-service/src/routes/routes.constants.ts b/packages/manager/apps/key-management-service/src/routes/routes.constants.ts index e8c7b74730a7..c7c47288b056 100644 --- a/packages/manager/apps/key-management-service/src/routes/routes.constants.ts +++ b/packages/manager/apps/key-management-service/src/routes/routes.constants.ts @@ -7,8 +7,15 @@ export const ROUTES_URLS = { okmsId: ':okmsId', keys: 'keys', keyId: ':keyId', - serviceKeyEditName: 'edit-name', - certificates: 'certificates', createKmsServiceKey: 'create', + serviceKeyEditName: 'edit-name', serviceKeyDeactivate: 'deactivate', + credentials: 'credentials', + createCredential: 'create', + createCredentialAddUserModal: 'add-users', + createCredentialAddGroupsModal: 'add-groups', + createCredentialAddServiceAccountModal: 'add-service-account', + credentialId: ':credentialId', + credentialIdentities: 'identities', + credentialDelete: 'delete', }; diff --git a/packages/manager/apps/key-management-service/src/routes/routes.tsx b/packages/manager/apps/key-management-service/src/routes/routes.tsx index 0e29a9005312..a37274924b0e 100644 --- a/packages/manager/apps/key-management-service/src/routes/routes.tsx +++ b/packages/manager/apps/key-management-service/src/routes/routes.tsx @@ -88,14 +88,30 @@ export default [ { path: ROUTES_URLS.keys, ...lazyRouteConfig(() => - import('@/pages/dashboard/serviceKeyList/serviceKeyList.page'), + import('@/pages/dashboard/serviceKeyList/ServiceKeyList.page'), ), children: [ { path: `${ROUTES_URLS.serviceKeyDeactivate}/${ROUTES_URLS.keyId}`, ...lazyRouteConfig(() => import( - '@/pages/serviceKey/deactivateServiceKeyModal/deactivateServiceKeyModal.page' + '@/pages/serviceKey/deactivateServiceKeyModal/DeactivateServiceKeyModal.page' + ), + ), + }, + ], + }, + { + path: ROUTES_URLS.credentials, + ...lazyRouteConfig(() => + import('@/pages/dashboard/credentialList/CredentialList.page'), + ), + children: [ + { + path: `${ROUTES_URLS.credentialDelete}/${ROUTES_URLS.credentialId}`, + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/credentialList/delete/DeleteCredentialModal.page' ), ), }, @@ -105,17 +121,79 @@ export default [ }, { path: `${ROUTES_URLS.okmsId}/${ROUTES_URLS.keys}/${ROUTES_URLS.createKmsServiceKey}`, - ...lazyRouteConfig(() => import('@/pages/serviceKey/createKey.page')), + ...lazyRouteConfig(() => import('@/pages/serviceKey/CreateKey.page')), + }, + { + path: `${ROUTES_URLS.okmsId}/${ROUTES_URLS.credentials}/${ROUTES_URLS.createCredential}`, + ...lazyRouteConfig(() => + import('@/pages/credential/create/CreateCredential.page'), + ), + children: [ + { + path: ROUTES_URLS.createCredentialAddUserModal, + ...lazyRouteConfig(() => + import( + '@/pages/credential/create/addUsers/CreateCredentialIdentityUserList.page' + ), + ), + }, + { + path: ROUTES_URLS.createCredentialAddGroupsModal, + ...lazyRouteConfig(() => + import( + '@/pages/credential/create/addGroups/CreateCredentialIdentityGroupList.page' + ), + ), + }, + { + path: ROUTES_URLS.createCredentialAddServiceAccountModal, + ...lazyRouteConfig(() => + import( + '@/pages/credential/create/addServiceAccount/CreateCredentialIdentityServiceAccountList.page' + ), + ), + }, + ], + }, + { + path: `${ROUTES_URLS.okmsId}/${ROUTES_URLS.credentials}/${ROUTES_URLS.credentialId}`, + ...lazyRouteConfig(() => import('@/pages/credential/Credential.page')), + children: [ + { + path: '', + ...lazyRouteConfig(() => + import( + '@/pages/credential/generalInformations/generalInformations.page' + ), + ), + children: [ + { + path: ROUTES_URLS.credentialDelete, + ...lazyRouteConfig(() => + import( + '@/pages/credential/generalInformations/delete/DeleteCredentialModal.page' + ), + ), + }, + ], + }, + { + path: ROUTES_URLS.credentialIdentities, + ...lazyRouteConfig(() => + import('@/pages/credential/identities/identities.page'), + ), + }, + ], }, { path: `${ROUTES_URLS.okmsId}/${ROUTES_URLS.keys}/${ROUTES_URLS.keyId}`, - ...lazyRouteConfig(() => import('@/pages/serviceKey/serviceKey.page')), + ...lazyRouteConfig(() => import('@/pages/serviceKey/ServiceKey.page')), children: [ { path: ROUTES_URLS.serviceKeyEditName, ...lazyRouteConfig(() => import( - '@/pages/serviceKey/editServiceKeyNameModal/editServiceKeyNameModal.page' + '@/pages/serviceKey/editServiceKeyNameModal/EditServiceKeyNameModal.page' ), ), }, @@ -123,7 +201,7 @@ export default [ path: ROUTES_URLS.serviceKeyDeactivate, ...lazyRouteConfig(() => import( - '@/pages/serviceKey/deactivateServiceKeyModal/deactivateServiceKeyModal.page' + '@/pages/serviceKey/deactivateServiceKeyModal/DeactivateServiceKeyModal.page' ), ), }, diff --git a/packages/manager/apps/key-management-service/src/types/identity.type.ts b/packages/manager/apps/key-management-service/src/types/identity.type.ts new file mode 100644 index 000000000000..38161ab4681d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/types/identity.type.ts @@ -0,0 +1,64 @@ +export type IdentityType = 'user' | 'account' | 'group' | 'credential'; +export type IdentityRegion = 'eu' | 'ca' | 'us' | 'labeu'; +export type IdentityEntity = 'identity'; + +export type IdentityObject = { + version: number; + region: IdentityRegion; + entity: IdentityEntity; + type: IdentityType; + account: string; + id: string | null; + urn: string; +}; + +export enum IdentityStatus { + disabled = 'DISABLED', + ok = 'OK', + password_change_required = 'PASSWORD_CHANGE_REQUIRED', +} + +export type IdentityUser = { + creation: string; + description: string; + email: string; + group: string; + lastUpdate: string; + login: string; + passwordLastUpdate: string; + status: IdentityStatus; + urn: string; +}; +enum IdentityGroupRole { + admin = 'ADMIN', + none = 'NONE', + regular = 'REGULAR', + unprivileged = 'UNPRIVILEGED', +} + +export type IdentityGroup = { + creation: string; + defaultGroup: boolean; + description: string | null; + lastUpdate: string; + name: string; + role: IdentityGroupRole; + urn: string; +}; + +enum IdentityOauthClientFlow { + authorization_code = 'AUTHORIZATION_CODE', + client_credentials = 'CLIENT_CREDENTIALS', +} + +export type IdentityOauthClient = { + callbackUrls: string[]; + clientId: string; + createdAt: string; + description: string; + flow: IdentityOauthClientFlow; + identity: string | null; + name: string; +}; + +export type IdentitiesType = IdentityUser | IdentityGroup | IdentityOauthClient; diff --git a/packages/manager/apps/key-management-service/src/types/okmsCredential.type.ts b/packages/manager/apps/key-management-service/src/types/okmsCredential.type.ts new file mode 100644 index 000000000000..90af4c485e10 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/types/okmsCredential.type.ts @@ -0,0 +1,34 @@ +/* + * CREDENTIAL + */ +export type OkmsCredential = { + createdAt: string; + id: string; + name: string; + certificatePEM?: string; + description?: string; + expiredAt: string; + fromCSR: boolean; + identityURNs: string[]; + status: OkmsCredentialStatus; + privateKeyPEM?: string; +}; + +/* +CREDENTIAL STATUS +*/ +export enum OkmsCredentialStatus { + creating = 'CREATING', + deleting = 'DELETING', + error = 'ERROR', + expired = 'EXPIRED', + ready = 'READY', +} + +export type OkmsCredentialCreation = { + name: string; + identityURNs: string[]; + description?: string | null; + validity?: number; + csr?: string; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.spec.ts new file mode 100644 index 000000000000..8bbda0cedc72 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.spec.ts @@ -0,0 +1,40 @@ +import { OkmsCredentialStatus } from '@/types/okmsCredential.type'; +import { isDownloadCredentialDisabled } from './credentialDownload'; + +describe('isDownloadCertificateDisabled test suite', () => { + const useCases: { state: OkmsCredentialStatus; isDisabled: boolean }[] = [ + { + state: OkmsCredentialStatus.creating, + isDisabled: true, + }, + { + state: OkmsCredentialStatus.deleting, + isDisabled: true, + }, + { + state: OkmsCredentialStatus.error, + isDisabled: false, + }, + { + state: OkmsCredentialStatus.expired, + isDisabled: false, + }, + { + state: OkmsCredentialStatus.ready, + isDisabled: false, + }, + ]; + + test.each(useCases)( + 'sould return $isDisabled for $state', + ({ state, isDisabled }) => { + // given state + + // when + const result = isDownloadCredentialDisabled(state); + + // then + expect(result).toBe(isDisabled); + }, + ); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts new file mode 100644 index 000000000000..d85895eb1717 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/credentialDownload.ts @@ -0,0 +1,25 @@ +import { + OkmsCredential, + OkmsCredentialStatus, +} from '@/types/okmsCredential.type'; + +export const isDownloadCredentialDisabled = ( + credentialStatus: OkmsCredential['status'], +) => { + return ( + credentialStatus === OkmsCredentialStatus.creating || + credentialStatus === OkmsCredentialStatus.deleting + ); +}; + +export const getDownloadCredentialParameters = (credential: OkmsCredential) => { + return { + href: credential.certificatePEM + ? `data:text/plain;charset=utf-8,${encodeURIComponent( + credential.certificatePEM.replace(/\n/g, '\r\n'), + )}` + : undefined, + filename: `${credential.name}.pem`, + isDisabled: isDownloadCredentialDisabled(credential.status), + }; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.spec.ts new file mode 100644 index 000000000000..78a74a330368 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.spec.ts @@ -0,0 +1,68 @@ +import { IdentityObject } from '@/types/identity.type'; +import { decodeIdentity } from './decodeIdentities'; + +describe('decodeIdentities test suite', () => { + const useCases: { urn: string; identityObject: IdentityObject }[] = [ + { + urn: 'urn:v1:eu:identity:user:xx111-ovh/user-1', + identityObject: { + version: 1, + region: 'eu', + entity: 'identity', + type: 'user', + account: 'xx111-ovh', + id: 'user-1', + urn: 'urn:v1:eu:identity:user:xx111-ovh/user-1', + }, + }, + { + urn: 'urn:v2:ca:identity:group:aa123-ovh/user-group-1', + identityObject: { + version: 2, + region: 'ca', + entity: 'identity', + type: 'group', + account: 'aa123-ovh', + id: 'user-group-1', + urn: 'urn:v2:ca:identity:group:aa123-ovh/user-group-1', + }, + }, + { + urn: 'urn:v3:us:identity:credential:bb234-ovh/credential-1', + identityObject: { + version: 3, + region: 'us', + entity: 'identity', + type: 'credential', + account: 'bb234-ovh', + id: 'credential-1', + urn: 'urn:v3:us:identity:credential:bb234-ovh/credential-1', + }, + }, + { + urn: 'urn:v4:labeu:identity:account:cc345-ovh', + identityObject: { + version: 4, + region: 'labeu', + entity: 'identity', + type: 'account', + account: 'cc345-ovh', + id: undefined, + urn: 'urn:v4:labeu:identity:account:cc345-ovh', + }, + }, + ]; + + test.each(useCases)( + 'should return $identityObject for $urn', + ({ urn, identityObject }) => { + // given urn and identityObject + + // when + const decodedIdentity = decodeIdentity(urn); + + // then + expect(decodedIdentity).toStrictEqual(identityObject); + }, + ); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.ts b/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.ts new file mode 100644 index 000000000000..9cb70d6a3e81 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/decodeIdentities.ts @@ -0,0 +1,27 @@ +import { + IdentityEntity, + IdentityObject, + IdentityRegion, + IdentityType, +} from '@/types/identity.type'; + +const urnIdentityRegExp = /^urn:v(\d):(eu|ca|us|labeu):([a-z]+):([a-z]+):([a-z]{2}\d{1,6}-ovh)\/?(.+?)?$/; + +export const decodeIdentity = (identityUrn: string): IdentityObject => { + const [match, version, region, entity, type, account, id] = + urnIdentityRegExp.exec(identityUrn) || []; + + if (!match) { + return null; + } + + return { + version: parseInt(version, 10), + region: region as IdentityRegion, + entity: entity as IdentityEntity, + type: type as IdentityType, + account, + id, + urn: identityUrn, + }; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.spec.ts new file mode 100644 index 000000000000..29a508bf4699 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.spec.ts @@ -0,0 +1,105 @@ +import { describe, expect, test } from 'vitest'; +import { filterIdentities } from './filterIdentities'; +import { IdentityType } from '@/types/identity.type'; + +const userIdentities: string[] = [ + 'urn:v1:eu:identity:user:xx111-ovh/user-1', + 'urn:v1:eu:identity:user:xx111-ovh/user-2', +]; + +const groupIdentities: string[] = [ + 'urn:v1:eu:identity:group:xx111-ovh/usergroup-1', + 'urn:v1:eu:identity:group:xx111-ovh/usergroup-2', + 'urn:v1:eu:identity:group:xx111-ovh/usergroup-3', +]; + +const credentialIdentities: string[] = [ + 'urn:v1:eu:identity:credential:xx111-ovh/service-account-1', + 'urn:v1:eu:identity:credential:xx111-ovh/service-account-2', + 'urn:v1:eu:identity:credential:xx111-ovh/service-account-3', + 'urn:v1:eu:identity:credential:xx111-ovh/service-account-4', +]; + +const accountIdentities = [ + 'urn:v1:eu:identity:account:xx111-ovh', + 'urn:v1:eu:identity:account:xx222-ovh', + 'urn:v1:eu:identity:account:xx333-ovh', + 'urn:v1:eu:identity:account:xx444-ovh', + 'urn:v1:eu:identity:account:xx555-ovh', +]; + +const allIdentities = [ + ...userIdentities, + ...groupIdentities, + ...credentialIdentities, + ...accountIdentities, +]; + +describe('filterIdentities test suite', () => { + const useCases: { + identityType: IdentityType; + identityNumber: number; + identities: string[]; + }[] = [ + { + identityType: 'account', + identityNumber: accountIdentities.length, + identities: allIdentities, + }, + { + identityType: 'credential', + identityNumber: credentialIdentities.length, + identities: allIdentities, + }, + { + identityType: 'group', + identityNumber: groupIdentities.length, + identities: allIdentities, + }, + { + identityType: 'user', + identityNumber: userIdentities.length, + identities: allIdentities, + }, + { + identityType: 'account', + identityNumber: 0, + identities: [], + }, + { + identityType: 'credential', + identityNumber: 0, + identities: [], + }, + { + identityType: 'group', + identityNumber: 0, + identities: [], + }, + { + identityType: 'user', + identityNumber: 0, + identities: [], + }, + ]; + + test.each(useCases)( + 'should only return $identityNumber identities of type $identityType', + ({ identityType, identityNumber, identities }) => { + // given type, identityNumber and identities + + // when + const filteredIdentities = filterIdentities({ + identities, + type: identityType, + }); + + // then + expect(filteredIdentities).toHaveLength(identityNumber); + + for (let i = 0; i < filteredIdentities.length; i += 1) { + expect(filteredIdentities[i]).toHaveProperty('type', identityType); + } + }, + ); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.ts b/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.ts new file mode 100644 index 000000000000..32049c9a5f01 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/filterIdentities.ts @@ -0,0 +1,15 @@ +import { IdentityType } from '@/types/identity.type'; +import { decodeIdentity } from './decodeIdentities'; + +interface IfilterIdentities { + identities: string[]; + type: IdentityType; +} + +export const filterIdentities = ({ identities, type }: IfilterIdentities) => { + const decodedIdentities = identities + .map((i) => decodeIdentity(i)) + .filter((i) => i.type === type); + + return decodedIdentities; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/identityListSortAndFilter.tsx b/packages/manager/apps/key-management-service/src/utils/credential/identityListSortAndFilter.tsx new file mode 100644 index 000000000000..8cbb6ac134ed --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/identityListSortAndFilter.tsx @@ -0,0 +1,20 @@ +export default function identityListSortAndFilter( + items: T[], + sortKey: keyof T, + searchTerm?: string, + keys?: (keyof T)[], +): T[] { + const sortedItems = [...items].sort((a, b) => + String(a[sortKey]).localeCompare(String(b[sortKey])), + ); + + if (!searchTerm || !keys) return sortedItems; + + return sortedItems.filter((item) => + keys.some((key) => + String(item[key]) + .toLowerCase() + .includes(searchTerm.toLowerCase()), + ), + ); +} diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.spec.ts new file mode 100644 index 000000000000..93b17b6ea558 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.spec.ts @@ -0,0 +1,40 @@ +import { describe, it, expect } from 'vitest'; +import { + validateCredentialCreationMethod, + CredentialCreationMethodErrors, +} from './validateCredentialCreationMethod'; + +describe('validateCredentialCreationMethod', () => { + it('should return undefined if csr is a valid non-empty string', () => { + const validCsr = + 'MIICvTCCAaUCAQAwNTELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEJyaXR0YW55MRMw'; + expect(validateCredentialCreationMethod(validCsr)).toBeUndefined(); + }); + + it('should return "REQUIRED" error if csr is an empty string', () => { + const emptyCsr = ''; + expect(validateCredentialCreationMethod(emptyCsr)).toBe( + CredentialCreationMethodErrors.required, + ); + }); + + it('should return undefined error if csr is null', () => { + const nullCsr: string = null; + expect(validateCredentialCreationMethod(nullCsr)).toBeUndefined(); + }); + + it('should return undefined if csr is a non-empty string with spaces', () => { + const validCsrWithSpaces = + ' MIICvTCCAaUCAQAwNTELMAkGA1UEBhMCRlIxETAPBgNVBAgMCEJyaXR0YW55MRMw '; + expect( + validateCredentialCreationMethod(validCsrWithSpaces), + ).toBeUndefined(); + }); + + it('should return "REQUIRED" error if csr is a string with only spaces', () => { + const spacesOnlyCsr = ' '; + expect(validateCredentialCreationMethod(spacesOnlyCsr.trim())).toBe( + CredentialCreationMethodErrors.required, + ); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.ts new file mode 100644 index 000000000000..469d0f039dbc --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialCreationMethod.ts @@ -0,0 +1,11 @@ +export const CredentialCreationMethodErrors = { + required: 'REQUIRED', +} as const; + +export type CredentialCreationMethodErrorsType = typeof CredentialCreationMethodErrors[keyof typeof CredentialCreationMethodErrors]; + +export const validateCredentialCreationMethod = (csr: string | null) => { + if (csr?.length === 0) return CredentialCreationMethodErrors.required; + + return undefined; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.spec.ts new file mode 100644 index 000000000000..8f6ed477290d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.spec.ts @@ -0,0 +1,51 @@ +import { describe, it, expect } from 'vitest'; +import { + CredentialDescriptionErrors, + CredentialDescriptionMaxCharacters, + validateCredentialDescription, +} from './validateCredentialDescription'; + +describe('validateCredentialDescription', () => { + it('should return undefined for a valid description', () => { + const validDescription = 'This is a valid description!'; + expect(validateCredentialDescription(validDescription)).toBeUndefined(); + }); + + it('should return tooManyCharacters error if description exceeds 200 characters', () => { + const longDescription = 'a'.repeat(CredentialDescriptionMaxCharacters + 1); + expect(validateCredentialDescription(longDescription)).toBe( + CredentialDescriptionErrors.tooManyCharacters, + ); + }); + + it('should return invalidCharacters error if description contains invalid characters', () => { + const invalidDescription = + 'This description contains invalid characters: \u00A9'; // © is outside the ASCII range + expect(validateCredentialDescription(invalidDescription)).toBe( + CredentialDescriptionErrors.invalidCharacters, + ); + }); + + it('should return undefined for an empty description', () => { + expect(validateCredentialDescription(null)).toBeUndefined(); + }); + + it('should return invalidCharacters error if description contains characters below "space"', () => { + const invalidDescription = 'Invalid\tDescription'; // \t (tab) is not valid + expect(validateCredentialDescription(invalidDescription)).toBe( + CredentialDescriptionErrors.invalidCharacters, + ); + }); + + it('should return undefined for a description with exactly 1 character', () => { + const singleCharDescription = 'a'; + expect( + validateCredentialDescription(singleCharDescription), + ).toBeUndefined(); + }); + + it('should return undefined for a description with exactly 200 characters', () => { + const maxDescription = 'a'.repeat(CredentialDescriptionMaxCharacters); + expect(validateCredentialDescription(maxDescription)).toBeUndefined(); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.ts new file mode 100644 index 000000000000..3fc8e38d92e7 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialDescription.ts @@ -0,0 +1,25 @@ +/* RULES + * - min 1 character + * - max 200 characters + * - valid characters: ASCII characters from "space" to "~" + */ + +export const CredentialDescriptionErrors = { + invalidCharacters: 'INVALID_CHARACTERS', + tooManyCharacters: 'TOO_MANY_CHARACTERS', +} as const; + +export type CredentialDescriptionErrorsType = typeof CredentialDescriptionErrors[keyof typeof CredentialDescriptionErrors]; + +export const CredentialDescriptionMaxCharacters = 200; + +export const validateCredentialDescription = (description: string | null) => { + if (!description) return undefined; + if (description.length > CredentialDescriptionMaxCharacters) + return CredentialDescriptionErrors.tooManyCharacters; + + if (!/^[ -~]+$/.test(description)) + return CredentialDescriptionErrors.invalidCharacters; + + return undefined; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.spec.ts new file mode 100644 index 000000000000..1dddea507e7a --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.spec.ts @@ -0,0 +1,51 @@ +import { describe, it, expect } from 'vitest'; +import { + CredentialNameErrors, + credentialNameMaxCharacters, + validateCredentialName, +} from './validateCredentialName'; + +describe('validateCredentialName', () => { + it('should return undefined for a valid name', () => { + const validName = 'Valid Credential Name'; + expect(validateCredentialName(validName)).toBeUndefined(); + }); + + it('should return required error if name is empty', () => { + const emptyName = ''; + expect(validateCredentialName(emptyName)).toBe( + CredentialNameErrors.required, + ); + }); + + it('should return tooManyCharacters error if name exceeds 50 characters', () => { + const longName = 'a'.repeat(credentialNameMaxCharacters + 1); + expect(validateCredentialName(longName)).toBe( + CredentialNameErrors.tooManyCharacters, + ); + }); + + it('should return invalidCharacters error if name contains invalid characters', () => { + const invalidNameWithNonAscii = 'Invalid©Name'; + expect(validateCredentialName(invalidNameWithNonAscii)).toBe( + CredentialNameErrors.invalidCharacters, + ); + }); + + it('should return undefined for a name with exactly 1 character', () => { + const singleCharName = 'a'; + expect(validateCredentialName(singleCharName)).toBeUndefined(); + }); + + it('should return undefined for a name with exactly 50 characters', () => { + const maxLengthName = 'a'.repeat(credentialNameMaxCharacters); + expect(validateCredentialName(maxLengthName)).toBeUndefined(); + }); + + it('should return invalidCharacters error if name contains characters below "space"', () => { + const invalidName = 'Invalid\tName'; // \t (tab) is not valid + expect(validateCredentialName(invalidName)).toBe( + CredentialNameErrors.invalidCharacters, + ); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.ts new file mode 100644 index 000000000000..1e93b0e6fa61 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateCredentialName.ts @@ -0,0 +1,26 @@ +/* RULES + * - min 1 character + * - max 50 characters + * - valid characters: ASCII characters from "space" to "~" + */ + +export const CredentialNameErrors = { + required: 'REQUIRED', + invalidCharacters: 'INVALID_CHARACTERS', + tooManyCharacters: 'TOO_MANY_CHARACTERS', +} as const; + +export type CredentialNameErrorsType = typeof CredentialNameErrors[keyof typeof CredentialNameErrors]; + +export const credentialNameMaxCharacters = 50; + +export const validateCredentialName = (name: string) => { + if (name.length === 0) return CredentialNameErrors.required; + + if (name.length > credentialNameMaxCharacters) + return CredentialNameErrors.tooManyCharacters; + + if (!/^[ -~]+$/.test(name)) return CredentialNameErrors.invalidCharacters; + + return undefined; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.spec.ts new file mode 100644 index 000000000000..a23932652c00 --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.spec.ts @@ -0,0 +1,50 @@ +import { describe, it, expect } from 'vitest'; +import { + ValidityPeriodErrors, + validateValidityDate, +} from './validateValidityDate'; + +describe('validateValidityDate', () => { + it('should return undefined for a validity within the valid range', () => { + const validValidity = 30; + expect(validateValidityDate(validValidity)).toBeUndefined(); + }); + + it('should return minPeriod error if validity is less than 1', () => { + const invalidValidityLow = 0; + expect(validateValidityDate(invalidValidityLow)).toBe( + ValidityPeriodErrors.minPeriod, + ); + }); + + it('should return maxPeriod error if validity exceeds 365', () => { + const invalidValidityHigh = 366; + expect(validateValidityDate(invalidValidityHigh)).toBe( + ValidityPeriodErrors.maxPeriod, + ); + }); + + it('should return undefined for a validity of exactly 1 day', () => { + const minValidity = 1; + expect(validateValidityDate(minValidity)).toBeUndefined(); + }); + + it('should return undefined for a validity of exactly 365 days', () => { + const maxValidity = 365; + expect(validateValidityDate(maxValidity)).toBeUndefined(); + }); + + it('should return minPeriod error for a negative validity', () => { + const negativeValidity = -10; + expect(validateValidityDate(negativeValidity)).toBe( + ValidityPeriodErrors.minPeriod, + ); + }); + + it('should return maxPeriod error for a very large validity number', () => { + const largeValidity = 1000; + expect(validateValidityDate(largeValidity)).toBe( + ValidityPeriodErrors.maxPeriod, + ); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.ts b/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.ts new file mode 100644 index 000000000000..2488bf5f956e --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validateValidityDate.ts @@ -0,0 +1,15 @@ +export const ValidityPeriodErrors = { + minPeriod: 'MIN_PERIOD', + maxPeriod: 'MAX_PERIOD', +} as const; + +export type ValidityPeriodErrorsType = typeof ValidityPeriodErrors[keyof typeof ValidityPeriodErrors]; + +const ValidityMaxPeriod = 365; +const ValidityMinPeriod = 1; + +export const validateValidityDate = (validity: number) => { + if (validity < ValidityMinPeriod) return ValidityPeriodErrors.minPeriod; + if (validity > ValidityMaxPeriod) return ValidityPeriodErrors.maxPeriod; + return undefined; +}; diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.spec.ts b/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.spec.ts new file mode 100644 index 000000000000..0f33cf2cba1b --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.spec.ts @@ -0,0 +1,143 @@ +import { describe, it, expect } from 'vitest'; +import { + getNextMonth, + getDaysFromDate, + addDaysToDate, + getDateFromDays, +} from './validityDateUtils'; + +describe('getNextMonth', () => { + it('should return a date one month from now', () => { + const today = new Date(); + const nextMonth = getNextMonth(); + + // Adjust the year if necessary (e.g., December to January) + const expectedMonth = (today.getMonth() + 1) % 12; + const expectedYear = + today.getFullYear() + (today.getMonth() === 11 ? 1 : 0); + + expect(nextMonth.getMonth()).toBe(expectedMonth); + expect(nextMonth.getFullYear()).toBe(expectedYear); + }); + + it('should keep the same day of the month if possible', () => { + const today = new Date(); + const nextMonth = getNextMonth(); + + const expectedDay = today.getDate(); + expect(nextMonth.getDate()).toBe(expectedDay); + }); +}); + +describe('getDaysFromDate', () => { + it('should return the correct number of days from today', () => { + const today = new Date(); + const tomorrow = new Date(today); + tomorrow.setDate(today.getDate() + 1); + + expect(getDaysFromDate(tomorrow)).toBe(1); + }); + + it('should return a negative number for dates in the past', () => { + const today = new Date(); + const yesterday = new Date(today); + yesterday.setDate(today.getDate() - 1); + + expect(getDaysFromDate(yesterday)).toBe(-1); + }); + + it('should return 0 if the date is today', () => { + const today = new Date(); + expect(getDaysFromDate(today)).toBe(0); + }); + + it('should handle large differences correctly', () => { + const today = new Date(); + const futureDate = new Date(today); + futureDate.setDate(today.getDate() + 100); + + expect(getDaysFromDate(futureDate)).toBe(100); + }); + + it('should handle leap years correctly', () => { + const referenceDate = new Date(2024, 1, 28); + const leapDay = new Date(2024, 1, 29); + + const diffInDays = Math.floor( + (leapDay.getTime() - referenceDate.getTime()) / (24 * 60 * 60 * 1000), + ); + + expect(diffInDays).toBe(1); + }); +}); + +describe('addDaysToDate', () => { + it('should return the correct date when adding days', () => { + const today = new Date(); + const result = addDaysToDate(5); + + const expectedDate = new Date(today); + expectedDate.setDate(today.getDate() + 5); + + expect(result.getUTCDate()).toBe(expectedDate.getUTCDate()); + expect(result.getUTCMonth()).toBe(expectedDate.getUTCMonth()); + expect(result.getUTCFullYear()).toBe(expectedDate.getUTCFullYear()); + }); + + it('should handle leap years correctly', () => { + const result = addDaysToDate(365); + const expectedDate = new Date(); + expectedDate.setFullYear(expectedDate.getFullYear() + 1); + expect(result.getUTCFullYear()).toBe(expectedDate.getUTCFullYear()); + }); +}); + +describe('getDateFromDays', () => { + it('should return the correct date when adding positive days', () => { + const today = new Date(); + const daysToAdd = 10; + const futureDate = getDateFromDays(daysToAdd); + + const expectedDate = new Date(today); + expectedDate.setDate(today.getDate() + daysToAdd); + + expect(futureDate.getUTCDate()).toBe(expectedDate.getUTCDate()); + expect(futureDate.getUTCMonth()).toBe(expectedDate.getUTCMonth()); + expect(futureDate.getUTCFullYear()).toBe(expectedDate.getUTCFullYear()); + }); + + it('should return the correct date when adding negative days', () => { + const today = new Date(); + const daysToSubtract = -10; + const pastDate = getDateFromDays(daysToSubtract); + + const expectedDate = new Date(today); + expectedDate.setDate(today.getDate() + daysToSubtract); + + expect(pastDate.getUTCDate()).toBe(expectedDate.getUTCDate()); + expect(pastDate.getUTCMonth()).toBe(expectedDate.getUTCMonth()); + expect(pastDate.getUTCFullYear()).toBe(expectedDate.getUTCFullYear()); + }); + + it("should return today's date when adding 0 days", () => { + const today = new Date(); + const result = getDateFromDays(0); + + expect(result.getUTCDate()).toBe(today.getUTCDate()); + expect(result.getUTCMonth()).toBe(today.getUTCMonth()); + expect(result.getUTCFullYear()).toBe(today.getUTCFullYear()); + }); + + it('should correctly handle large numbers of days', () => { + const today = new Date(); + const daysToAdd = 3650; // 10 years + const futureDate = getDateFromDays(daysToAdd); + + const expectedDate = new Date(today); + expectedDate.setDate(today.getDate() + daysToAdd); + + expect(futureDate.getUTCDate()).toBe(expectedDate.getUTCDate()); + expect(futureDate.getUTCMonth()).toBe(expectedDate.getUTCMonth()); + expect(futureDate.getUTCFullYear()).toBe(expectedDate.getUTCFullYear()); + }); +}); diff --git a/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.ts b/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.ts new file mode 100644 index 000000000000..377a580c682d --- /dev/null +++ b/packages/manager/apps/key-management-service/src/utils/credential/validityDateUtils.ts @@ -0,0 +1,31 @@ +export function addDaysToDate(days: number): Date { + const targetDate = new Date(); + targetDate.setDate(targetDate.getDate() + days); + return targetDate; +} + +export function getNextMonth(): Date { + const today = new Date(); + today.setMonth(today.getMonth() + 1); + return today; +} + +export function getDaysFromDate(date: Date): number { + const referenceDate = new Date(); + const oneDay = 24 * 60 * 60 * 1000; + const diffInTime = + Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - + Date.UTC( + referenceDate.getFullYear(), + referenceDate.getMonth(), + referenceDate.getDate(), + ); + return Math.floor(diffInTime / oneDay); +} + +export function getDateFromDays(days: number): Date { + const referenceDate = new Date(); + const oneDay = 24 * 60 * 60 * 1000; + const futureDate = new Date(referenceDate.getTime() + days * oneDay); + return futureDate; +}