diff --git a/packages/manager/apps/okms/package.json b/packages/manager/apps/okms/package.json index 56017f075226..b194d5592820 100644 --- a/packages/manager/apps/okms/package.json +++ b/packages/manager/apps/okms/package.json @@ -14,8 +14,8 @@ "build": "tsc && vite build", "lint:check": "eslint --ext .ts,.tsx . && tsc --noEmit", "start": "tsc && vite", - "test": "vitest run --reporter=verbose", - "test:coverage": "vitest run --coverage" + "test": "manager-test run --reporter=verbose", + "test:coverage": "manager-test run --coverage" }, "dependencies": { "@hookform/resolvers": "5.2.1", @@ -49,18 +49,14 @@ }, "devDependencies": { "@ovh-ux/manager-core-test-utils": "^0.9.1", + "@ovh-ux/manager-tests-setup": "latest", "@ovh-ux/manager-vite-config": "^0.14.1", "@tanstack/react-query-devtools": "^5.51.21", - "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", - "@testing-library/user-event": "^14.5.2", "@types/file-saver": "^2.0.7", - "@vitejs/plugin-react": "^4.3.4", - "@vitest/coverage-v8": "^2.1.9", "element-internals-polyfill": "^3.0.2", "msw": "2.1.7", - "typescript": "^5.1.6", - "vitest": "^2.1.9" + "typescript": "^5.1.6" }, "regions": [ "CA", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_de_DE.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_de_DE.json index 8c3ca8c3cb60..8d58a8c2ab48 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_de_DE.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_de_DE.json @@ -3,48 +3,56 @@ "actions": "Aktionen", "activated": "Aktiviert", "add_new_version": "Neue Version hinzufügen", - "add_new_version_no_value_message": "Die neueste Version dieses Secret ist nicht aktiv und kann nicht als Vorlage verwendet werden. Bitte rufen Sie den Wert einer früheren aktiven Version ab, um Ihre neue Version zu erstellen.", "add_new_version_error": "Bei der Erstellung der Version ist ein Fehler aufgetreten", + "add_new_version_no_value_message": "Die neueste Version dieses Secret ist nicht aktiv und kann nicht als Vorlage verwendet werden. Bitte rufen Sie den Wert einer früheren aktiven Version ab, um Ihre neue Version zu erstellen.", "back_to_okms_list": "Zurück zur Liste der OKMS-Domains", "back_to_secret_list": "Zurück zur Liste der Secrets", "cas_with_description": "CAS (Check-And-Set Version Control)", "cas_with_description_tooltip": "Wenn CAS aktiviert ist, ist bei Änderungen systematisch die aktuelle Versionsnummer anzugeben.", "create_a_secret": "Secret erstellen", "create_okms_success": "Ihre OKMS-Domain wurde erfolgreich erstellt.", - "create_okms_terms_and_conditions_confirm_label": "Ich habe die allgemeinen Geschäftsbedingungen, die Anlage zur Verarbeitung personenbezogener Daten sowie die besonderen Vertragsbedingungen von OVHcloud zur Kenntnis genommen und akzeptiere diese.", + "create_okms_terms_and_conditions_confirm_label": "Ich habe die allgemeinen Geschäftsbedingungen, den Anhang zur Verarbeitung personenbezogener Daten sowie die besonderen Vertragsbedingungen von OVHcloud zur Kenntnis genommen und akzeptiere diese.", "create_okms_terms_and_conditions_description": "Um Ihre Region zu aktivieren, muss zuerst eine OKMS-Domain erstellt werden. Möchten Sie mit der Aktivierung Ihrer Region fortfahren?", "create_okms_terms_and_conditions_title": "Aktivierung der Region", + "create_secret_form_okms_selector_title": "Wählen Sie eine OKMS-Domain aus", + "create_secret_form_payment_section_title": "3. Zahlungsmittel", "create_secret_form_region_section_title": "1. Auswahl der Region", "create_secret_form_region_selector_title": "Wählen Sie eine Region aus", - "create_secret_form_okms_selector_title": "Wählen Sie eine OKMS-Domain aus", "create_secret_form_secret_section_title": "2. Konfiguration des Secret", - "create_secret_form_payment_section_title": "3. Zahlungsmittel", + "current_version": "Aktuelle Version", "custom_metadata_title": "Benutzerdefinierte Metadaten", - "deactivate_version_after": "Ablaufdauer einer Version", + "deactivate_version_after": "Ablaufzeit einer Version", "delete_secret": "Secret löschen", "delete_secret_modal_description": "Sind Sie sicher, dass Sie folgendes Secret löschen möchten: {{secretPath}}? Dieser Vorgang kann nicht rückgängig gemacht werden.", "delete_secret_modal_title": "Secret löschen", "delete_secret_success": "Secret wurde erfolgreich gelöscht", "delete_version_modal_description": "Sind Sie sicher, dass Sie diese Version löschen möchten? Dieser Vorgang kann nicht rückgängig gemacht werden.", "delete_version_modal_title": "Version {{versionId}} löschen", - "okms_activation_in_progress": "Bitte warten, wird erstellt.", - "okms_list": "Liste der OKMS-Domains", + "edit_metadata": "Einstellungen ändern", "editor": "JSON-Editor", + "error_invalid_duration": "Die Ablaufzeit muss eine Dauer sein (z.B.: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "Ungültiges JSON", "error_path_allowed_characters": "Der Pfad darf nur die folgenden Zeichen enthalten: A-Z a-z 0-9 . _ : / = @ und -", "error_path_structure": "Der Pfad darf nicht mit '/' beginnen oder darauf enden und darf nicht zwei '/' hintereinander enthalten.", + "error_update_settings": "Ein Fehler ist bei der Aktualisierung der Einstellungen aufgetreten", "expiration_date": "Ablaufdatum", + "form_helper_cas_required_okms": "CAS ist für die Domain OKMS aktiviert, die Deaktivierung im Geheimnis wird nicht berücksichtigt.", + "form_helper_deactivate_version_after": "Geben Sie \"0s\" ein, um die Ablaufzeit zu deaktivieren.", + "form_helper_max_versions": "Geben Sie \"0\" ein, um den Standardwert ({{default}}) zu verwenden.", + "form_tooltip_deactivate_version_after": "Format: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Letztes Update", "maximum_number_of_versions": "Maximale Anzahl an Versionen", - "never_expire": "Keine Ablaufzeit", + "never_expire": "Kein Ablaufdatum", "not_provided": "Nicht angegeben", + "okms_activation_in_progress": "Bitte warten, wird erstellt.", + "okms_list": "Liste der OKMS-Domains", "onboarding_description_1": "Sichern Sie Ihre Secrets", "onboarding_description_2": "Der Secret Manager ist der zentrale, vollständig verwaltete und auf OKMS basierende Dienst zur Verwaltung von Secrets für Ihre OVHcloud Anwendungen und Dienste.", "path_field_helper": "Um eine Hierarchie zu erstellen, verwenden Sie '/'. Beispiel: prod/database/MySQL", "reveal_secret": "Wert anzeigen", "secret_manager": "Secret Manager", "setting_default": "Standardeinstellung", - "setting_domain": "OKMS-Domaineinstellungen", + "setting_domain": "OKMS-Domaineinstellung", "settings": "Einstellungen", "settings_default": "Standardeinstellungen", "values": "Werte", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_en_GB.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_en_GB.json index 27e335abb1e5..0c1970368197 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_en_GB.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_en_GB.json @@ -1,10 +1,10 @@ { - "access_versions": "Access versions", + "access_versions": "Access the versions", "actions": "Actions", "activated": "Enabled", "add_new_version": "Add a new version", - "add_new_version_no_value_message": "The most recent version of this secret is not active and cannot be used as a template. Please retrieve the value of a previous active version to create your new version.", "add_new_version_error": "An error occurred while creating the version", + "add_new_version_no_value_message": "The most recent version of this secret is not active and cannot be used as a template. Please retrieve the value of a previous active version to create your new version.", "back_to_okms_list": "Back to OKMS domains list", "back_to_secret_list": "Back to Secrets list", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "I have read and agree to the terms and conditions, the appendix relating to the processing of personal data, and the special terms and conditions of OVH services.", "create_okms_terms_and_conditions_description": "To activate your region, you need to create an OKMS domain. Do you want to proceed with activating your region?", "create_okms_terms_and_conditions_title": "Activating region...", + "create_secret_form_okms_selector_title": "Select an OKMS domain", + "create_secret_form_payment_section_title": "3. Payment method", "create_secret_form_region_section_title": "1. Select region", "create_secret_form_region_selector_title": "Select a region", - "create_secret_form_okms_selector_title": "Select an OKMS domain", "create_secret_form_secret_section_title": "2. Secret configuration", - "create_secret_form_payment_section_title": "3. Payment method", + "current_version": "Current version", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Duration of version validity", "delete_secret": "Delete secret", @@ -27,18 +28,25 @@ "delete_secret_success": "Your secret has been deleted", "delete_version_modal_description": "Are you sure you want to delete this version? This action cannot be reversed.", "delete_version_modal_title": "Delete version {{versionId}}", - "okms_activation_in_progress": "Creating version...Please wait.", - "okms_list": "OKMS domain list", + "edit_metadata": "Modify the settings", "editor": "JSON editor", + "error_invalid_duration": "The expiration duration must be a duration (e.g. 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "Invalid JSON", "error_path_allowed_characters": "The path can only contain the following characters: A-Z a-z 0-9 . _ : / = @ and -", "error_path_structure": "The path cannot start or end with '/', nor can it contain two '/' in a row.", + "error_update_settings": "An error occurred while updating the settings", "expiration_date": "Expiry date", + "form_helper_cas_required_okms": "CAS is enabled on the OKMS domain, disabling on the secret will not be taken into account.", + "form_helper_deactivate_version_after": "Specify \"0s\" to disable expiration.", + "form_helper_max_versions": "Specify \"0\" to use the default value ({{default}}).", + "form_tooltip_deactivate_version_after": "Format: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Last updated", "maximum_number_of_versions": "Maximum number of versions", "never_expire": "No expiration", "not_provided": "Not stated", - "onboarding_description_1": "Keep your secrets secure", + "okms_activation_in_progress": "Creating version...Please wait.", + "okms_list": "OKMS domain list", + "onboarding_description_1": "Secure your secrets", "onboarding_description_2": "Secret Manager, based on OKMS, is the fully managed centralised secret management service for your OVHcloud applications and services.", "path_field_helper": "To create a hierarchy, use '/' Example: prod/database/MySQL", "reveal_secret": "Show value", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_es_ES.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_es_ES.json index 256aea0ebfeb..6de3cf927649 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_es_ES.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_es_ES.json @@ -3,8 +3,8 @@ "actions": "Acciones", "activated": "Activado", "add_new_version": "Añadir una nueva versión", - "add_new_version_no_value_message": "La versión más reciente de este secreto no está activa y no se puede utilizar como modelo. Por favor, recupere el valor de una versión activa anterior para crear su nueva versión.", "add_new_version_error": "Se ha producido un error al crear la versión", + "add_new_version_no_value_message": "La versión más reciente de este secreto no está activa y no se puede utilizar como modelo. Por favor, recupere el valor de una versión activa anterior para crear su nueva versión.", "back_to_okms_list": "Volver a la lista de dominios OKMS", "back_to_secret_list": "Volver a la lista de secretos", "cas_with_description": "CAS («Check-And-Set Version Control»)", @@ -14,30 +14,38 @@ "create_okms_terms_and_conditions_confirm_label": "He leído y acepto las Condiciones Generales, el Anexo relativo al tratamiento de datos personales y las Condiciones Particulares del Servicio de OVH.", "create_okms_terms_and_conditions_description": "Para activar su región es necesario crear un dominio OKMS. ¿Desea continuar con la activación de su región?", "create_okms_terms_and_conditions_title": "Activación de la región", + "create_secret_form_okms_selector_title": "Seleccione un dominio OKMS", + "create_secret_form_payment_section_title": "3. Forma de pago", "create_secret_form_region_section_title": "1. Selección de la región", "create_secret_form_region_selector_title": "Seleccione una región", - "create_secret_form_okms_selector_title": "Seleccione un dominio OKMS", "create_secret_form_secret_section_title": "2. Configuración del secreto", - "create_secret_form_payment_section_title": "3. Forma de pago", + "current_version": "Versión actual", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Periodo de expiración de una versión", "delete_secret": "Eliminar el secreto", "delete_secret_modal_description": "¿Seguro que quiere eliminar el secreto: {{secretPath}}? Esta acción es irreversible.", "delete_secret_modal_title": "Eliminar un secreto", "delete_secret_success": "Su secreto se ha eliminado correctamente", - "delete_version_modal_description": "¿Seguro/a que quiere eliminar esta versión? Esta acción es irreversible.", + "delete_version_modal_description": "¿Seguro que quiere eliminar esta versión? Esta acción es irreversible.", "delete_version_modal_title": "Eliminar la versión {{versionId}}", - "okms_activation_in_progress": "Por favor, espere, creando...", - "okms_list": "Lista de dominios OKMS", + "edit_metadata": "Modificar la configuración", "editor": "Editor JSON", + "error_invalid_duration": "La duración de la expiración debe ser un período (ej: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON no válido", "error_path_allowed_characters": "La ruta solo puede contener los siguientes caracteres: A-Z a-z 0-9 . _ : / = @ y -", "error_path_structure": "La ruta no puede comenzar ni terminar con '/', ni contener dos '/' consecutivos.", + "error_update_settings": "Ocurrió un error al actualizar la configuración", "expiration_date": "Fecha de expiración", + "form_helper_cas_required_okms": "CAS está activado en el dominio OKMS, la desactivación en el secreto no será tenida en cuenta.", + "form_helper_deactivate_version_after": "Indique \"0s\" para desactivar la expiración.", + "form_helper_max_versions": "Indique \"0\" para usar el valor predeterminado ({{default}}).", + "form_tooltip_deactivate_version_after": "Formato: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Última actualización", "maximum_number_of_versions": "Número máximo de versiones", "never_expire": "Sin expiración", "not_provided": "No indicado", + "okms_activation_in_progress": "Por favor, espere, creando...", + "okms_list": "Lista de dominios OKMS", "onboarding_description_1": "Proteja sus secretos", "onboarding_description_2": "Secret Manager es un servicio centralizado de gestión de secretos basado en OKMS completamente administrado para sus aplicaciones y servicios de OVHcloud.", "path_field_helper": "Para crear una jerarquía, use '/' . Ejemplo: prod/database/MySQL", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_CA.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_CA.json index 6e7ff908bbfc..5d52a670e532 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_CA.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_CA.json @@ -3,8 +3,8 @@ "actions": "Actions", "activated": "Activé", "add_new_version": "Ajouter une nouvelle version", - "add_new_version_no_value_message": "La version la plus récente de ce secret n'est pas active et ne peut pas être utilisée comme modèle. Veuillez récupérer la valeur d'une version active antérieure pour créer votre nouvelle version.", "add_new_version_error": "Une erreur est survenue lors de la création de la version", + "add_new_version_no_value_message": "La version la plus récente de ce secret n'est pas active et ne peut pas être utilisée comme modèle. Veuillez récupérer la valeur d'une version active antérieure pour créer votre nouvelle version.", "back_to_okms_list": "Retour à la liste des domaines OKMS", "back_to_secret_list": "Retour à la liste des secrets", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "J'ai pris connaissance et j'accepte les conditions générales, l'annexe relative au traitement des données personnelles et les conditions particulières de services d'OVH.", "create_okms_terms_and_conditions_description": "Pour activer votre région il est nécessaire de créer un domaine OKMS. Souhaitez-vous continuer l'activation de votre région ?", "create_okms_terms_and_conditions_title": "Activation de la région", + "create_secret_form_okms_selector_title": "Sélectionnez un domaine OKMS", + "create_secret_form_payment_section_title": "3. Moyen de paiement", "create_secret_form_region_section_title": "1. Sélection de la région", "create_secret_form_region_selector_title": "Sélectionnez une région", - "create_secret_form_okms_selector_title": "Sélectionnez un domaine OKMS", "create_secret_form_secret_section_title": "2. Configuration du secret", - "create_secret_form_payment_section_title": "3. Moyen de paiement", + "current_version": "Version courante", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Durée d'expiration d'une version", "delete_secret": "Supprimer le secret", @@ -27,17 +28,24 @@ "delete_secret_success": "Votre secret a été supprimé avec succès", "delete_version_modal_description": "Êtes-vous sûr de vouloir supprimer cette version ? Cette action est irréversible.", "delete_version_modal_title": "Supprimer la version {{versionId}}", - "okms_activation_in_progress": "Veuillez patienter, création en cours.", - "okms_list": "Liste de domaines OKMS", + "edit_metadata": "Modifier les paramètres", "editor": "Éditeur JSON", + "error_invalid_duration": "La durée d'expiration doit être une durée (ex: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON non valide", "error_path_allowed_characters": "Le path ne peut contenir que les caractères suivants: A-Z a-z 0-9 . _ : / = @ et -", "error_path_structure": "Le path ne peut commencer ou finir par '/', ni contenir deux '/' à la suite.", + "error_update_settings": "Une erreur est survenue lors de la mise à jour des paramètres", "expiration_date": "Date d'expiration", + "form_helper_cas_required_okms": "CAS est activé sur le domaine OKMS, la désactivation sur le secret ne sera pas prise en compte.", + "form_helper_deactivate_version_after": "Indiquez \"0s\" pour désactiver l'expiration.", + "form_helper_max_versions": "Indiquez \"0\" pour utiliser la valeur par défaut ({{default}}).", + "form_tooltip_deactivate_version_after": "Format : 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Dernière mise à jour", "maximum_number_of_versions": "Nombre maximum de versions", "never_expire": "Pas d'expiration", "not_provided": "Non renseigné", + "okms_activation_in_progress": "Veuillez patienter, création en cours.", + "okms_list": "Liste de domaines OKMS", "onboarding_description_1": "Securisez vos secrets", "onboarding_description_2": "Secret Manager est le service centralisé de gestion des secrets basé sur OKMS entièrement managé pour vos applications et vos services OVHcloud.", "path_field_helper": "Pour créer une hiérarchie, utilisez des '/'. Exemple : prod/database/MySQL", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_FR.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_FR.json index 6e7ff908bbfc..5d52a670e532 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_FR.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_fr_FR.json @@ -3,8 +3,8 @@ "actions": "Actions", "activated": "Activé", "add_new_version": "Ajouter une nouvelle version", - "add_new_version_no_value_message": "La version la plus récente de ce secret n'est pas active et ne peut pas être utilisée comme modèle. Veuillez récupérer la valeur d'une version active antérieure pour créer votre nouvelle version.", "add_new_version_error": "Une erreur est survenue lors de la création de la version", + "add_new_version_no_value_message": "La version la plus récente de ce secret n'est pas active et ne peut pas être utilisée comme modèle. Veuillez récupérer la valeur d'une version active antérieure pour créer votre nouvelle version.", "back_to_okms_list": "Retour à la liste des domaines OKMS", "back_to_secret_list": "Retour à la liste des secrets", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "J'ai pris connaissance et j'accepte les conditions générales, l'annexe relative au traitement des données personnelles et les conditions particulières de services d'OVH.", "create_okms_terms_and_conditions_description": "Pour activer votre région il est nécessaire de créer un domaine OKMS. Souhaitez-vous continuer l'activation de votre région ?", "create_okms_terms_and_conditions_title": "Activation de la région", + "create_secret_form_okms_selector_title": "Sélectionnez un domaine OKMS", + "create_secret_form_payment_section_title": "3. Moyen de paiement", "create_secret_form_region_section_title": "1. Sélection de la région", "create_secret_form_region_selector_title": "Sélectionnez une région", - "create_secret_form_okms_selector_title": "Sélectionnez un domaine OKMS", "create_secret_form_secret_section_title": "2. Configuration du secret", - "create_secret_form_payment_section_title": "3. Moyen de paiement", + "current_version": "Version courante", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Durée d'expiration d'une version", "delete_secret": "Supprimer le secret", @@ -27,17 +28,24 @@ "delete_secret_success": "Votre secret a été supprimé avec succès", "delete_version_modal_description": "Êtes-vous sûr de vouloir supprimer cette version ? Cette action est irréversible.", "delete_version_modal_title": "Supprimer la version {{versionId}}", - "okms_activation_in_progress": "Veuillez patienter, création en cours.", - "okms_list": "Liste de domaines OKMS", + "edit_metadata": "Modifier les paramètres", "editor": "Éditeur JSON", + "error_invalid_duration": "La durée d'expiration doit être une durée (ex: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON non valide", "error_path_allowed_characters": "Le path ne peut contenir que les caractères suivants: A-Z a-z 0-9 . _ : / = @ et -", "error_path_structure": "Le path ne peut commencer ou finir par '/', ni contenir deux '/' à la suite.", + "error_update_settings": "Une erreur est survenue lors de la mise à jour des paramètres", "expiration_date": "Date d'expiration", + "form_helper_cas_required_okms": "CAS est activé sur le domaine OKMS, la désactivation sur le secret ne sera pas prise en compte.", + "form_helper_deactivate_version_after": "Indiquez \"0s\" pour désactiver l'expiration.", + "form_helper_max_versions": "Indiquez \"0\" pour utiliser la valeur par défaut ({{default}}).", + "form_tooltip_deactivate_version_after": "Format : 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Dernière mise à jour", "maximum_number_of_versions": "Nombre maximum de versions", "never_expire": "Pas d'expiration", "not_provided": "Non renseigné", + "okms_activation_in_progress": "Veuillez patienter, création en cours.", + "okms_list": "Liste de domaines OKMS", "onboarding_description_1": "Securisez vos secrets", "onboarding_description_2": "Secret Manager est le service centralisé de gestion des secrets basé sur OKMS entièrement managé pour vos applications et vos services OVHcloud.", "path_field_helper": "Pour créer une hiérarchie, utilisez des '/'. Exemple : prod/database/MySQL", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_it_IT.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_it_IT.json index 396699bfa65e..96ab8adea9e0 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_it_IT.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_it_IT.json @@ -3,8 +3,8 @@ "actions": "Azioni", "activated": "Attivato", "add_new_version": "Aggiungere una nuova versione", - "add_new_version_no_value_message": "La versione più recente di questo “secret” non è attiva e non può essere utilizzata come modello. Recupera il valore di una versione attiva precedente per creare la tua nuova versione.", "add_new_version_error": "Si è verificato un errore durante la creazione della versione", + "add_new_version_no_value_message": "La versione più recente di questo “secret” non è attiva e non può essere utilizzata come modello. Recupera il valore di una versione attiva precedente per creare la tua nuova versione.", "back_to_okms_list": "Ritorna alla lista dei domini OKMS", "back_to_secret_list": "Ritorna alla lista dei “secret”", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "Ho preso visione e accetto le Condizioni Generali, l'Appendice relativa al trattamento dei dati personali e le Condizioni Particolari di Servizio di OVHcloud.", "create_okms_terms_and_conditions_description": "Per attivare la tua Region è necessario creare un dominio OKMS. Vuoi continuare l'attivazione della tua Region?", "create_okms_terms_and_conditions_title": "Attivazione della Region", + "create_secret_form_okms_selector_title": "Seleziona un dominio OKMS", + "create_secret_form_payment_section_title": "3. Metodo di pagamento", "create_secret_form_region_section_title": "1. Selezione della Region", "create_secret_form_region_selector_title": "Seleziona una Region", - "create_secret_form_okms_selector_title": "Seleziona un dominio OKMS", "create_secret_form_secret_section_title": "2. Configurazione del “secret”", - "create_secret_form_payment_section_title": "3. Metodo di pagamento", + "current_version": "Versione attuale", "custom_metadata_title": "Metadati personalizzati", "deactivate_version_after": "Periodo di validità di una versione", "delete_secret": "Eliminare il “secret”", @@ -27,17 +28,24 @@ "delete_secret_success": "Il tuo v è stato eliminato correttamente", "delete_version_modal_description": "Vuoi davvero eliminare questa versione? Questa operazione è irreversibile.", "delete_version_modal_title": "Eliminare la versione {{versionId}}", - "okms_activation_in_progress": "Attendi, creazione in corso...", - "okms_list": "Lista dei domini OKMS", + "edit_metadata": "Modifica le impostazioni", "editor": "Editor JSON", + "error_invalid_duration": "La durata di scadenza deve essere una durata (es: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON non valido", "error_path_allowed_characters": "Il percorso può contenere solo i seguenti caratteri: A-Z a-z 0-9 . _ : / = @ e -", "error_path_structure": "Il percorso non può iniziare o terminare con '/', né contenere due '/' consecutivi.", + "error_update_settings": "Si è verificato un errore durante l'aggiornamento delle impostazioni", "expiration_date": "Data di scadenza", + "form_helper_cas_required_okms": "CAS è attivato sul dominio OKMS, la disattivazione sul segreto non sarà presa in considerazione.", + "form_helper_deactivate_version_after": "Indica \"0s\" per disattivare la scadenza.", + "form_helper_max_versions": "Indica \"0\" per utilizzare il valore predefinito ({{default}}).", + "form_tooltip_deactivate_version_after": "Formato: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Ultimo aggiornamento", "maximum_number_of_versions": "Numero massimo di versioni", "never_expire": "Nessuna scadenza", "not_provided": "Non indicato", + "okms_activation_in_progress": "Attendi, creazione in corso...", + "okms_list": "Lista dei domini OKMS", "onboarding_description_1": "Proteggere i tuoi “secret”", "onboarding_description_2": "Secret Manager è il servizio centralizzato di gestione dei “secret” basato su OKMS completamente gestito per le tue applicazioni e i tuoi servizi OVHcloud.", "path_field_helper": "Per creare una gerarchia, utilizza '/' . Esempio: prod/database/MySQL", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_pl_PL.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_pl_PL.json index 4c0273357d85..ed6b5048f908 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_pl_PL.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_pl_PL.json @@ -3,8 +3,8 @@ "actions": "Operacje", "activated": "Włączony", "add_new_version": "Dodaj nową wersję", - "add_new_version_no_value_message": "Najnowsza wersja tego „sekretu” nie jest aktywna i nie może służyć jako wzór. Pobierz wartość jednej z wcześniejszych aktywnych wersji, aby utworzyć nową wersję.", "add_new_version_error": "Wystąpił błąd podczas tworzenia wersji", + "add_new_version_no_value_message": "Najnowsza wersja tego „sekretu” nie jest aktywna i nie może służyć jako wzór. Pobierz wartość jednej z wcześniejszych aktywnych wersji, aby utworzyć nową wersję.", "back_to_okms_list": "Powrót do listy domen OKMS", "back_to_secret_list": "Powrót do listy „sekretów”", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "Zapoznałem się z ogólnymi i szczegółowymi warunkami świadczenia usług OVHcloud oraz dokumentem dotyczącym przetwarzania danych osobowych i akceptuję je.", "create_okms_terms_and_conditions_description": "Aby aktywować region, konieczne jest utworzenie domeny OKMS. Czy chcesz kontynuować aktywację regionu?", "create_okms_terms_and_conditions_title": "Aktywacja regionu", + "create_secret_form_okms_selector_title": "Wybierz domenę OKMS", + "create_secret_form_payment_section_title": "3. Sposób płatności", "create_secret_form_region_section_title": "1. Wybór regionu", "create_secret_form_region_selector_title": "Wybierz region", - "create_secret_form_okms_selector_title": "Wybierz domenę OKMS", "create_secret_form_secret_section_title": "2. Konfiguracja „sekretu”", - "create_secret_form_payment_section_title": "3. Sposób płatności", + "current_version": "Bieżąca wersja", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Okres ważności wersji", "delete_secret": "Usuń „sekret”", @@ -27,17 +28,24 @@ "delete_secret_success": "Twój „sekret” został pomyślnie usunięty", "delete_version_modal_description": "Czy na pewno chcesz usunąć tę wersję ? Operacja ta jest nieodwracalna.", "delete_version_modal_title": "Usuń wersję {{versionId}}", - "okms_activation_in_progress": "Proszę czekać, trwa aktywacja.", - "okms_list": "Lista domen OKMS", + "edit_metadata": "Zmień ustawienia", "editor": "Edytor JSON", + "error_invalid_duration": "Czas wygaśnięcia musi być określony jako czas (np: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON jest nieprawidłowy", "error_path_allowed_characters": "Ścieżka może zawierać tylko następujące znaki: A-Z a-z 0-9 . _ : / = @ et -", "error_path_structure": "Ścieżka nie może zaczynać się ani kończyć na '/', ani zawierać dwóch '/' z rzędu.", + "error_update_settings": "Wystąpił błąd podczas aktualizacji ustawień", "expiration_date": "Data wygasania", + "form_helper_cas_required_okms": "CAS jest włączony w domenie OKMS, wyłączenie na sekrecie nie będzie brane pod uwagę.", + "form_helper_deactivate_version_after": "Podaj \"0s\", aby wyłączyć wygaśnięcie.", + "form_helper_max_versions": "Podaj \"0\", aby użyć wartości domyślnej ({{default}}).", + "form_tooltip_deactivate_version_after": "Format: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Ostatnia aktualizacja", "maximum_number_of_versions": "Maksymalna liczba wersji", "never_expire": "Brak terminu wygaśnięcia", "not_provided": "Nie podano", + "okms_activation_in_progress": "Proszę czekać, trwa tworzenie wersji.", + "okms_list": "Lista domen OKMS", "onboarding_description_1": "Zabezpiecz „sekrety”", "onboarding_description_2": "Secret Manager to centralna, w pełni zarządzana usługa zarządzania tzw. sekretami oparta na OKMS, przeznaczona dla aplikacji i usług OVHcloud.", "path_field_helper": "Aby utworzyć hierarchię, użyj '/' . Przykład: prod/database/MySQL", diff --git a/packages/manager/apps/okms/public/translations/secret-manager/Messages_pt_PT.json b/packages/manager/apps/okms/public/translations/secret-manager/Messages_pt_PT.json index adb540b7efa4..362dd4963a61 100644 --- a/packages/manager/apps/okms/public/translations/secret-manager/Messages_pt_PT.json +++ b/packages/manager/apps/okms/public/translations/secret-manager/Messages_pt_PT.json @@ -3,8 +3,8 @@ "actions": "Ações", "activated": "Ativado", "add_new_version": "Adicionar uma nova versão", - "add_new_version_no_value_message": "A versão mais recente deste segredo não está ativa e não pode ser usada como modelo. Recupere o valor de uma versão ativa anterior para criar a sua nova versão.", "add_new_version_error": "Ocorreu um erro durante a criação da versão", + "add_new_version_no_value_message": "A versão mais recente deste segredo não está ativa e não pode ser usada como modelo. Recupere o valor de uma versão ativa anterior para criar a sua nova versão.", "back_to_okms_list": "Voltar à lista dos domínios OKMS", "back_to_secret_list": "Voltar à lista dos segredos", "cas_with_description": "CAS (Check-And-Set Version Control)", @@ -14,11 +14,12 @@ "create_okms_terms_and_conditions_confirm_label": "Li e aceito os termos e condições, o apêndice relacionado com o processamento de dados pessoais, bem como os termos e condições especiais dos serviços da OVHcloud.", "create_okms_terms_and_conditions_description": "Para ativar a sua região, é preciso criar um domínio OKMS. Pretende prosseguir a ativação da sua região?", "create_okms_terms_and_conditions_title": "Ativação da região", + "create_secret_form_okms_selector_title": "Selecione um domínio OKMS", + "create_secret_form_payment_section_title": "3. Método de pagamento", "create_secret_form_region_section_title": "1. Escolha da região", "create_secret_form_region_selector_title": "Selecione uma região", - "create_secret_form_okms_selector_title": "Selecione um domínio OKMS", "create_secret_form_secret_section_title": "2. Configuração do segredo", - "create_secret_form_payment_section_title": "3. Método de pagamento", + "current_version": "Versão atual", "custom_metadata_title": "Custom Metadata", "deactivate_version_after": "Prazo de expiração de uma versão", "delete_secret": "Eliminar o segredo", @@ -27,17 +28,24 @@ "delete_secret_success": "O seu segredo foi devidamente eliminado", "delete_version_modal_description": "Quer mesmo eliminar esta versão? Esta operação não pode ser anulada.", "delete_version_modal_title": "Eliminar a versão {{versionId}}", - "okms_activation_in_progress": "Aguarde, por favor. A criação está em curso.", - "okms_list": "Lista de domínios OKMS", + "edit_metadata": "Modificar as definições", "editor": "Editor JSON", + "error_invalid_duration": "A duração da expiração deve ser um período (ex: 30s, 5m, 2h, 7d, 7d1h30m10s)", "error_invalid_json": "JSON inválido", "error_path_allowed_characters": "O path só pode conter os seguintes caracteres: A-Z a-z 0-9 . _ : / = @ e -", "error_path_structure": "O path não pode começar ou terminar com «/», nem conter duas «/» seguidas.", + "error_update_settings": "Ocorreu um erro ao atualizar as definições", "expiration_date": "Data de expiração", + "form_helper_cas_required_okms": "O CAS está ativado no domínio OKMS, a desativação no segredo não será considerada.", + "form_helper_deactivate_version_after": "Indique \"0s\" para desativar a expiração.", + "form_helper_max_versions": "Indique \"0\" para usar o valor padrão ({{default}}).", + "form_tooltip_deactivate_version_after": "Formato: 30s, 5m, 2h, 7d, 7d1h30m10s", "last_update": "Última atualização", "maximum_number_of_versions": "Número máximo de versões", "never_expire": "Sem expiração", "not_provided": "Sem informação", + "okms_activation_in_progress": "Aguarde, por favor. A criação está em curso.", + "okms_list": "Lista de domínios OKMS", "onboarding_description_1": "Proteja os seus segredos", "onboarding_description_2": "O Secret Manager é um serviço centralizado de gestão de segredos baseado em OKMS, totalmente gerido, para as aplicações e os serviços OVHcloud.", "path_field_helper": "Para criar uma hierarquia, utilize «/». Exemplo: prod/database/MySQL", diff --git a/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.component.tsx b/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.component.tsx index f9d8c2cc3181..0ab84f8739af 100644 --- a/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.component.tsx +++ b/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.component.tsx @@ -18,9 +18,16 @@ import { OkmsServiceState } from '@/components/layout-helpers/Dashboard/okmsServ import { KMS_ROUTES_URLS } from '@/routes/routes.constants'; import { OkmsDatagridType } from './okmsDatagrid.type'; import { Link } from '@/common/components/Link/Link.component'; +import { OKMS_LIST_CELL_TEST_IDS } from './ListingCells.constants'; export const DatagridCellId = (okms: OKMS) => { - return ; + return ( + + ); }; export const DatagridCellName = ( @@ -43,6 +50,7 @@ export const DatagridCellName = ( href={urls[type]} label={okms.iam.displayName} isRouterLink + data-testid={OKMS_LIST_CELL_TEST_IDS.name(okms.id)} onClick={() => { if (tracking[type].length > 0) { trackClick({ @@ -59,7 +67,7 @@ export const DatagridCellName = ( export const DatagridCellRegion = (okms: OKMS) => { return ( - + { if (isError) { return <>; } - return ; + return ( + + ); }; export const DatagridCellKmipCount = (okms: OKMS) => { - return {okms.kmipObjectCount}; + return ( + + {okms.kmipObjectCount} + + ); }; export const DatagridCellServiceKeyCount = (okms: OKMS) => { - return {okms.serviceKeyCount}; + return ( + + {okms.serviceKeyCount} + + ); }; export const DatagridCellSecretCount = (okms: OKMS) => { - return {okms.secretCount}; + return ( + + {okms.secretCount} + + ); }; diff --git a/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.constants.tsx b/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.constants.tsx new file mode 100644 index 000000000000..63ca349a7eb8 --- /dev/null +++ b/packages/manager/apps/okms/src/common/components/okmsDatagrid/ListingCells.constants.tsx @@ -0,0 +1,9 @@ +export const OKMS_LIST_CELL_TEST_IDS = { + id: (id: string) => `okms-list-cell-${id}-id`, + name: (id: string) => `okms-list-cell-${id}-name`, + region: (id: string) => `okms-list-cell-${id}-region`, + status: (id: string) => `okms-list-cell-${id}-status`, + kmipCount: (id: string) => `okms-list-cell-${id}-kmip-count`, + serviceKeyCount: (id: string) => `okms-list-cell-${id}-service-key-count`, + secretCount: (id: string) => `okms-list-cell-${id}-secret-count`, +}; diff --git a/packages/manager/apps/okms/src/common/pages/OrderOkmsModal/OrderOkmsModal.page.spec.tsx b/packages/manager/apps/okms/src/common/pages/OrderOkmsModal/OrderOkmsModal.page.spec.tsx index 8cf1d85eb9c1..d560272f88d6 100644 --- a/packages/manager/apps/okms/src/common/pages/OrderOkmsModal/OrderOkmsModal.page.spec.tsx +++ b/packages/manager/apps/okms/src/common/pages/OrderOkmsModal/OrderOkmsModal.page.spec.tsx @@ -105,7 +105,7 @@ const clickOnConfirmCheckbox = async () => { ORDER_OKMS_TC_CONFIRM_CHECKBOX_TEST_ID, // eslint-disable-next-line @typescript-eslint/no-explicit-any ) as any; - await act(() => { + act(() => { confirmCheckbox.odsChange.emit({ checked: 'true', }); @@ -113,11 +113,13 @@ const clickOnConfirmCheckbox = async () => { }; const clickOnConfirmButton = async (user: UserEvent) => { - const confirmButton = screen.getByTestId( - ORDER_OKMS_TC_CONFIRM_BUTTON_TEST_ID, - ); + // Small wait to ensure state updates + // Fails intermittently without this - button click does not always works + await wait(300); + let confirmButton: HTMLElement; await waitFor(() => { + confirmButton = screen.getByTestId(ORDER_OKMS_TC_CONFIRM_BUTTON_TEST_ID); expect(confirmButton).toHaveAttribute('is-disabled', 'false'); }); await act(() => user.click(confirmButton)); @@ -273,12 +275,10 @@ describe('Order Okms Modal test suite', () => { ); // WHEN + + // THEN - Test loading state await clickOnConfirmCheckbox(); - // Small wait to ensure state updates - // Fails intermittently without this - button click does not always works - await wait(500); const confirmButton = await clickOnConfirmButton(user); - // THEN - Test loading state await waitFor(() => { expect(confirmButton).toHaveAttribute('is-loading', 'true'); @@ -296,9 +296,6 @@ describe('Order Okms Modal test suite', () => { // WHEN await clickOnConfirmCheckbox(); - // Small wait to ensure state updates - // Fails intermittently without this - button click does not always works - await wait(500); await clickOnConfirmButton(user); // THEN diff --git a/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.spec.tsx b/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.spec.tsx index b04da6492153..5c078c0db20f 100644 --- a/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.spec.tsx +++ b/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.spec.tsx @@ -28,6 +28,10 @@ vi.mock('@/utils/dom/download', () => ({ initiateTextFileDownload: vi.fn(), })); +vi.mock('@ovh-ux/manager-react-shell-client', () => ({ + useOvhTracking: () => ({ trackClick: vi.fn() }), +})); + const mockOkms = { id: 'test-okms-id', region: 'test-region', @@ -55,6 +59,7 @@ const renderComponentAndGetLink = async ({ container, label, isLink: true, + timeout: 2000, }); return { downloadLink }; @@ -69,46 +74,74 @@ describe('DownloadKmsPublicCaLink component tests suite', () => { vi.clearAllMocks(); }); - test('should render publicCa download link correctly', async () => { - const { downloadLink } = await renderComponentAndGetLink({ - type: 'publicCa', + const buttons: { + type: CertificateType; + label: string; + expectedCa: 'publicCA' | 'publicRsaCA'; + expectedFilename: string; + expectedCertificate: string; + }[] = [ + { + type: 'publicCaRest', label: 'key_management_service_dashboard_button_label_download_ca', - }); - expect(downloadLink).toBeInTheDocument(); - }); - - test('should render publicRsaCa download link correctly', async () => { - const { downloadLink } = await renderComponentAndGetLink({ - type: 'publicRsaCa', + expectedCa: 'publicCA', + expectedFilename: 'okms_test-region_public_ca.pem', + expectedCertificate: mockCertificates.publicCA, + }, + { + type: 'publicCaKmip', + label: 'key_management_service_dashboard_button_label_download_ca', + expectedCa: 'publicCA', + expectedFilename: 'okms_test-region_public_ca.pem', + expectedCertificate: mockCertificates.publicCA, + }, + { + type: 'publicCaRsaKmip', label: 'key_management_service_dashboard_button_label_download_rsa_ca', - }); - expect(downloadLink).toBeInTheDocument(); - }); + expectedCa: 'publicRsaCA', + expectedFilename: 'okms_test-region_public_rsa_ca.pem', + expectedCertificate: mockCertificates.publicRsaCA, + }, + ]; + + test.each(buttons)( + 'should render $type download link correctly', + async ({ type, label }) => { + const { downloadLink } = await renderComponentAndGetLink({ + type, + label, + }); + expect(downloadLink).toBeInTheDocument(); + }, + ); - test('should download publicCa certificate when clicked', async () => { - const { downloadLink } = await renderComponentAndGetLink({ - type: 'publicCa', - label: 'key_management_service_dashboard_button_label_download_ca', - }); + test.each(buttons)( + 'should download $expectedCa certificate when clicked on $type button', + async ({ type, label, expectedFilename, expectedCertificate }) => { + const { downloadLink } = await renderComponentAndGetLink({ + type, + label, + }); - const user = userEvent.setup(); - await waitFor(() => user.click(downloadLink)); + const user = userEvent.setup(); + await waitFor(() => user.click(downloadLink)); - await waitFor(() => { - expect(api.getOkmsPublicCa).toHaveBeenCalledWith(mockOkms.id); - }); + await waitFor(() => { + expect(api.getOkmsPublicCa).toHaveBeenCalledWith(mockOkms.id); + }); - await waitFor(() => { - expect(initiateTextFileDownload).toHaveBeenCalledWith({ - text: mockCertificates.publicCA, - filename: 'okms_test-region_public_ca.pem', + await waitFor(() => { + expect(initiateTextFileDownload).toHaveBeenCalledWith({ + text: expectedCertificate, + filename: expectedFilename, + }); }); - }); - }); + }, + ); test('should download publicRsaCa certificate when clicked', async () => { const { downloadLink } = await renderComponentAndGetLink({ - type: 'publicRsaCa', + type: 'publicCaRsaKmip', label: 'key_management_service_dashboard_button_label_download_rsa_ca', }); @@ -134,7 +167,7 @@ describe('DownloadKmsPublicCaLink component tests suite', () => { ); const { downloadLink } = await renderComponentAndGetLink({ - type: 'publicCa', + type: 'publicCaRest', label: 'key_management_service_dashboard_button_label_download_ca', }); diff --git a/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.tsx b/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.tsx index 1293074da863..0d77c3e1265b 100644 --- a/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.tsx +++ b/packages/manager/apps/okms/src/components/dashboard/downloadKmsPublicCaLink/DownloadKmsPublicCaLink.tsx @@ -1,17 +1,32 @@ -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNotifications } from '@ovh-ux/manager-react-components'; import { OdsLink, OdsSpinner } from '@ovhcloud/ods-components/react'; import { ODS_BUTTON_COLOR } from '@ovhcloud/ods-components'; +import { + ButtonType, + PageLocation, + useOvhTracking, +} from '@ovh-ux/manager-react-shell-client'; import { getOkmsPublicCa } from '@/data/api/okms'; import { initiateTextFileDownload } from '@/utils/dom/download'; import { PUBLIC_CA_FILENAME, PUBLIC_RSA_CA_FILENAME, } from './downloadKmsPublicCaLink.constants'; -import { OKMS } from '@/types/okms.type'; +import { OKMS, OkmsPublicCa } from '@/types/okms.type'; + +export type CertificateType = + | 'publicCaRest' + | 'publicCaKmip' + | 'publicCaRsaKmip'; -export type CertificateType = 'publicCa' | 'publicRsaCa'; +type ButtonResource = { + label: string; + filename: string; + certificateType: keyof OkmsPublicCa; + tracking: string; +}; type DownloadCaButtonProps = { okms: OKMS; @@ -25,22 +40,28 @@ export const DownloadKmsPublicCaLink = ({ const { t } = useTranslation('key-management-service/dashboard'); const [loading, setLoading] = useState(false); const { addError } = useNotifications(); + const { trackClick } = useOvhTracking(); - const resources = useMemo( - () => ({ - publicCa: { - label: t('key_management_service_dashboard_button_label_download_ca'), - filename: PUBLIC_CA_FILENAME, - }, - publicRsaCa: { - label: t( - 'key_management_service_dashboard_button_label_download_rsa_ca', - ), - filename: PUBLIC_RSA_CA_FILENAME, - }, - }), - [], - ); + const resources: Record = { + publicCaRest: { + label: t('key_management_service_dashboard_button_label_download_ca'), + filename: PUBLIC_CA_FILENAME, + certificateType: 'publicCA', + tracking: 'download_rest-api-endpoint-ca', + }, + publicCaKmip: { + label: t('key_management_service_dashboard_button_label_download_ca'), + filename: PUBLIC_CA_FILENAME, + certificateType: 'publicCA', + tracking: 'download_kmip-endpoint-ca', + }, + publicCaRsaKmip: { + label: t('key_management_service_dashboard_button_label_download_rsa_ca'), + filename: PUBLIC_RSA_CA_FILENAME, + certificateType: 'publicRsaCA', + tracking: 'download_kmip-endpoint-ca-rsa', + }, + }; const handleDownloadCa = async ( event: React.MouseEvent, @@ -51,15 +72,17 @@ export const DownloadKmsPublicCaLink = ({ setLoading(true); const certificates = await getOkmsPublicCa(okms.id); - const content: Record = { - publicCa: certificates.publicCA, - publicRsaCa: certificates.publicRsaCA, - }; - initiateTextFileDownload({ - text: content[type], + text: certificates[resources[type].certificateType], filename: resources[type].filename.replace('{region}', okms.region), }); + + trackClick({ + location: PageLocation.page, + buttonType: ButtonType.button, + actionType: 'navigation', + actions: [resources[type].tracking], + }); } catch { addError(t('key_management_service_dashboard_error_download_ca')); } finally { diff --git a/packages/manager/apps/okms/src/components/helpIconWithTooltip/HelpIconWithTooltip.component.tsx b/packages/manager/apps/okms/src/components/helpIconWithTooltip/HelpIconWithTooltip.component.tsx new file mode 100644 index 000000000000..a1860b3a4025 --- /dev/null +++ b/packages/manager/apps/okms/src/components/helpIconWithTooltip/HelpIconWithTooltip.component.tsx @@ -0,0 +1,31 @@ +import React, { useId } from 'react'; +import { ODS_TEXT_PRESET } from '@ovhcloud/ods-components'; +import { OdsText, OdsIcon, OdsTooltip } from '@ovhcloud/ods-components/react'; + +type HelpIconWithTooltipProps = { + label: string; +}; + +export const HelpIconWithTooltip = ({ label }: HelpIconWithTooltipProps) => { + const tooltipId = useId(); + + return ( + <> + + + + {label} + + + + ); +}; diff --git a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/KmipTile.tsx b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/KmipTile.tsx index e3a73e75c3be..676af357f7da 100644 --- a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/KmipTile.tsx +++ b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/KmipTile.tsx @@ -19,7 +19,7 @@ const KmipTile = ({ okmsData }: KmipTileProps) => { value: (
- +
), }, @@ -34,7 +34,7 @@ const KmipTile = ({ okmsData }: KmipTileProps) => { className="block w-full" value={okmsData.kmipRsaEndpoint} /> - + ), }); diff --git a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/RestApiTile.tsx b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/RestApiTile.tsx index aeca3affddd5..65d6952b6c1b 100644 --- a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/RestApiTile.tsx +++ b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/GeneralInformationsTiles/RestApiTile.tsx @@ -29,7 +29,7 @@ const RestApiTile = ({ okmsData }: RestApiTileProps) => { value: (
- +
), }, @@ -40,6 +40,7 @@ const RestApiTile = ({ okmsData }: RestApiTileProps) => { trackClick({ location: PageLocation.page, diff --git a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/okmsServiceState/OkmsServiceState.component.tsx b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/okmsServiceState/OkmsServiceState.component.tsx index b916171fe51e..a9802267c32b 100644 --- a/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/okmsServiceState/OkmsServiceState.component.tsx +++ b/packages/manager/apps/okms/src/components/layout-helpers/Dashboard/okmsServiceState/OkmsServiceState.component.tsx @@ -7,6 +7,7 @@ import { ResourceStatus } from '@ovh-ux/manager-react-components'; export type OkmsStateProps = { size?: ODS_BADGE_SIZE; state: ResourceStatus; + 'data-testid'?: string; } & Record; export const OkmsServiceState = ({ state, ...props }: OkmsStateProps) => { diff --git a/packages/manager/apps/okms/src/hooks/breadcrumb/useBreadcrumb.spec.tsx b/packages/manager/apps/okms/src/hooks/breadcrumb/useBreadcrumb.spec.tsx index 8e2b13522092..c3a19d6fca49 100644 --- a/packages/manager/apps/okms/src/hooks/breadcrumb/useBreadcrumb.spec.tsx +++ b/packages/manager/apps/okms/src/hooks/breadcrumb/useBreadcrumb.spec.tsx @@ -16,8 +16,6 @@ vi.mock(`react-router-dom`, async (reactRouterDom) => { }; }); -const rootLabel = 'root-label'; - const locationPaths = ['123123', 'path', '234234']; const locationPathname = '/'.concat(locationPaths.join('/')); diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/VersionState/VersionState.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/VersionState/VersionState.component.tsx index ac6b7349658e..43f53215c0b2 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/components/VersionState/VersionState.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/VersionState/VersionState.component.tsx @@ -35,18 +35,20 @@ export type VersionStatusParams = Omit< > & { state: SecretVersionState; size?: ODS_BADGE_SIZE; + 'data-testid'?: string; }; export const VersionState = ({ state, size = ODS_BADGE_SIZE.md, + 'data-testid': dataTestId, ...rest }: VersionStatusParams) => { const { t } = useTranslation('secret-manager'); return ( { const navigate = useNavigate(); @@ -14,7 +14,7 @@ export const CreateSecretBreadcrumbItem = () => { return ( navigate(SECRET_MANAGER_ROUTES_URLS.createSecret)} diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/OkmsBreadcrumbItem.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/OkmsBreadcrumbItem.component.tsx index d22e09e23915..06f37d361995 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/OkmsBreadcrumbItem.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/OkmsBreadcrumbItem.component.tsx @@ -5,8 +5,8 @@ import { LocationPathParams, SECRET_MANAGER_ROUTES_URLS, } from '@secret-manager/routes/routes.constants'; -import { OKMS_BREADCRUMB_ITEM_TEST_ID } from '@secret-manager/utils/tests/breadcrumb.constants'; import { isLocationParamsDefined } from '@secret-manager/utils/locationParams'; +import { BREADCRUMB_ITEM_TEST_IDS } from './BreadcrumbItem.constants'; import { useOkmsById } from '@/data/hooks/useOkms'; const Item = ({ okmsId }: { okmsId: string }) => { @@ -23,7 +23,7 @@ const Item = ({ okmsId }: { okmsId: string }) => { return ( navigate(SECRET_MANAGER_ROUTES_URLS.secretList(okmsId))} diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/RootBreadcrumbItem.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/RootBreadcrumbItem.component.tsx index f656e4d62489..22e61127a8c2 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/RootBreadcrumbItem.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/RootBreadcrumbItem.component.tsx @@ -6,7 +6,7 @@ import { SECRET_MANAGER_ROUTES_URLS, } from '@secret-manager/routes/routes.constants'; import { useTranslation } from 'react-i18next'; -import { ROOT_BREADCRUMB_ITEM_TEST_ID } from '@secret-manager/utils/tests/breadcrumb.constants'; +import { BREADCRUMB_ITEM_TEST_IDS } from './BreadcrumbItem.constants'; export const RootBreadcrumbItem = () => { const navigate = useNavigate(); @@ -14,7 +14,7 @@ export const RootBreadcrumbItem = () => { return ( navigate(SECRET_MANAGER_ROUTES_URLS.root)} diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/SecretBreadcrumbItem.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/SecretBreadcrumbItem.component.tsx index 1f09d75b474d..8530f29a5c68 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/SecretBreadcrumbItem.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/breadcrumb/items/SecretBreadcrumbItem.component.tsx @@ -6,8 +6,8 @@ import { SECRET_MANAGER_ROUTES_URLS, } from '@secret-manager/routes/routes.constants'; import { decodeSecretPath } from '@secret-manager/utils/secretPath'; -import { SECRET_BREADCRUMB_ITEM_TEST_ID } from '@secret-manager/utils/tests/breadcrumb.constants'; import { isLocationParamsDefined } from '@secret-manager/utils/locationParams'; +import { BREADCRUMB_ITEM_TEST_IDS } from './BreadcrumbItem.constants'; const Item = ({ okmsId, @@ -20,7 +20,7 @@ const Item = ({ return ( diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretCasRequiredFormField.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretCasRequiredFormField.component.tsx new file mode 100644 index 000000000000..da5f60562b6e --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretCasRequiredFormField.component.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { Controller, UseControllerProps } from 'react-hook-form'; +import { + OdsFormField, + OdsRadio, + OdsText, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { NAMESPACES } from '@ovh-ux/manager-common-translations'; +import { SECRET_FORM_FIELD_TEST_IDS } from './form.constants'; +import { HelpIconWithTooltip } from '@/components/helpIconWithTooltip/HelpIconWithTooltip.component'; + +type CasRequiredFormValue = 'active' | 'inactive'; + +type FormFieldInput = { + casRequired: CasRequiredFormValue; +}; + +type SecretCasRequiredFormFieldProps< + T extends FormFieldInput +> = UseControllerProps & { + isCasRequiredSetOnOkms?: boolean; +}; + +export const SecretCasRequiredFormField = ({ + name, + control, + isCasRequiredSetOnOkms, +}: SecretCasRequiredFormFieldProps) => { + const { t } = useTranslation(['secret-manager', NAMESPACES.STATUS]); + return ( + ( + + +
+
+ + +
+
+ + +
+
+ {isCasRequiredSetOnOkms && ( + + {t('form_helper_cas_required_okms')} + + )} +
+ )} + /> + ); +}; + +export const casRequiredToFormValue = ( + casRequired: boolean, +): CasRequiredFormValue => { + return casRequired ? 'active' : 'inactive'; +}; + +export const formValueToCasRequired = ( + formValue: CasRequiredFormValue, +): boolean => { + return formValue === 'active'; +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDataFormField.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDataFormField.component.tsx index 90cb187eaa1a..7ba04e21981d 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDataFormField.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDataFormField.component.tsx @@ -2,9 +2,13 @@ import React from 'react'; import { Controller, UseControllerProps } from 'react-hook-form'; import { OdsFormField, OdsTextarea } from '@ovhcloud/ods-components/react'; import { useTranslation } from 'react-i18next'; -import { DATA_INPUT_TEST_ID } from '@secret-manager/utils/tests/secret.constants'; +import { SECRET_FORM_FIELD_TEST_IDS } from './form.constants'; -export const SecretDataFormField = >({ +type FormFieldInput = { + data: string; +}; + +export const SecretDataFormField = ({ name, control, }: UseControllerProps) => { @@ -26,7 +30,7 @@ export const SecretDataFormField = >({ onOdsChange={field.onChange} isResizable rows={12} - data-testid={DATA_INPUT_TEST_ID} + data-testid={SECRET_FORM_FIELD_TEST_IDS.INPUT_DATA} /> )} diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDeactivateVersionAfterFormField.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDeactivateVersionAfterFormField.component.tsx new file mode 100644 index 000000000000..6bb46e812312 --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretDeactivateVersionAfterFormField.component.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Controller, UseControllerProps } from 'react-hook-form'; +import { + OdsText, + OdsFormField, + OdsInput, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { SECRET_FORM_FIELD_TEST_IDS } from './form.constants'; +import { HelpIconWithTooltip } from '@/components/helpIconWithTooltip/HelpIconWithTooltip.component'; + +type FormFieldInput = { + deactivateVersionAfter: string; +}; + +export const SecretDeactivateVersionAfterFormField = < + T extends FormFieldInput +>({ + name, + control, +}: UseControllerProps) => { + const { t } = useTranslation('secret-manager'); + return ( + ( + + + + + {t('form_helper_deactivate_version_after')} + + + )} + /> + ); +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretMaxVersionsFormField.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretMaxVersionsFormField.component.tsx new file mode 100644 index 000000000000..b2fbad8d0918 --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/form/SecretMaxVersionsFormField.component.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { Controller, UseControllerProps } from 'react-hook-form'; +import { + OdsText, + OdsFormField, + OdsQuantity, +} from '@ovhcloud/ods-components/react'; +import { useTranslation } from 'react-i18next'; +import { + MAX_VERSIONS_MAX_VALUE, + MAX_VERSIONS_MIN_VALUE, +} from '@secret-manager/validation/metadata/metadataSchema'; +import { SECRET_FORM_FIELD_TEST_IDS } from './form.constants'; + +type FormFieldInput = { + maxVersions: number; +}; + +type SecretMaxVersionsFormFieldProps< + T extends FormFieldInput +> = UseControllerProps & { + defaultMaxVersions: number; +}; + +export const SecretMaxVersionsFormField = ({ + name, + control, + defaultMaxVersions, +}: SecretMaxVersionsFormFieldProps) => { + const { t } = useTranslation('secret-manager'); + return ( + ( + + + + + {t('form_helper_max_versions', { default: defaultMaxVersions })} + + + )} + /> + ); +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/components/form/form.constants.ts b/packages/manager/apps/okms/src/modules/secret-manager/components/form/form.constants.ts new file mode 100644 index 000000000000..6b5af0059c77 --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/components/form/form.constants.ts @@ -0,0 +1,7 @@ +export const SECRET_FORM_FIELD_TEST_IDS = { + INPUT_DATA: 'secret-input-data', + MAX_VERSIONS: 'secret-input-max-versions', + CAS_REQUIRED_ACTIVE: 'secret-input-cas-required-active', + CAS_REQUIRED_INACTIVE: 'secret-input-cas-required-inactive', + DEACTIVATE_VERSION_AFTER: 'secret-input-deactivate-version-after', +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/data/api/secretVersions.ts b/packages/manager/apps/okms/src/modules/secret-manager/data/api/secretVersions.ts index c4fe5bebb431..e251b720917e 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/data/api/secretVersions.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/data/api/secretVersions.ts @@ -4,6 +4,7 @@ import { SecretVersionDataField, SecretVersionWithData, } from '@secret-manager/types/secret.type'; +import { buildQueryString } from '@secret-manager/utils/queryStrings'; export const secretVersionsQueryKeys = { list: (okmsId: string, path: string) => ['secret', okmsId, path, 'versions'], @@ -47,14 +48,9 @@ export const createSecretVersion = async ({ data, cas, }: CreateSecretVersionParams) => { - const queryParams = new URLSearchParams(); - if (cas) { - queryParams.set('cas', cas.toString()); - } - const queryString = queryParams.toString(); const url = `okms/resource/${okmsId}/secret/${encodeURIComponent( path, - )}/version${queryString ? `?${queryString}` : ''}`; + )}/version${buildQueryString({ cas })}`; const { data: response } = await apiClient.v2.post< CreateSecretVersionResponse diff --git a/packages/manager/apps/okms/src/modules/secret-manager/data/api/secrets.ts b/packages/manager/apps/okms/src/modules/secret-manager/data/api/secrets.ts index 624e144b9132..a2048078aee0 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/data/api/secrets.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/data/api/secrets.ts @@ -5,6 +5,7 @@ import { SecretMetadata, SecretVersionDataField, } from '@secret-manager/types/secret.type'; +import { buildQueryString } from '@secret-manager/utils/queryStrings'; export const secretQueryKeys = { list: (okmsId: string) => ['secret', okmsId], @@ -74,10 +75,34 @@ export type UpdateSecretBody = { SecretMetadata, 'casRequired' | 'customMetadata' | 'deactivateVersionAfter' | 'maxVersions' >; - version: SecretVersionDataField; + version?: SecretVersionDataField; }; export type UpdateSecretResponse = Pick; +export type UpdateSecretParams = { + okmsId: string; + path: string; + cas: number; + data: UpdateSecretBody; +}; + +export const updateSecret = async ({ + okmsId, + path, + cas, + data: updateData, +}: UpdateSecretParams) => { + const url = `okms/resource/${okmsId}/secret/${encodeURIComponent( + path, + )}${buildQueryString({ cas })}`; + + const { data } = await apiClient.v2.put( + url, + updateData, + ); + return data; +}; + // DELETE Secret export type DeleteSecretParams = { okmsId: string; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/data/hooks/useUpdateSecret.ts b/packages/manager/apps/okms/src/modules/secret-manager/data/hooks/useUpdateSecret.ts new file mode 100644 index 000000000000..38b98ab0990a --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/data/hooks/useUpdateSecret.ts @@ -0,0 +1,20 @@ +import { ApiError } from '@ovh-ux/manager-core-api'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { + UpdateSecretResponse, + updateSecret, + UpdateSecretParams, + secretQueryKeys, +} from '../api/secrets'; + +export const useUpdateSecret = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (params) => updateSecret(params), + onSuccess: (_, params) => { + queryClient.invalidateQueries({ + queryKey: secretQueryKeys.detail(params.okmsId, params.path), + }); + }, + }); +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/hooks/useSecretSmartConfig.spec.ts b/packages/manager/apps/okms/src/modules/secret-manager/hooks/useSecretSmartConfig.spec.ts index b095e0b067f0..a92f048a825a 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/hooks/useSecretSmartConfig.spec.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/hooks/useSecretSmartConfig.spec.ts @@ -90,6 +90,8 @@ const mockSecretSmartConfig: SecretSmartConfig = { value: 15, origin: 'DOMAIN', }, + isCasRequiredSetOnOkms: true, + maxVersionsDefault: 10, }; describe('useSecretSmartConfig', () => { diff --git a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretConfigOkms/secretConfigOkms.handler.ts b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretConfigOkms/secretConfigOkms.handler.ts index 152ebd409b18..b87c2bb74d0d 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretConfigOkms/secretConfigOkms.handler.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretConfigOkms/secretConfigOkms.handler.ts @@ -1,7 +1,10 @@ import { Handler } from '@ovh-ux/manager-core-test-utils'; import { mockSecretConfigOkms } from './secretConfigOkms.mock'; +import { buildMswResponseMock } from '@/utils/tests/msw'; // GET Secret Config +export const getSecretConfigErrorMessage = 'get-secret-config-error-message'; + export type GetSecretConfigOkmsMockParams = { isSecretConfigKO?: boolean; }; @@ -11,14 +14,11 @@ export const getSecretConfigOkmsMock = ({ }: GetSecretConfigOkmsMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secretConfig', - response: isSecretConfigKO - ? { - status: 500, - data: { - message: 'secret config error', - }, - } - : mockSecretConfigOkms, + response: buildMswResponseMock({ + data: mockSecretConfigOkms, + errorMessage: getSecretConfigErrorMessage, + isError: isSecretConfigKO, + }), status: isSecretConfigKO ? 500 : 200, api: 'v2', }, diff --git a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretReference/secretReference.handler.ts b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretReference/secretReference.handler.ts index a08501e81617..75442dd60b9a 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretReference/secretReference.handler.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secretReference/secretReference.handler.ts @@ -1,23 +1,24 @@ import { Handler } from '@ovh-ux/manager-core-test-utils'; import { mockSecretConfigReference } from './secretReference.mock'; +import { buildMswResponseMock } from '@/utils/tests/msw'; export type GetSecretConfigReferenceMockParams = { isSecretConfigReferenceKO?: boolean; }; +export const getSecretConfigReferenceErrorMessage = + 'get-secret-config-reference-error-message'; + export const getSecretConfigReferenceMock = ({ isSecretConfigReferenceKO, }: GetSecretConfigReferenceMockParams): Handler[] => [ { url: '/okms/reference/secretConfig', - response: isSecretConfigReferenceKO - ? { - status: 500, - data: { - message: 'secret config reference error', - }, - } - : mockSecretConfigReference, + response: buildMswResponseMock({ + data: mockSecretConfigReference, + errorMessage: getSecretConfigReferenceErrorMessage, + isError: isSecretConfigReferenceKO, + }), status: isSecretConfigReferenceKO ? 500 : 200, api: 'v2', }, diff --git a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secrets/secrets.handler.ts b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secrets/secrets.handler.ts index 083bbd6476b6..42cc123d1cb2 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/mocks/secrets/secrets.handler.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/mocks/secrets/secrets.handler.ts @@ -1,9 +1,11 @@ -import { PathParams } from 'msw'; import { Handler } from '@ovh-ux/manager-core-test-utils'; import { createSecretResponseMock, secretListMock } from './secrets.mock'; import { findSecretMockByPath } from './secretsMock.utils'; +import { buildMswResponseMock } from '@/utils/tests/msw'; // LIST +export const getSecretsErrorMessage = 'get-secrets-error-message'; + export type GetSecretsMockParams = { isSecretListKO?: boolean; nbSecrets?: number; @@ -15,20 +17,19 @@ export const getSecretsMock = ({ }: GetSecretsMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret', - response: isSecretListKO - ? { - status: 500, - data: { - message: 'secrets error', - }, - } - : secretListMock.slice(0, nbSecrets), + response: buildMswResponseMock({ + data: secretListMock.slice(0, nbSecrets), + errorMessage: getSecretsErrorMessage, + isError: isSecretListKO, + }), status: isSecretListKO ? 500 : 200, api: 'v2', }, ]; // GET +export const getSecretErrorMessage = 'get-secret-error-message'; + export type GetSecretMockParams = { isSecretKO?: boolean; }; @@ -38,15 +39,12 @@ export const getSecretMock = ({ }: GetSecretMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret/:secretPath', - response: isSecretKO - ? { - status: 500, - data: { - message: 'secrets error', - }, - } - : (request: Request, params: PathParams) => - findSecretMockByPath(secretListMock, request, params), + response: buildMswResponseMock({ + data: (request, params) => + findSecretMockByPath(secretListMock, request, params), + errorMessage: getSecretErrorMessage, + isError: isSecretKO, + }), status: isSecretKO ? 500 : 200, api: 'v2', }, @@ -64,17 +62,46 @@ export const createSecretsMock = ({ }: CreateSecretsMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret', - response: isCreateSecretKO - ? { - message: createSecretErrorMessage, - } - : createSecretResponseMock, + response: buildMswResponseMock({ + data: createSecretResponseMock, + errorMessage: createSecretErrorMessage, + isError: isCreateSecretKO, + }), status: isCreateSecretKO ? 500 : 200, api: 'v2', method: 'post', }, ]; +// PUT (UPDATE) +export const updateSecretErrorMessage = 'update-secret-error-message'; + +export type UpdateSecretMockParams = { + isUpdateSecretKO?: boolean; +}; + +export const updateSecretMock = ({ + isUpdateSecretKO, +}: UpdateSecretMockParams): Handler[] => [ + { + url: '/okms/resource/:okmsId/secret/:secretPath', + response: buildMswResponseMock({ + data: (request, params) => { + const secret = findSecretMockByPath(secretListMock, request, params); + return { + path: secret.path, + metadata: secret.metadata, + }; + }, + errorMessage: updateSecretErrorMessage, + isError: isUpdateSecretKO, + }), + status: isUpdateSecretKO ? 500 : 200, + api: 'v2', + method: 'put', + }, +]; + // DELETE export const deleteSecretErrorMessage = 'delete-secret-error-message'; @@ -87,11 +114,11 @@ export const deleteSecretMock = ({ }: DeleteSecretMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret/:path', - response: isDeleteSecretKO - ? { - message: deleteSecretErrorMessage, - } - : null, + response: buildMswResponseMock({ + data: null, + errorMessage: deleteSecretErrorMessage, + isError: isDeleteSecretKO, + }), status: isDeleteSecretKO ? 500 : 200, api: 'v2', method: 'delete', diff --git a/packages/manager/apps/okms/src/modules/secret-manager/mocks/versions/versions.handler.ts b/packages/manager/apps/okms/src/modules/secret-manager/mocks/versions/versions.handler.ts index 4d34da737ede..171d54630b2b 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/mocks/versions/versions.handler.ts +++ b/packages/manager/apps/okms/src/modules/secret-manager/mocks/versions/versions.handler.ts @@ -1,7 +1,6 @@ -import { PathParams } from 'msw'; import { Handler } from '@ovh-ux/manager-core-test-utils'; import { versionListMock, createVersionResponseMock } from './versions.mock'; -import { createHandlerResponseMock } from '@/utils/tests/testUtils'; +import { buildMswResponseMock } from '@/utils/tests/msw'; import { findVersionMockById } from './versionsMock.utils'; // LIST VERSION @@ -10,20 +9,19 @@ export type GetVersionsMockParams = { nbVersions?: number; }; +export const getVersionsErrorMessage = 'get-versions-error-message'; + export const getVersionsMock = ({ isVersionsKO, nbVersions = versionListMock.length, }: GetVersionsMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret/:secretPath/version', - response: isVersionsKO - ? { - status: 500, - data: { - message: 'versions error', - }, - } - : versionListMock.slice(0, nbVersions), + response: buildMswResponseMock({ + data: versionListMock.slice(0, nbVersions), + errorMessage: getVersionsErrorMessage, + isError: isVersionsKO, + }), status: isVersionsKO ? 500 : 200, api: 'v2', }, @@ -34,20 +32,19 @@ export type GetVersionMockParams = { isVersionKO?: boolean; }; +export const getVersionErrorMessage = 'get-version-error-message'; + export const getVersionMock = ({ isVersionKO, }: GetVersionMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret/:secretPath/version/:versionId', - response: isVersionKO - ? { - status: 500, - data: { - message: 'version error', - }, - } - : (request: Request, params: PathParams) => - findVersionMockById(versionListMock, request, params), + response: buildMswResponseMock({ + data: (request, params) => + findVersionMockById(versionListMock, request, params), + errorMessage: getVersionErrorMessage, + isError: isVersionKO, + }), status: isVersionKO ? 500 : 200, api: 'v2', }, @@ -65,11 +62,11 @@ export const createVersionMock = ({ }: CreateVersionMockParams): Handler[] => [ { url: '/okms/resource/:okmsId/secret/:secretPath/version', - response: isCreateVersionKO - ? { - message: createVersionErrorMessage, - } - : createVersionResponseMock, + response: buildMswResponseMock({ + data: createVersionResponseMock, + errorMessage: createVersionErrorMessage, + isError: isCreateVersionKO, + }), status: isCreateVersionKO ? 500 : 200, api: 'v2', method: 'post', @@ -89,7 +86,7 @@ export const updateVersionMock = ({ { url: '/okms/resource/:okmsId/secret/:secretPath/version/:versionId', method: 'put', - response: createHandlerResponseMock({ + response: buildMswResponseMock({ data: {}, errorMessage: updateVersionErrorMessage, isError: isVersionUpdateKO, diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.spec.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.spec.tsx index 84ba33a7c531..52cd3447e06d 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.spec.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.spec.tsx @@ -7,10 +7,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { vi } from 'vitest'; import { assertTextVisibility } from '@ovh-ux/manager-core-test-utils'; import { render, screen } from '@testing-library/react'; -import { - ACTIVATE_OKMS_BTN_TEST_ID, - ACTIVATE_OKMS_SPINNER_TEST_ID, -} from '@secret-manager/utils/tests/secret.constants'; +import { SECRET_ACTIVATE_OKMS_TEST_IDS } from '@secret-manager/pages/createSecret/ActivateRegion.contants'; import { labels, initTestI18n } from '@/utils/tests/init.i18n'; import { REGION_EU_WEST_RBX } from '@/mocks/catalog/catalog.mock'; import { @@ -70,7 +67,9 @@ describe('ActivateRegion test suite', () => { }); // THEN - const activateButton = screen.queryByTestId(ACTIVATE_OKMS_BTN_TEST_ID); + const activateButton = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.BUTTON, + ); expect(activateButton).toBeVisible(); await user.click(activateButton); @@ -95,7 +94,9 @@ describe('ActivateRegion test suite', () => { }); // THEN - const Spinner = screen.queryByTestId(ACTIVATE_OKMS_SPINNER_TEST_ID); + const Spinner = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.SPINNER, + ); expect(Spinner).toBeVisible(); await assertTextVisibility( diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.tsx index 84afbc20131a..8921254f5fc1 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.component.tsx @@ -2,10 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { OdsButton, OdsSpinner, OdsText } from '@ovhcloud/ods-components/react'; -import { - ACTIVATE_OKMS_BTN_TEST_ID, - ACTIVATE_OKMS_SPINNER_TEST_ID, -} from '@secret-manager/utils/tests/secret.constants'; +import { SECRET_ACTIVATE_OKMS_TEST_IDS } from '@secret-manager/pages/createSecret/ActivateRegion.contants'; import { SECRET_MANAGER_ROUTES_URLS } from '@secret-manager/routes/routes.constants'; import { NAMESPACES } from '@ovh-ux/manager-common-translations'; @@ -23,13 +20,16 @@ export const ActivateRegion = ({ return isOkmsOrderProcessing ? (
- + {t('okms_activation_in_progress')}
) : (
navigate( diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.contants.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.contants.tsx new file mode 100644 index 000000000000..9dbec96e4360 --- /dev/null +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/ActivateRegion.contants.tsx @@ -0,0 +1,4 @@ +export const SECRET_ACTIVATE_OKMS_TEST_IDS = { + BUTTON: 'secret-activate-okms-button', + SPINNER: 'secret-activate-okms-spinner', +}; diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/CreateSecret.page.spec.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/CreateSecret.page.spec.tsx index b4a17641356c..6c6e34cb6741 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/CreateSecret.page.spec.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/CreateSecret.page.spec.tsx @@ -4,12 +4,11 @@ import { } from '@ovh-ux/manager-core-test-utils'; import { waitFor } from '@testing-library/dom'; import { - DATA_INPUT_TEST_ID, MOCK_DATA_VALID_JSON, - PATH_INPUT_TEST_ID, MOCK_PATH_VALID, - SUBMIT_BTN_TEST_ID, } from '@secret-manager/utils/tests/secret.constants'; +import { SECRET_FORM_TEST_IDS } from '@secret-manager/pages/createSecret/SecretForm.constants'; +import { SECRET_FORM_FIELD_TEST_IDS } from '@secret-manager/components/form/form.constants'; import { fireEvent, act, screen } from '@testing-library/react'; import userEvent, { UserEvent } from '@testing-library/user-event'; import { assertBreadcrumbItems } from '@secret-manager/utils/tests/breadcrumb'; @@ -29,8 +28,8 @@ const selectRegion = async (user: UserEvent) => { }; const fillRequiredFields = () => { - const inputPath = screen.getByTestId(PATH_INPUT_TEST_ID); - const inputData = screen.getByTestId(DATA_INPUT_TEST_ID); + const inputPath = screen.getByTestId(SECRET_FORM_TEST_IDS.INPUT_PATH); + const inputData = screen.getByTestId(SECRET_FORM_FIELD_TEST_IDS.INPUT_DATA); act(() => { fireEvent.input(inputPath, { @@ -69,7 +68,7 @@ describe('Create secret page test suite', () => { await selectRegion(user); fillRequiredFields(); - const submitButton = screen.getByTestId(SUBMIT_BTN_TEST_ID); + const submitButton = screen.getByTestId(SECRET_FORM_TEST_IDS.SUBMIT_BUTTON); expect(submitButton).toBeInTheDocument(); await waitFor(() => expect(submitButton).toBeEnabled()); @@ -100,7 +99,7 @@ describe('Create secret page test suite', () => { await selectRegion(user); fillRequiredFields(); - const submitButton = screen.getByTestId(SUBMIT_BTN_TEST_ID); + const submitButton = screen.getByTestId(SECRET_FORM_TEST_IDS.SUBMIT_BUTTON); expect(submitButton).toBeInTheDocument(); await waitFor(() => expect(submitButton).toBeEnabled()); diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/OkmsManagement.component.spec.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/OkmsManagement.component.spec.tsx index c238f30638a0..2b6c47de024e 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/OkmsManagement.component.spec.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/OkmsManagement.component.spec.tsx @@ -22,10 +22,7 @@ import { vi } from 'vitest'; import { assertTextVisibility } from '@ovh-ux/manager-core-test-utils'; import { waitFor } from '@testing-library/dom'; import { act, render, screen } from '@testing-library/react'; -import { - ACTIVATE_OKMS_BTN_TEST_ID, - ACTIVATE_OKMS_SPINNER_TEST_ID, -} from '@secret-manager/utils/tests/secret.constants'; +import { SECRET_ACTIVATE_OKMS_TEST_IDS } from '@secret-manager/pages/createSecret/ActivateRegion.contants'; import { labels, initTestI18n } from '@/utils/tests/init.i18n'; import { OkmsManagement } from './OkmsManagement.component'; import { catalogMock } from '@/mocks/catalog/catalog.mock'; @@ -167,28 +164,36 @@ const assertOkmsListIsInTheDocument = async (okmsList: OKMS[]) => { }; const assertActivateButtonIsInTheDocument = async () => { - const activateButton = screen.queryByTestId(ACTIVATE_OKMS_BTN_TEST_ID); + const activateButton = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.BUTTON, + ); await waitFor(() => { expect(activateButton).toBeVisible(); }); }; const assertActivateButtonIsNotInTheDocument = async () => { - const activateButton = screen.queryByTestId(ACTIVATE_OKMS_BTN_TEST_ID); + const activateButton = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.BUTTON, + ); await waitFor(() => { expect(activateButton).toBeNull(); }); }; const assertLoadingListIsInTheDocument = async () => { - const activateSpinner = screen.queryByTestId(ACTIVATE_OKMS_SPINNER_TEST_ID); + const activateSpinner = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.SPINNER, + ); await waitFor(() => { expect(activateSpinner).toBeVisible(); }); }; const assertLoadingListIsNotInTheDocument = async () => { - const activateSpinner = screen.queryByTestId(ACTIVATE_OKMS_SPINNER_TEST_ID); + const activateSpinner = screen.queryByTestId( + SECRET_ACTIVATE_OKMS_TEST_IDS.SPINNER, + ); await waitFor(() => { expect(activateSpinner).toBeNull(); }); diff --git a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/SecretForm.component.spec.tsx b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/SecretForm.component.spec.tsx index a83939289af7..7a9e141552be 100644 --- a/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/SecretForm.component.spec.tsx +++ b/packages/manager/apps/okms/src/modules/secret-manager/pages/createSecret/SecretForm.component.spec.tsx @@ -7,16 +7,16 @@ import { vi } from 'vitest'; import { assertTextVisibility } from '@ovh-ux/manager-core-test-utils'; import { waitFor } from '@testing-library/dom'; import { - DATA_INPUT_TEST_ID, MOCK_DATA_VALID_JSON, - PATH_INPUT_TEST_ID, MOCK_PATH_VALID, - SUBMIT_BTN_TEST_ID, } from '@secret-manager/utils/tests/secret.constants'; -import { fireEvent, act, render, screen } from '@testing-library/react'; +import { SECRET_FORM_TEST_IDS } from '@secret-manager/pages/createSecret/SecretForm.constants'; +import { SECRET_FORM_FIELD_TEST_IDS } from '@secret-manager/components/form/form.constants'; +import { render, screen } from '@testing-library/react'; import { labels, initTestI18n } from '@/utils/tests/init.i18n'; import { SecretForm } from './SecretForm.component'; import { SECRET_DATA_TEMPLATE } from './SecretForm.constants'; +import { changeOdsInputValueByTestId } from '@/utils/tests/uiTestHelpers'; let i18nValue: i18n; @@ -30,6 +30,38 @@ vi.mock('react-router-dom', async (importOriginal) => { }; }); +// Mocking ODS Input component +vi.mock('@ovhcloud/ods-components/react', async () => { + const original = await vi.importActual('@ovhcloud/ods-components/react'); + return { + ...original, + OdsInput: vi.fn( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ className, onOdsChange, onOdsBlur, ...rest }) => ( + onOdsChange && onOdsChange(e.target.value)} + onBlur={(e) => onOdsBlur && onOdsBlur(e.target.value)} + {...rest} + /> + ), + ), + OdsTextarea: vi.fn( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ className, onOdsChange, onOdsBlur, isResizable, ...rest }) => ( +