diff --git a/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/WebSidebar.tsx b/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/WebSidebar.tsx index bbe49a9b55cb..031d7e25d399 100644 --- a/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/WebSidebar.tsx +++ b/packages/manager/apps/container/src/container/legacy/server-sidebar/universe/WebSidebar.tsx @@ -30,6 +30,7 @@ export const webFeatures = [ 'web-paas', 'cloud-web', 'cloud-database', + 'zimbra' ]; export default function WebSidebar() { @@ -154,6 +155,19 @@ export default function WebSidebar() { }); } + if (features.zimbra) { + menu.push({ + id: 'zimbra', + label: t('sidebar_zimbra'), + icon: getIcon('ovh-font ovh-font-mail'), + routeMatcher: new RegExp('^/zimbra'), + href: navigation.getURL( + 'zimbra', + '#/', + ), + }); + } + if (features['email-pro']) { menu.push({ id: 'emailPros', diff --git a/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/webCloud.ts b/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/webCloud.ts index 55153027cb8d..d1f23b475365 100644 --- a/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/webCloud.ts +++ b/packages/manager/apps/container/src/container/nav-reshuffle/sidebar/navigation-tree/services/webCloud.ts @@ -122,8 +122,18 @@ webCloudUniverse.children = [ idAttr: 'emails-link', universe: webCloudUniverse.id, translation: 'sidebar_emails', - features: ['email-pro', 'emails:mxplan'], + features: ['email-pro', 'emails:mxplan', 'zimbra'], children: [ + { + id: 'zimbra', + translation: 'sidebar_zimbra', + routing: { + application: 'zimbra', + hash: '#/', + }, + features: ['zimbra'], + count: false, + }, { id: 'email-pro', idAttr: 'email-pro-link', diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json index 2a63b51e631e..c7494f61b1ad 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_en_GB.json @@ -194,8 +194,5 @@ "sidebar_back_menu": "Back to menu", "sidebar_identity_security_operations": "Identity, Security & Operations", "sidebar_key-management-service": "Key Management Service", - "sidebar_pci_ai_dashboard": "AI Dashboard", - "sidebar_reduce": "Minimise", - "sidebar_security_operations": "Operations", - "sidebar_security_identity": "Identity and Security" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json index 9d578162ce6f..17daecc30fad 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_es_ES.json @@ -194,8 +194,5 @@ "sidebar_back_menu": "Volver al menú", "sidebar_identity_security_operations": "Identidad, Seguridad y Operaciones", "sidebar_key-management-service": "Key Management Service", - "sidebar_pci_ai_dashboard": "AI Dashboard", - "sidebar_reduce": "Minimizar", - "sidebar_security_operations": "Operaciones", - "sidebar_security_identity": "Identidad y seguridad" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json index 523c138c1001..a69ee78469af 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_CA.json @@ -187,7 +187,5 @@ "sidebar_network_security": "Network Security Dashboard", "sidebar_identity_security_operations": "Identité, Sécurité & Opérations", "sidebar_key-management-service": "Key Management Service", - "sidebar_reduce": "Réduire", - "sidebar_security_operations": "Opérations", - "sidebar_security_identity": "Identité et Sécurité" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json index 523c138c1001..a69ee78469af 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_fr_FR.json @@ -187,7 +187,5 @@ "sidebar_network_security": "Network Security Dashboard", "sidebar_identity_security_operations": "Identité, Sécurité & Opérations", "sidebar_key-management-service": "Key Management Service", - "sidebar_reduce": "Réduire", - "sidebar_security_operations": "Opérations", - "sidebar_security_identity": "Identité et Sécurité" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json index e27923b60610..8e23f8f4171f 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_it_IT.json @@ -194,8 +194,5 @@ "sidebar_back_menu": "Torna al menu", "sidebar_identity_security_operations": "Identità, Sicurezza & Operazioni", "sidebar_key-management-service": "Key Management Service", - "sidebar_pci_ai_dashboard": "AI Dashboard", - "sidebar_reduce": "Riduci", - "sidebar_security_operations": "Operazioni", - "sidebar_security_identity": "Identità e sicurezza" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json index 9ade1bbd63a4..a2c9c2867735 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pl_PL.json @@ -194,8 +194,5 @@ "sidebar_back_menu": "Powrót do menu", "sidebar_identity_security_operations": "Tożsamość, Bezpieczeństwo I Operacje", "sidebar_key-management-service": "Usługa zarządzania kluczami", - "sidebar_pci_ai_dashboard": "AI Dashboard", - "sidebar_reduce": "Zmniejsz", - "sidebar_security_operations": "Operacje", - "sidebar_security_identity": "Tożsamość i bezpieczeństwo" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json index 5c4653bae06d..bf3a2cc5fb7f 100644 --- a/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json +++ b/packages/manager/apps/container/src/public/translations/sidebar/Messages_pt_PT.json @@ -194,8 +194,5 @@ "sidebar_back_menu": "Voltar ao menu", "sidebar_identity_security_operations": "Identidade, Segurança e Operações", "sidebar_key-management-service": "Key Management Service", - "sidebar_pci_ai_dashboard": "AI Dashboard", - "sidebar_reduce": "Reduzir", - "sidebar_security_operations": "Operações", - "sidebar_security_identity": "Identidade e Segurança" + "sidebar_zimbra": "Zimbra" } diff --git a/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.controller.js b/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.controller.js index 75ae722e2f53..d7d7fc5413ca 100644 --- a/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.controller.js +++ b/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.controller.js @@ -7,8 +7,17 @@ import { export default class XdslAccessListCtrl { /* @ngInject */ - constructor($q, coreURLBuilder, XdslAccessListService, TucToastError) { + constructor( + $filter, + $q, + $translate, + coreURLBuilder, + XdslAccessListService, + TucToastError, + ) { + this.$filter = $filter; this.$q = $q; + this.$translate = $translate; this.coreURLBuilder = coreURLBuilder; this.XdslAccessListService = XdslAccessListService; this.TucToastError = TucToastError; @@ -27,7 +36,7 @@ export default class XdslAccessListCtrl { } getServices() { - this.XdslAccessListService.getServices() + return this.XdslAccessListService.getServices() .then((data) => this.buildServicesList(data || []).then((services) => { this.services = services; @@ -38,10 +47,47 @@ export default class XdslAccessListCtrl { }); } + static sortList(list) { + const sorted = list.sort((a, b) => { + if (a.accessType < b.accessType) { + return -1; + } + if (a.accessType > b.accessType) { + return 1; + } + + return 0; + }); + return sorted; + } + + static getSortedServiceList(services) { + // First group by ADSL and VDSL then others access type + const accessTypeGroupBy = Object.groupBy(services, ({ accessType }) => { + return [ACCESS_TYPE.adsl, ACCESS_TYPE.vdsl].includes(accessType) + ? ELIGIBILITY.eligible + : ELIGIBILITY.not_eligible; + }); + + // Order each group and add them to the sorted services list + const sortedServicesList = [ + ...this.sortList(accessTypeGroupBy.eligible), + ...this.sortList(accessTypeGroupBy.not_eligible), + ]; + return sortedServicesList; + } + buildServicesList(services) { + // Sort services to have ADSL and VDSL services in first positions + const sortedServices = this.constructor.getSortedServiceList(services); + // Retrieve service info for each service - const serviceList = services.map((service) => { - if (service.accessType !== this.ACCESS_TYPE.ftth) { + const serviceList = sortedServices.map((service) => { + if ( + ![this.ACCESS_TYPE.ftth, this.ACCESS_TYPE.sdsl].includes( + service.accessType, + ) + ) { return this.XdslAccessListService.getFiberEligibilityList( service.accessName, ).then((data) => @@ -54,6 +100,7 @@ export default class XdslAccessListCtrl { } return this.createService(service, this.ELIGIBILITY.not_concerned); }); + return this.$q.all(serviceList); } @@ -74,8 +121,24 @@ export default class XdslAccessListCtrl { `#/pack/${packName}/migration`, ), }; + // Set closure date + newService.closureDate = this.$translate.instant( + 'xdsl_access_list_not_concerned', + ); if (copperGridClosureTrajectory) { newService.copperGridClosureTrajectory = copperGridClosureTrajectory; + if (migrationAvailable) { + if (copperGridClosureTrajectory.technicalClosureDate) { + newService.closureDate = this.$filter('date')( + copperGridClosureTrajectory.technicalClosureDate, + 'shortDate', + ); + } else { + newService.closureDate = this.$translate.instant( + 'xdsl_access_list_not_available', + ); + } + } } return newService; } diff --git a/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.html b/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.html index 020c47c8ca26..d42cb0a55a0e 100644 --- a/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.html +++ b/packages/manager/apps/telecom/src/app/telecom/pack/access-list/xdsl-access-list.html @@ -30,7 +30,7 @@
@@ -65,20 +65,10 @@ - - - - + Ihre letzten Änderungen wurden daher nicht übernommen. Bitte beheben Sie folgende Probleme:", "domain_tab_ZONE_status_warning": "Ihre Zone wurde bereitgestellt. Es wurden jedoch folgende Anomalien festgestellt:", "domain_tab_ZONE_empty_zone": "Es sind keine Einträge in Ihrer DNS-Zone vorhanden.", diff --git a/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_en_GB.json b/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_en_GB.json index fcba1cc0ecc5..a888ce359740 100644 --- a/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_en_GB.json +++ b/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_en_GB.json @@ -214,7 +214,7 @@ "domain_tab_ZONE_no_defaut_dns_used": "You currently use the following DNS servers: ", "domain_tab_ZONE_set_defaut_dns": "Please use the following DNS servers, so that your DNS zone is registered:", "domain_tab_ZONE_title": "Here you can see the configuration of various domain name records. ", - "domain_tab_ZONE_info": "You can also configure these records to connect your domain to your different services (the \"Add a record\" button).", + "domain_tab_ZONE_info": "You can also configure these records to connect your domain to your different services (the “Add an entry” button).", "domain_tab_ZONE_status_error": "Our systems detected errors while checking your zone. For this reason, your most recent modifications were not taken into account. To remedy this, please correct the following problems:", "domain_tab_ZONE_status_warning": "Your zone has been deployed successfully. However, the following anomalies have been detected:", "domain_tab_ZONE_empty_zone": "There are no records in your DNS zone.", diff --git a/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_pl_PL.json b/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_pl_PL.json index 97985cb893ba..6b2eb6946c89 100644 --- a/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_pl_PL.json +++ b/packages/manager/apps/web/client/app/domain/dashboard/translations/Messages_pl_PL.json @@ -214,7 +214,7 @@ "domain_tab_ZONE_no_defaut_dns_used": "Aktualnie korzystasz z następujących serwerów DNS:", "domain_tab_ZONE_set_defaut_dns": "Aby poniższa strefa DNS działała, zmień serwery DNS na:", "domain_tab_ZONE_title": "W tej części możesz sprawdzić konfigurację poszczególnych wpisów dla swojej domeny.", - "domain_tab_ZONE_info": "Możesz również skonfigurować te wpisy i połączyć je z różnymi usługami (przycisk « dodaj wpis »).", + "domain_tab_ZONE_info": "Możesz również skonfigurować te rekordy i połączyć je z różnymi usługami (przycisk „Dodaj rekord”).", "domain_tab_ZONE_status_error": "Nasz system wykrył błędy w trakcie sprawdzania strefy. Twoje ostatnie zmiany nie zostały więc zarejestrowane. Prosimy o poprawienie następujących błędów:", "domain_tab_ZONE_status_warning": "Strefa jest wdrażana. Nasz system wykrył następujące problemy:", "domain_tab_ZONE_empty_zone": "Brak wpisów w strefie DNS.", diff --git a/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.controller.js b/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.controller.js index 50319f496db1..ae2bb62a4ebc 100644 --- a/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.controller.js +++ b/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.controller.js @@ -13,14 +13,15 @@ import maxBy from 'lodash/maxBy'; import reduce from 'lodash/reduce'; import some from 'lodash/some'; +import { DOMAIN_TRACKING } from '../../hosting/hosting.constants'; +import { DOMAINS_BADGES_STATUS } from '../list/list-domain-layout.constants'; import { DNSSEC_STATUS, - PRODUCT_TYPE, - PROTECTION_TYPES, DOMAIN_SERVICE_STATES, DOMAIN_STATE_TYPE, + PRODUCT_TYPE, + PROTECTION_TYPES, } from './general-information.constants'; -import { DOMAIN_TRACKING } from '../../hosting/hosting.constants'; export default class DomainTabGeneralInformationsCtrl { /* @ngInject */ @@ -86,6 +87,7 @@ export default class DomainTabGeneralInformationsCtrl { } $onInit() { + this.DOMAINS_BADGES_STATUS = DOMAINS_BADGES_STATUS; this.domain = this.$scope.ctrlDomain.domain; this.domainInfos = this.$scope.ctrlDomain.domainInfos; this.allDom = this.$scope.ctrlDomain.allDom; diff --git a/packages/manager/apps/web/client/app/domain/general-informations/GENERAL_INFORMATIONS.html b/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.html similarity index 98% rename from packages/manager/apps/web/client/app/domain/general-informations/GENERAL_INFORMATIONS.html rename to packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.html index a99bc272819f..c19e5b4736b0 100644 --- a/packages/manager/apps/web/client/app/domain/general-informations/GENERAL_INFORMATIONS.html +++ b/packages/manager/apps/web/client/app/domain/general-informations/domain-general-informations.html @@ -33,6 +33,19 @@ class="h-100" data-loading="$ctrl.loading.dnsStatus || $ctrl.loading.hosting || $ctrl.loading.associatedHosting" > + + + + {{ ::'domains_status_' + $ctrl.domainInfos.state | + translate }} + + + +

-

-

-
- - - +
+

+

+
+ + + +

diff --git a/packages/manager/apps/web/client/app/hosting/multisite/hosting-multisite.controller.js b/packages/manager/apps/web/client/app/hosting/multisite/hosting-multisite.controller.js index b46daa8399df..1833a6f31963 100644 --- a/packages/manager/apps/web/client/app/hosting/multisite/hosting-multisite.controller.js +++ b/packages/manager/apps/web/client/app/hosting/multisite/hosting-multisite.controller.js @@ -191,6 +191,24 @@ angular ); }; + function isMainDomain(hosting, domain) { + return ['ovh.net', 'hosting.ovh.net'] + .map( + (suffix) => `${hosting.primaryLogin}.${hosting.cluster}.${suffix}`, + ) + .some((mainDomain) => mainDomain === domain.name); + } + + $scope.isUpdateDomainDisabled = function isUpdateDomainDisabled( + hosting, + domain, + ) { + return ( + domain.status === HOSTING_STATUS.UPDATING || + isMainDomain(hosting, domain) + ); + }; + $scope.loadDomains = function loadDomains(count, offset) { $scope.loading.domains = true; diff --git a/packages/manager/apps/zimbra/package.json b/packages/manager/apps/zimbra/package.json index 954421cc130f..5983297c6013 100644 --- a/packages/manager/apps/zimbra/package.json +++ b/packages/manager/apps/zimbra/package.json @@ -10,15 +10,15 @@ }, "license": "BSD-3-Clause", "author": "OVH SAS", + "type": "module", "scripts": { "build": "tsc && vite build", "dev": "tsc && vite", "start": "lerna exec --stream --scope='@ovh-ux/manager-zimbra-app' --include-dependencies -- npm run build --if-present", "start:dev": "lerna exec --stream --scope='@ovh-ux/manager-zimbra-app' --include-dependencies -- npm run dev --if-present", "start:watch": "lerna exec --stream --parallel --scope='@ovh-ux/manager-zimbra-app' --include-dependencies -- npm run dev:watch --if-present", - "test:e2e": "tsc && npx playwright test --headed", - "test:e2e:cii": "tsc && npx playwright test", - "test:e2e:script": "tsc && node ../../../../scripts/run-playwright.js" + "test": "vitest run", + "test:coverage": "vitest run --coverage" }, "dependencies": { "@ovh-ux/manager-config": "^7.3.3", @@ -27,7 +27,7 @@ "@ovh-ux/manager-react-components": "^1.26.0", "@ovh-ux/manager-react-core-application": "^0.10.0", "@ovh-ux/manager-react-shell-client": "^0.7.0", - "@ovh-ux/manager-tailwind-config": "*", + "@ovh-ux/manager-tailwind-config": "^0.2.0", "@ovh-ux/request-tagger": "^0.3.0", "@ovh-ux/shell": "^3.7.0", "@ovhcloud/ods-common-core": "17.2.2", @@ -36,6 +36,7 @@ "@ovhcloud/ods-theme-blue-jeans": "17.2.2", "@tanstack/react-query": "^5.51.21", "@tanstack/react-table": "^8.20.1", + "element-internals-polyfill": "^1.3.10", "i18next": "^23.8.2", "i18next-http-backend": "2.5.0", "react": "^18.2.0", @@ -46,9 +47,19 @@ }, "devDependencies": { "@ovh-ux/manager-vite-config": "^0.8.0", - "@playwright/test": "^1.34.3", "@tanstack/react-query-devtools": "^5.51.21", - "vite": "^5.2.13" + "@testing-library/dom": "^10.1.0", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.5.2", + "@types/jest": "^29.5.12", + "@types/react": "^18.2.55", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4.2.1", + "@vitest/coverage-v8": "^1.6.0", + "typescript": "^4.3.2", + "vite": "^5.2.13", + "vitest": "^2.0.5" }, "regions": [ "CA", diff --git a/packages/manager/apps/zimbra/playwright.config.ts b/packages/manager/apps/zimbra/playwright.config.ts deleted file mode 100644 index 4a033cc8d87d..000000000000 --- a/packages/manager/apps/zimbra/playwright.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@playwright/test'; - -export default defineConfig({ - workers: 3, - fullyParallel: false, - timeout: 30 * 1000, - reporter: [['html', { open: 'on-failure' }]], - expect: { - timeout: 20000, - }, - use: { - // Collect trace when retrying the failed test. - trace: 'retain-on-failure', - }, -}); diff --git a/packages/manager/apps/zimbra/postcss.config.js b/packages/manager/apps/zimbra/postcss.config.cjs similarity index 100% rename from packages/manager/apps/zimbra/postcss.config.js rename to packages/manager/apps/zimbra/postcss.config.cjs diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_en_GB.json new file mode 100644 index 000000000000..6887c288fe7d --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_en_GB.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Email accounts", + "zimbra_account_datagrid_organization_label": "Organisation", + "zimbra_account_datagrid_offer_label": "Service plan", + "zimbra_account_datagrid_webmail_label": "Webmail:", + "zimbra_account_datagrid_quota": "Size", + "zimbra_account_datagrid_quota_octets": "Bytes", + "zimbra_account_datagrid_quota_ko": "KB", + "zimbra_account_datagrid_quota_mo": "MB", + "zimbra_account_datagrid_quota_go": "GB", + "zimbra_account_datagrid_quota_to": "TB", + "zimbra_account_datagrid_tooltip_modification": "Edit", + "zimbra_account_datagrid_tooltip_delete": "Delete", + "zimbra_account_account_add": "Create an account" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_es_ES.json new file mode 100644 index 000000000000..0ce85a810e52 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_es_ES.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Cuentas de correo", + "zimbra_account_datagrid_organization_label": "Organización", + "zimbra_account_datagrid_offer_label": "Plan", + "zimbra_account_datagrid_webmail_label": "Webmail:", + "zimbra_account_datagrid_quota": "Tamaño", + "zimbra_account_datagrid_quota_octets": "Bytes", + "zimbra_account_datagrid_quota_ko": "KB", + "zimbra_account_datagrid_quota_mo": "MB", + "zimbra_account_datagrid_quota_go": "GB", + "zimbra_account_datagrid_quota_to": "TB", + "zimbra_account_datagrid_tooltip_modification": "Modificar", + "zimbra_account_datagrid_tooltip_delete": "Eliminar", + "zimbra_account_account_add": "Crear una cuenta" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_CA.json new file mode 100644 index 000000000000..1431ec2a7b32 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_CA.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Comptes email", + "zimbra_account_datagrid_organization_label": "Organisation", + "zimbra_account_datagrid_offer_label": "Offre", + "zimbra_account_datagrid_webmail_label": "Webmail :", + "zimbra_account_datagrid_quota": "Taille", + "zimbra_account_datagrid_quota_octets": "Octets", + "zimbra_account_datagrid_quota_ko": "Ko", + "zimbra_account_datagrid_quota_mo": "Mo", + "zimbra_account_datagrid_quota_go": "Go", + "zimbra_account_datagrid_quota_to": "To", + "zimbra_account_datagrid_tooltip_modification": "Modifier", + "zimbra_account_datagrid_tooltip_delete": "Supprimer", + "zimbra_account_account_add": "Créer un compte" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_FR.json new file mode 100644 index 000000000000..1431ec2a7b32 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_fr_FR.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Comptes email", + "zimbra_account_datagrid_organization_label": "Organisation", + "zimbra_account_datagrid_offer_label": "Offre", + "zimbra_account_datagrid_webmail_label": "Webmail :", + "zimbra_account_datagrid_quota": "Taille", + "zimbra_account_datagrid_quota_octets": "Octets", + "zimbra_account_datagrid_quota_ko": "Ko", + "zimbra_account_datagrid_quota_mo": "Mo", + "zimbra_account_datagrid_quota_go": "Go", + "zimbra_account_datagrid_quota_to": "To", + "zimbra_account_datagrid_tooltip_modification": "Modifier", + "zimbra_account_datagrid_tooltip_delete": "Supprimer", + "zimbra_account_account_add": "Créer un compte" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_it_IT.json new file mode 100644 index 000000000000..6157adc5359e --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_it_IT.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Account email", + "zimbra_account_datagrid_organization_label": "Organizzazione", + "zimbra_account_datagrid_offer_label": "Piano", + "zimbra_account_datagrid_webmail_label": "Webmail:", + "zimbra_account_datagrid_quota": "Taglia", + "zimbra_account_datagrid_quota_octets": "byte", + "zimbra_account_datagrid_quota_ko": "KB", + "zimbra_account_datagrid_quota_mo": "MB", + "zimbra_account_datagrid_quota_go": "GB", + "zimbra_account_datagrid_quota_to": "TB", + "zimbra_account_datagrid_tooltip_modification": "Modificare", + "zimbra_account_datagrid_tooltip_delete": "Eliminare", + "zimbra_account_account_add": "Crea un account" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_pl_PL.json new file mode 100644 index 000000000000..ee25455bb6b7 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_pl_PL.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Konta e-mail", + "zimbra_account_datagrid_organization_label": "Organizacja", + "zimbra_account_datagrid_offer_label": "Pakiet", + "zimbra_account_datagrid_webmail_label": "Webmail - dostęp do poczty przez przeglądarkę:", + "zimbra_account_datagrid_quota": "Rozmiar", + "zimbra_account_datagrid_quota_octets": "Bajty", + "zimbra_account_datagrid_quota_ko": "KB", + "zimbra_account_datagrid_quota_mo": "MB", + "zimbra_account_datagrid_quota_go": "GB", + "zimbra_account_datagrid_quota_to": "TB", + "zimbra_account_datagrid_tooltip_modification": "Edytuj", + "zimbra_account_datagrid_tooltip_delete": "Usuń", + "zimbra_account_account_add": "Załóż konto" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/accounts/Messages_pt_PT.json new file mode 100644 index 000000000000..4655b53c544a --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/Messages_pt_PT.json @@ -0,0 +1,15 @@ +{ + "zimbra_account_datagrid_email_label": "Contas de email", + "zimbra_account_datagrid_organization_label": "Organização", + "zimbra_account_datagrid_offer_label": "Plano", + "zimbra_account_datagrid_webmail_label": "Webmail:", + "zimbra_account_datagrid_quota": "Dimensão", + "zimbra_account_datagrid_quota_octets": "Bytes", + "zimbra_account_datagrid_quota_ko": "KB", + "zimbra_account_datagrid_quota_mo": "MB", + "zimbra_account_datagrid_quota_go": "GB", + "zimbra_account_datagrid_quota_to": "TB", + "zimbra_account_datagrid_tooltip_modification": "Alterar", + "zimbra_account_datagrid_tooltip_delete": "Eliminar", + "zimbra_account_account_add": "Criar uma conta" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_en_GB.json new file mode 100644 index 000000000000..0dcdea1c1667 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_en_GB.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Back to my email accounts", + "zimbra_account_add_title": "Create an email account", + "zimbra_account_edit_title": "Edit the {{ account }} account", + "zimbra_account_add_input_email_label": "Email account", + "zimbra_account_add_input_email_placeholder": "Account Name", + "zimbra_account_add_input_email_helper": "The text preceding the ‘@’ in your email address must meet the following criteria:", + "zimbra_account_add_input_email_helper_rule_1": "It must end with a letter or number", + "zimbra_account_add_input_email_helper_rule_2": "Authorised special characters are ‘.’, ‘+’, ‘-’ and ‘_’", + "zimbra_account_add_input_email_helper_rule_3": "Special characters cannot be placed next to each other", + "zimbra_account_add_select_domain_placeholder": "Select a domain name", + "zimbra_account_add_message_organization": "Your account will be part of the organisation {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Name", + "zimbra_account_add_input_lastName_placeholder": "Name", + "zimbra_account_add_input_firstName_label": "First name", + "zimbra_account_add_input_firstName_placeholder": "First name", + "zimbra_account_add_input_displayName_label": "Full name", + "zimbra_account_add_input_displayName_placeholder": "Full name", + "zimbra_account_add_input_initials_label": "Initials", + "zimbra_account_add_input_initials_placeholder": "Initials", + "zimbra_account_add_input_description_label": "Description", + "zimbra_account_add_input_description_placeholder": "Description", + "zimbra_account_add_input_password_label": "Password", + "zimbra_account_add_input_password_helper": "Your password must contain:", + "zimbra_account_add_input_password_helper_rule_1": "At least 9 characters", + "zimbra_account_add_input_password_helper_rule_2": "A number", + "zimbra_account_add_input_password_helper_rule_3": "Special character (€, !, &)", + "zimbra_account_add_input_mandatory": "Fields marked with an asterisk (*) are mandatory", + "zimbra_account_add_button_save": "Save", + "zimbra_account_add_button_cancel": "Cancel", + "zimbra_account_add_button_confirm": "Confirm", + "zimbra_account_add_success_message": "Your email account creation request has been submitted. It will be processed in a few moments.", + "zimbra_account_add_error_message": "Unable to submit your email account creation request. {{ error }}", + "zimbra_account_edit_success_message": "Your request to edit your email account has been submitted. It will be processed in a few moments.", + "zimbra_account_edit_error_message": "Unable to submit the request to edit your email account. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_es_ES.json new file mode 100644 index 000000000000..59812e310292 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_es_ES.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Volver a mis cuentas de correo", + "zimbra_account_add_title": "Crear una cuenta de correo", + "zimbra_account_edit_title": "Modificar la cuenta {{ account }}", + "zimbra_account_add_input_email_label": "Cuenta de correo", + "zimbra_account_add_input_email_placeholder": "Nombre de la cuenta", + "zimbra_account_add_input_email_helper": "La parte local de su dirección de correo (el texto que sigue a «@») debe cumplir los siguientes requisitos:", + "zimbra_account_add_input_email_helper_rule_1": "debe terminar por una letra o un número;", + "zimbra_account_add_input_email_helper_rule_2": "los caracteres especiales autorizados son los siguientes: «.», «+», «-» y «_»;", + "zimbra_account_add_input_email_helper_rule_3": "los caracteres especiales no pueden ir seguidos.", + "zimbra_account_add_select_domain_placeholder": "Seleccionar un dominio", + "zimbra_account_add_message_organization": "Su cuenta formará parte de la organización {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Apellido", + "zimbra_account_add_input_lastName_placeholder": "Apellido", + "zimbra_account_add_input_firstName_label": "Nombre", + "zimbra_account_add_input_firstName_placeholder": "Nombre", + "zimbra_account_add_input_displayName_label": "Nombre completo", + "zimbra_account_add_input_displayName_placeholder": "Nombre completo", + "zimbra_account_add_input_initials_label": "Iniciales", + "zimbra_account_add_input_initials_placeholder": "Iniciales", + "zimbra_account_add_input_description_label": "Descripción", + "zimbra_account_add_input_description_placeholder": "Descripción", + "zimbra_account_add_input_password_label": "Contraseña", + "zimbra_account_add_input_password_helper": "Su contraseña debe contener:", + "zimbra_account_add_input_password_helper_rule_1": "Un mínimo de 9 caracteres", + "zimbra_account_add_input_password_helper_rule_2": "Un número", + "zimbra_account_add_input_password_helper_rule_3": "Carácter especial (€, !, &...)", + "zimbra_account_add_input_mandatory": "Los campos marcados con un asterisco (*) son obligatorios.", + "zimbra_account_add_button_save": "Guardar", + "zimbra_account_add_button_cancel": "Cancelar", + "zimbra_account_add_button_confirm": "Confirmar", + "zimbra_account_add_success_message": "La solicitud de creación de la cuenta de correo se ha enviado. Será tratada en unos instantes.", + "zimbra_account_add_error_message": "Se ha producido un error al enviar la solicitud de creación de cuenta de correo: {{ error }}", + "zimbra_account_edit_success_message": "La solicitud de modificación de la cuenta de correo se ha enviado. Será tratada en unos instantes.", + "zimbra_account_edit_error_message": "Se ha producido un error al enviar la solicitud de modificación de cuenta de correo: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_CA.json new file mode 100644 index 000000000000..a2dc22c206f4 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_CA.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Retour vers mes comptes emails", + "zimbra_account_add_title": "Créer un compte email", + "zimbra_account_edit_title": "Modifier le compte {{ account }}", + "zimbra_account_add_input_email_label": "Compte email", + "zimbra_account_add_input_email_placeholder": "Nom du compte", + "zimbra_account_add_input_email_helper": "La partie locale de votre adresse mail (le texte précédant le « @ ») doit suivre les lignes directrices suivantes :", + "zimbra_account_add_input_email_helper_rule_1": "Elle doit se terminer par une lettre ou un numéro", + "zimbra_account_add_input_email_helper_rule_2": "Les caractères spéciaux autorisés sont \".\", \"+\", \"-\" et \"_\"", + "zimbra_account_add_input_email_helper_rule_3": "Les caractères spéciaux ne peuvent pas être placés côte à côte", + "zimbra_account_add_select_domain_placeholder": "Sélectionner un nom de domaine", + "zimbra_account_add_message_organization": "Votre compte fera partie de l'organisation {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Nom", + "zimbra_account_add_input_lastName_placeholder": "Nom", + "zimbra_account_add_input_firstName_label": "Prénom", + "zimbra_account_add_input_firstName_placeholder": "Prénom", + "zimbra_account_add_input_displayName_label": "Nom complet", + "zimbra_account_add_input_displayName_placeholder": "Nom complet", + "zimbra_account_add_input_initials_label": "Initiales", + "zimbra_account_add_input_initials_placeholder": "Initiales", + "zimbra_account_add_input_description_label": "Description", + "zimbra_account_add_input_description_placeholder": "Description", + "zimbra_account_add_input_password_label": "Mot de passe", + "zimbra_account_add_input_password_helper": "Votre mot de passe doit contenir :", + "zimbra_account_add_input_password_helper_rule_1": "Au moins 9 caractères", + "zimbra_account_add_input_password_helper_rule_2": "Un nombre", + "zimbra_account_add_input_password_helper_rule_3": "Caractère particulier (€, !, &,…)", + "zimbra_account_add_input_mandatory": "Les champs mentionnés avec un astérisque * sont obligatoires", + "zimbra_account_add_button_save": "Enregistrer", + "zimbra_account_add_button_cancel": "Annuler", + "zimbra_account_add_button_confirm": "Confirmer", + "zimbra_account_add_success_message": "Votre demande de création de compte email a bien été prise en compte. Elle sera traitée d'ici quelques instants.", + "zimbra_account_add_error_message": "Votre demande de création d'email de compte n'a pas pu aboutir. {{ error }}", + "zimbra_account_edit_success_message": "Votre demande de modification de compte email a bien été prise en compte. Elle sera traitée d'ici quelques instants.", + "zimbra_account_edit_error_message": "Votre demande de modification d'email de compte n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_FR.json new file mode 100644 index 000000000000..a2dc22c206f4 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_fr_FR.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Retour vers mes comptes emails", + "zimbra_account_add_title": "Créer un compte email", + "zimbra_account_edit_title": "Modifier le compte {{ account }}", + "zimbra_account_add_input_email_label": "Compte email", + "zimbra_account_add_input_email_placeholder": "Nom du compte", + "zimbra_account_add_input_email_helper": "La partie locale de votre adresse mail (le texte précédant le « @ ») doit suivre les lignes directrices suivantes :", + "zimbra_account_add_input_email_helper_rule_1": "Elle doit se terminer par une lettre ou un numéro", + "zimbra_account_add_input_email_helper_rule_2": "Les caractères spéciaux autorisés sont \".\", \"+\", \"-\" et \"_\"", + "zimbra_account_add_input_email_helper_rule_3": "Les caractères spéciaux ne peuvent pas être placés côte à côte", + "zimbra_account_add_select_domain_placeholder": "Sélectionner un nom de domaine", + "zimbra_account_add_message_organization": "Votre compte fera partie de l'organisation {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Nom", + "zimbra_account_add_input_lastName_placeholder": "Nom", + "zimbra_account_add_input_firstName_label": "Prénom", + "zimbra_account_add_input_firstName_placeholder": "Prénom", + "zimbra_account_add_input_displayName_label": "Nom complet", + "zimbra_account_add_input_displayName_placeholder": "Nom complet", + "zimbra_account_add_input_initials_label": "Initiales", + "zimbra_account_add_input_initials_placeholder": "Initiales", + "zimbra_account_add_input_description_label": "Description", + "zimbra_account_add_input_description_placeholder": "Description", + "zimbra_account_add_input_password_label": "Mot de passe", + "zimbra_account_add_input_password_helper": "Votre mot de passe doit contenir :", + "zimbra_account_add_input_password_helper_rule_1": "Au moins 9 caractères", + "zimbra_account_add_input_password_helper_rule_2": "Un nombre", + "zimbra_account_add_input_password_helper_rule_3": "Caractère particulier (€, !, &,…)", + "zimbra_account_add_input_mandatory": "Les champs mentionnés avec un astérisque * sont obligatoires", + "zimbra_account_add_button_save": "Enregistrer", + "zimbra_account_add_button_cancel": "Annuler", + "zimbra_account_add_button_confirm": "Confirmer", + "zimbra_account_add_success_message": "Votre demande de création de compte email a bien été prise en compte. Elle sera traitée d'ici quelques instants.", + "zimbra_account_add_error_message": "Votre demande de création d'email de compte n'a pas pu aboutir. {{ error }}", + "zimbra_account_edit_success_message": "Votre demande de modification de compte email a bien été prise en compte. Elle sera traitée d'ici quelques instants.", + "zimbra_account_edit_error_message": "Votre demande de modification d'email de compte n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_it_IT.json new file mode 100644 index 000000000000..0110143a57fd --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_it_IT.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Tornare ai miei account email", + "zimbra_account_add_title": "Creare un account email", + "zimbra_account_edit_title": "Modificare l'account {{ account }}", + "zimbra_account_add_input_email_label": "Account email", + "zimbra_account_add_input_email_placeholder": "Nome account", + "zimbra_account_add_input_email_helper": "La parte locale del tuo indirizzo email (il testo che precede \"@\") deve rispettare i seguenti requisiti:", + "zimbra_account_add_input_email_helper_rule_1": "deve terminare con una lettera o un numero", + "zimbra_account_add_input_email_helper_rule_2": "i caratteri speciali autorizzati sono \".\", \"+\", \"-\" e \"_\"", + "zimbra_account_add_input_email_helper_rule_3": "i caratteri speciali non possono susseguirsi l’uno all’altro", + "zimbra_account_add_select_domain_placeholder": "Selezionare un dominio", + "zimbra_account_add_message_organization": "Il tuo account farà parte dell'organizzazione {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Cognome", + "zimbra_account_add_input_lastName_placeholder": "Cognome", + "zimbra_account_add_input_firstName_label": "Nome", + "zimbra_account_add_input_firstName_placeholder": "Nome", + "zimbra_account_add_input_displayName_label": "Nome completo", + "zimbra_account_add_input_displayName_placeholder": "Nome completo", + "zimbra_account_add_input_initials_label": "Iniziali", + "zimbra_account_add_input_initials_placeholder": "Iniziali", + "zimbra_account_add_input_description_label": "Descrizione", + "zimbra_account_add_input_description_placeholder": "Descrizione", + "zimbra_account_add_input_password_label": "Password", + "zimbra_account_add_input_password_helper": "La tua password deve contenere:", + "zimbra_account_add_input_password_helper_rule_1": "almeno 9 caratteri", + "zimbra_account_add_input_password_helper_rule_2": "un numero", + "zimbra_account_add_input_password_helper_rule_3": "carattere speciale (€, !, &...)", + "zimbra_account_add_input_mandatory": "I campi contrassegnati con un asterisco * sono obbligatori", + "zimbra_account_add_button_save": "Registra", + "zimbra_account_add_button_cancel": "Annullare", + "zimbra_account_add_button_confirm": "Confermare", + "zimbra_account_add_success_message": "La tua richiesta di creazione dell’account email è stata presa in carico. Sarà elaborata entro pochi minuti.", + "zimbra_account_add_error_message": "La tua richiesta di creazione dell'account email non è andata a buon fine: {{ error }}", + "zimbra_account_edit_success_message": "La tua richiesta di modifica dell'account email è stata presa in carico. Sarà elaborata entro pochi minuti.", + "zimbra_account_edit_error_message": "La tua richiesta di modifica dell'account email non è andata a buon fine: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pl_PL.json new file mode 100644 index 000000000000..7cecda95a575 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pl_PL.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Powrót do kont e-mail", + "zimbra_account_add_title": "Załóż konto e-mail", + "zimbra_account_edit_title": "Zmodyfikuj konto {{account}}", + "zimbra_account_add_input_email_label": "Konto e-mail", + "zimbra_account_add_input_email_placeholder": "Nazwa konta", + "zimbra_account_add_input_email_helper": "Pierwsza część adresu e-mail (tekst przed „@”) musi być utworzona zgodnie z następującymi wytycznymi:", + "zimbra_account_add_input_email_helper_rule_1": "Musi kończyć się literą lub cyfrą", + "zimbra_account_add_input_email_helper_rule_2": "Dozwolone są następujące znaki specjalne: \".\", \"+\", \"-\" i \"_\"", + "zimbra_account_add_input_email_helper_rule_3": "Znaki specjalne nie mogą być umieszczone obok siebie.", + "zimbra_account_add_select_domain_placeholder": "Wybierz nazwę domeny", + "zimbra_account_add_message_organization": "Twoje konto będzie częścią organizacji {{organizationLabel}}", + "zimbra_account_add_input_lastName_label": "Nazwisko", + "zimbra_account_add_input_lastName_placeholder": "Nazwisko", + "zimbra_account_add_input_firstName_label": "Imię", + "zimbra_account_add_input_firstName_placeholder": "Imię", + "zimbra_account_add_input_displayName_label": "Pełna nazwa", + "zimbra_account_add_input_displayName_placeholder": "Pełna nazwa", + "zimbra_account_add_input_initials_label": "Inicjały", + "zimbra_account_add_input_initials_placeholder": "Inicjały", + "zimbra_account_add_input_description_label": "Opis", + "zimbra_account_add_input_description_placeholder": "Opis", + "zimbra_account_add_input_password_label": "Hasło", + "zimbra_account_add_input_password_helper": "Twoje hasło musi zawierać:", + "zimbra_account_add_input_password_helper_rule_1": "minimum 9 znaków", + "zimbra_account_add_input_password_helper_rule_2": "Cyfra", + "zimbra_account_add_input_password_helper_rule_3": "Znak specjalny (€, !, &,...)", + "zimbra_account_add_input_mandatory": "Pola oznaczone gwiazdką * są obowiązkowe", + "zimbra_account_add_button_save": "Zapisz", + "zimbra_account_add_button_cancel": "Anuluj", + "zimbra_account_add_button_confirm": "Zatwierdź", + "zimbra_account_add_success_message": "Dyspozycja utworzenia konta e-mail została przyjęta. Zostanie przetworzona w ciągu kilku minut.", + "zimbra_account_add_error_message": "Utworzenie konta e-mail nie powiodło się. {{error}}", + "zimbra_account_edit_success_message": "Dyspozycja modyfikacji konta e-mail została przyjęta. Zostanie przetworzona w ciągu kilku minut.", + "zimbra_account_edit_error_message": "Modyfikacja konta e-mail nie powiodła się. {{error}}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pt_PT.json new file mode 100644 index 000000000000..3c9c62cc16d8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/addAndEdit/Messages_pt_PT.json @@ -0,0 +1,36 @@ +{ + "zimbra_account_add_cta_back": "Voltar para as minhas contas de e-mail", + "zimbra_account_add_title": "Criar uma conta de e-mail", + "zimbra_account_edit_title": "Modificar a conta {{ account }}", + "zimbra_account_add_input_email_label": "Conta de e-mail", + "zimbra_account_add_input_email_placeholder": "Nome da conta", + "zimbra_account_add_input_email_helper": "A parte local do seu endereço de e-mail (o texto que precede o «@») deve seguir as seguintes diretrizes:", + "zimbra_account_add_input_email_helper_rule_1": "Deve terminar por uma letra ou um algarismo", + "zimbra_account_add_input_email_helper_rule_2": "Os caracteres especiais autorizados são «.», «+», «-» e «_»", + "zimbra_account_add_input_email_helper_rule_3": "Os caracteres especiais não podem seguir-se", + "zimbra_account_add_select_domain_placeholder": "Escolher um nome de domínio", + "zimbra_account_add_message_organization": "A sua conta fará parte da organização {{ organizationLabel }}", + "zimbra_account_add_input_lastName_label": "Nome", + "zimbra_account_add_input_lastName_placeholder": "Nome", + "zimbra_account_add_input_firstName_label": "Nome", + "zimbra_account_add_input_firstName_placeholder": "Nome", + "zimbra_account_add_input_displayName_label": "Nome completo", + "zimbra_account_add_input_displayName_placeholder": "Nome completo", + "zimbra_account_add_input_initials_label": "Iniciais", + "zimbra_account_add_input_initials_placeholder": "Iniciais", + "zimbra_account_add_input_description_label": "Descrição", + "zimbra_account_add_input_description_placeholder": "Descrição", + "zimbra_account_add_input_password_label": "Palavra-passe", + "zimbra_account_add_input_password_helper": "A sua palavra-passe deve conter:", + "zimbra_account_add_input_password_helper_rule_1": "No mínimo 9 caracteres", + "zimbra_account_add_input_password_helper_rule_2": "Um algarismo", + "zimbra_account_add_input_password_helper_rule_3": "Um caráter especial (€, !, &, ...)", + "zimbra_account_add_input_mandatory": "Os campos marcados com um asterisco são de preenchimento obrigatório", + "zimbra_account_add_button_save": "Guardar ", + "zimbra_account_add_button_cancel": "Anular", + "zimbra_account_add_button_confirm": "Confirmar", + "zimbra_account_add_success_message": "O seu pedido de criação de uma conta de e-mail foi registado. Será tratado dentro de alguns instantes.", + "zimbra_account_add_error_message": "O seu pedido de criação de uma conta de e-mail não foi bem-sucedido. {{ error }}", + "zimbra_account_edit_success_message": "O seu pedido de alteração de uma conta de e-mail foi registado. Será tratado dentro de alguns instantes.", + "zimbra_account_edit_error_message": "O seu pedido de alteração de uma conta de e-mail não foi bem-sucedido. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_en_GB.json new file mode 100644 index 000000000000..33d437495abb --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_en_GB.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Delete mailbox", + "zimbra_account_delete_modal_content_step1": "You are about to delete the mailbox from the Zimbra server.", + "zimbra_account_delete_modal_mail_label": "Mailbox:", + "zimbra_account_delete_modal_content_step2": "Are you sure you want to delete the mailbox from the Zimbra server?", + "zimbra_account_delete_modal_warn_message": "Warning: this action is irreversible and will erase the data.", + "zimbra_account_delete_button_delete": "Delete", + "zimbra_account_delete_button_cancel": "Cancel", + "zimbra_account_delete_success_message": "Your deletion request has been submitted.", + "zimbra_account_delete_error_message": "Unable to submit your deletion request. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_es_ES.json new file mode 100644 index 000000000000..b2233a48cf8c --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_es_ES.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Eliminar la cuenta de correo", + "zimbra_account_delete_modal_content_step1": "Va a eliminar la cuenta de correo del servidor Zimbra.", + "zimbra_account_delete_modal_mail_label": "Cuenta de correo:", + "zimbra_account_delete_modal_content_step2": "¿Seguro que quiere eliminar la cuenta de correo del servidor Zimbra?", + "zimbra_account_delete_modal_warn_message": "Atención: Esta acción es irreversible y conlleva la eliminación de los datos.", + "zimbra_account_delete_button_delete": "Eliminar", + "zimbra_account_delete_button_cancel": "Cancelar", + "zimbra_account_delete_success_message": "La solicitud de eliminación se ha enviado.", + "zimbra_account_delete_error_message": "Se ha producido un error al enviar la solicitud de eliminación: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_CA.json new file mode 100644 index 000000000000..6b84242d9da5 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_CA.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Supprimer la boite mail", + "zimbra_account_delete_modal_content_step1": "Vous êtes sur le point de supprimer la boîte mail du serveur Zimbra.", + "zimbra_account_delete_modal_mail_label": "Boîte mail :", + "zimbra_account_delete_modal_content_step2": "Êtes-vous sûr de vouloir supprimer la boite mail du serveur Zimbra ?", + "zimbra_account_delete_modal_warn_message": "Attention cette action est irréversible et entraîne la suppression des données.", + "zimbra_account_delete_button_delete": "Supprimer", + "zimbra_account_delete_button_cancel": "Annuler", + "zimbra_account_delete_success_message": "Votre demande de suppression a bien été prise en compte.", + "zimbra_account_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_FR.json new file mode 100644 index 000000000000..6b84242d9da5 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_fr_FR.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Supprimer la boite mail", + "zimbra_account_delete_modal_content_step1": "Vous êtes sur le point de supprimer la boîte mail du serveur Zimbra.", + "zimbra_account_delete_modal_mail_label": "Boîte mail :", + "zimbra_account_delete_modal_content_step2": "Êtes-vous sûr de vouloir supprimer la boite mail du serveur Zimbra ?", + "zimbra_account_delete_modal_warn_message": "Attention cette action est irréversible et entraîne la suppression des données.", + "zimbra_account_delete_button_delete": "Supprimer", + "zimbra_account_delete_button_cancel": "Annuler", + "zimbra_account_delete_success_message": "Votre demande de suppression a bien été prise en compte.", + "zimbra_account_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_it_IT.json new file mode 100644 index 000000000000..84a94d30504e --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_it_IT.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Eliminare la casella email", + "zimbra_account_delete_modal_content_step1": "Stai per eliminare la casella email del server Zimbra.", + "zimbra_account_delete_modal_mail_label": "Casella email:", + "zimbra_account_delete_modal_content_step2": "Vuoi davvero eliminare la casella email del server Zimbra?", + "zimbra_account_delete_modal_warn_message": "Attenzione: questa azione è irreversibile e comporta la cancellazione dei dati.", + "zimbra_account_delete_button_delete": "Eliminare", + "zimbra_account_delete_button_cancel": "Annullare", + "zimbra_account_delete_success_message": "La richiesta di eliminazione è stata presa in carico correttamente", + "zimbra_account_delete_error_message": "La tua richiesta di eliminazione non è andata a buon fine. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pl_PL.json new file mode 100644 index 000000000000..e156f2e7751f --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pl_PL.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Usuń skrzynkę e-mail", + "zimbra_account_delete_modal_content_step1": "Chcesz usunąć skrzynkę e-mail z serwera Zimbra.", + "zimbra_account_delete_modal_mail_label": "Skrzynka e-mail:", + "zimbra_account_delete_modal_content_step2": "Czy chcesz usunąć skrzynkę e-mail z serwera Zimbra?", + "zimbra_account_delete_modal_warn_message": "Uwaga: operacja ta jest nieodwracalna i skutkuje usunięciem danych.", + "zimbra_account_delete_button_delete": "Usuń", + "zimbra_account_delete_button_cancel": "Anuluj", + "zimbra_account_delete_success_message": "Dyspozycja usunięcia została przyjęta.", + "zimbra_account_delete_error_message": "Usunięcie nie powiodło się. {{error}}" +} diff --git a/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pt_PT.json new file mode 100644 index 000000000000..28990b3e30d7 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/accounts/delete/Messages_pt_PT.json @@ -0,0 +1,11 @@ +{ + "zimbra_account_delete_modal_title": "Eliminar a caixa de e-mail", + "zimbra_account_delete_modal_content_step1": "Está prestes a eliminar a caixa de email do servidor Zimbra.", + "zimbra_account_delete_modal_mail_label": "Caixa de email:", + "zimbra_account_delete_modal_content_step2": "Quer mesmo eliminar a caixa de email do servidor Zimbra?", + "zimbra_account_delete_modal_warn_message": "Atenção: esta ação é irreversível e implica a eliminação dos dados.", + "zimbra_account_delete_button_delete": "Eliminar", + "zimbra_account_delete_button_cancel": "Anular", + "zimbra_account_delete_success_message": "O pedido de eliminação foi registado.", + "zimbra_account_delete_error_message": "O seu pedido de eliminação não foi bem-sucedido. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_en_GB.json index 3cbf8b1ff9ec..844b6228d52f 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_en_GB.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_en_GB.json @@ -6,5 +6,33 @@ "general_informations": "General information", "organizations": "Organisation", "domains": "Domain", - "email_accounts": "Email accounts" + "email_accounts": "Email accounts", + "zimbra_dashboard_administrator_guide": "Administrator Guide", + "zimbra_dashboard_domains": "Domain", + "zimbra_dashboard_domains_add": "Add a domain", + "zimbra_dashboard_domains_delete": "Delete a domain", + "zimbra_dashboard_email_accounts": "Email accounts", + "zimbra_dashboard_email_accounts_add": "Create an email account", + "zimbra_dashboard_email_accounts_edit": "Edit account", + "zimbra_dashboard_email_accounts_delete": "Delete mailbox", + "zimbra_dashboard_error_service": "No service", + "zimbra_dashboard_general_informations": "General information", + "zimbra_dashboard_header_guides": "Guides", + "zimbra_dashboard_organizations": "Organisation", + "zimbra_dashboard_organizations_add": "Add an organisation", + "zimbra_dashboard_organizations_edit": "Edit organisation", + "zimbra_dashboard_organizations_delete": "Delete organisation", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Useful links", + "zimbra_dashboard_user_guides": "User guide", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Status", + "zimbra_dashboard_tile_status_serviceStatus": "Service status", + "zimbra_dashboard_tile_status_ongoingTask": "Ongoing tasks", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "See more", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "See less", + "zimbra_dashboard_tile_serviceConsumption_title": "Statistics", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Account per solution", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "You currently do not have any mailboxes.", + "zimbra_dashboard_tile_usefulLinks_title": "Useful links" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_es_ES.json index 271270197736..f763de8b3b96 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_es_ES.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_es_ES.json @@ -6,5 +6,33 @@ "general_informations": "Información general", "organizations": "Organización", "domains": "Dominio", - "email_accounts": "Cuentas de correo" + "email_accounts": "Cuentas de correo", + "zimbra_dashboard_administrator_guide": "Guía de administrador", + "zimbra_dashboard_domains": "Dominio", + "zimbra_dashboard_domains_add": "Añadir un dominio", + "zimbra_dashboard_domains_delete": "Eliminar un dominio", + "zimbra_dashboard_email_accounts": "Cuentas de correo", + "zimbra_dashboard_email_accounts_add": "Crear una cuenta de correo", + "zimbra_dashboard_email_accounts_edit": "Editar la cuenta", + "zimbra_dashboard_email_accounts_delete": "Eliminar la cuenta de correo", + "zimbra_dashboard_error_service": "No hay información sobre el servicio", + "zimbra_dashboard_general_informations": "Información general", + "zimbra_dashboard_header_guides": "Guías", + "zimbra_dashboard_organizations": "Organización", + "zimbra_dashboard_organizations_add": "Añadir una organización", + "zimbra_dashboard_organizations_edit": "Modificar la organización", + "zimbra_dashboard_organizations_delete": "Eliminar la organización", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Enlaces útiles", + "zimbra_dashboard_user_guides": "Guía de usuario", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Estado", + "zimbra_dashboard_tile_status_serviceStatus": "Estado del servicio", + "zimbra_dashboard_tile_status_ongoingTask": "Tareas en curso", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Ver más", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Ver menos", + "zimbra_dashboard_tile_serviceConsumption_title": "Estadísticas", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Cuenta por servicio", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Actualmente no tiene ninguna cuenta de correo.", + "zimbra_dashboard_tile_usefulLinks_title": "Enlaces útiles" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_CA.json index fe80982abfda..5b4e4ab37a43 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_CA.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_CA.json @@ -1,10 +1,30 @@ { - "title": "Zimbra", - "header_guides": "Guides", - "guides_title_1": "FAQ sur la solution Zimbra OVHcloud", - "error_service": "No services info", - "general_informations": "Informations générales", - "organizations": "Organisation", - "domains": "Domaine", - "email_accounts": "Comptes email" + "zimbra_dashboard_administrator_guide": "Guide administrateur", + "zimbra_dashboard_domains": "Domaine", + "zimbra_dashboard_domains_add": "Ajouter un domaine", + "zimbra_dashboard_domains_delete": "Supprimer un domaine", + "zimbra_dashboard_email_accounts": "Comptes email", + "zimbra_dashboard_email_accounts_add": "Créer un compte email", + "zimbra_dashboard_email_accounts_edit": "Modifier le compte", + "zimbra_dashboard_email_accounts_delete": "Supprimer la boite mail", + "zimbra_dashboard_error_service": "No services info", + "zimbra_dashboard_general_informations": "Informations générales", + "zimbra_dashboard_header_guides": "Guides", + "zimbra_dashboard_organizations": "Organisation", + "zimbra_dashboard_organizations_add": "Ajouter une organisation", + "zimbra_dashboard_organizations_edit": "Modifier l'organisation", + "zimbra_dashboard_organizations_delete": "Supprimer l'organisation", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Liens utiles", + "zimbra_dashboard_user_guides": "Guide d'utilisateur", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Statut", + "zimbra_dashboard_tile_status_serviceStatus": "Statut service", + "zimbra_dashboard_tile_status_ongoingTask": "Tâches en cours", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Voir plus", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Voir moins", + "zimbra_dashboard_tile_serviceConsumption_title": "Statistiques", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Compte par offre", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Vous ne possedez actuellement aucune boite email.", + "zimbra_dashboard_tile_usefulLinks_title": "Liens utiles" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_FR.json index fe80982abfda..5b4e4ab37a43 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_FR.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_fr_FR.json @@ -1,10 +1,30 @@ { - "title": "Zimbra", - "header_guides": "Guides", - "guides_title_1": "FAQ sur la solution Zimbra OVHcloud", - "error_service": "No services info", - "general_informations": "Informations générales", - "organizations": "Organisation", - "domains": "Domaine", - "email_accounts": "Comptes email" + "zimbra_dashboard_administrator_guide": "Guide administrateur", + "zimbra_dashboard_domains": "Domaine", + "zimbra_dashboard_domains_add": "Ajouter un domaine", + "zimbra_dashboard_domains_delete": "Supprimer un domaine", + "zimbra_dashboard_email_accounts": "Comptes email", + "zimbra_dashboard_email_accounts_add": "Créer un compte email", + "zimbra_dashboard_email_accounts_edit": "Modifier le compte", + "zimbra_dashboard_email_accounts_delete": "Supprimer la boite mail", + "zimbra_dashboard_error_service": "No services info", + "zimbra_dashboard_general_informations": "Informations générales", + "zimbra_dashboard_header_guides": "Guides", + "zimbra_dashboard_organizations": "Organisation", + "zimbra_dashboard_organizations_add": "Ajouter une organisation", + "zimbra_dashboard_organizations_edit": "Modifier l'organisation", + "zimbra_dashboard_organizations_delete": "Supprimer l'organisation", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Liens utiles", + "zimbra_dashboard_user_guides": "Guide d'utilisateur", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Statut", + "zimbra_dashboard_tile_status_serviceStatus": "Statut service", + "zimbra_dashboard_tile_status_ongoingTask": "Tâches en cours", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Voir plus", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Voir moins", + "zimbra_dashboard_tile_serviceConsumption_title": "Statistiques", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Compte par offre", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Vous ne possedez actuellement aucune boite email.", + "zimbra_dashboard_tile_usefulLinks_title": "Liens utiles" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_it_IT.json index 3d5b7eeef716..0d1b8d109c16 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_it_IT.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_it_IT.json @@ -6,5 +6,33 @@ "general_informations": "Informazioni generali", "organizations": "Organizzazione", "domains": "Domini", - "email_accounts": "Account email" + "email_accounts": "Account email", + "zimbra_dashboard_administrator_guide": "Guida amministratore", + "zimbra_dashboard_domains": "Domini", + "zimbra_dashboard_domains_add": "Aggiungere un dominio", + "zimbra_dashboard_domains_delete": "Eliminare un dominio", + "zimbra_dashboard_email_accounts": "Account email", + "zimbra_dashboard_email_accounts_add": "Creare un account email", + "zimbra_dashboard_email_accounts_edit": "Modificare l'account ", + "zimbra_dashboard_email_accounts_delete": "Eliminare la casella email", + "zimbra_dashboard_error_service": "No services info", + "zimbra_dashboard_general_informations": "Informazioni generali", + "zimbra_dashboard_header_guides": "Guide", + "zimbra_dashboard_organizations": "Organizzazione", + "zimbra_dashboard_organizations_add": "Aggiungere un'organizzazione", + "zimbra_dashboard_organizations_edit": "Modificare l'organizzazione", + "zimbra_dashboard_organizations_delete": "Eliminare l'organizzazione", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Link utili", + "zimbra_dashboard_user_guides": "Guida utente", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Stato", + "zimbra_dashboard_tile_status_serviceStatus": "Stato del servizio", + "zimbra_dashboard_tile_status_ongoingTask": "Operazioni in corso ", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Espandi", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Nascondi", + "zimbra_dashboard_tile_serviceConsumption_title": "Statistiche", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Account per servizio", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Al momento non disponi di nessuna casella email.", + "zimbra_dashboard_tile_usefulLinks_title": "Link utili" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pl_PL.json index 26b26fa0d643..3cdadcc220a8 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pl_PL.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pl_PL.json @@ -6,5 +6,33 @@ "general_informations": "Informacje ogólne", "organizations": "Podmiot", "domains": "Domena", - "email_accounts": "Konta e-mail" + "email_accounts": "Konta e-mail", + "zimbra_dashboard_administrator_guide": "Przewodnik administratora", + "zimbra_dashboard_domains": "Domena", + "zimbra_dashboard_domains_add": "Dodaj domenę", + "zimbra_dashboard_domains_delete": "Usuń domenę", + "zimbra_dashboard_email_accounts": "Konta e-mail", + "zimbra_dashboard_email_accounts_add": "Załóż konto e-mail", + "zimbra_dashboard_email_accounts_edit": "Zmodyfikuj konto", + "zimbra_dashboard_email_accounts_delete": "Usuń skrzynkę e-mail", + "zimbra_dashboard_error_service": "No services info", + "zimbra_dashboard_general_informations": "Informacje ogólne", + "zimbra_dashboard_header_guides": "Przewodniki", + "zimbra_dashboard_organizations": "Organizacja", + "zimbra_dashboard_organizations_add": "Dodaj organizację", + "zimbra_dashboard_organizations_edit": "Zmodyfikuj organizację", + "zimbra_dashboard_organizations_delete": "Usuń organizację", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Przydatne linki", + "zimbra_dashboard_user_guides": "Przewodnik użytkownika", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Status", + "zimbra_dashboard_tile_status_serviceStatus": "Status usługi", + "zimbra_dashboard_tile_status_ongoingTask": "Zadania w toku", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Wyświetl więcej", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Wyświetl mniej", + "zimbra_dashboard_tile_serviceConsumption_title": "Statystyki", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Konto wg oferty", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Aktualnie nie posiadasz żadnej skrzynki e-mail.", + "zimbra_dashboard_tile_usefulLinks_title": "Przydatne linki" } diff --git a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pt_PT.json index 33718d492330..e165ef2d7122 100644 --- a/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pt_PT.json +++ b/packages/manager/apps/zimbra/public/translations/dashboard/Messages_pt_PT.json @@ -6,5 +6,33 @@ "general_informations": "Informações gerais", "organizations": "Organização", "domains": "Domínio", - "email_accounts": "Contas de email" + "email_accounts": "Contas de email", + "zimbra_dashboard_administrator_guide": "Manual do administrador", + "zimbra_dashboard_domains": "Domínio", + "zimbra_dashboard_domains_add": "Adicionar domínio", + "zimbra_dashboard_domains_delete": "Eliminar um domínio", + "zimbra_dashboard_email_accounts": "Contas de email", + "zimbra_dashboard_email_accounts_add": "Criar uma conta de e-mail", + "zimbra_dashboard_email_accounts_edit": "Modificar a conta", + "zimbra_dashboard_email_accounts_delete": "Eliminar a caixa de e-mail", + "zimbra_dashboard_error_service": "No services info", + "zimbra_dashboard_general_informations": "Informações gerais", + "zimbra_dashboard_header_guides": "Manuais", + "zimbra_dashboard_organizations": "Organização", + "zimbra_dashboard_organizations_add": "Adicionar uma organização", + "zimbra_dashboard_organizations_edit": "Modificar a organização", + "zimbra_dashboard_organizations_delete": "Eliminar a organização", + "zimbra_dashboard_title": "Zimbra", + "zimbra_dashboard_usefull_links": "Ligações úteis", + "zimbra_dashboard_user_guides": "Manual do utilizador", + "zimbra_dashboard_webmail": "Webmail", + "zimbra_dashboard_tile_status_title": "Estado", + "zimbra_dashboard_tile_status_serviceStatus": "Estado do serviço", + "zimbra_dashboard_tile_status_ongoingTask": "Tarefas em curso", + "zimbra_dashboard_tile_status_ongoingTask_viewMore": "Mostrar mais", + "zimbra_dashboard_tile_status_ongoingTask_viewLess": "Mostrar menos", + "zimbra_dashboard_tile_serviceConsumption_title": "Estatísticas", + "zimbra_dashboard_tile_serviceConsumption_accountOffer": "Conta por oferta", + "zimbra_dashboard_tile_serviceConsumption_noAccountOffer": "Atualmente não dispõe de nenhuma caixa de e-mail.", + "zimbra_dashboard_tile_usefulLinks_title": "Ligações úteis" } diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_en_GB.json new file mode 100644 index 000000000000..101f93dc002b --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_en_GB.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Add a domain", + "zimbra_domains_datagrid_account_label": "Number of accounts", + "zimbra_domains_datagrid_diagnostic_label": "Diagnostic", + "zimbra_domains_datagrid_domain_label": "Domain", + "zimbra_domains_datagrid_organization_label": "Organisation", + "zimbra_domains_datagrid_account_number": "Number of accounts", + "zimbra_domains_tooltip_delete": "Delete" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_es_ES.json new file mode 100644 index 000000000000..2a71346c1752 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_es_ES.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Añadir un dominio", + "zimbra_domains_datagrid_account_label": "Número de cuentas", + "zimbra_domains_datagrid_diagnostic_label": "Diagnóstico", + "zimbra_domains_datagrid_domain_label": "Dominio", + "zimbra_domains_datagrid_organization_label": "Organización", + "zimbra_domains_datagrid_account_number": "Número de cuentas", + "zimbra_domains_tooltip_delete": "Eliminar" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_CA.json new file mode 100644 index 000000000000..0cbefc001962 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_CA.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Ajouter un domaine", + "zimbra_domains_datagrid_account_label": "Nombre de comptes", + "zimbra_domains_datagrid_diagnostic_label": "Diagnostique", + "zimbra_domains_datagrid_domain_label": "Domaine", + "zimbra_domains_datagrid_organization_label": "Organisation", + "zimbra_domains_datagrid_account_number": "Nombre de comptes", + "zimbra_domains_tooltip_delete": "Supprimer" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_FR.json new file mode 100644 index 000000000000..0cbefc001962 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_fr_FR.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Ajouter un domaine", + "zimbra_domains_datagrid_account_label": "Nombre de comptes", + "zimbra_domains_datagrid_diagnostic_label": "Diagnostique", + "zimbra_domains_datagrid_domain_label": "Domaine", + "zimbra_domains_datagrid_organization_label": "Organisation", + "zimbra_domains_datagrid_account_number": "Nombre de comptes", + "zimbra_domains_tooltip_delete": "Supprimer" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_it_IT.json new file mode 100644 index 000000000000..f45b0c63c346 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_it_IT.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Aggiungere un dominio", + "zimbra_domains_datagrid_account_label": "Numero di account", + "zimbra_domains_datagrid_diagnostic_label": "Diagnostica", + "zimbra_domains_datagrid_domain_label": "Domini", + "zimbra_domains_datagrid_organization_label": "Organizzazione", + "zimbra_domains_datagrid_account_number": "Numero di account", + "zimbra_domains_tooltip_delete": "Eliminare" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_pl_PL.json new file mode 100644 index 000000000000..f0a7d903141e --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_pl_PL.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Dodaj domenę", + "zimbra_domains_datagrid_account_label": "Liczba kont", + "zimbra_domains_datagrid_diagnostic_label": "Diagnostyka", + "zimbra_domains_datagrid_domain_label": "Domena", + "zimbra_domains_datagrid_organization_label": "Organizacja", + "zimbra_domains_datagrid_account_number": "Liczba kont", + "zimbra_domains_tooltip_delete": "Usuń" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/domains/Messages_pt_PT.json new file mode 100644 index 000000000000..ddd577d54bf5 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/Messages_pt_PT.json @@ -0,0 +1,9 @@ +{ + "zimbra_domains_add_domain_title": "Adicionar domínio", + "zimbra_domains_datagrid_account_label": "Número de contas", + "zimbra_domains_datagrid_diagnostic_label": "Diagnóstico", + "zimbra_domains_datagrid_domain_label": "Domínio", + "zimbra_domains_datagrid_organization_label": "Organização", + "zimbra_domains_datagrid_account_number": "Número de contas", + "zimbra_domains_tooltip_delete": "Eliminar" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_en_GB.json new file mode 100644 index 000000000000..f94bacb96814 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_en_GB.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Back to domain names", + "zimbra_domains_add_domain_cta_confirm": "Confirm", + "zimbra_domains_add_domain_cta_next": "Next", + "zimbra_domains_add_domain_title": "Domain name", + "zimbra_domains_add_domain_title_select": "Add a domain", + "zimbra_domains_add_domain_select_title": "Select a domain from the list", + "zimbra_domains_add_domain_select": "Select a domain name", + "zimbra_domains_add_domain_input": "Enter your domain name", + "zimbra_domains_add_domain_input_title": "Enter a domain name not managed by our OVHcloud account", + "zimbra_domains_add_domain_organization": "Organisation", + "zimbra_domains_add_domain_organization_select": "Select an organisation", + "zimbra_domains_add_domain_configuration_title": "Configuration", + "zimbra_domains_add_domain_success_message": "Your add-in request has been submitted. It will be executed in a few moments.", + "zimbra_domains_add_domain_error_message": "Unable to submit your add-in request. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_es_ES.json new file mode 100644 index 000000000000..8199db68ec3f --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_es_ES.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Volver a los dominios", + "zimbra_domains_add_domain_cta_confirm": "Confirmar", + "zimbra_domains_add_domain_cta_next": "Siguiente", + "zimbra_domains_add_domain_title": "Dominio", + "zimbra_domains_add_domain_title_select": "Añadir un dominio", + "zimbra_domains_add_domain_select_title": "Seleccionar un dominio de la lista", + "zimbra_domains_add_domain_select": "Seleccionar un dominio", + "zimbra_domains_add_domain_input": "Introduzca su dominio", + "zimbra_domains_add_domain_input_title": "Introducir un dominio no gestionado por nuestra cuenta de OVHcloud", + "zimbra_domains_add_domain_organization": "Organización", + "zimbra_domains_add_domain_organization_select": "Seleccionar una organización", + "zimbra_domains_add_domain_configuration_title": "Configuración", + "zimbra_domains_add_domain_success_message": "La solicitud de adición se ha enviado. Se ejecutará en unos instantes.", + "zimbra_domains_add_domain_error_message": "Se ha producido un error al enviar la solicitud de adición: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_CA.json new file mode 100644 index 000000000000..6321341206f4 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_CA.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Retour vers les noms de domaine", + "zimbra_domains_add_domain_cta_confirm": "Confirmer", + "zimbra_domains_add_domain_cta_next": "Suivant", + "zimbra_domains_add_domain_title": "Nom de domaine", + "zimbra_domains_add_domain_title_select": "Ajouter un domaine", + "zimbra_domains_add_domain_select_title": "Sélectionner un domaine dans la liste", + "zimbra_domains_add_domain_select": "Sélectionner un nom de domaine", + "zimbra_domains_add_domain_input": "Saisissez votre nom de domaine", + "zimbra_domains_add_domain_input_title": "Saisir un nom de domaine non géré par notre compte OVHcloud", + "zimbra_domains_add_domain_organization": "Organisation", + "zimbra_domains_add_domain_organization_select": "Sélectionner une organisation", + "zimbra_domains_add_domain_configuration_title": "Configuration", + "zimbra_domains_add_domain_success_message": "Votre demande d'ajout a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_domains_add_domain_error_message": "Votre demande d'ajout n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_FR.json new file mode 100644 index 000000000000..6321341206f4 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_fr_FR.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Retour vers les noms de domaine", + "zimbra_domains_add_domain_cta_confirm": "Confirmer", + "zimbra_domains_add_domain_cta_next": "Suivant", + "zimbra_domains_add_domain_title": "Nom de domaine", + "zimbra_domains_add_domain_title_select": "Ajouter un domaine", + "zimbra_domains_add_domain_select_title": "Sélectionner un domaine dans la liste", + "zimbra_domains_add_domain_select": "Sélectionner un nom de domaine", + "zimbra_domains_add_domain_input": "Saisissez votre nom de domaine", + "zimbra_domains_add_domain_input_title": "Saisir un nom de domaine non géré par notre compte OVHcloud", + "zimbra_domains_add_domain_organization": "Organisation", + "zimbra_domains_add_domain_organization_select": "Sélectionner une organisation", + "zimbra_domains_add_domain_configuration_title": "Configuration", + "zimbra_domains_add_domain_success_message": "Votre demande d'ajout a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_domains_add_domain_error_message": "Votre demande d'ajout n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_it_IT.json new file mode 100644 index 000000000000..efda8df4850e --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_it_IT.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Ritornare ai domini", + "zimbra_domains_add_domain_cta_confirm": "Confermare", + "zimbra_domains_add_domain_cta_next": "Successivo", + "zimbra_domains_add_domain_title": "Dominio", + "zimbra_domains_add_domain_title_select": "Aggiungere un dominio", + "zimbra_domains_add_domain_select_title": "Selezionare un dominio nella lista", + "zimbra_domains_add_domain_select": "Selezionare un dominio", + "zimbra_domains_add_domain_input": "Inserisci il tuo dominio", + "zimbra_domains_add_domain_input_title": "Inserisci un dominio non gestito dal nostro account OVHcloud", + "zimbra_domains_add_domain_organization": "Organizzazione", + "zimbra_domains_add_domain_organization_select": "Selezionare un'organizzazione", + "zimbra_domains_add_domain_configuration_title": "Configurazione", + "zimbra_domains_add_domain_success_message": "La tua richiesta di aggiunta è stata presa in carico. Sarà eseguita entro pochi minuti.", + "zimbra_domains_add_domain_error_message": "La tua richiesta di aggiunta non è andata a buon fine: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pl_PL.json new file mode 100644 index 000000000000..709ac808a2e6 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pl_PL.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Powrót do domen", + "zimbra_domains_add_domain_cta_confirm": "Zatwierdź", + "zimbra_domains_add_domain_cta_next": "Dalej", + "zimbra_domains_add_domain_title": "Domena", + "zimbra_domains_add_domain_title_select": "Dodaj domenę", + "zimbra_domains_add_domain_select_title": "Wybierz domenę z listy", + "zimbra_domains_add_domain_select": "Wybierz nazwę domeny", + "zimbra_domains_add_domain_input": "Wpisz nazwę domeny", + "zimbra_domains_add_domain_input_title": "Wpisz domenę, która nie jest zarządzana w ramach konta OVHcloud", + "zimbra_domains_add_domain_organization": "Organizacja", + "zimbra_domains_add_domain_organization_select": "Wybierz organizację", + "zimbra_domains_add_domain_configuration_title": "Konfiguracja", + "zimbra_domains_add_domain_success_message": "Dyspozycja dodania została przyjęta. Zostanie wykonana w ciągu kilku minut.", + "zimbra_domains_add_domain_error_message": "Dodanie nie powiodło się. {{error}}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pt_PT.json new file mode 100644 index 000000000000..79a68a3c6432 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/addDomain/Messages_pt_PT.json @@ -0,0 +1,16 @@ +{ + "zimbra_domains_add_domain_cta_back": "Voltar para os nomes de domínio", + "zimbra_domains_add_domain_cta_confirm": "Confirmar", + "zimbra_domains_add_domain_cta_next": "Seguinte", + "zimbra_domains_add_domain_title": "Domínio", + "zimbra_domains_add_domain_title_select": "Adicionar domínio", + "zimbra_domains_add_domain_select_title": "Selecione um domínio da lista", + "zimbra_domains_add_domain_select": "Escolher um nome de domínio", + "zimbra_domains_add_domain_input": "Introduza o seu nome de domínio", + "zimbra_domains_add_domain_input_title": "Introduzir um nome de domínio não gerido pela sua conta OVHcloud", + "zimbra_domains_add_domain_organization": "Organização", + "zimbra_domains_add_domain_organization_select": "Escolher uma organização", + "zimbra_domains_add_domain_configuration_title": "Configuração", + "zimbra_domains_add_domain_success_message": "O seu pedido de adição foi registado. Será executado dentro de alguns instantes.", + "zimbra_domains_add_domain_error_message": "O seu pedido de adição não foi bem-sucedido. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_en_GB.json new file mode 100644 index 000000000000..755bff3cb712 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_en_GB.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Delete", + "zimbra_domain_delete_modal_title": "Delete domain", + "zimbra_domain_delete_modal_content": "Are you sure you want to delete the domain from the Zimbra server?", + "zimbra_domain_delete_modal_message_disabled": "Your domain is in use. You cannot delete this domain while it is still in use.", + "zimbra_domain_delete_success_message": "Your deletion request has been processed. It will be executed in a few moments.", + "zimbra_domain_delete_error_message": "Unable to submit your deletion request. {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "There is at least one email account still linked to this domain name.", + "zimbra_domain_delete_modal_message_disabled_part2": "Please delete the linked email accounts before deleting your domain name." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_es_ES.json new file mode 100644 index 000000000000..ed34a5254387 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_es_ES.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Eliminar", + "zimbra_domain_delete_modal_title": "Eliminar el dominio", + "zimbra_domain_delete_modal_content": "¿Seguro que quiere eliminar el dominio del servidor Zimbra?", + "zimbra_domain_delete_modal_message_disabled": "Su dominio está en uso. No es posible eliminar este dominio mientras esté en uso.", + "zimbra_domain_delete_success_message": "La solicitud de eliminación se ha enviado. Se ejecutará en unos instantes.", + "zimbra_domain_delete_error_message": "Se ha producido un error al enviar la solicitud de eliminación: {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "Este dominio todavía tiene al menos una cuenta de correo asociada.", + "zimbra_domain_delete_modal_message_disabled_part2": "Por favor, elimine las cuentas de correo asociadas antes de eliminar el dominio." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_CA.json new file mode 100644 index 000000000000..85b530f9bee8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_CA.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Supprimer", + "zimbra_domain_delete_modal_title": "Supprimer le domaine", + "zimbra_domain_delete_modal_content": "Êtes-vous sûr(e) de vouloir supprimer le domaine du serveur Zimbra ?", + "zimbra_domain_delete_modal_message_disabled": "Votre domaine est en cours d'utilisation. Vous ne pouvez pas supprimer ce domaine tant qu'il est dans ce cas.", + "zimbra_domain_delete_success_message": "Votre demande de suppression a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_domain_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "Au moins un compte email est encore associé à ce nom de domaine.", + "zimbra_domain_delete_modal_message_disabled_part2": "Veuillez supprimer les comptes emails associés avant de supprimer votre nom de domaine." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_FR.json new file mode 100644 index 000000000000..85b530f9bee8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_fr_FR.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Supprimer", + "zimbra_domain_delete_modal_title": "Supprimer le domaine", + "zimbra_domain_delete_modal_content": "Êtes-vous sûr(e) de vouloir supprimer le domaine du serveur Zimbra ?", + "zimbra_domain_delete_modal_message_disabled": "Votre domaine est en cours d'utilisation. Vous ne pouvez pas supprimer ce domaine tant qu'il est dans ce cas.", + "zimbra_domain_delete_success_message": "Votre demande de suppression a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_domain_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "Au moins un compte email est encore associé à ce nom de domaine.", + "zimbra_domain_delete_modal_message_disabled_part2": "Veuillez supprimer les comptes emails associés avant de supprimer votre nom de domaine." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_it_IT.json new file mode 100644 index 000000000000..2abcc165151f --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_it_IT.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Eliminare", + "zimbra_domain_delete_modal_title": "Elimina il dominio", + "zimbra_domain_delete_modal_content": "Vuoi davvero eliminare il dominio del server Zimbra?", + "zimbra_domain_delete_modal_message_disabled": "Il tuo dominio è attualmente in uso. Non è possibile eliminare questo dominio finché risulta in corso di utilizzo.", + "zimbra_domain_delete_success_message": "La tua richiesta di eliminazione è stata presa in carico correttamente. Sarà eseguita entro pochi minuti.", + "zimbra_domain_delete_error_message": "La tua richiesta di eliminazione non è andata a buon fine: {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "A questo dominio è ancora associato almeno un account email.", + "zimbra_domain_delete_modal_message_disabled_part2": "Elimina gli account email associati prima di eliminare il dominio." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pl_PL.json new file mode 100644 index 000000000000..aeb9bec2c95a --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pl_PL.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Usuń", + "zimbra_domain_delete_modal_title": "Usuń domenę", + "zimbra_domain_delete_modal_content": "Czy na pewno chcesz usunąć domenę z serwera Zimbra?", + "zimbra_domain_delete_modal_message_disabled": "Domena jest aktualnie używana. Dopóki znajduje się w tym stanie, nie możesz jej usunąć.", + "zimbra_domain_delete_success_message": "Dyspozycja usunięcia została przyjęta. Zostanie wykonana w ciągu kilku minut.", + "zimbra_domain_delete_error_message": "Usunięcie nie powiodło się. {{error}}", + "zimbra_domain_delete_modal_message_disabled_part1": "Z tą domeną powiązane jest co najmniej jedno konto e-mail.", + "zimbra_domain_delete_modal_message_disabled_part2": "Przed usunięciem domeny usuń powiązane z nią konta e-mail." +} diff --git a/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pt_PT.json new file mode 100644 index 000000000000..886a847a8bb2 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/domains/delete/Messages_pt_PT.json @@ -0,0 +1,10 @@ +{ + "zimbra_domain_delete": "Eliminar", + "zimbra_domain_delete_modal_title": "Eliminar domínio", + "zimbra_domain_delete_modal_content": "Quer mesmo eliminar o domínio do servidor Zimbra?", + "zimbra_domain_delete_modal_message_disabled": "O seu domínio está a ser utilizado. Não é possível eliminar o domínio enquanto estiver a ser usado.", + "zimbra_domain_delete_success_message": "O pedido de eliminação foi registado. Será executado dentro de alguns instantes.", + "zimbra_domain_delete_error_message": "O seu pedido de eliminação não foi bem-sucedido. {{ error }}", + "zimbra_domain_delete_modal_message_disabled_part1": "Pelo menos uma conta de e-mail ainda está associada a este nome de domínio.", + "zimbra_domain_delete_modal_message_disabled_part2": "Elimine as contas de e-mail associadas antes de suprimir o seu nome de domínio." +} diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_en_GB.json index edd4496d8e53..717429a7945a 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_en_GB.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_en_GB.json @@ -1,7 +1,7 @@ { "title": "Zimbra", - "description": "Explore managed storage services that are based on the OpenZFS file system. Use centralised storage spaces in just a few clicks to store or back up your data and files.", - "orderButtonLabel": "Order a Zimbra service", + "description": "The Zimbra email solution will be available soon. Want to join the Zimbra beta testing?", + "orderButtonLabel": "Join beta testing", "orderButtonLink": "/#/dedicated/zimbra/order", "moreInfoButtonLabel": "Find out more about Zimbra", "moreInfoButtonLink": "/#/dedicated/zimbra/info", diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_es_ES.json index b0ea770bbbd7..a79035843d94 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_es_ES.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_es_ES.json @@ -1,7 +1,7 @@ { "title": "Zimbra", - "description": "Descubra los servicios de almacenamiento administrados basados en el sistema de archivos OpenZFS. Disfrute en solo unos clics de espacios de almacenamiento centralizados para almacenar o guardar copias de seguridad de sus datos y archivos.", - "orderButtonLabel": "Contratar Ziimbra", + "description": "La solución de correo electrónico Zimbra estará disponible próximamente. ¿Quiere unirse a la beta de Zimbra?", + "orderButtonLabel": "Unirme a la beta", "orderButtonLink": "/#/dedicated/zimbra/order", "moreInfoButtonLabel": "Saber más sobre Zimbra", "moreInfoButtonLink": "/#/dedicated/zimbra/info", diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_CA.json index 9c8204c21cb3..3ec40e14a33b 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_CA.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_CA.json @@ -1,18 +1,5 @@ { "title": "Zimbra", - "description": "Découvrez des services de stockage managés qui s’appuient sur le système de fichiers OpenZFS. Bénéficiez en quelques clics d’espaces de stockage centralisés pour entreposer ou sauvegarder vos données et fichiers.", - "orderButtonLabel": "Commander un zimbra", - "orderButtonLink": "/#/dedicated/zimbra/order", - "moreInfoButtonLabel": "En savoir plus sur zimbra", - "moreInfoButtonLink": "/#/dedicated/zimbra/info", - "guideCategory": "Tutoriel", - "guide1Title": "Premiers pas avec un zimbra", - "guide1Description": "Découvrez comment gérer un NAS-HA depuis l'espace-client OVHcloud", - "guide1Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-get-started?id=kb_article_view&sysparm_article=KB0046704", - "guide2Title": "Monter votre NAS via un partage NFS", - "guide2Description": "Découvrez comment monter un NAS via un partage NFS", - "guide2Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-nfs?id=kb_article_view&sysparm_article=KB0046742", - "guide3Title": "Monter votre NAS sur Windows Server via CIFS", - "guide3Description": "Découvrez comment monter un NAS sur Windows Server via le protocole CIFS", - "guide3Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-cifs?id=kb_article_view&sysparm_article=KB0046672" + "description": "L'offre email Zimbra sera bientôt disponible. Vous souhaitez rejoindre la Beta Zimbra ?", + "orderButtonLabel": "Rejoindre la beta" } diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_FR.json index 9c8204c21cb3..3ec40e14a33b 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_FR.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_fr_FR.json @@ -1,18 +1,5 @@ { "title": "Zimbra", - "description": "Découvrez des services de stockage managés qui s’appuient sur le système de fichiers OpenZFS. Bénéficiez en quelques clics d’espaces de stockage centralisés pour entreposer ou sauvegarder vos données et fichiers.", - "orderButtonLabel": "Commander un zimbra", - "orderButtonLink": "/#/dedicated/zimbra/order", - "moreInfoButtonLabel": "En savoir plus sur zimbra", - "moreInfoButtonLink": "/#/dedicated/zimbra/info", - "guideCategory": "Tutoriel", - "guide1Title": "Premiers pas avec un zimbra", - "guide1Description": "Découvrez comment gérer un NAS-HA depuis l'espace-client OVHcloud", - "guide1Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-get-started?id=kb_article_view&sysparm_article=KB0046704", - "guide2Title": "Monter votre NAS via un partage NFS", - "guide2Description": "Découvrez comment monter un NAS via un partage NFS", - "guide2Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-nfs?id=kb_article_view&sysparm_article=KB0046742", - "guide3Title": "Monter votre NAS sur Windows Server via CIFS", - "guide3Description": "Découvrez comment monter un NAS sur Windows Server via le protocole CIFS", - "guide3Link": "https://help.ovhcloud.com/csm/fr-public-cloud-storage-nas-cifs?id=kb_article_view&sysparm_article=KB0046672" + "description": "L'offre email Zimbra sera bientôt disponible. Vous souhaitez rejoindre la Beta Zimbra ?", + "orderButtonLabel": "Rejoindre la beta" } diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_it_IT.json index 178d7c2ebe2f..1c65348d8892 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_it_IT.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_it_IT.json @@ -1,7 +1,7 @@ { "title": "Zimbra", - "description": "Scopri le soluzioni di storage gestite basate sul file system OpenZFS. Usufruisci in pochi click di spazi di storage centralizzati per archiviare o salvare dati e file.", - "orderButtonLabel": "Ordinare zimbra", + "description": "Il servizio email Zimbra sarà presto disponibile. Vuoi partecipare alla beta di Zimbra?", + "orderButtonLabel": "Partecipa alla beta", "orderButtonLink": "/#/dedicated/zimbra/order", "moreInfoButtonLabel": "Per saperne di più su zimbra", "moreInfoButtonLink": "/#/dedicated/zimbra/info", diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pl_PL.json index acb1047569d8..c5e9f633d225 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pl_PL.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pl_PL.json @@ -1,7 +1,7 @@ { "title": "Zimbra", - "description": "Poznaj usługi zarządzanej przestrzeni dyskowej oparte na systemie plików OpenZFS. Skorzystaj za pomocą kilku kliknięć ze scentralizowanej przestrzeni dyskowej do przechowywania i zapisywania danych i plików.", - "orderButtonLabel": "Zamów rozwiązanie Zimbra", + "description": "Oferta e-mail Zimbra będzie wkrótce dostępna. Chcesz dołączyć do grona użytkowników testujących wersję beta Zimbra?", + "orderButtonLabel": "Dołącz do wersji beta", "orderButtonLink": "/#/dedicated/zimbra/order", "moreInfoButtonLabel": "Więcej informacji o rozwiązaniu Zimbra", "moreInfoButtonLink": "/#/dedicated/zimbra/info", diff --git a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pt_PT.json index 15ef12a190a6..684dec48d8b5 100644 --- a/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pt_PT.json +++ b/packages/manager/apps/zimbra/public/translations/onboarding/Messages_pt_PT.json @@ -1,7 +1,7 @@ { "title": "Zimbra", - "description": "Descubra os serviços de armazenamento geridos que se baseiam no sistema de ficheiros OpenZFS. Usufrua de espaços de armazenamento centralizados em apenas alguns cliques para armazenar ou salvaguardar os seus dados e ficheiros.", - "orderButtonLabel": "Encomendar um Zimbra", + "description": "A oferta de e-mail Zimbra estará disponível em breve. Quer fazer parte do Zimbra Beta?", + "orderButtonLabel": "Integrar a fase beta", "orderButtonLink": "/#/dedicated/zimbra/order", "moreInfoButtonLabel": "Saber mais sobre Zimbra", "moreInfoButtonLink": "/#/dedicated/zimbra/info", diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_en_GB.json deleted file mode 100644 index 21d103042dab..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_en_GB.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Add an organisation" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_es_ES.json deleted file mode 100644 index f3a51a4a5536..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_es_ES.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Añadir una organización" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_CA.json deleted file mode 100644 index 8ab7f50b8e51..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_CA.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Ajouter une organisation" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_FR.json deleted file mode 100644 index 8ab7f50b8e51..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_fr_FR.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Ajouter une organisation" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_it_IT.json deleted file mode 100644 index 58e58790ebb6..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_it_IT.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Aggiungi un'organizzazione" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_pl_PL.json deleted file mode 100644 index 189006e487e8..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_pl_PL.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Dodaj organizację" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/organisations/Messages_pt_PT.json deleted file mode 100644 index c127ed9334b3..000000000000 --- a/packages/manager/apps/zimbra/public/translations/organisations/Messages_pt_PT.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "add_organisation_cta": "Adicionar uma organização" -} diff --git a/packages/manager/apps/zimbra/public/translations/organisations/Messages_de_DE.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_de_DE.json similarity index 100% rename from packages/manager/apps/zimbra/public/translations/organisations/Messages_de_DE.json rename to packages/manager/apps/zimbra/public/translations/organizations/Messages_de_DE.json diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_en_GB.json new file mode 100644 index 000000000000..df168691e917 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_en_GB.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Add an organisation", + "zimbra_organization_cta": "Add an organisation", + "zimbra_organization_account_number": "Number of accounts", + "zimbra_organization_edit": "Edit", + "zimbra_organization_delete": "Delete", + "zimbra_organization_label": "Label", + "zimbra_organization_name": "Name", + "zimbra_organization_status": "Status" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_es_ES.json new file mode 100644 index 000000000000..c8f2b81cfbb7 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_es_ES.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Añadir una organización", + "zimbra_organization_cta": "Añadir una organización", + "zimbra_organization_account_number": "Número de cuentas", + "zimbra_organization_edit": "Modificar", + "zimbra_organization_delete": "Eliminar", + "zimbra_organization_label": "Label", + "zimbra_organization_name": "Nombre", + "zimbra_organization_status": "Estado" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_CA.json new file mode 100644 index 000000000000..0e9b283dc680 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_CA.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Ajouter une organisation", + "zimbra_organization_cta": "Ajouter une organisation", + "zimbra_organization_account_number": "Nombre de comptes", + "zimbra_organization_edit": "Modifier", + "zimbra_organization_delete": "Supprimer", + "zimbra_organization_label": "Label", + "zimbra_organization_name": "Nom", + "zimbra_organization_status": "Statut" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_FR.json new file mode 100644 index 000000000000..0e9b283dc680 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_fr_FR.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Ajouter une organisation", + "zimbra_organization_cta": "Ajouter une organisation", + "zimbra_organization_account_number": "Nombre de comptes", + "zimbra_organization_edit": "Modifier", + "zimbra_organization_delete": "Supprimer", + "zimbra_organization_label": "Label", + "zimbra_organization_name": "Nom", + "zimbra_organization_status": "Statut" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_it_IT.json new file mode 100644 index 000000000000..c347c303c34e --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_it_IT.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Aggiungere un'organizzazione", + "zimbra_organization_cta": "Aggiungere un'organizzazione", + "zimbra_organization_account_number": "Numero di account", + "zimbra_organization_edit": "Modificare", + "zimbra_organization_delete": "Eliminare", + "zimbra_organization_label": "Label", + "zimbra_organization_name": "Nome", + "zimbra_organization_status": "Stato" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_pl_PL.json new file mode 100644 index 000000000000..62e7db51ea62 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_pl_PL.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Dodaj organizację", + "zimbra_organization_cta": "Dodaj organizację", + "zimbra_organization_account_number": "Liczba kont", + "zimbra_organization_edit": "Zmień", + "zimbra_organization_delete": "Usuń", + "zimbra_organization_label": "Etykieta", + "zimbra_organization_name": "Nazwa", + "zimbra_organization_status": "Status" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/organizations/Messages_pt_PT.json new file mode 100644 index 000000000000..1db5704a60a8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/Messages_pt_PT.json @@ -0,0 +1,10 @@ +{ + "add_organisation_cta": "Adicionar uma organização", + "zimbra_organization_cta": "Adicionar uma organização", + "zimbra_organization_account_number": "Número de contas", + "zimbra_organization_edit": "Alterar", + "zimbra_organization_delete": "Eliminar", + "zimbra_organization_label": "Etiqueta", + "zimbra_organization_name": "Nome", + "zimbra_organization_status": "Estado" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_en_GB.json new file mode 100644 index 000000000000..3ec9527c3691 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_en_GB.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confirm", + "zimbra_organization_add_modal_title": "Add an organisation", + "zimbra_organization_add_modal_content_part1": "The organisation comprises logically grouped domains and mailboxes.", + "zimbra_organization_add_modal_content_part2": "You can define grouped management policies and set mailbox isolation, which includes limiting access to the company directory.", + "zimbra_organization_edit_modal_title": "Edit organisation", + "zimbra_organization_add_form_input_mandatory": "Fields marked with an asterisk (*) are mandatory", + "zimbra_organization_add_form_input_name_title": "Name", + "zimbra_organization_add_form_input_name_placeholder": "Name", + "zimbra_organization_add_form_input_name_error": "Mandatory field. Must only contain alphanumeric characters.", + "zimbra_organization_add_form_input_label_title": "Organisation Label", + "zimbra_organization_add_form_input_label_placeholder": "Label", + "zimbra_organization_add_form_input_label_error": "Mandatory field. Must only contain alphanumeric characters. Maximum of {{ value }} characters.", + "zimbra_organization_add_form_input_label_tooltip": "The label is a brief text that is used to filter and navigate in the Control Panel.", + "zimbra_organization_add_form_input_label_helper": "{{ value }} characters maximum.", + "zimbra_organization_add_success_message": "Your request to add an organisation has been submitted. It will be effective in a few moments.", + "zimbra_organization_add_error_message": "Unable to submit your request to add an organisation. {{ error }}", + "zimbra_organization_edit_success_message": "Your request to edit has been submitted. It will be executed in a few moments.", + "zimbra_organization_edit_error_message": "Unable to submit your request to edit. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_es_ES.json new file mode 100644 index 000000000000..5778b0293cab --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_es_ES.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confirmar", + "zimbra_organization_add_modal_title": "Añadir una organización", + "zimbra_organization_add_modal_content_part1": "La organización hace referencia a un conjunto lógico de dominios y cuentas de correo.", + "zimbra_organization_add_modal_content_part2": "Permite aplicar políticas de gestión agrupadas y definir el aislamiento de sus cuentas de correo (límite del directorio de empresa).", + "zimbra_organization_edit_modal_title": "Modificar la organización", + "zimbra_organization_add_form_input_mandatory": "Los campos marcados con un asterisco (*) son obligatorios.", + "zimbra_organization_add_form_input_name_title": "Nombre", + "zimbra_organization_add_form_input_name_placeholder": "nombre", + "zimbra_organization_add_form_input_name_error": "Campo obligatorio. Solo puede incluir caracteres alfanuméricos.", + "zimbra_organization_add_form_input_label_title": "Label de la organización", + "zimbra_organization_add_form_input_label_placeholder": "label", + "zimbra_organization_add_form_input_label_error": "Campo obligatorio. Solo puede incluir caracteres alfanuméricos. Máximo {{ value }} caracteres.", + "zimbra_organization_add_form_input_label_tooltip": "El «label» (etiqueta) es un texto corto que se utiliza para filtrar los resultados y navegar por el área de cliente.", + "zimbra_organization_add_form_input_label_helper": "{{ value }} caracteres máximo.", + "zimbra_organization_add_success_message": "La solicitud de adición de la organización se ha enviado. Será efectiva en unos instantes.", + "zimbra_organization_add_error_message": "Se ha producido un error al enviar la solicitud de adición de la organización: {{ error }}", + "zimbra_organization_edit_success_message": "La solicitud de modificación se ha enviado. Se ejecutará en unos instantes.", + "zimbra_organization_edit_error_message": "Se ha producido un error al enviar la solicitud de modificación: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_CA.json new file mode 100644 index 000000000000..27647ce08a24 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_CA.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confirmer", + "zimbra_organization_add_modal_title": "Ajouter une organisation", + "zimbra_organization_add_modal_content_part1": "L'organisation représente un groupement logique de domaines et de boites mails.", + "zimbra_organization_add_modal_content_part2": "Elle permet de définir des politiques de gestion groupées et définit l'isolation de vos boites mails (limite de l'annuaire d'entreprise).", + "zimbra_organization_edit_modal_title": "Modifier l'organisation", + "zimbra_organization_add_form_input_mandatory": "Les champs mentionnés avec un astérisque * sont obligatoires", + "zimbra_organization_add_form_input_name_title": "Nom", + "zimbra_organization_add_form_input_name_placeholder": "nom", + "zimbra_organization_add_form_input_name_error": "Champs obligatoire. Doit être composé uniquement de caractères alphanumériques.", + "zimbra_organization_add_form_input_label_title": "Label de l'organisation", + "zimbra_organization_add_form_input_label_placeholder": "label", + "zimbra_organization_add_form_input_label_error": "Champs obligatoire. Doit être composé uniquement de caractères alphanumériques. Maximum {{ value }} caractères.", + "zimbra_organization_add_form_input_label_tooltip": "Le label est un texte court utilisé pour le filtrage et la navigation dans l'espace client.", + "zimbra_organization_add_form_input_label_helper": "{{ value }} caractères maximum.", + "zimbra_organization_add_success_message": "Votre demande d'ajout d'organisation a bien été prise en compte. Elle sera effective d'ici quelques instants.", + "zimbra_organization_add_error_message": "Votre demande d'ajout d'organisation n'a pas pu aboutir. {{ error }}", + "zimbra_organization_edit_success_message": "Votre demande de modification a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_organization_edit_error_message": "Votre demande de modification n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_FR.json new file mode 100644 index 000000000000..27647ce08a24 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_fr_FR.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confirmer", + "zimbra_organization_add_modal_title": "Ajouter une organisation", + "zimbra_organization_add_modal_content_part1": "L'organisation représente un groupement logique de domaines et de boites mails.", + "zimbra_organization_add_modal_content_part2": "Elle permet de définir des politiques de gestion groupées et définit l'isolation de vos boites mails (limite de l'annuaire d'entreprise).", + "zimbra_organization_edit_modal_title": "Modifier l'organisation", + "zimbra_organization_add_form_input_mandatory": "Les champs mentionnés avec un astérisque * sont obligatoires", + "zimbra_organization_add_form_input_name_title": "Nom", + "zimbra_organization_add_form_input_name_placeholder": "nom", + "zimbra_organization_add_form_input_name_error": "Champs obligatoire. Doit être composé uniquement de caractères alphanumériques.", + "zimbra_organization_add_form_input_label_title": "Label de l'organisation", + "zimbra_organization_add_form_input_label_placeholder": "label", + "zimbra_organization_add_form_input_label_error": "Champs obligatoire. Doit être composé uniquement de caractères alphanumériques. Maximum {{ value }} caractères.", + "zimbra_organization_add_form_input_label_tooltip": "Le label est un texte court utilisé pour le filtrage et la navigation dans l'espace client.", + "zimbra_organization_add_form_input_label_helper": "{{ value }} caractères maximum.", + "zimbra_organization_add_success_message": "Votre demande d'ajout d'organisation a bien été prise en compte. Elle sera effective d'ici quelques instants.", + "zimbra_organization_add_error_message": "Votre demande d'ajout d'organisation n'a pas pu aboutir. {{ error }}", + "zimbra_organization_edit_success_message": "Votre demande de modification a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_organization_edit_error_message": "Votre demande de modification n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_it_IT.json new file mode 100644 index 000000000000..073e3fe0d842 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_it_IT.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confermare", + "zimbra_organization_add_modal_title": "Aggiungi un'organizzazione", + "zimbra_organization_add_modal_content_part1": "L'organizzazione rappresenta un insieme logico di domini e caselle email.", + "zimbra_organization_add_modal_content_part2": "Permette di definire le politiche di gestione raggruppate e precisare l'isolamento delle tue caselle email (limite della directory aziendale).", + "zimbra_organization_edit_modal_title": "Modificare l'organizzazione", + "zimbra_organization_add_form_input_mandatory": "I campi contrassegnati con un asterisco * sono obbligatori", + "zimbra_organization_add_form_input_name_title": "Nome", + "zimbra_organization_add_form_input_name_placeholder": "nome", + "zimbra_organization_add_form_input_name_error": "Campo obbligatorio Deve essere composto esclusivamente da caratteri alfanumerici.", + "zimbra_organization_add_form_input_label_title": "Label dell’organizzazione", + "zimbra_organization_add_form_input_label_placeholder": "label", + "zimbra_organization_add_form_input_label_error": "Campo obbligatorio Deve essere composto esclusivamente da caratteri alfanumerici. Massimo {{ value }} caratteri.", + "zimbra_organization_add_form_input_label_tooltip": "Il label è un testo breve utilizzato per filtrare e navigare nello Spazio Cliente.", + "zimbra_organization_add_form_input_label_helper": "{{ value }} caratteri massimo.", + "zimbra_organization_add_success_message": "La tua richiesta di aggiunta dell'organizzazione è stata presa in carico. Sarà effettiva entro pochi minuti.", + "zimbra_organization_add_error_message": "La tua richiesta di aggiunta dell'organizzazione non è andata a buon fine: {{ error }}", + "zimbra_organization_edit_success_message": "La tua richiesta di modifica è stata presa in carico. Sarà eseguita entro pochi minuti.", + "zimbra_organization_edit_error_message": "La tua richiesta di modifica non è andata a buon fine: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pl_PL.json new file mode 100644 index 000000000000..d22860eb9945 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pl_PL.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Zatwierdź", + "zimbra_organization_add_modal_title": "Dodaj organizację", + "zimbra_organization_add_modal_content_part1": "Organizacja to logiczne połączenie domen i skrzynek e-mail.", + "zimbra_organization_add_modal_content_part2": "Pozwala na zdefiniowanie zasad zarządzania grupą i na odizolowanie skrzynek e-mail (limit firmowej książki adresowej).", + "zimbra_organization_edit_modal_title": "Zmodyfikuj organizację", + "zimbra_organization_add_form_input_mandatory": "Pola oznaczone gwiazdką * są obowiązkowe", + "zimbra_organization_add_form_input_name_title": "Nazwa", + "zimbra_organization_add_form_input_name_placeholder": "nazwa", + "zimbra_organization_add_form_input_name_error": "Pole obowiązkowe Może składać się wyłącznie ze znaków alfanumerycznych.", + "zimbra_organization_add_form_input_label_title": "Etykieta organizacji", + "zimbra_organization_add_form_input_label_placeholder": "etykieta", + "zimbra_organization_add_form_input_label_error": "Pole obowiązkowe Może składać się wyłącznie ze znaków alfanumerycznych. Maksymalna liczba znaków: {{value}} ", + "zimbra_organization_add_form_input_label_tooltip": "Etykieta to krótki tekst używany do filtrowania i nawigacji w Panelu klienta.", + "zimbra_organization_add_form_input_label_helper": "Maksymalna liczba znaków: {{value}}", + "zimbra_organization_add_success_message": "Dyspozycja dodania organizacji została przyjęta. Zostanie wykonana w ciągu kilku minut.", + "zimbra_organization_add_error_message": "Dodanie organizacji nie powiodło się. {{error}}", + "zimbra_organization_edit_success_message": "Dyspozycja modyfikacji została przyjęta. Zostanie wykonana w ciągu kilku minut.", + "zimbra_organization_edit_error_message": "Modyfikacja nie powiodła się. {{error}}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pt_PT.json new file mode 100644 index 000000000000..538b2d2d8bd4 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/addAndEdit/Messages_pt_PT.json @@ -0,0 +1,20 @@ +{ + "zimbra_organization_add": "Confirmar", + "zimbra_organization_add_modal_title": "Adicionar uma organização", + "zimbra_organization_add_modal_content_part1": "A organização representa um agrupamento lógico de domínios e caixas de email.", + "zimbra_organization_add_modal_content_part2": "Permite definir políticas de gestão agrupadas e define o isolamento das suas caixas de email (limite do diretório empresarial).", + "zimbra_organization_edit_modal_title": "Modificar a organização", + "zimbra_organization_add_form_input_mandatory": "Os campos marcados com um asterisco são de preenchimento obrigatório", + "zimbra_organization_add_form_input_name_title": "Nome", + "zimbra_organization_add_form_input_name_placeholder": "Nome", + "zimbra_organization_add_form_input_name_error": "Campos obrigatórios. Devem ser compostos unicamente por caracteres alfanuméricos.", + "zimbra_organization_add_form_input_label_title": "Etiqueta da organização", + "zimbra_organization_add_form_input_label_placeholder": "etiqueta", + "zimbra_organization_add_form_input_label_error": "Campos obrigatórios. Devem ser compostos unicamente por caracteres alfanuméricos. Máximo de {{ value }} caracteres.", + "zimbra_organization_add_form_input_label_tooltip": "A etiqueta é um texto curto utilizado para a filtragem e a navegação na Área de Cliente.", + "zimbra_organization_add_form_input_label_helper": "Máximo de {{ value }} caracteres.", + "zimbra_organization_add_success_message": "O seu pedido de adição de uma organização foi registado. Será aplicado dentro de alguns instantes.", + "zimbra_organization_add_error_message": "Não foi possível adicionar uma organização. {{ error }}", + "zimbra_organization_edit_success_message": "O seu pedido de modificação foi registado. Será executado dentro de alguns instantes.", + "zimbra_organization_edit_error_message": "Não foi possível realizar o pedido de modificação. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_en_GB.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_en_GB.json new file mode 100644 index 000000000000..4fa8bfbbd8b8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_en_GB.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Delete", + "zimbra_organization_delete_modal_title": "Delete organisation", + "zimbra_organization_delete_modal_content": "Are you sure you want to delete the organisation?", + "zimbra_organization_delete_modal_message_disabled_part1": "There is at least one domain still linked to this organisation.", + "zimbra_organization_delete_modal_message_disabled_part2": "Please delete the linked domains before deleting your organisation.", + "zimbra_organization_delete_success_message": "Your deletion request has been processed. It will be executed in a few moments.", + "zimbra_organization_delete_error_message": "Unable to submit your deletion request. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_es_ES.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_es_ES.json new file mode 100644 index 000000000000..a4317af3e1c8 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_es_ES.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Eliminar", + "zimbra_organization_delete_modal_title": "Eliminar la organización", + "zimbra_organization_delete_modal_content": "¿Seguro que quiere eliminar la organización?", + "zimbra_organization_delete_modal_message_disabled_part1": "Hay al menos un dominio asociado a esta organización.", + "zimbra_organization_delete_modal_message_disabled_part2": "Por favor, elimine los dominios asociados antes de eliminar la organización.", + "zimbra_organization_delete_success_message": "La solicitud de eliminación se ha enviado. Se ejecutará en unos instantes.", + "zimbra_organization_delete_error_message": "Se ha producido un error al enviar la solicitud de eliminación: {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_CA.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_CA.json new file mode 100644 index 000000000000..f1815a6c94be --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_CA.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Supprimer", + "zimbra_organization_delete_modal_title": "Supprimer l'organisation", + "zimbra_organization_delete_modal_content": "Voulez-vous vraiment supprimer l'organisation ?", + "zimbra_organization_delete_modal_message_disabled_part1": "Au moins un domaine est encore associé à cette organisation.", + "zimbra_organization_delete_modal_message_disabled_part2": "Veuillez supprimer les domaines associés avant de supprimer votre organisation.", + "zimbra_organization_delete_success_message": "Votre demande de suppression a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_organization_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_FR.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_FR.json new file mode 100644 index 000000000000..f1815a6c94be --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_fr_FR.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Supprimer", + "zimbra_organization_delete_modal_title": "Supprimer l'organisation", + "zimbra_organization_delete_modal_content": "Voulez-vous vraiment supprimer l'organisation ?", + "zimbra_organization_delete_modal_message_disabled_part1": "Au moins un domaine est encore associé à cette organisation.", + "zimbra_organization_delete_modal_message_disabled_part2": "Veuillez supprimer les domaines associés avant de supprimer votre organisation.", + "zimbra_organization_delete_success_message": "Votre demande de suppression a bien été prise en compte. Elle sera exécutée d'ici quelques instants.", + "zimbra_organization_delete_error_message": "Votre demande de suppression n'a pas pu aboutir. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_it_IT.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_it_IT.json new file mode 100644 index 000000000000..40a7949b45b6 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_it_IT.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Eliminare", + "zimbra_organization_delete_modal_title": "Eliminare l'organizzazione", + "zimbra_organization_delete_modal_content": "Vuoi davvero eliminare l'organizzazione?", + "zimbra_organization_delete_modal_message_disabled_part1": "All'organizzazione è ancora associato almeno un dominio.", + "zimbra_organization_delete_modal_message_disabled_part2": "Elimina i domini associati prima di eliminare la tua organizzazione.", + "zimbra_organization_delete_success_message": "La richiesta di eliminazione è stata presa in carico correttamente Sarà eseguita entro pochi minuti.", + "zimbra_organization_delete_error_message": "La tua richiesta di eliminazione non è andata a buon fine. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pl_PL.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pl_PL.json new file mode 100644 index 000000000000..e5134d9163c5 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pl_PL.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Usuń", + "zimbra_organization_delete_modal_title": "Usuń organizację", + "zimbra_organization_delete_modal_content": "Czy na pewno chcesz usunąć organizację?", + "zimbra_organization_delete_modal_message_disabled_part1": "Co najmniej jedna domena jest nadal powiązana z tą organizacją.", + "zimbra_organization_delete_modal_message_disabled_part2": "Przed usunięciem organizacji usuń powiązane domeny.", + "zimbra_organization_delete_success_message": "Dyspozycja usunięcia została przyjęta. Zostanie wykonana w ciągu kilku minut.", + "zimbra_organization_delete_error_message": "Usunięcie nie powiodło się. {{error}}" +} diff --git a/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pt_PT.json b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pt_PT.json new file mode 100644 index 000000000000..3c0f88572092 --- /dev/null +++ b/packages/manager/apps/zimbra/public/translations/organizations/delete/Messages_pt_PT.json @@ -0,0 +1,9 @@ +{ + "zimbra_organization_delete": "Eliminar", + "zimbra_organization_delete_modal_title": "Eliminar a organização", + "zimbra_organization_delete_modal_content": "Quer mesmo eliminar a organização?", + "zimbra_organization_delete_modal_message_disabled_part1": "Ainda há pelo menos um domínio associado a esta organização.", + "zimbra_organization_delete_modal_message_disabled_part2": "Elimine os domínios associados antes de suprimir a sua organização.", + "zimbra_organization_delete_success_message": "O pedido de eliminação foi registado. Será executado dentro de alguns instantes.", + "zimbra_organization_delete_error_message": "O seu pedido de eliminação não foi bem-sucedido. {{ error }}" +} diff --git a/packages/manager/apps/zimbra/src/api/GET/apiv2/services.ts b/packages/manager/apps/zimbra/src/api/GET/apiv2/services.ts deleted file mode 100644 index 2a8a4dc22a55..000000000000 --- a/packages/manager/apps/zimbra/src/api/GET/apiv2/services.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { apiClient } from '@ovh-ux/manager-core-api'; - -type Response = unknown; - -export type GetZimbraPlatformParams = { - /** Pagination cursor */ - 'X-Pagination-Cursor': string; - /** Add extra information about resources in output */ - details: boolean; - /** Filter on the readOnly attribute */ - readOnly: boolean; -}; - -export const getZimbraPlatformQueryKey = ['get//zimbra/platform']; - -/** - * : Retrieve platform - */ -export const getZimbraPlatform = async ( - params: GetZimbraPlatformParams, -): Promise => - apiClient.v2.get('/zimbra/platform', { data: params }); diff --git a/packages/manager/apps/zimbra/src/api/_mock_/account.ts b/packages/manager/apps/zimbra/src/api/_mock_/account.ts new file mode 100644 index 000000000000..edfb72d6eb72 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/_mock_/account.ts @@ -0,0 +1,81 @@ +import { AccountType } from '@/api/account'; + +export const accountMock: AccountType[] = [ + { + checksum: 'string', + currentState: { + contactInformation: { + city: 'string', + company: 'string', + country: 'string', + faxNumber: 'string', + mobileNumber: 'string', + office: 'string', + phoneNumber: 'string', + postcode: 'string', + profession: 'string', + service: 'string', + street: 'string', + }, + createdAt: '2024-07-09T13:27:12.775Z', + description: 'string', + detailedStatus: [ + { + details: 'string', + link: 'string', + status: 'BLOCKEDFORSPAM', + }, + ], + displayName: 'string', + domainId: '19097ad4-2870-4000-8bb0-470f414b0301', + email: 'string', + firstName: 'string', + hideInGal: false, + lastConnectionAt: '2024-07-09T13:27:12.775Z', + lastName: 'string', + offer: 'BUSINESS', + organizationId: '19097ad4-2870-4000-82b3-b71a147bc580', + organizationLabel: 'string', + quota: { + available: 0, + used: 0, + }, + updatedAt: '2024-07-09T13:27:12.775Z', + }, + currentTasks: [ + { + id: '19097ad4-2870-4000-8bed-ecab3a061780', + link: 'string', + status: 'ERROR', + type: 'string', + }, + ], + id: '19097ad4-2880-4000-8b03-9d110f0b8f80', + resourceStatus: 'CREATING', + targetSpec: { + contactInformation: { + city: 'string', + company: 'string', + country: 'string', + faxNumber: 'string', + mobileNumber: 'string', + office: 'string', + phoneNumber: 'string', + postcode: 'string', + profession: 'string', + service: 'string', + street: 'string', + }, + description: 'string', + displayName: 'string', + email: 'string', + firstName: 'string', + hideInGal: false, + lastName: 'string', + quota: { + available: 0, + used: 0, + }, + }, + }, +]; diff --git a/packages/manager/apps/zimbra/src/api/_mock_/domain.ts b/packages/manager/apps/zimbra/src/api/_mock_/domain.ts new file mode 100644 index 000000000000..c07548d0f208 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/_mock_/domain.ts @@ -0,0 +1,97 @@ +import { DomainType } from '@/api/domain'; + +export const domainMock: DomainType[] = [ + { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + resourceStatus: 'READY', + checksum: 'string', + targetSpec: { + organizationId: '00000000-0000-0000-0000-000000000000', + }, + currentState: { + organizationId: '00000000-0000-0000-0000-000000000000', + name: 'NormalDomain', + status: 'READY', + createdAt: '2024-04-12T12:27:47.213Z', + updatedAt: '2024-04-12T12:27:47.213Z', + organizationLabel: 'ToyStory', + cnameToCheck: '', + accountsStatistics: [ + { + offer: 'STARTER', + configuredAccountsCount: 0, + availableAccountsCount: 4, + }, + ], + }, + currentTasks: [ + { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + type: 'string', + link: 'string', + }, + ], + }, + { + id: '3fa91f64-0000-4562-b3fc-000000000000', + resourceStatus: 'READY', + checksum: 'string', + targetSpec: { + organizationId: '00000000-0000-0000-0000-000000000000', + }, + currentState: { + organizationId: '00000000-0000-0000-0000-000000000000', + name: 'AwesomeDomain', + status: 'READY', + createdAt: '2024-04-12T12:27:47.213Z', + updatedAt: '2024-04-12T12:27:47.213Z', + organizationLabel: 'Magret', + cnameToCheck: '', + accountsStatistics: [ + { + offer: 'STARTER', + configuredAccountsCount: 0, + availableAccountsCount: 4, + }, + ], + }, + currentTasks: [ + { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + type: 'string', + link: 'string', + }, + ], + }, + { + id: '3fa91f64-0000-4562-b2fc-000000000000', + resourceStatus: 'READY', + checksum: 'string', + targetSpec: { + organizationId: '00000000-0000-0000-0000-000000000001', + }, + currentState: { + organizationId: '00000000-0000-0000-0000-000000000001', + name: 'BlablaDomain', + status: 'READY', + createdAt: '2024-04-12T12:27:47.213Z', + updatedAt: '2024-04-12T12:27:47.213Z', + organizationLabel: 'Canard', + cnameToCheck: '', + accountsStatistics: [ + { + offer: 'STARTER', + configuredAccountsCount: 0, + availableAccountsCount: 4, + }, + ], + }, + currentTasks: [ + { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + type: 'string', + link: 'string', + }, + ], + }, +]; diff --git a/packages/manager/apps/zimbra/src/api/_mock_/index.ts b/packages/manager/apps/zimbra/src/api/_mock_/index.ts new file mode 100644 index 000000000000..e2e0b17eda9e --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/_mock_/index.ts @@ -0,0 +1,4 @@ +export * from './platform'; +export * from './organization'; +export * from './domain'; +export * from './account'; diff --git a/packages/manager/apps/zimbra/src/api/_mock_/organization.ts b/packages/manager/apps/zimbra/src/api/_mock_/organization.ts new file mode 100644 index 000000000000..cd0266c3b123 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/_mock_/organization.ts @@ -0,0 +1,97 @@ +import { OrganizationType } from '@/api/organization'; + +export const organizationDetailMock: OrganizationType = { + checksum: 'string', + currentState: { + accountsStatistics: [ + { + configuredAccountsCount: 0, + offer: 'BUSINESS', + availableAccountsCount: 4, + }, + ], + createdAt: '2024-06-21T14:52:43.601Z', + description: 'description', + label: 'label', + name: 'name', + storageConsumed: 0, + updatedAt: '2024-06-21T14:52:43.601Z', + }, + currentTasks: [ + { + id: '1903b491-4d10-4000-8763-1f9a992bbf01', + link: 'string', + status: 'ERROR', + type: 'string', + }, + ], + id: '1903b491-4d10-4000-8b70-f474d1abe601', + resourceStatus: 'CREATING', + targetSpec: { + description: 'description', + label: 'label', + name: 'name', + }, +}; + +export const organizationListMock: OrganizationType[] = [ + { + checksum: 'string', + currentState: { + accountsStatistics: [ + { + configuredAccountsCount: 0, + offer: 'BUSINESS', + availableAccountsCount: 4, + }, + ], + createdAt: '2024-06-21T14:52:43.601Z', + description: 'description', + label: 'label', + name: 'name', + storageConsumed: 0, + updatedAt: '2024-06-21T14:52:43.601Z', + }, + currentTasks: [ + { + id: '1903b491-4d10-4000-8763-1f9a992bbf01', + link: 'string', + status: 'ERROR', + type: 'string', + }, + ], + id: '1903b491-4d10-4000-8b70-f474d1abe601', + resourceStatus: 'CREATING', + targetSpec: { + description: 'description', + label: 'label', + name: 'name', + }, + }, + { + checksum: 'string', + currentState: { + accountsStatistics: [ + { + configuredAccountsCount: 3, + offer: 'READY', + availableAccountsCount: 4, + }, + ], + createdAt: '2024-06-01T14:52:43.601Z', + description: 'description2', + label: 'label2', + name: 'name2', + storageConsumed: 0, + updatedAt: '2024-06-02T14:52:43.601Z', + }, + currentTasks: [], + id: '1903b491-4d10-4000-8b70-f474d1abe602', + resourceStatus: 'READY', + targetSpec: { + description: 'description2', + label: 'label2', + name: 'name2', + }, + }, +]; diff --git a/packages/manager/apps/zimbra/src/api/_mock_/platform.ts b/packages/manager/apps/zimbra/src/api/_mock_/platform.ts new file mode 100644 index 000000000000..f7980cf8b737 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/_mock_/platform.ts @@ -0,0 +1,26 @@ +import { ZimbraPlatformType } from '@/api/platform'; + +export const platformMock: ZimbraPlatformType[] = [ + { + checksum: 'c6022a95d9ce258d6d534ec355bec6c9', + currentState: { + accountsStatistics: [], + description: 'some description', + name: 'Manager Team platform', + numberOfOrganizations: 0, + quota: 1, + }, + currentTasks: [], + id: '00000000-0000-0000-0000-000000000001', + resourceStatus: 'READY', + targetSpec: { + description: 'some description', + name: 'Manager Team platform', + }, + iam: { + id: 'ce6c1c21-565a-42c3-b1fd-53d9d09c7395', + urn: + 'urn:v1:labeu:resource:zimbraPlatform:00000000-0000-0000-0000-000000000001', + }, + }, +]; diff --git a/packages/manager/apps/zimbra/src/api/account/api.ts b/packages/manager/apps/zimbra/src/api/account/api.ts new file mode 100644 index 000000000000..1384586fe417 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/account/api.ts @@ -0,0 +1,70 @@ +import { v2 } from '@ovh-ux/manager-core-api'; +import { AccountBodyParamsType, AccountType } from './type'; +import { getApiPath } from '../utils/apiPath'; + +// GET + +export const getZimbraPlatformAccount = async ( + platformId: string, + queryParameters?: { + organizationId?: string; + domainId?: string; + }, +) => { + const params = new URLSearchParams(queryParameters).toString(); + const queryString = params ? `?${params}` : ''; + const { data } = await v2.get( + `${getApiPath(platformId)}account${queryString}`, + ); + return data; +}; + +export const getZimbraPlatformAccountDetail = async ( + platformId: string, + accountId: string, +) => { + const { data } = await v2.get( + `${getApiPath(platformId)}account/${accountId}`, + ); + return data; +}; + +// POST + +export const postZimbraPlatformAccount = async ( + platformId: string, + params: AccountBodyParamsType, +) => { + const { data } = await v2.post(`${getApiPath(platformId)}account`, { + targetSpec: { ...params, offer: 'STARTER' }, // offer hardcoded for beta scope + }); + return data; +}; + +// PUT + +export const putZimbraPlatformAccount = async ( + platformId: string, + accountId: string, + params: AccountBodyParamsType, +) => { + const { data } = await v2.put( + `${getApiPath(platformId)}account/${accountId}`, + { + targetSpec: params, + }, + ); + return data; +}; + +// DELETE + +export const deleteZimbraPlatformAccount = async ( + platformId: string, + accountId: string, +) => { + const { data } = await v2.delete( + `${getApiPath(platformId)}account/${accountId}`, + ); + return data; +}; diff --git a/packages/manager/apps/zimbra/src/api/account/index.ts b/packages/manager/apps/zimbra/src/api/account/index.ts new file mode 100644 index 000000000000..8eb7e0eb2cca --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/account/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './key'; +export * from './type'; diff --git a/packages/manager/apps/zimbra/src/api/account/key.ts b/packages/manager/apps/zimbra/src/api/account/key.ts new file mode 100644 index 000000000000..64bad2ef1b82 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/account/key.ts @@ -0,0 +1,16 @@ +export const getZimbraPlatformAccountQueryKey = ( + platformId: string, + queryParameters?: { + organizationId?: string; + domainId?: string; + }, +) => { + const params = new URLSearchParams(queryParameters).toString(); + const queryString = params ? `?${params}` : ''; + return [`get/zimbra/platform/${platformId}/account${queryString}`]; +}; + +export const getZimbraPlatformAccountDetailQueryKey = ( + platformId: string, + accountId?: string, +) => [`get/zimbra/platform/${platformId}/account/${accountId}`]; diff --git a/packages/manager/apps/zimbra/src/api/account/type.ts b/packages/manager/apps/zimbra/src/api/account/type.ts new file mode 100644 index 000000000000..66f87d421086 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/account/type.ts @@ -0,0 +1,101 @@ +import { ResourceStatus } from '../api.type'; + +export type AccountType = { + checksum: string; + currentState: { + contactInformation: { + city: string; + company: string; + country: string; + faxNumber: string; + mobileNumber: string; + office: string; + phoneNumber: string; + postcode: string; + profession: string; + service: string; + street: string; + }; + createdAt: string; + description: string; + detailedStatus: { + details: string; + link: string; + status: string; + }[]; + displayName: string; + domainId: string; + email: string; + firstName: string; + hideInGal: boolean; + lastConnectionAt: string; + lastName: string; + organizationId: string; + organizationLabel: string; + offer: string; + quota: { + available: number; + used: number; + }; + updatedAt: string; + }; + currentTasks: { + id: string; + link: string; + status: 'ERROR' | '...'; + type: string; + }[]; + id: string; + resourceStatus: keyof typeof ResourceStatus; + targetSpec: { + contactInformation: { + city: string; + company: string; + country: string; + faxNumber: string; + mobileNumber: string; + office: string; + phoneNumber: string; + postcode: string; + profession: string; + service: string; + street: string; + }; + description: string; + displayName: string; + email: string; + firstName: string; + hideInGal: boolean; + lastName: string; + quota: { + available: number; + used: number; + }; + }; +}; + +export type AccountBodyParamsType = { + contactInformation?: { + city?: string; + company?: string; + country?: string; + faxNumber?: string; + mobileNumber?: string; + office?: string; + phoneNumber?: string; + postcode?: string; + profession?: string; + service?: string; + street?: string; + }; + description?: string; + displayName?: string; + email: string; + firstName?: string; + forceChangePasswordAfterLogin?: boolean; + hideInGal?: boolean; + lastName?: string; + password?: string; + responder?: string; + offer?: string; +}; diff --git a/packages/manager/apps/zimbra/src/api/api.type.ts b/packages/manager/apps/zimbra/src/api/api.type.ts new file mode 100644 index 000000000000..be74b21e6eab --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/api.type.ts @@ -0,0 +1,29 @@ +export type AccountStatistics = { + offer: string; + configuredAccountsCount: number; + availableAccountsCount: number; +}; + +export type ErrorResponse = { + response: { + status: number; + data: { message: string }; + }; +}; + +export type TaskErrorMessage = { + message: string; +}; + +export type TaskProgressStatus = { + name: string; + status: string; +}; + +export enum ResourceStatus { + CREATING = 'CREATING', + DELETING = 'DELETING', + ERROR = 'ERROR', + READY = 'READY', + UPDATING = 'UPDATING', +} diff --git a/packages/manager/apps/zimbra/src/api/domain/api.ts b/packages/manager/apps/zimbra/src/api/domain/api.ts new file mode 100644 index 000000000000..367034f24a8a --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/domain/api.ts @@ -0,0 +1,46 @@ +import { v2, v6 } from '@ovh-ux/manager-core-api'; +import { DomainBodyParamsType, DomainType } from './type'; +import { getApiPath } from '../utils/apiPath'; + +// GET + +export const getZimbraPlatformDomains = async ( + platformId: string, + organizationId?: string, +) => { + const { data } = await v2.get( + `${getApiPath(platformId)}domain${ + organizationId ? `?organizationId=${organizationId}` : '' + }`, + ); + return data; +}; + +export const getDomainsZoneList = async () => { + const { data } = await v6.get('/domain/zone'); + return data; +}; + +// POST + +export const postZimbraDomain = async ( + platformId: string, + params: DomainBodyParamsType, +) => { + const { data } = await v2.post(`${getApiPath(platformId)}domain`, { + targetSpec: params, + }); + return data; +}; + +// DELETE + +export const deleteZimbraPlatformDomain = async ( + platformId: string, + domainId: string, +) => { + const { data } = await v2.delete( + `${getApiPath(platformId)}domain/${domainId}`, + ); + return data; +}; diff --git a/packages/manager/apps/zimbra/src/api/domain/index.ts b/packages/manager/apps/zimbra/src/api/domain/index.ts new file mode 100644 index 000000000000..8eb7e0eb2cca --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/domain/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './key'; +export * from './type'; diff --git a/packages/manager/apps/zimbra/src/api/domain/key.ts b/packages/manager/apps/zimbra/src/api/domain/key.ts new file mode 100644 index 000000000000..d042350933ef --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/domain/key.ts @@ -0,0 +1,8 @@ +export const getZimbraPlatformDomainsQueryKey = ( + platformId: string, + organizationId?: string, +) => [ + `get/zimbra/platform/${platformId}/domain?organizationId=${organizationId}`, +]; + +export const getDomainsZoneListQueryKey = ['get/domain/zone']; diff --git a/packages/manager/apps/zimbra/src/api/domain/type.ts b/packages/manager/apps/zimbra/src/api/domain/type.ts new file mode 100644 index 000000000000..6a42cd367236 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/domain/type.ts @@ -0,0 +1,31 @@ +import { AccountStatistics, ResourceStatus } from '../api.type'; + +export type DomainBodyParamsType = { + organizationId?: string; + name?: string; +}; + +export type DomainType = { + checksum: string; + currentState: { + cnameToCheck: string; + createdAt: string; + name: string; + organizationId: string; + organizationLabel: string; + status: keyof typeof ResourceStatus; + updatedAt: string; + accountsStatistics: AccountStatistics[]; + }; + currentTasks: Array<{ + id: string; + link: string; + status?: keyof typeof ResourceStatus; + type: string; + }>; + id: string; + resourceStatus: keyof typeof ResourceStatus; + targetSpec: { + organizationId: string; + }; +}; diff --git a/packages/manager/apps/zimbra/src/api/index.ts b/packages/manager/apps/zimbra/src/api/index.ts deleted file mode 100644 index 51ec1c349125..000000000000 --- a/packages/manager/apps/zimbra/src/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './GET/apiv2/services'; diff --git a/packages/manager/apps/zimbra/src/api/organization/api.ts b/packages/manager/apps/zimbra/src/api/organization/api.ts new file mode 100644 index 000000000000..bbc86824410e --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/organization/api.ts @@ -0,0 +1,60 @@ +import { v2 } from '@ovh-ux/manager-core-api'; +import { OrganizationBodyParamsType, OrganizationType } from './type'; +import { getApiPath } from '../utils/apiPath'; + +// GET + +export const getZimbraPlatformOrganization = async (platformId: string) => { + const { data } = await v2.get( + `${getApiPath(platformId)}organization`, + ); + return data; +}; + +export const getZimbraPlatformOrganizationDetails = async ( + platformId: string, + organizationId: string, +) => { + const { data } = await v2.get( + `${getApiPath(platformId)}organization/${organizationId}`, + ); + return data; +}; + +// POST + +export const postZimbraPlatformOrganization = async ( + platformId: string, + params: OrganizationBodyParamsType, +) => { + const { data } = await v2.post(`${getApiPath(platformId)}organization`, { + targetSpec: params, + }); + return data; +}; + +// PUT + +export const putZimbraPlatformOrganization = async ( + platformId: string, + organizationId: string, + params: OrganizationBodyParamsType, +) => { + const { data } = await v2.put( + `${getApiPath(platformId)}organization/${organizationId}`, + { targetSpec: params }, + ); + return data; +}; + +// DELETE + +export const deleteZimbraPlatformOrganization = async ( + platformId: string, + organizationId: string, +) => { + const { data } = await v2.delete( + `${getApiPath(platformId)}organization/${organizationId}`, + ); + return data; +}; diff --git a/packages/manager/apps/zimbra/src/api/organization/index.ts b/packages/manager/apps/zimbra/src/api/organization/index.ts new file mode 100644 index 000000000000..8eb7e0eb2cca --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/organization/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './key'; +export * from './type'; diff --git a/packages/manager/apps/zimbra/src/api/organization/key.ts b/packages/manager/apps/zimbra/src/api/organization/key.ts new file mode 100644 index 000000000000..46bc996b65e9 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/organization/key.ts @@ -0,0 +1,8 @@ +export const getZimbraPlatformOrganizationQueryKey = (platformId: string) => [ + `get/zimbra/platform/${platformId}/organization`, +]; + +export const getZimbraPlatformOrganizationDetailsQueryKey = ( + platformId: string, + organizationId: string, +) => [`get/zimbra/platform/${platformId}/organization/${organizationId}`]; diff --git a/packages/manager/apps/zimbra/src/api/organization/type.ts b/packages/manager/apps/zimbra/src/api/organization/type.ts new file mode 100644 index 000000000000..ad92162f4d68 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/organization/type.ts @@ -0,0 +1,33 @@ +import { AccountStatistics } from '../api.type'; + +export type OrganizationType = { + id: string; + resourceStatus: string; + checksum: string; + targetSpec: { + name: string; + description: string; + label: string; + }; + currentState: { + name: string; + description: string; + label: string; + storageConsumed: number; + updatedAt: string; + createdAt: string; + accountsStatistics: AccountStatistics[]; + }; + currentTasks: Array<{ + id: string; + link: string; + status: string; + type: string; + }>; +}; + +export type OrganizationBodyParamsType = { + description?: string; + label?: string; + name?: string; +}; diff --git a/packages/manager/apps/zimbra/src/api/platform/api.ts b/packages/manager/apps/zimbra/src/api/platform/api.ts new file mode 100644 index 000000000000..f589eccd3f61 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/platform/api.ts @@ -0,0 +1,7 @@ +import { v2 } from '@ovh-ux/manager-core-api'; +import { ZimbraPlatformType } from './type'; + +export const getZimbraPlatformList = async () => { + const { data } = await v2.get('/zimbra/platform'); + return data; +}; diff --git a/packages/manager/apps/zimbra/src/api/platform/index.ts b/packages/manager/apps/zimbra/src/api/platform/index.ts new file mode 100644 index 000000000000..8eb7e0eb2cca --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/platform/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './key'; +export * from './type'; diff --git a/packages/manager/apps/zimbra/src/api/platform/key.ts b/packages/manager/apps/zimbra/src/api/platform/key.ts new file mode 100644 index 000000000000..0d35430831e9 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/platform/key.ts @@ -0,0 +1 @@ +export const getZimbraPlatformListQueryKey = ['get/zimbra/platform']; diff --git a/packages/manager/apps/zimbra/src/api/platform/type.ts b/packages/manager/apps/zimbra/src/api/platform/type.ts new file mode 100644 index 000000000000..2db0a95d9273 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/platform/type.ts @@ -0,0 +1,27 @@ +import { AccountStatistics } from '../api.type'; + +export type ZimbraPlatformType = { + id: string; + resourceStatus: string; + checksum: string; + targetSpec: { + name: string; + description: string; + }; + currentState: { + name: string; + description: string; + numberOfOrganizations: number; + accountsStatistics: AccountStatistics[]; + quota: number; + }; + currentTasks: Array<{ + id: string; + type: string; + link: string; + }>; + iam: { + id: string; + urn: string; + }; +}; diff --git a/packages/manager/apps/zimbra/src/api/task/api.ts b/packages/manager/apps/zimbra/src/api/task/api.ts new file mode 100644 index 000000000000..335f47e1eddd --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/task/api.ts @@ -0,0 +1,15 @@ +import { v2 } from '@ovh-ux/manager-core-api'; +import { TaskType } from './type'; +import { getApiPath } from '../utils/apiPath'; + +export const getZimbraPlatformTask = async ( + platformId: string, + organizationId?: string, +) => { + const { data } = await v2.get( + `${getApiPath(platformId)}task${ + organizationId ? `?organizationId=${organizationId}` : '' + }`, + ); + return data; +}; diff --git a/packages/manager/apps/zimbra/src/api/task/index.ts b/packages/manager/apps/zimbra/src/api/task/index.ts new file mode 100644 index 000000000000..8eb7e0eb2cca --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/task/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './key'; +export * from './type'; diff --git a/packages/manager/apps/zimbra/src/api/task/key.ts b/packages/manager/apps/zimbra/src/api/task/key.ts new file mode 100644 index 000000000000..9abf18cae994 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/task/key.ts @@ -0,0 +1,6 @@ +export const getZimbraPlatformTaskQueryKey = ( + platformId: string, + organizationId?: string, +) => [ + `get/zimbra/platform/${platformId}/task?organizationId=${organizationId}`, +]; diff --git a/packages/manager/apps/zimbra/src/api/task/type.ts b/packages/manager/apps/zimbra/src/api/task/type.ts new file mode 100644 index 000000000000..8e62ad00ecb3 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/task/type.ts @@ -0,0 +1,15 @@ +import { TaskErrorMessage, TaskProgressStatus } from '../api.type'; + +export type TaskType = { + createdAt: string; + errors: TaskErrorMessage[]; + finishedAt: string; + id: string; + link: string; + message: string; + progress: TaskProgressStatus[]; + startedAt: string; + status: string; + type: string; + updatedAt: string; +}; diff --git a/packages/manager/apps/zimbra/src/api/utils/apiPath.ts b/packages/manager/apps/zimbra/src/api/utils/apiPath.ts new file mode 100644 index 000000000000..874826a4a823 --- /dev/null +++ b/packages/manager/apps/zimbra/src/api/utils/apiPath.ts @@ -0,0 +1,2 @@ +export const getApiPath = (platformId: string) => + `/zimbra/platform/${platformId}/`; diff --git a/packages/manager/apps/zimbra/src/components/BadgeStatus.tsx b/packages/manager/apps/zimbra/src/components/BadgeStatus.tsx new file mode 100644 index 000000000000..f097c0413acf --- /dev/null +++ b/packages/manager/apps/zimbra/src/components/BadgeStatus.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OsdsChip } from '@ovhcloud/ods-components/react'; +import { ResourceStatus } from '@/api/api.type'; + +export type BadgeStatusProps = { + itemStatus: string; +}; + +export const BadgeStatus: React.FC = ({ itemStatus }) => { + const getStatusColor = (status: string) => { + switch (status) { + case ResourceStatus.READY: + return ODS_THEME_COLOR_INTENT.success; + case ResourceStatus.ERROR: + return ODS_THEME_COLOR_INTENT.error; + default: + return ODS_THEME_COLOR_INTENT.primary; + } + }; + + const statusColor = getStatusColor(itemStatus); + + return ( + + {itemStatus} + + ); +}; diff --git a/packages/manager/apps/zimbra/src/components/Breadcrumb/Breadcrumb.tsx b/packages/manager/apps/zimbra/src/components/Breadcrumb/Breadcrumb.tsx index 52e69daa607d..e4a6074561dd 100644 --- a/packages/manager/apps/zimbra/src/components/Breadcrumb/Breadcrumb.tsx +++ b/packages/manager/apps/zimbra/src/components/Breadcrumb/Breadcrumb.tsx @@ -2,7 +2,8 @@ import React from 'react'; import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { OsdsBreadcrumb } from '@ovhcloud/ods-components/react'; import { useTranslation } from 'react-i18next'; -import { urls } from './constants'; +import { urls } from '@/routes/routes.constants'; +import { useGenerateUrl, useOrganization } from '@/hooks'; export type BreadcrumbProps = { items?: { label: string; href?: string }[]; @@ -17,33 +18,44 @@ export const Breadcrumb: React.FC = ({ const { t } = useTranslation('dashboard'); const navigate = useNavigate(); const location = useLocation(); + const { data: organization, isLoading } = useOrganization(); - const overviewUrlValue = + const overviewUrlValue = useGenerateUrl( overviewUrl || - (serviceName ? urls.overview.replace(':serviceName', serviceName) : '/'); - - const activeTab = location.pathname.split('/')[2]; - const activeTabTranslation = t(activeTab); - return ( - navigate(urls.root), - }, - serviceName && { - label: serviceName, - onClick: () => navigate(overviewUrlValue), - }, - activeTab && { - label: t(activeTabTranslation), - onClick: () => navigate(location.pathname), - }, - ...items, - ].filter(Boolean)} - /> + (serviceName ? urls.overview.replace(':serviceName', serviceName) : '/'), + 'path', ); + const pathParts = location.pathname.split('/').filter(Boolean); + const breadcrumbParts = pathParts.slice(1); + const breadcrumbItems = [ + { + label: t('zimbra_dashboard_title'), + onClick: () => navigate(urls.root), + }, + ...(organization && !isLoading + ? [ + { + label: organization?.currentState.name, + onClick: () => navigate(overviewUrlValue), + }, + ] + : []), + ...breadcrumbParts.map((_, index) => { + const url = `/${pathParts + .slice(0, index + 2) + .join('/')}${location.search ?? ''}`; + const label = t( + `zimbra_dashboard_${breadcrumbParts.slice(0, index + 1).join('_')}`, + ); + return { + label, + onClick: () => navigate(url), + }; + }), + ...items, + ].filter(Boolean); + + return ; }; export default Breadcrumb; diff --git a/packages/manager/apps/zimbra/src/components/Error/Error.tsx b/packages/manager/apps/zimbra/src/components/Error/Error.tsx index 514170ba4793..d0766c637490 100644 --- a/packages/manager/apps/zimbra/src/components/Error/Error.tsx +++ b/packages/manager/apps/zimbra/src/components/Error/Error.tsx @@ -23,6 +23,7 @@ function getTrackingTypology(error: ErrorMessage) { const Errors: React.FC = ({ error }) => { const navigate = useNavigate(); const location = useLocation(); + const shell = useShell(); const { tracking, environment } = shell; const env = environment.getEnvironment(); diff --git a/packages/manager/apps/zimbra/src/components/LabelChip.tsx b/packages/manager/apps/zimbra/src/components/LabelChip.tsx new file mode 100644 index 000000000000..d78c5217b7bd --- /dev/null +++ b/packages/manager/apps/zimbra/src/components/LabelChip.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OsdsChip } from '@ovhcloud/ods-components/react'; +import { useNavigate, useLocation } from 'react-router-dom'; + +interface LabelChipProps { + id: string; + children: string; +} + +const LabelChip: React.FC = ({ id, children }) => { + const navigate = useNavigate(); + const location = useLocation(); + + const handleLinkClick = () => { + const searchParams = new URLSearchParams(location.search); + searchParams.set('organizationId', id); + if (location.pathname.includes('organization')) { + navigate(`..?organizationId=${id}`); + } else { + navigate({ + pathname: location.pathname, + search: searchParams.toString(), + }); + } + }; + + return ( + + {children} + + ); +}; + +export default LabelChip; diff --git a/packages/manager/apps/zimbra/src/components/Modals/Modal.tsx b/packages/manager/apps/zimbra/src/components/Modals/Modal.tsx new file mode 100644 index 000000000000..fdef3a13af31 --- /dev/null +++ b/packages/manager/apps/zimbra/src/components/Modals/Modal.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import { + OsdsButton, + OsdsModal, + OsdsSpinner, +} from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { ODS_BUTTON_VARIANT, ODS_SPINNER_MODE } from '@ovhcloud/ods-components'; + +export interface ButtonType { + testid?: string; + action: () => void; + label: string; + disabled?: boolean; + color?: ODS_THEME_COLOR_INTENT; + variant?: ODS_BUTTON_VARIANT; +} + +export interface ModalProps { + title?: string; + color?: ODS_THEME_COLOR_INTENT; + dismissible?: boolean; + isLoading?: boolean; + onDismissible?: () => void; + children?: React.ReactElement; + primaryButton?: ButtonType; + secondaryButton?: ButtonType; +} + +const Modal: React.FC = ({ + title, + color, + dismissible, + onDismissible, + isLoading, + primaryButton, + secondaryButton, + children, +}) => { + return ( + + {!isLoading &&
{children}
} + {isLoading && ( +
+ +
+ )} + + {secondaryButton && ( + + {secondaryButton.label} + + )} + {primaryButton && ( + + {primaryButton.label} + + )} +
+ ); +}; + +export default Modal; diff --git a/packages/manager/apps/zimbra/src/components/TileBlock.tsx b/packages/manager/apps/zimbra/src/components/TileBlock.tsx new file mode 100644 index 000000000000..58aedb8f5d3b --- /dev/null +++ b/packages/manager/apps/zimbra/src/components/TileBlock.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { OsdsText, OsdsDivider } from '@ovhcloud/ods-components/react'; +import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; + +export type TileBlockProps = { + label: string; +}; + +export const TileBlock: React.FC> = ({ + label, + children, +}) => ( +
+ + + {label} + + + {children} + +
+); diff --git a/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/Dashboard.tsx b/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/Dashboard.tsx index 447b5b9cd272..1637830438a8 100644 --- a/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/Dashboard.tsx +++ b/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/Dashboard.tsx @@ -1,61 +1,90 @@ -import React from 'react'; -import { Outlet, useResolvedPath } from 'react-router-dom'; +import React /* useContext */ from 'react'; +import { + Outlet, + useResolvedPath, + useLocation, + useParams, +} from 'react-router-dom'; import { DashboardLayout, - DashboardLayoutProps, - GuideButton, - GuideItem, + /* GuideButton, + GuideItem, */ } from '@ovh-ux/manager-react-components'; -import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; + +// import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; import { useTranslation } from 'react-i18next'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import TabsPanel, { TabItemProps } from './TabsPanel'; import Breadcrumb from '@/components/Breadcrumb/Breadcrumb'; -import TabsPanel from './TabsPanel'; +// import { GUIDES_LIST } from '@/guides.constants'; +import { urls } from '@/routes/routes.constants'; import './Dashboard.scss'; -export const Dashboard: React.FC = () => { +export const Dashboard: React.FC = () => { + const { platformId } = useParams(); const { t } = useTranslation('dashboard'); + // const context = useContext(ShellContext); + // const { ovhSubsidiary } = context.environment.getUser(); + const location = useLocation(); + const basePath = useResolvedPath('').pathname; - const guideItems: GuideItem[] = [ + /* const guideItems: GuideItem[] = [ { id: 1, - href: 'https://www.ovh.com', + href: `${GUIDES_LIST.administrator_guide.url[ovhSubsidiary] || + GUIDES_LIST.administrator_guide.url.DEFAULT}`, target: OdsHTMLAnchorElementTarget._blank, - label: t('guides_title_1'), + label: t('zimbra_dashboard_administrator_guide'), }, - ]; + ]; */ - const tabsList = [ + const params = new URLSearchParams(location.search); + const selectedOrganizationId = params.get('organizationId'); + function computePathMatchers(routes: string[]) { + return routes.map( + (path) => new RegExp(path.replace(':serviceName', platformId)), + ); + } + const tabsList: TabItemProps[] = [ { name: 'general_informations', - title: t('general_informations'), - to: useResolvedPath('').pathname, + title: t('zimbra_dashboard_general_informations'), + to: basePath, + pathMatchers: computePathMatchers([urls.dashboard]), }, { name: 'organizations', - title: t('organizations'), - to: useResolvedPath('organizations').pathname, + title: t('zimbra_dashboard_organizations'), + to: `${basePath}/organizations`, + pathMatchers: computePathMatchers([ + urls.organizations, + urls.organizationsDelete, + ]), + hidden: selectedOrganizationId !== null, }, { name: 'domains', - title: t('domains'), - to: useResolvedPath('domains').pathname, + title: t('zimbra_dashboard_domains'), + to: `${basePath}/domains`, + pathMatchers: computePathMatchers([urls.domains]), }, { name: 'email_accounts', - title: t('email_accounts'), - to: useResolvedPath('email_accounts').pathname, + title: t('zimbra_dashboard_email_accounts'), + to: `${basePath}/email_accounts`, + pathMatchers: computePathMatchers([urls.email_accounts]), }, ]; return ( } header={{ title: 'Zimbra', - headerButton: , + // headerButton: , }} - breadcrumb={} tabs={} content={} /> diff --git a/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/TabsPanel.tsx b/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/TabsPanel.tsx index d1b20f0e4a5f..96697321089c 100644 --- a/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/TabsPanel.tsx +++ b/packages/manager/apps/zimbra/src/components/layout-helpers/Dashboard/TabsPanel.tsx @@ -4,12 +4,19 @@ import { OsdsTabs, OsdsTabBar, OsdsTabBarItem, + OsdsChip, } from '@ovhcloud/ods-components/react'; +import { Headers } from '@ovh-ux/manager-react-components'; +import { ODS_CHIP_SIZE } from '@ovhcloud/ods-components'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { useOverridePage, useOrganization } from '@/hooks'; export type TabItemProps = { name: string; title: string; + pathMatchers?: RegExp[]; to: string; + hidden?: boolean; }; export type TabsProps = { @@ -17,34 +24,71 @@ export type TabsProps = { }; const TabsPanel: React.FC = ({ tabs }) => { - const [panel, setActivePanel] = useState(''); + const [activePanel, setActivePanel] = useState(''); const location = useLocation(); const navigate = useNavigate(); + const { data } = useOrganization(); + const isOverriddedPage = useOverridePage(); useEffect(() => { - const activeTab = tabs.find((tab) => tab.to === location.pathname); - if (activeTab) { - setActivePanel(activeTab.name); - } else { + if (!location.pathname) { setActivePanel(tabs[0].name); - navigate(`${tabs[0].to}`); + navigate(tabs[0].to); + } else { + const activeTab = tabs.find( + (tab) => + tab.to === location.pathname || + tab.pathMatchers?.some((pathMatcher) => + pathMatcher.test(location.pathname), + ), + ); + if (activeTab) { + setActivePanel(activeTab.name); + } } }, [location.pathname]); return ( - - - {tabs.map((tab: TabItemProps) => ( - + {data && ( +
+ + navigate(location.pathname)} + className="ml-4" > - {tab.title} - - ))} - - + {data.currentState.label} + +
+ )} + + {!isOverriddedPage && ( + + + {tabs.map( + (tab: TabItemProps) => + !tab.hidden && ( + + + {tab.title} + + + ), + )} + + + )} + ); }; diff --git a/packages/manager/apps/zimbra/src/guides.constants.ts b/packages/manager/apps/zimbra/src/guides.constants.ts new file mode 100644 index 000000000000..ee17626a16c4 --- /dev/null +++ b/packages/manager/apps/zimbra/src/guides.constants.ts @@ -0,0 +1,71 @@ +interface GuideLinks { + [key: string]: string | undefined; + FR?: string; + GB: string; + DE?: string; + ES?: string; + IT?: string; + PL?: string; + PT?: string; + IE: string; + DEFAULT: string; + MA?: string; + TN?: string; + SN?: string; + IN?: string; +} + +const helpRoot = 'https://help.ovhcloud.com/csm/'; +const WEBMAIL = 'https://webmail.mail.ovh.net/'; + +export const ZIMBRA_USER_GUIDE: GuideLinks = { + FR: `${helpRoot}fr-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061410`, + GB: `${helpRoot}en-gb-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061404`, + DE: `${helpRoot}de-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061403`, + ES: `${helpRoot}es-es-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061406`, + IT: `${helpRoot}it-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061408`, + PL: `${helpRoot}pl-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061407`, + PT: `${helpRoot}fr-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061410`, + IE: `${helpRoot}en-ie-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061405`, + DEFAULT: `${helpRoot}fr-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061410`, + MA: `${helpRoot}en-gb-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061404`, + TN: `${helpRoot}fr-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061410`, + SN: `${helpRoot}fr-mx-plan-zimbra-faq?id=kb_article_view&sysparm_article=KB0061410`, +}; + +export const ZIMBRA_ADMINISTRATOR_GUIDE: GuideLinks = { + FR: `${helpRoot}`, + GB: `${helpRoot}`, + DE: `${helpRoot}`, + ES: `${helpRoot}`, + IT: `${helpRoot}`, + PL: `${helpRoot}`, + PT: `${helpRoot}`, + IE: `${helpRoot}`, + DEFAULT: `${helpRoot}`, + MA: `${helpRoot}`, + TN: `${helpRoot}`, + SN: `${helpRoot}`, +}; + +export const GUIDES_LIST = { + webmail: { + key: 'zimbra_dashboard_webmail', + url: WEBMAIL, + tracking: '::to define', + }, + administrator_guide: { + key: 'zimbra_dashboard_administrator_guide', + url: ZIMBRA_ADMINISTRATOR_GUIDE, + tracking: '::to define', + }, + user_guide: { + key: 'zimbra_dashboard_user_guides', + url: ZIMBRA_USER_GUIDE, + tracking: '::to define', + }, +}; + +export default { + GUIDES_LIST, +}; diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/useAccountList.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/useAccountList.spec.tsx new file mode 100644 index 000000000000..82988fb54df0 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/useAccountList.spec.tsx @@ -0,0 +1,46 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { platformMock, accountMock } from '@/api/_mock_'; +import { useAccountList } from '../useAccountList'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + }; +}); + +vi.mock('@/api/account/api', () => { + const apiZimbraPlatformAccount = vi.fn(() => Promise.resolve(accountMock)); + return { + getZimbraPlatformAccount: apiZimbraPlatformAccount, + }; +}); + +vi.mock('react-router-dom', () => { + return { + useSearchParams: vi.fn(() => [new URLSearchParams()]), + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('Account list', () => { + it('Return list of account', async () => { + const { result } = renderHook(() => useAccountList(), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toEqual(accountMock); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/useDomains.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/useDomains.spec.tsx new file mode 100644 index 000000000000..d1fd534d028a --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/useDomains.spec.tsx @@ -0,0 +1,43 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { platformMock, organizationDetailMock, domainMock } from '@/api/_mock_'; +import { useDomains } from '../useDomains'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useOrganization: vi.fn(() => ({ + data: organizationDetailMock, + })), + }; +}); + +vi.mock('@/api/domain/api', () => { + const apiGetDomains = vi.fn(() => Promise.resolve(domainMock)); + return { + getZimbraPlatformDomains: apiGetDomains, + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('Domains', () => { + it('Return domain list', async () => { + const { result } = renderHook(() => useDomains(), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toEqual(domainMock); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/useGenerateUrl.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/useGenerateUrl.spec.tsx new file mode 100644 index 000000000000..60733a30ed5b --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/useGenerateUrl.spec.tsx @@ -0,0 +1,77 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { useGenerateUrl } from '../useGenerateUrl'; + +vi.mock('@/hooks', () => { + return { + useOrganization: vi.fn(() => ({ data: undefined })), + }; +}); + +vi.mock('react-router-dom', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + useHref: vi.fn( + (text) => + `#/00000000-0000-0000-0000-000000000001/organizations/${text.slice(2)}`, + ), + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('href', () => { + it('Return url href', async () => { + const { result } = renderHook(() => useGenerateUrl('./add', 'href'), { + wrapper, + }); + expect(result.current).toBe( + '#/00000000-0000-0000-0000-000000000001/organizations/add?', + ); + }); + + it('Return url href with params', async () => { + const { result } = renderHook( + () => + useGenerateUrl('./delete', 'href', { + deleteOrganizationId: '5859f8b7-3ebf-4cd5-a483-68b7fc48ce56', + }), + { + wrapper, + }, + ); + expect(result.current).toBe( + '#/00000000-0000-0000-0000-000000000001/organizations/delete?deleteOrganizationId=5859f8b7-3ebf-4cd5-a483-68b7fc48ce56', + ); + }); + + it('Return url path', async () => { + const { result } = renderHook(() => useGenerateUrl('./add', 'path'), { + wrapper, + }); + expect(result.current).toBe('./add?'); + }); + + it('Return url path with params', async () => { + const { result } = renderHook( + () => + useGenerateUrl('./delete', 'path', { + deleteOrganizationId: '5859f8b7-3ebf-4cd5-a483-68b7fc48ce56', + }), + { + wrapper, + }, + ); + expect(result.current).toBe( + './delete?deleteOrganizationId=5859f8b7-3ebf-4cd5-a483-68b7fc48ce56', + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/useOrganization.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/useOrganization.spec.tsx new file mode 100644 index 000000000000..121d64002fe1 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/useOrganization.spec.tsx @@ -0,0 +1,64 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { platformMock, organizationDetailMock } from '@/api/_mock_'; +import { useOrganization } from '../useOrganization'; + +const useLocationMock: { + pathname: string; + search: string; + hash: string; + state: string | null; + key: string; +} = { + pathname: '/00000000-0000-0000-0000-000000000001', + search: '?organizationId=1903b491-4d10-4000-8b70-f474d1abe601', + hash: '', + state: null, + key: 'naq3ecco', +}; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + }; +}); + +vi.mock('@/api/organization/api', () => { + const apiOrganizationDetail = vi.fn(() => + Promise.resolve(organizationDetailMock), + ); + return { + getZimbraPlatformOrganizationDetails: apiOrganizationDetail, + }; +}); + +vi.mock('react-router-dom', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + useLocation: () => useLocationMock, + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('Organization', () => { + it('Return detail of organization in params url', async () => { + const { result } = renderHook(() => useOrganization(), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toEqual(organizationDetailMock); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/useOrganizationsList.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/useOrganizationsList.spec.tsx new file mode 100644 index 000000000000..bea1bc80a34a --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/useOrganizationsList.spec.tsx @@ -0,0 +1,40 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { platformMock, organizationListMock } from '@/api/_mock_'; +import { useOrganizationList } from '../useOrganizationsList'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + }; +}); + +vi.mock('@/api/organization/api', () => { + const apiOrganization = vi.fn(() => Promise.resolve(organizationListMock)); + return { + getZimbraPlatformOrganization: apiOrganization, + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('OrganizationList', () => { + it('Return list of organization', async () => { + const { result } = renderHook(() => useOrganizationList(), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toEqual(organizationListMock); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/__test__/usePlatform.spec.tsx b/packages/manager/apps/zimbra/src/hooks/__test__/usePlatform.spec.tsx new file mode 100644 index 000000000000..5757b5d6d00e --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/__test__/usePlatform.spec.tsx @@ -0,0 +1,32 @@ +import { describe, expect, vi } from 'vitest'; +import '@testing-library/jest-dom'; +import { renderHook, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import React from 'react'; +import { usePlatform } from '../usePlatform'; +import { platformMock } from '@/api/_mock_'; + +vi.mock('@/api/platform/api', () => { + const mock = vi.fn(() => Promise.resolve(platformMock)); + return { + getZimbraPlatformList: mock, + }; +}); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }: any) => ( + {children} +); + +describe('Platform', () => { + it('We have to return the firt element', async () => { + const { result } = renderHook(() => usePlatform(), { wrapper }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toEqual(platformMock[0]); + }); +}); diff --git a/packages/manager/apps/zimbra/src/hooks/index.ts b/packages/manager/apps/zimbra/src/hooks/index.ts new file mode 100644 index 000000000000..6a47e762c9c6 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/index.ts @@ -0,0 +1,8 @@ +export * from './useAccountList'; +export * from './useDomains'; +export * from './useGenerateUrl'; +export * from './useOrganization'; +export * from './useOrganizationsList'; +export * from './useOverridePage'; +export * from './usePlatform'; +export * from './types'; diff --git a/packages/manager/apps/zimbra/src/hooks/types.ts b/packages/manager/apps/zimbra/src/hooks/types.ts new file mode 100644 index 000000000000..4ffb8b9ea9a2 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/types.ts @@ -0,0 +1,8 @@ +export interface Match { + params: { + serviceName?: string; + }; + handle?: { + isOverridePage?: boolean; + }; +} diff --git a/packages/manager/apps/zimbra/src/hooks/useAccountList.ts b/packages/manager/apps/zimbra/src/hooks/useAccountList.ts new file mode 100644 index 000000000000..7c2574cc098c --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useAccountList.ts @@ -0,0 +1,40 @@ +import { useQuery } from '@tanstack/react-query'; +import { useSearchParams } from 'react-router-dom'; +import { usePlatform } from '@/hooks'; +import { + getZimbraPlatformAccount, + getZimbraPlatformAccountQueryKey, +} from '@/api/account'; + +interface UseAccountListParams { + domainId?: string; + organizationId?: string; +} + +export const useAccountList = (props: UseAccountListParams = {}) => { + const { domainId, organizationId } = props; + const { platformId } = usePlatform(); + const [searchParams] = useSearchParams(); + + const selectedOrganizationId = + organizationId ?? searchParams.get('organizationId'); + const selectedDomainId = domainId ?? searchParams.get('domainId'); + + const queryParameters = { + ...(selectedOrganizationId && { organizationId: selectedOrganizationId }), + ...(selectedDomainId && { domainId: selectedDomainId }), + }; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: getZimbraPlatformAccountQueryKey(platformId, queryParameters), + queryFn: () => getZimbraPlatformAccount(platformId, queryParameters), + enabled: !!platformId, + }); + + return { + isLoading, + isError, + error, + data, + }; +}; diff --git a/packages/manager/apps/zimbra/src/hooks/useDomains.ts b/packages/manager/apps/zimbra/src/hooks/useDomains.ts new file mode 100644 index 000000000000..a4756935fa2a --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useDomains.ts @@ -0,0 +1,34 @@ +import { useQuery } from '@tanstack/react-query'; +import { usePlatform, useOrganization } from '@/hooks'; + +import { + getZimbraPlatformDomains, + getZimbraPlatformDomainsQueryKey, +} from '@/api/domain'; + +export const useDomains = (organizationId?: string, noCache?: boolean) => { + const { platformId } = usePlatform(); + const { data: organization } = useOrganization(); + const selectedOrganizationId = organization?.id; + + const { data, isLoading, isError, error } = useQuery({ + queryKey: getZimbraPlatformDomainsQueryKey( + platformId, + organizationId || selectedOrganizationId, + ), + queryFn: () => + getZimbraPlatformDomains( + platformId, + organizationId || selectedOrganizationId, + ), + enabled: !!platformId, + gcTime: noCache ? 0 : 5000, + }); + + return { + isLoading, + isError, + error, + data, + }; +}; diff --git a/packages/manager/apps/zimbra/src/hooks/useGenerateUrl.ts b/packages/manager/apps/zimbra/src/hooks/useGenerateUrl.ts new file mode 100644 index 000000000000..59f39906a0f3 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useGenerateUrl.ts @@ -0,0 +1,24 @@ +import { useHref } from 'react-router-dom'; +import { useOrganization } from '@/hooks'; + +export const useGenerateUrl = ( + baseURL: string, + type: 'path' | 'href' = 'path', + params?: Record, +) => { + const { data: organization } = useOrganization(); + + const queryParams = { + ...params, + ...(organization?.id && { organizationId: organization.id }), + }; + + const fullURL = `${baseURL}?${Object.entries(queryParams) + .map(([key, value]) => `${key}=${value}`) + .join('&')}`; + + if (type === 'href') { + return useHref(fullURL); + } + return fullURL; +}; diff --git a/packages/manager/apps/zimbra/src/hooks/useOrganization.ts b/packages/manager/apps/zimbra/src/hooks/useOrganization.ts new file mode 100644 index 000000000000..e36ab1559293 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useOrganization.ts @@ -0,0 +1,34 @@ +import { useQuery } from '@tanstack/react-query'; +import { useLocation } from 'react-router-dom'; +import { usePlatform } from '@/hooks'; +import { + getZimbraPlatformOrganizationDetails, + getZimbraPlatformOrganizationDetailsQueryKey, +} from '@/api/organization'; + +export const useOrganization = (organizationId?: string, noCache?: boolean) => { + const { platformId } = usePlatform(); + const location = useLocation(); + const params = new URLSearchParams(location.search); + const selectedOrganizationId = params.get('organizationId'); + const { data, isLoading, isError, error } = useQuery({ + queryKey: getZimbraPlatformOrganizationDetailsQueryKey( + platformId, + organizationId || selectedOrganizationId, + ), + queryFn: () => + getZimbraPlatformOrganizationDetails( + platformId, + organizationId || selectedOrganizationId, + ), + enabled: (!!organizationId || !!selectedOrganizationId) && !!platformId, + gcTime: noCache ? 0 : 5000, + }); + + return { + isLoading, + isError, + error, + data, + }; +}; diff --git a/packages/manager/apps/zimbra/src/hooks/useOrganizationsList.ts b/packages/manager/apps/zimbra/src/hooks/useOrganizationsList.ts new file mode 100644 index 000000000000..6996785faa3e --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useOrganizationsList.ts @@ -0,0 +1,23 @@ +import { useQuery } from '@tanstack/react-query'; +import { usePlatform } from '@/hooks'; +import { + getZimbraPlatformOrganization, + getZimbraPlatformOrganizationQueryKey, +} from '@/api/organization'; + +export const useOrganizationList = () => { + const { platformId } = usePlatform(); + + const { data, isLoading, isError, error } = useQuery({ + queryKey: getZimbraPlatformOrganizationQueryKey(platformId), + queryFn: () => getZimbraPlatformOrganization(platformId), + enabled: !!platformId, + }); + + return { + isLoading, + isError, + error, + data, + }; +}; diff --git a/packages/manager/apps/zimbra/src/hooks/useOverridePage.ts b/packages/manager/apps/zimbra/src/hooks/useOverridePage.ts new file mode 100644 index 000000000000..584e6a61e490 --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/useOverridePage.ts @@ -0,0 +1,7 @@ +import { useMatches } from 'react-router-dom'; +import { Match } from '@/hooks'; + +export const useOverridePage = (): boolean => { + const matches = useMatches() as Match[]; + return matches.some((match) => match.handle?.isOverridePage); +}; diff --git a/packages/manager/apps/zimbra/src/hooks/usePlatform.ts b/packages/manager/apps/zimbra/src/hooks/usePlatform.ts new file mode 100644 index 000000000000..84f7ece5dfff --- /dev/null +++ b/packages/manager/apps/zimbra/src/hooks/usePlatform.ts @@ -0,0 +1,21 @@ +import { useQuery } from '@tanstack/react-query'; +import { + getZimbraPlatformList, + getZimbraPlatformListQueryKey, +} from '@/api/platform'; + +export const usePlatform = () => { + const { data, isLoading, isError, error } = useQuery({ + queryKey: [getZimbraPlatformListQueryKey], + queryFn: () => getZimbraPlatformList(), + }); + + return { + isLoading, + isError, + error, + platformId: data ? data[0].id : undefined, + platformUrn: data ? data[0].iam.urn : undefined, + data: data ? data[0] : null, + }; +}; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains.tsx deleted file mode 100644 index 6a3ffc623bcf..000000000000 --- a/packages/manager/apps/zimbra/src/pages/dashboard/Domains.tsx +++ /dev/null @@ -1 +0,0 @@ -export default function Domains() {} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ActionButtonDomain.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ActionButtonDomain.tsx new file mode 100644 index 000000000000..61f99ede1d0c --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ActionButtonDomain.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ActionMenu } from '@ovh-ux/manager-react-components'; +import { DomainsItem } from './Domains'; +import { useGenerateUrl, usePlatform } from '@/hooks'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +interface ActionButtonDomainProps { + domainItem: DomainsItem; +} +const ActionButtonDomain: React.FC = ({ + domainItem, +}) => { + const { t } = useTranslation('domains'); + const hrefDeleteDomain = useGenerateUrl('./delete', 'href', { + deleteDomainId: domainItem.id, + }); + const { platformUrn } = usePlatform(); + const actionItems = [ + { + id: 1, + href: hrefDeleteDomain, + label: t('zimbra_domains_tooltip_delete'), + urn: platformUrn, + iamActions: [IAM_ACTIONS.domain.delete], + }, + ]; + return ; +}; + +export default ActionButtonDomain; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/AddDomain.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/AddDomain.tsx new file mode 100644 index 000000000000..729508b53eef --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/AddDomain.tsx @@ -0,0 +1,239 @@ +import React, { useEffect, useState } from 'react'; +import { + LinkType, + Links, + Subtitle, + useNotifications, +} from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; +import { + OsdsFormField, + OsdsSelect, + OsdsSelectOption, + OsdsSpinner, + OsdsText, + OsdsButton, +} from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_SPINNER_MODE, + ODS_SPINNER_SIZE, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, +} from '@ovhcloud/ods-components'; +import { useQuery } from '@tanstack/react-query'; + +import { + useOrganization, + useOrganizationList, + usePlatform, + useGenerateUrl, +} from '@/hooks'; +import { + getDomainsZoneList, + getDomainsZoneListQueryKey, + postZimbraDomain, +} from '@/api/domain'; + +export default function AddDomain() { + const { t } = useTranslation('domains/addDomain'); + const { platformId } = usePlatform(); + + const { data, isLoading } = useOrganizationList(); + const { addError, addSuccess } = useNotifications(); + const navigate = useNavigate(); + + const { data: organization } = useOrganization(); + const [selectedOrganization, setSelectedOrganization] = useState( + organization?.id || '', + ); + const [isSubmitting, setIsSubmitting] = useState(false); + const goBackUrl = useGenerateUrl('..', 'path'); + const onClose = () => navigate(goBackUrl); + + const { data: domains, isLoading: isLoadingDomain } = useQuery({ + queryKey: getDomainsZoneListQueryKey, + queryFn: () => getDomainsZoneList(), + }); + + const [selectedDomainName, setSelectedDomainName] = useState(''); + + const handleAddDomainClick = () => { + const formData = { + organizationId: selectedOrganization, + name: selectedDomainName, + autoConfigureMX: true, + }; + setIsSubmitting(true); + postZimbraDomain(platformId, formData) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_domains_add_domain_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_domains_add_domain_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + useEffect(() => { + if (organization && !isLoading) { + setSelectedOrganization(organization?.id); + } + }, [organization, isLoading]); + + const backLinkUrl = useGenerateUrl('..', 'href'); + + return ( +
+ + + {t('zimbra_domains_add_domain_title_select')} + + +
+ + {t('zimbra_domains_add_domain_organization')} + +
+ + setSelectedOrganization(e.detail.value as string) + } + className="mt-2 w-1/2" + data-testid="select-organization" + > + + {t('zimbra_domains_add_domain_organization_select')} + + {data?.map((item) => ( + + {item.currentState?.name} + + ))} + + {isLoading && ( +
+ +
+ )} +
+ + {selectedOrganization && !isLoadingDomain && ( + +
+ + {t('zimbra_domains_add_domain_title')} + +
+ + setSelectedDomainName(e.detail.value as string) + } + {...(isLoadingDomain ? { disabled: true } : {})} + > + + + {t('zimbra_domains_add_domain_select')} + + + {domains?.map((domain: string) => ( + + {domain} + + ))} + + {isLoadingDomain && ( +
+ +
+ )} +
+ )} + + + + + {isSubmitting && ( + + )} + + {t('zimbra_domains_add_domain_cta_confirm')} + + +
+ ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/Domains.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/Domains.tsx new file mode 100644 index 000000000000..ff072eec12b0 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/Domains.tsx @@ -0,0 +1,142 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { OsdsIcon, OsdsText } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_SIZE, + ODS_ICON_NAME, + ODS_ICON_SIZE, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, +} from '@ovhcloud/ods-components'; +import { + Datagrid, + DatagridColumn, + ManagerButton, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { Outlet } from 'react-router-dom'; + +import { + useOverridePage, + useDomains, + useGenerateUrl, + usePlatform, +} from '@/hooks'; +import ActionButtonDomain from './ActionButtonDomain'; +import LabelChip from '@/components/LabelChip'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +export type DomainsItem = { + id: string; + name: string; + organizationLabel: string; + account: number; +}; + +const columns: DatagridColumn[] = [ + { + id: 'domains', + cell: (item) => ( + + {item.name} + + ), + label: 'zimbra_domains_datagrid_domain_label', + }, + { + id: 'organization', + cell: (item) => + item.organizationLabel && ( + {item.organizationLabel} + ), + label: 'zimbra_domains_datagrid_organization_label', + }, + { + id: 'account', + cell: (item) => + item.account && ( + + {item.account} + + ), + label: 'zimbra_domains_datagrid_account_number', + }, + { + id: 'tooltip', + cell: (item: DomainsItem) => , + label: '', + }, +]; + +export default function Domains() { + const { t } = useTranslation('domains'); + const { platformUrn } = usePlatform(); + + const { data } = useDomains(); + const isOverriddedPage = useOverridePage(); + + const hrefAddDomain = useGenerateUrl('./add', 'href'); + + const items: DomainsItem[] = + data?.map((item) => ({ + name: item.currentState.name, + id: item.id, + organizationLabel: item.currentState.organizationLabel, + account: item.currentState.accountsStatistics.reduce( + (acc, current) => acc + current.configuredAccountsCount, + 0, + ), + })) ?? []; + + return ( + <> + {!isOverriddedPage && ( +
+ +
+ {platformUrn && ( + + + + + {t('zimbra_domains_add_domain_title')} + + )} +
+ ({ + ...column, + label: t(column.label), + }))} + items={items} + totalItems={items.length} + /> +
+ )} + + + ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ModalDeleteDomain.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ModalDeleteDomain.tsx new file mode 100644 index 000000000000..d3076eae93c2 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/ModalDeleteDomain.tsx @@ -0,0 +1,127 @@ +import React, { useEffect, useState } from 'react'; +import { useSearchParams, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_SIZE, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_COLOR_HUE, +} from '@ovhcloud/ods-common-theming'; +import { ODS_ICON_NAME } from '@ovhcloud/ods-components'; +import { OsdsMessage, OsdsText } from '@ovhcloud/ods-components/react'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useAccountList, useGenerateUrl, usePlatform } from '@/hooks'; +import { deleteZimbraPlatformDomain } from '@/api/domain'; +import Modal from '@/components/Modals/Modal'; + +export default function ModalDeleteDomain() { + const { t } = useTranslation('domains/delete'); + const navigate = useNavigate(); + + const [searchParams] = useSearchParams(); + const deleteDomainId = searchParams.get('deleteDomainId'); + + const { platformId } = usePlatform(); + const { data, isLoading } = useAccountList({ + domainId: deleteDomainId, + }); + + const { addError, addSuccess } = useNotifications(); + + const [hasEmailAccount, setHasEmailAccount] = useState(false); + + const goBackUrl = useGenerateUrl('..', 'path'); + const onClose = () => navigate(goBackUrl); + + useEffect(() => { + setHasEmailAccount(data?.length > 0); + }, [isLoading]); + + const handleDeleteClick = () => { + deleteZimbraPlatformDomain(platformId, deleteDomainId) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_domain_delete_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_domain_delete_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + return ( + + <> + + {t('zimbra_domain_delete_modal_content')} + + {hasEmailAccount && ( + +
+ + {t('zimbra_domain_delete_modal_message_disabled_part1')} + + + {t('zimbra_domain_delete_modal_message_disabled_part2')} + +
+
+ )} + +
+ ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ActionButtonDomain.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ActionButtonDomain.spec.tsx new file mode 100644 index 000000000000..554c12ce6b16 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ActionButtonDomain.spec.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import ActionButtonDomain from '../ActionButtonDomain'; +import { render } from '@/utils/test.provider'; +import domainTranslation from '@/public/translations/domains/Messages_fr_FR.json'; +import { domainMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + usePlatform: vi.fn(() => ({ + platformUrn: platformMock[0].iam.urn, + })), + }; +}); + +describe('Domains datagrid action menu', () => { + it('we have good number of item with good content', () => { + const { container } = render( + , + ); + + expect(container.querySelectorAll('osds-menu-item').length).toBe(1); + + expect(container.querySelectorAll('osds-menu-item')[0]).toHaveTextContent( + domainTranslation.zimbra_domains_tooltip_delete, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/AddDomains.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/AddDomains.spec.tsx new file mode 100644 index 000000000000..5ef2b2e7d09f --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/AddDomains.spec.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import AddDomain from '../AddDomain'; +import { render } from '@/utils/test.provider'; +import addDomainTranslation from '@/public/translations/domains/addDomain/Messages_fr_FR.json'; +import { platformMock, organizationListMock } from '@/api/_mock_'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useOrganization: vi.fn(() => ({ + data: null, + isLoading: false, + })), + useOrganizationList: vi.fn(() => ({ + data: organizationListMock, + isLoading: false, + })), + useOverridePage: vi.fn(() => true), + useGenerateUrl: vi.fn(() => null), + }; +}); + +describe('Add Domains page', () => { + const { getByTestId } = render(); + it('Page should display correctly', () => { + const page = getByTestId('add-domain-page'); + expect(page).toHaveTextContent( + addDomainTranslation.zimbra_domains_add_domain_title_select, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/Domains.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/Domains.spec.tsx new file mode 100644 index 000000000000..f523197514b5 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/Domains.spec.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import Domains from '../Domains'; +import { render } from '@/utils/test.provider'; +import domainTranslation from '@/public/translations/domains/Messages_fr_FR.json'; +import { domainMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + platformUrn: platformMock[0].iam.urn, + })), + useDomains: vi.fn(() => ({ + data: domainMock, + })), + useGenerateUrl: vi.fn( + () => '#/00000000-0000-0000-0000-000000000001/domains/add?', + ), + useOverridePage: vi.fn(() => false), + }; +}); + +vi.mock('@ovh-ux/manager-react-components', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + Notifications: vi.fn().mockReturnValue(
Notifications
), + Datagrid: vi.fn().mockReturnValue(
Datagrid
), + }; +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +describe('Domains page', () => { + it('Page should display correctly', () => { + const { getByTestId } = render(); + const button = getByTestId('add-domain-btn'); + expect(button).toHaveAttribute( + 'href', + '#/00000000-0000-0000-0000-000000000001/domains/add?', + ); + expect(button).toHaveTextContent( + domainTranslation.zimbra_domains_add_domain_title, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ModalDeleteDomain.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ModalDeleteDomain.spec.tsx new file mode 100644 index 000000000000..7a20ad60e973 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Domains/__test__/ModalDeleteDomain.spec.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; +import { vi, describe, expect } from 'vitest'; +import { render } from '@/utils/test.provider'; +import { platformMock, accountMock } from '@/api/_mock_'; +import ModalDeleteDomain from '../ModalDeleteDomain'; +import domainsDeleteTranslation from '@/public/translations/domains/delete/Messages_fr_FR.json'; + +const { useAccountListMock } = vi.hoisted(() => ({ + useAccountListMock: vi.fn(() => ({ + data: accountMock, + isLoading: false, + })), +})); + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useGenerateUrl: vi.fn(), + useAccountList: useAccountListMock, + }; +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: vi.fn(), + MemoryRouter: vi.fn(() => ), + useSearchParams: vi.fn(() => [ + new URLSearchParams({ + deleteDomainId: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + }), + ]), +})); + +vi.mock('@ovh-ux/manager-react-components', () => { + return { + useNotifications: vi.fn(() => ({ + addError: () => vi.fn(), + addSuccess: () => vi.fn(), + })), + }; +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('Domains delete modal', () => { + it('check if it is displayed', () => { + const { getByTestId } = render(); + const modal = getByTestId('modal'); + expect(modal).toHaveProperty( + 'headline', + domainsDeleteTranslation.zimbra_domain_delete_modal_title, + ); + }); + + it('if have email use the domain', () => { + const { getByTestId } = render(); + expect(getByTestId('banner-message')).toBeVisible(); + expect(getByTestId('delete-btn')).toBeDisabled(); + }); + + it('if there is not email use the domain', () => { + useAccountListMock.mockImplementation( + vi.fn(() => ({ + data: [], + isLoading: false, + })), + ); + const { getByTestId, queryByTestId } = render(); + expect(queryByTestId('banner-message')).toBeNull(); + expect(getByTestId('delete-btn')).not.toBeDisabled(); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts.tsx deleted file mode 100644 index 35186fc3645e..000000000000 --- a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts.tsx +++ /dev/null @@ -1 +0,0 @@ -export default function EmailAccounts() {} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ActionButtonEmail.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ActionButtonEmail.tsx new file mode 100644 index 000000000000..6966c585a1fd --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ActionButtonEmail.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ActionMenu } from '@ovh-ux/manager-react-components'; +import { EmailsItem } from './EmailAccounts'; +import { useGenerateUrl, usePlatform } from '@/hooks'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +interface ActionButtonEmailAccountProps { + emailsItem: EmailsItem; +} + +const ActionButtonEmail: React.FC = ({ + emailsItem, +}) => { + const { t } = useTranslation('accounts'); + const { platformUrn } = usePlatform(); + + const hrefEditEmailAccount = useGenerateUrl('./edit', 'href', { + editEmailAccountId: emailsItem.id, + }); + + const hrefDeleteEmailAccount = useGenerateUrl('./delete', 'href', { + deleteEmailAccountId: emailsItem.id, + }); + const actionItems = [ + { + id: 1, + href: hrefEditEmailAccount, + urn: platformUrn, + iamActions: [IAM_ACTIONS.account.edit], + label: t('zimbra_account_datagrid_tooltip_modification'), + }, + { + id: 2, + href: hrefDeleteEmailAccount, + urn: platformUrn, + iamActions: [IAM_ACTIONS.account.delete], + label: t('zimbra_account_datagrid_tooltip_delete'), + }, + ]; + return ; +}; + +export default ActionButtonEmail; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/AddAndEditEmailAccount.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/AddAndEditEmailAccount.tsx new file mode 100644 index 000000000000..81ceb8e3bb99 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/AddAndEditEmailAccount.tsx @@ -0,0 +1,650 @@ +import React, { useEffect, useState } from 'react'; +import { + LinkType, + Links, + Subtitle, + useNotifications, +} from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { + OsdsButton, + OsdsFormField, + OsdsInput, + OsdsMessage, + OsdsPassword, + OsdsSelect, + OsdsSelectOption, + OsdsText, + OsdsTextarea, +} from '@ovhcloud/ods-components/react'; +import { + ODS_THEME_COLOR_HUE, + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_TYPOGRAPHY_SIZE, +} from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_VARIANT, + ODS_INPUT_SIZE, + ODS_INPUT_TYPE, + ODS_MESSAGE_TYPE, + ODS_TEXTAREA_SIZE, +} from '@ovhcloud/ods-components'; +import { useQuery } from '@tanstack/react-query'; +import { useGenerateUrl, usePlatform, useDomains } from '@/hooks'; +import { + getZimbraPlatformAccountDetail, + getZimbraPlatformAccountDetailQueryKey, + postZimbraPlatformAccount, + putZimbraPlatformAccount, +} from '@/api/account'; +import Loading from '@/components/Loading/Loading'; + +export default function AddAndEditAccount() { + const { t } = useTranslation('accounts/addAndEdit'); + const navigate = useNavigate(); + const { addError, addSuccess } = useNotifications(); + const { platformId } = usePlatform(); + const [searchParams] = useSearchParams(); + const editEmailAccountId = searchParams.get('editEmailAccountId'); + const [isLoading, setIsLoading] = useState(true); + const [isFormValid, setIsFormValid] = useState(false); + const [selectedDomainOrganization, setSelectedDomainOrganization] = useState( + '', + ); + const goBackUrl = useGenerateUrl('..', 'path'); + + const goBack = () => { + return navigate(goBackUrl); + }; + + type FieldType = { + value: string; + touched: boolean; + hasError?: boolean; + required?: boolean; + }; + + interface FormTypeInterface { + [key: string]: FieldType; + } + + interface FormInputRegexInterface { + [key: string]: RegExp; + } + + const formInputRegex: FormInputRegexInterface = { + account: /^(?:[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*)(?:(?:[.|+])(?:[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*))*$/, + password: /^(?=(.*\d))(?=.*[!@#$%^&*()\\[\]{}\-_+=~`|:;"'<>,./?])(?=.*[a-zA-Z])(?=(.*)).{9,}$/, + }; + + const [form, setForm] = useState({ + ...{ + account: { + value: '', + touched: false, + hasError: false, + required: true, + }, + domain: { + value: '', + touched: false, + required: true, + }, + lastName: { + value: '', + touched: false, + }, + firstName: { + value: '', + touched: false, + }, + displayName: { + value: '', + touched: false, + }, + password: { + value: '', + touched: false, + hasError: false, + required: !editEmailAccountId, + }, + }, + ...(editEmailAccountId && { + description: { + value: '', + touched: false, + }, + }), + }); + + const { + data: editAccountDetail, + isLoading: isLoadingEmailDetailRequest, + } = useQuery({ + queryKey: getZimbraPlatformAccountDetailQueryKey( + platformId, + editEmailAccountId, + ), + queryFn: () => + getZimbraPlatformAccountDetail(platformId, editEmailAccountId), + enabled: !!platformId && !!editEmailAccountId, + }); + + const { data: domainList, isLoading: isLoadingDomainRequest } = useDomains( + null, + true, + ); + + useEffect(() => { + if (!isLoadingEmailDetailRequest && !isLoadingDomainRequest) { + if (editAccountDetail) { + const newForm: FormTypeInterface = form; + const { + email, + lastName, + firstName, + displayName, + description, + } = editAccountDetail.currentState; + const [account, domain] = email.split('@'); + newForm.account.value = account; + newForm.domain.value = domain; + newForm.lastName.value = lastName; + newForm.firstName.value = firstName; + newForm.displayName.value = displayName; + newForm.description.value = description; + setForm((oldForm) => ({ ...oldForm, ...newForm })); + } + setIsLoading(false); + } + }, [ + isLoading, + isLoadingEmailDetailRequest, + isLoadingDomainRequest, + editAccountDetail, + domainList, + ]); + + const checkValidityField = (name: string, value: string) => { + return formInputRegex[name] + ? formInputRegex[name].test(value) || + (!form[name].required && form[name].value === '') + : true; + }; + + const checkValidityForm = () => { + const touched = Object.values(form).find((field) => field.touched); + const error = Object.values(form).find( + (field) => field.hasError || (field.required && field.value === ''), + ); + return touched && !error; + }; + + const handleFormChange = (name: string, value: string) => { + const newForm: FormTypeInterface = form; + newForm[name] = { + value, + touched: true, + required: form[name].required, + hasError: !checkValidityField(name, value), + }; + setForm((oldForm) => ({ ...oldForm, ...newForm })); + setIsFormValid(checkValidityForm); + }; + + const handleDomainChange = (selectedDomain: string) => { + const organizationLabel = domainList.find( + ({ currentState }) => currentState.name === selectedDomain, + )?.currentState.organizationLabel; + handleFormChange('domain', selectedDomain); + setSelectedDomainOrganization(organizationLabel); + }; + + const handleNewAccountClick = () => { + const { + account: { value: account }, + domain: { value: domain }, + } = form; + + let dataBody = { + email: `${account}@${domain}`, + }; + + Object.entries(form).forEach(([key, { value }]) => { + if (!['account', 'domain'].includes(key)) { + dataBody = { ...dataBody, [key]: value }; + } + }); + + postZimbraPlatformAccount(platformId, dataBody) + .then(() => { + goBack(); + addSuccess( + + {t('zimbra_account_add_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + goBack(); + addError( + + {t('zimbra_account_add_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + const handleModifyAccountClick = () => { + const { + account: { value: account }, + domain: { value: domain }, + } = form; + + let dataBody = { + email: `${account}@${domain}`, + }; + + Object.entries(form).forEach(([key, { value }]) => { + if ( + ![ + ...['account', 'domain'], + ...[form.password.value === '' ? 'password' : ''], + ].includes(key) + ) { + dataBody = { ...dataBody, [key]: value }; + } + }); + + putZimbraPlatformAccount(platformId, editEmailAccountId, dataBody) + .then(() => { + goBack(); + addSuccess( + + {t('zimbra_account_edit_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + goBack(); + addError( + + {t('zimbra_account_edit_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + return ( + <> + {isLoading && } + {!isLoading && ( + <> +
+ + + {!editAccountDetail + ? t('zimbra_account_add_title') + : t('zimbra_account_edit_title', { + account: editAccountDetail?.currentState?.email, + })} + +
+ +
+ + {t('zimbra_account_add_input_mandatory')} + + + +
+ + {t('zimbra_account_add_input_email_label')} * + +
+
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + required + className="rounded-r-none border-r-0 w-1/2" + data-testid="input-account" + > + + + handleDomainChange(e.detail.value as string) + } + data-testid="select-domain" + > + + {t('zimbra_account_add_select_domain_placeholder')} + + {domainList?.map(({ currentState: domain }) => ( + + {domain.name} + + ))} + +
+
+ + {t('zimbra_account_add_input_email_helper')} + {[1, 2, 3].map((elm) => ( + + - {t(`zimbra_account_add_input_email_helper_rule_${elm}`)} + + ))} + +
+
+ {selectedDomainOrganization && ( + + + {t('zimbra_account_add_message_organization', { + organizationLabel: selectedDomainOrganization, + })} + + + )} +
+ +
+ + {t('zimbra_account_add_input_lastName_label')} + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + > +
+ + +
+ + {t('zimbra_account_add_input_firstName_label')} + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + > +
+
+ +
+ +
+ + {t('zimbra_account_add_input_displayName_label')} + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + > +
+
+ + {editAccountDetail && ( +
+ +
+ + {t('zimbra_account_add_input_description_label')} + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + > +
+
+ )} + +
+ +
+ + {t('zimbra_account_add_input_password_label')} + {!editAccountDetail && ' *'} + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + data-testid="input-password" + > +
+ + {t('zimbra_account_add_input_password_helper')} + {[1, 2, 3].map((elm) => ( + + -{' '} + {t( + `zimbra_account_add_input_password_helper_rule_${elm}`, + )} + + ))} + +
+
+
+ +
+ + {!editAccountDetail + ? t('zimbra_account_add_button_confirm') + : t('zimbra_account_add_button_save')} + + + {editAccountDetail && ( + + {t('zimbra_account_add_button_cancel')} + + )} +
+
+ + )} + + ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/EmailAccounts.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/EmailAccounts.tsx new file mode 100644 index 000000000000..f830ff0b7e00 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/EmailAccounts.tsx @@ -0,0 +1,181 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { OsdsIcon, OsdsText } from '@ovhcloud/ods-components/react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; +import { + ODS_BUTTON_SIZE, + ODS_ICON_NAME, + ODS_ICON_SIZE, + ODS_TEXT_COLOR_HUE, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, +} from '@ovhcloud/ods-components'; +import { + Datagrid, + DatagridColumn, + Links, + LinkType, + ManagerButton, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { Outlet } from 'react-router-dom'; +import { AccountType } from '@/api/account'; +import { + useOverridePage, + useGenerateUrl, + useAccountList, + usePlatform, +} from '@/hooks'; +import LabelChip from '@/components/LabelChip'; +import guidesConstants from '@/guides.constants'; +import ActionButtonEmail from './ActionButtonEmail'; +import { convertOctets } from '@/utils'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +export type EmailsItem = { + id: string; + email: string; + offer: string; + organizationId: string; + organizationLabel: string; + used: number; + available: number; +}; + +const columns: DatagridColumn[] = [ + { + id: 'email account', + cell: (item) => ( + + {item.email} + + ), + label: 'zimbra_account_datagrid_email_label', + }, + { + id: 'organization', + cell: (item) => + item.organizationLabel && ( + {item.organizationLabel} + ), + label: 'zimbra_account_datagrid_organization_label', + }, + { + id: 'offer', + cell: (item) => + item.offer && ( + + {item.offer} + + ), + label: 'zimbra_account_datagrid_offer_label', + }, + { + id: 'quota', + cell: (item) => ( + + {convertOctets(item.used)} / {convertOctets(item.available)} + + ), + label: 'zimbra_account_datagrid_quota', + }, + { + id: 'tooltip', + cell: (item: EmailsItem) => , + label: '', + }, +]; + +export default function EmailAccounts() { + const { t } = useTranslation('accounts'); + const { platformUrn } = usePlatform(); + const { data } = useAccountList(); + const isOverriddedPage = useOverridePage(); + + const items: EmailsItem[] = + data?.map((item: AccountType) => ({ + id: item.id, + email: item.currentState.email, + offer: item.currentState.offer, + organizationId: item.currentState.organizationId, + organizationLabel: item.currentState.organizationLabel, + used: item.currentState.quota.used, + available: item.currentState.quota.available, + })) ?? []; + + const webmailUrl = guidesConstants.GUIDES_LIST.webmail.url; + + const hrefAddEmailAccount = useGenerateUrl('./add', 'href'); + + return ( + <> + +
+ + {!isOverriddedPage && ( + <> +
+ + {t('zimbra_account_datagrid_webmail_label')} + + +
+ {platformUrn && ( + + + + + {t('zimbra_account_account_add')} + + )} + ({ + ...column, + label: t(column.label), + }))} + items={items} + totalItems={items.length} + /> + + )} +
+ + ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ModalDeleteEmailAccount.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ModalDeleteEmailAccount.tsx new file mode 100644 index 000000000000..f46c94a8a275 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/ModalDeleteEmailAccount.tsx @@ -0,0 +1,167 @@ +import React, { useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_SIZE, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_COLOR_HUE, +} from '@ovhcloud/ods-common-theming'; +import { ODS_ICON_NAME } from '@ovhcloud/ods-components'; +import { + OsdsContentAddon, + OsdsMessage, + OsdsText, +} from '@ovhcloud/ods-components/react'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useQuery } from '@tanstack/react-query'; +import { useGenerateUrl, usePlatform } from '@/hooks'; +import Modal from '@/components/Modals/Modal'; +import { + getZimbraPlatformAccountDetail, + deleteZimbraPlatformAccount, + getZimbraPlatformAccountDetailQueryKey, +} from '@/api/account'; + +export default function ModalDeleteOrganization() { + const [searchParams] = useSearchParams(); + const deleteEmailAccountId = searchParams.get('deleteEmailAccountId'); + const { t } = useTranslation('accounts/delete'); + const { platformId } = usePlatform(); + const { addError, addSuccess } = useNotifications(); + const navigate = useNavigate(); + + const goBackUrl = useGenerateUrl('..', 'path'); + const onClose = () => navigate(goBackUrl); + + const [step, setStep] = useState(1); + const { data, isLoading } = useQuery({ + queryKey: getZimbraPlatformAccountDetailQueryKey( + platformId, + deleteEmailAccountId, + ), + queryFn: () => + getZimbraPlatformAccountDetail(platformId, deleteEmailAccountId), + enabled: !!platformId, + }); + + const handleDeleteClick = () => { + deleteZimbraPlatformAccount(platformId, deleteEmailAccountId) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_account_delete_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_account_delete_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + return ( + setStep(2) : handleDeleteClick, + testid: 'primary-btn', + }} + > + <> + {step === 1 && ( + <> + + {t('zimbra_account_delete_modal_content_step1')} + + + + + {t('zimbra_account_delete_modal_mail_label')} + + + + + + {data?.currentState.email} + + + + + )} + + {step === 2 && ( + <> + + {t('zimbra_account_delete_modal_content_step2')} + + + + {t('zimbra_account_delete_modal_warn_message')} + + + + )} + + + ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ActionButtonEmail.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ActionButtonEmail.spec.tsx new file mode 100644 index 000000000000..c059abe0b926 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ActionButtonEmail.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import ActionButtonEmail from '../ActionButtonEmail'; +import { render } from '@/utils/test.provider'; +import accountTranslation from '@/public/translations/accounts/Messages_fr_FR.json'; +import { accountMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + usePlatform: vi.fn(() => ({ + platformUrn: platformMock[0].iam.urn, + })), + }; +}); + +describe('EmailAccounts datagrid action menu', () => { + it('we have good number of item with good content', () => { + const { container } = render( + , + ); + + expect(container.querySelectorAll('osds-menu-item').length).toBe(2); + + expect(container.querySelectorAll('osds-menu-item')[0]).toHaveTextContent( + accountTranslation.zimbra_account_datagrid_tooltip_modification, + ); + + expect(container.querySelectorAll('osds-menu-item')[1]).toHaveTextContent( + accountTranslation.zimbra_account_datagrid_tooltip_delete, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/AddAndEditEmailAccount.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/AddAndEditEmailAccount.spec.tsx new file mode 100644 index 000000000000..ad3e5a442681 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/AddAndEditEmailAccount.spec.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; +import { vi, describe, expect } from 'vitest'; +import { act } from 'react-dom/test-utils'; +import { fireEvent, render } from '@/utils/test.provider'; +import { accountMock, domainMock, platformMock } from '@/api/_mock_'; +import AddAndEditEmailAccount from '../AddAndEditEmailAccount'; +import emailAccountAddAndEditTranslation from '@/public/translations/accounts/addAndEdit/Messages_fr_FR.json'; + +const { useSearchParamsMock } = vi.hoisted(() => ({ + useSearchParamsMock: vi.fn(() => [new URLSearchParams()]), +})); + +const { useQueryMock } = vi.hoisted(() => ({ + useQueryMock: vi.fn(() => ({ + data: null, + isLoading: false, + })), +})); + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useGenerateUrl: vi.fn(), + useDomains: vi.fn(() => ({ + data: domainMock, + isLoading: false, + })), + }; +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: vi.fn(), + MemoryRouter: vi.fn(() => ), + useSearchParams: useSearchParamsMock, +})); + +vi.mock('@ovh-ux/manager-react-components', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + useNotifications: vi.fn(() => ({ + addError: () => vi.fn(), + addSuccess: () => vi.fn(), + })), + }; +}); + +vi.mock('@tanstack/react-query', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + useQuery: useQueryMock, + }; +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('email account add and edit page', () => { + it('if there is not editEmailAccountId params', () => { + const { getByTestId } = render(); + expect(getByTestId('page-title')).toHaveTextContent( + emailAccountAddAndEditTranslation.zimbra_account_add_title, + ); + }); + + it('if there is editEmailAccountId params', () => { + useSearchParamsMock.mockImplementation( + vi.fn(() => [ + new URLSearchParams({ + editEmailAccountId: '19097ad4-2880-4000-8b03-9d110f0b8f80', + }), + ]), + ); + useQueryMock.mockImplementation( + vi.fn(() => ({ + data: accountMock[0], + isLoading: false, + })), + ); + const { getByTestId } = render(); + expect(getByTestId('page-title')).toHaveTextContent( + emailAccountAddAndEditTranslation.zimbra_account_edit_title.replace( + '{{ account }}', + accountMock[0].currentState?.email, + ), + ); + }); + + it('check validity form', () => { + const { getByTestId } = render(); + + const button = getByTestId('confirm-btn'); + const inputAccount = getByTestId('input-account'); + const selectDomain = getByTestId('select-domain'); + const inputPassword = getByTestId('input-password'); + + expect(button).not.toBeEnabled(); + + act(() => { + inputAccount.odsInputBlur.emit({ name: 'account', value: '' }); + }); + + expect(inputAccount).toHaveAttribute('color', 'error'); + + act(() => { + fireEvent.change(inputAccount, { target: { value: 'account' } }); + fireEvent.change(selectDomain, { target: { value: 'domain' } }); + fireEvent.change(inputPassword, { + target: { value: 'PasswordWithGoodPattern1&' }, + }); + // it seems we have to manually trigger the ods event + inputAccount.odsValueChange.emit({ name: 'account', value: 'account' }); + selectDomain.odsValueChange.emit({ name: 'domain', value: 'domain' }); + inputPassword.odsValueChange.emit({ + name: 'password', + value: 'PasswordWithGoodPattern1&', + }); + }); + + expect(inputAccount).toHaveAttribute('color', 'default'); + expect(button).toBeEnabled(); + + act(() => { + fireEvent.change(inputPassword, { + target: { value: 'PasswordWithGoodPattern1&' }, + }); + // it seems we have to manually trigger the ods event + inputPassword.odsValueChange.emit({ + name: 'password', + value: 'PasswordWithoutGoodPattern', + }); + }); + expect(button).not.toBeEnabled(); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/EmailAccount.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/EmailAccount.spec.tsx new file mode 100644 index 000000000000..ce8feefdbe74 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/EmailAccount.spec.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import EmailAccounts from '../EmailAccounts'; +import { render } from '@/utils/test.provider'; +import accountTranslation from '@/public/translations/accounts/Messages_fr_FR.json'; +import { accountMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + platformUrn: platformMock[0].iam.urn, + })), + useAccountList: vi.fn(() => ({ + data: accountMock, + isLoading: false, + })), + useGenerateUrl: vi.fn( + () => '#/00000000-0000-0000-0000-000000000001/email_accounts/add?', + ), + useOverridePage: vi.fn(() => false), + }; +}); + +vi.mock('@ovh-ux/manager-react-components', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + Notifications: vi.fn().mockReturnValue(
Notifications
), + Datagrid: vi.fn().mockReturnValue(
Datagrid
), + }; +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +describe('EmailAccounts page', () => { + it('Page should display correctly', () => { + const { getByTestId } = render(); + const button = getByTestId('add-account-btn'); + expect(button).toHaveAttribute( + 'href', + '#/00000000-0000-0000-0000-000000000001/email_accounts/add?', + ); + expect(button).toHaveTextContent( + accountTranslation.zimbra_account_account_add, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ModalDeleteEmailAccount.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ModalDeleteEmailAccount.spec.tsx new file mode 100644 index 000000000000..761873eea526 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/EmailAccounts/__test__/ModalDeleteEmailAccount.spec.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; +import { vi, describe, expect } from 'vitest'; +import { fireEvent, render } from '@/utils/test.provider'; +import { platformMock, accountMock } from '@/api/_mock_'; +import ModalDeleteEmailAccount from '../ModalDeleteEmailAccount'; +import accountsDeleteTranslation from '@/public/translations/accounts/delete/Messages_fr_FR.json'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useGenerateUrl: vi.fn(), + }; +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: vi.fn(), + MemoryRouter: vi.fn(() => ), + useSearchParams: vi.fn(() => [ + new URLSearchParams({ + deleteDomainId: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + }), + ]), +})); + +vi.mock('@ovh-ux/manager-react-components', () => { + return { + useNotifications: vi.fn(() => ({ + addError: () => vi.fn(), + addSuccess: () => vi.fn(), + })), + }; +}); + +vi.mock('@tanstack/react-query', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + useQuery: vi.fn(() => ({ + data: accountMock[0], + isLoading: false, + })), + }; +}); + +describe('Domains delete modal', () => { + it('check if it is displayed', () => { + const { getByTestId } = render(); + expect(getByTestId('modal')).toHaveProperty( + 'headline', + accountsDeleteTranslation.zimbra_account_delete_modal_title, + ); + }); + + it('check transition from step 1 to step 2', () => { + const { getByTestId } = render(); + expect(getByTestId('text-step-1')).toBeVisible(); + fireEvent.click(getByTestId('primary-btn')); + expect(getByTestId('text-step-2')).toBeVisible(); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation.tsx deleted file mode 100644 index 602c88ac58c9..000000000000 --- a/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { OsdsTile } from '@ovhcloud/ods-components/react'; - -function GeneralInformation() { - return ( -
-
- Tile 1 -
-
- Tile 2 -
-
- Tile 3 -
-
- ); -} - -export default GeneralInformation; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/GeneralInformation.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/GeneralInformation.tsx new file mode 100644 index 000000000000..e4189b18647c --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/GeneralInformation.tsx @@ -0,0 +1,141 @@ +import React, { useContext } from 'react'; +import { ShellContext } from '@ovh-ux/manager-react-shell-client'; +import { OsdsTile, OsdsDivider } from '@ovhcloud/ods-components/react'; +import { OdsHTMLAnchorElementTarget } from '@ovhcloud/ods-common-core'; +import { + LinkType, + Links, + ManagerText, + Subtitle, +} from '@ovh-ux/manager-react-components'; +import { useTranslation } from 'react-i18next'; +import { AccountStatistics } from '@/api/api.type'; +import { TileBlock } from '@/components/TileBlock'; +import { BadgeStatus } from '@/components/BadgeStatus'; +import { useOrganization, usePlatform } from '@/hooks'; +import { OngoingTasks } from './OngoingTasks'; +import { GUIDES_LIST } from '@/guides.constants'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +interface GuideLinks { + [key: string]: string | undefined; +} + +function GeneralInformation() { + const { t } = useTranslation('dashboard'); + const context = useContext(ShellContext); + const { ovhSubsidiary } = context.environment.getUser(); + const webmail = GUIDES_LIST.webmail.url; + + const { data: platform, platformUrn } = usePlatform(); + const { data: organisation } = useOrganization(); + + const guideLinks = (links: GuideLinks) => { + return Object.entries(links).map(([key, value]) => { + return ( +
+ + +
+ ); + }); + }; + + const accountsStatistics: AccountStatistics[] = organisation + ? organisation.currentState.accountsStatistics + : platform?.currentState?.accountsStatistics; + + return ( +
+
+ +
+ {t('zimbra_dashboard_tile_status_title')} + {organisation && ( + + + + )} + {/* To uncomment to have task + */} + */ + > + {/* {platformUrn && ( + + + + + )} */} + + Coming Soon + + +
+
+
+
+ +
+ + {t('zimbra_dashboard_tile_serviceConsumption_title')} + + + {platformUrn && ( + + {accountsStatistics?.length > 0 + ? accountsStatistics?.map((stats) => ( + {`${ + stats.configuredAccountsCount + } / ${stats.configuredAccountsCount + + stats.availableAccountsCount} ${stats.offer}`} + )) + : t( + 'zimbra_dashboard_tile_serviceConsumption_noAccountOffer', + )} + + )} + +
+
+
+
+ +
+ {t('zimbra_dashboard_tile_usefulLinks_title')} + {guideLinks({ + zimbra_dashboard_webmail: webmail, + /* To uncomment for adminstrator guide */ + /* zimbra_dashboard_administrator_guide: + GUIDES_LIST.administrator_guide.url[ovhSubsidiary], */ + zimbra_dashboard_user_guides: + GUIDES_LIST.user_guide.url[ovhSubsidiary], + })} +
+
+
+
+ ); +} + +export default GeneralInformation; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/OngoingTasks.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/OngoingTasks.tsx new file mode 100644 index 000000000000..c83408e450c5 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/GeneralInformation/OngoingTasks.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useQuery } from '@tanstack/react-query'; +import { OsdsIcon, OsdsLink } from '@ovhcloud/ods-components/react'; +import { ODS_ICON_NAME, ODS_ICON_SIZE } from '@ovhcloud/ods-components'; +import { + getZimbraPlatformTask, + getZimbraPlatformTaskQueryKey, +} from '@/api/task'; +import { useOrganization, usePlatform } from '@/hooks'; + +export const OngoingTasks: React.FC = () => { + const { t } = useTranslation('dashboard'); + const [loadMore, setLoadMore] = useState(false); + const [tasksDiplayed, setTasksDiplayed] = useState([]); + const { data: organisation } = useOrganization(); + const { platformId } = usePlatform(); + const { data } = useQuery({ + queryKey: getZimbraPlatformTaskQueryKey(platformId, organisation?.id), + queryFn: () => getZimbraPlatformTask(platformId, organisation?.id), + enabled: !!platformId, + }); + + useEffect(() => { + setTasksDiplayed(loadMore ? data : data?.slice(0, 5)); + }, [loadMore, data]); + + return ( +
+ {tasksDiplayed?.map((task) => ( + {`${task.type} ${task.message}`} + ))} + {data?.length > 5 && ( + setLoadMore(!loadMore)}> + + {!loadMore + ? t('zimbra_dashboard_tile_status_ongoingTask_viewMore') + : t('zimbra_dashboard_tile_status_ongoingTask_viewLess')} + + + + + )} +
+ ); +}; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations.tsx deleted file mode 100644 index 1951caffc826..000000000000 --- a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { OsdsButton, OsdsIcon } from '@ovhcloud/ods-components/react'; -import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; -import { ODS_BUTTON_SIZE, ODS_ICON_NAME } from '@ovhcloud/ods-components'; - -export default function Organizations() { - const { t } = useTranslation('organisations'); - return ( -
- - - - - {t('add_organisation_cta')} - -
- ); -} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ActionButtonOrganization.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ActionButtonOrganization.tsx new file mode 100644 index 000000000000..a315b90b1499 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ActionButtonOrganization.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ActionMenu } from '@ovh-ux/manager-react-components'; +import { OrganizationItem } from './Organizations'; +import { useGenerateUrl, usePlatform } from '@/hooks'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +interface ActionButtonOrganizationProps { + organizationItem: OrganizationItem; +} + +const ActionButtonOrganization: React.FC = ({ + organizationItem, +}) => { + const { t } = useTranslation('organizations'); + const { platformUrn } = usePlatform(); + + const hrefDeleteOrganization = useGenerateUrl('./delete', 'href', { + deleteOrganizationId: organizationItem.id, + }); + + const hrefEditOrganization = useGenerateUrl('./edit', 'href', { + editOrganizationId: organizationItem.id, + }); + const actionItems = [ + { + id: 1, + href: hrefEditOrganization, + urn: platformUrn, + iamActions: [IAM_ACTIONS.organization.edit], + label: t('zimbra_organization_edit'), + }, + { + id: 2, + href: hrefDeleteOrganization, + urn: platformUrn, + iamActions: [IAM_ACTIONS.organization.delete], + label: t('zimbra_organization_delete'), + }, + ]; + + return ; +}; + +export default ActionButtonOrganization; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/IdLink.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/IdLink.tsx new file mode 100644 index 000000000000..ffec17b290e0 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/IdLink.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { OsdsLink } from '@ovhcloud/ods-components/react'; +import { useNavigate } from 'react-router-dom'; + +interface IdLinkProps { + id: string; + children: string; +} + +const IdLink: React.FC = ({ id, children }) => { + const navigate = useNavigate(); + const handleLinkClick = () => { + navigate(`..?organizationId=${id}`); + }; + + return ( + + {children} + + ); +}; + +export default IdLink; diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalAddAndEditOrganization.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalAddAndEditOrganization.tsx new file mode 100644 index 000000000000..c594a961f318 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalAddAndEditOrganization.tsx @@ -0,0 +1,371 @@ +import React, { useEffect, useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_SIZE, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_COLOR_HUE, +} from '@ovhcloud/ods-common-theming'; +import { + OsdsFormField, + OsdsIcon, + OsdsInput, + OsdsText, + OsdsTooltip, + OsdsTooltipContent, +} from '@ovhcloud/ods-components/react'; +import { + ODS_ICON_NAME, + ODS_ICON_SIZE, + ODS_INPUT_SIZE, + ODS_INPUT_TYPE, + ODS_TOOLTIP_VARIANT, +} from '@ovhcloud/ods-components'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useGenerateUrl, useOrganization, usePlatform } from '@/hooks'; +import Modal from '@/components/Modals/Modal'; +import { + postZimbraPlatformOrganization, + putZimbraPlatformOrganization, +} from '@/api/organization'; + +type FieldType = { + value: string; + touched: boolean; + hasError: boolean; +}; + +interface FormTypeInterface { + [key: string]: FieldType; +} + +interface FormInputRegexInterface { + [key: string]: RegExp; +} + +export default function ModalAddAndEditOrganization() { + const { t } = useTranslation('organizations/addAndEdit'); + const { platformId } = usePlatform(); + const [searchParams] = useSearchParams(); + const editOrganizationId = searchParams?.get('editOrganizationId'); + const { addError, addSuccess } = useNotifications(); + const navigate = useNavigate(); + const goBackUrl = useGenerateUrl('..', 'path'); + const onClose = () => navigate(goBackUrl); + + const formInputRegex: FormInputRegexInterface = { + name: /^[a-zA-Z0-9]+$/, + label: /^[a-zA-Z0-9]{1,12}$/, + }; + + const [form, setForm] = useState({ + name: { + value: '', + touched: false, + hasError: false, + }, + label: { + value: '', + touched: false, + hasError: false, + }, + }); + + const [isLoading, setIsLoading] = useState(!!editOrganizationId); + const [isFormValid, setIsFormValid] = useState(false); + + const { + data: editOrganizationDetail, + isLoading: isLoadingRequest, + } = useOrganization(editOrganizationId, true); + + const handleNewOrganizationClick = () => { + const { + name: { value: name }, + label: { value: label }, + } = form; + postZimbraPlatformOrganization(platformId, { name, label }) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_organization_add_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_organization_add_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + const handleModifyOrganizationClick = () => { + const { + name: { value: name }, + label: { value: label }, + } = form; + putZimbraPlatformOrganization(platformId, editOrganizationId, { + name, + label, + }) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_organization_edit_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_organization_edit_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + const checkValidityField = (name: string, value: string) => { + return formInputRegex[name].test(value); + }; + + const checkValidityForm = () => { + const touched = Object.values(form).find((field) => field.touched); + const error = Object.values(form).find( + (field) => field.hasError || field.value === '', + ); + return touched && !error; + }; + + const handleFormChange = (name: string, value: string) => { + const newForm: FormTypeInterface = form; + newForm[name] = { + value, + touched: true, + hasError: !checkValidityField(name, value), + }; + setForm((oldForm) => ({ ...oldForm, ...newForm })); + setIsFormValid(checkValidityForm); + }; + + useEffect(() => { + if (editOrganizationDetail && !isLoadingRequest) { + const { name, label } = editOrganizationDetail.currentState; + const newForm: FormTypeInterface = form; + newForm.name.value = name; + newForm.label.value = label; + setForm((oldForm) => ({ ...oldForm, ...newForm })); + setIsLoading(false); + } + }, [isLoading, isLoadingRequest, editOrganizationDetail]); + + return ( + + <> + {!editOrganizationId && ( + <> + + {t('zimbra_organization_add_modal_content_part1')} + + + {t('zimbra_organization_add_modal_content_part2')} + + + )} + + {t('zimbra_organization_add_form_input_mandatory')} + + +
+ + {t('zimbra_organization_add_form_input_name_title')} * + +
+ + + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => { + handleFormChange(name, value); + }} + required + > +
+ +
+ + {t('zimbra_organization_add_form_input_label_title')} * + { + + + + {t('zimbra_organization_add_form_input_label_tooltip')} + + + + + } + +
+ + handleFormChange(name, value.toString()) + } + onOdsValueChange={({ detail: { name, value } }) => + handleFormChange(name, value) + } + required + > +
+ + {t('zimbra_organization_add_form_input_label_helper', { + value: 12, + })} + +
+
+ +
+ ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalDeleteOrganization.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalDeleteOrganization.tsx new file mode 100644 index 000000000000..ce255fd1cb71 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/ModalDeleteOrganization.tsx @@ -0,0 +1,123 @@ +import React, { useEffect, useState } from 'react'; +import { useSearchParams, useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { + ODS_THEME_COLOR_INTENT, + ODS_THEME_TYPOGRAPHY_SIZE, + ODS_THEME_TYPOGRAPHY_LEVEL, + ODS_THEME_COLOR_HUE, +} from '@ovhcloud/ods-common-theming'; +import { ODS_ICON_NAME } from '@ovhcloud/ods-components'; +import { OsdsMessage, OsdsText } from '@ovhcloud/ods-components/react'; +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useDomains, usePlatform } from '@/hooks'; +import { deleteZimbraPlatformOrganization } from '@/api/organization'; +import Modal from '@/components/Modals/Modal'; + +export default function ModalDeleteOrganization() { + const [searchParams] = useSearchParams(); + const deleteOrganizationId = searchParams.get('deleteOrganizationId'); + const { t } = useTranslation('organizations/delete'); + const { platformId } = usePlatform(); + const { addError, addSuccess } = useNotifications(); + const [hasDomain, setHasDomain] = useState(false); + const navigate = useNavigate(); + + const onClose = () => navigate('..'); + + const handleDeleteClick = () => { + deleteZimbraPlatformOrganization(platformId, deleteOrganizationId) + .then(() => { + onClose(); + addSuccess( + + {t('zimbra_organization_delete_success_message')} + , + true, + ); + }) + .catch(({ response }) => { + onClose(); + addError( + + {t('zimbra_organization_delete_error_message', { + error: response.data.message, + })} + , + true, + ); + }); + }; + + const { data, isLoading } = useDomains(deleteOrganizationId); + + useEffect(() => { + setHasDomain(data?.length > 0); + }, [isLoading]); + + return ( + + <> + + {t('zimbra_organization_delete_modal_content')} + + + {hasDomain && ( + +
+ + {t('zimbra_organization_delete_modal_message_disabled_part1')} + + + {t('zimbra_organization_delete_modal_message_disabled_part2')} + +
+
+ )} + +
+ ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/Organizations.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/Organizations.tsx new file mode 100644 index 000000000000..db4f585493e7 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/Organizations.tsx @@ -0,0 +1,135 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { OsdsIcon, OsdsText } from '@ovhcloud/ods-components/react'; +import { Outlet } from 'react-router-dom'; +import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; +import { + ODS_BUTTON_SIZE, + ODS_ICON_NAME, + ODS_ICON_SIZE, + ODS_TEXT_LEVEL, + ODS_TEXT_SIZE, +} from '@ovhcloud/ods-components'; +import { + Datagrid, + DatagridColumn, + ManagerButton, + Notifications, +} from '@ovh-ux/manager-react-components'; +import { ResourceStatus } from '@/api/api.type'; + +import { useOrganizationList, usePlatform, useGenerateUrl } from '@/hooks'; +import ActionButtonOrganization from './ActionButtonOrganization'; +import IdLink from './IdLink'; +import LabelChip from '@/components/LabelChip'; +import { BadgeStatus } from '@/components/BadgeStatus'; +import { IAM_ACTIONS } from '@/utils/iamAction.constants'; + +export type OrganizationItem = { + id: string; + name: string; + label: string; + account: number; + status: string; +}; + +const columns: DatagridColumn[] = [ + { + id: 'name', + cell: (item: OrganizationItem) => {item.name}, + label: 'zimbra_organization_name', + }, + { + id: 'label', + cell: (item: OrganizationItem) => + item.label && {item.label}, + label: 'zimbra_organization_label', + }, + { + id: 'account', + cell: (item: OrganizationItem) => ( + + {item.account} + + ), + label: 'zimbra_organization_account_number', + }, + { + id: 'status', + cell: (item: OrganizationItem) => ( + + ), + label: 'zimbra_organization_status', + }, + { + id: 'tooltip', + cell: (item: OrganizationItem) => + (item.status === ResourceStatus.READY || + item.status === ResourceStatus.ERROR) && ( + + ), + label: '', + }, +]; + +export default function Organizations() { + const { t } = useTranslation('organizations'); + const { platformId, platformUrn } = usePlatform(); + const { data } = useOrganizationList(); + + const items: OrganizationItem[] = + data?.map((item) => ({ + id: item.id, + name: item.currentState.name, + label: item.currentState.label, + account: item.currentState.accountsStatistics.reduce( + (acc, current) => acc + current.configuredAccountsCount, + 0, + ), + status: item.resourceStatus || '', + })) ?? []; + + const hrefAddOrganization = useGenerateUrl('./add', 'href'); + return ( +
+ + +
+ {platformUrn && ( + + + + + {t('zimbra_organization_cta')} + + )} +
+ ({ + ...column, + label: t(column.label), + }))} + items={items} + totalItems={platformId?.length || 0} + /> +
+ ); +} diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ActionButtonOrganization.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ActionButtonOrganization.spec.tsx new file mode 100644 index 000000000000..9753d351e565 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ActionButtonOrganization.spec.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import ActionButtonOrganization from '../ActionButtonOrganization'; +import { render } from '@/utils/test.provider'; +import organizationsTranslation from '@/public/translations/organizations/Messages_fr_FR.json'; +import { organizationListMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + usePlatform: vi.fn(() => ({ + platformUrn: platformMock[0].iam.urn, + })), + }; +}); + +describe('Organizations datagrid action menu', () => { + it('we have good number of item with good content', () => { + const { container } = render( + , + ); + + expect(container.querySelectorAll('osds-menu-item').length).toBe(2); + + expect(container.querySelectorAll('osds-menu-item')[0]).toHaveTextContent( + organizationsTranslation.zimbra_organization_edit, + ); + + expect(container.querySelectorAll('osds-menu-item')[1]).toHaveTextContent( + organizationsTranslation.zimbra_organization_delete, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalAddAndEditOrganization.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalAddAndEditOrganization.spec.tsx new file mode 100644 index 000000000000..fcbdf0108ffd --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalAddAndEditOrganization.spec.tsx @@ -0,0 +1,129 @@ +import React from 'react'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; +import { vi, describe, expect } from 'vitest'; +import { act } from 'react-dom/test-utils'; +import { fireEvent, render } from '@/utils/test.provider'; +import { platformMock } from '@/api/_mock_'; +import ModalAddAndEditOrganization from '../ModalAddAndEditOrganization'; +import organizationsAddAndEditTranslation from '@/public/translations/organizations/addAndEdit/Messages_fr_FR.json'; + +const { useSearchParamsMock } = vi.hoisted(() => ({ + useSearchParamsMock: vi.fn(() => [new URLSearchParams()]), +})); + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useGenerateUrl: vi.fn(), + useOrganization: vi.fn(() => ({ + data: null, + isLoading: false, + })), + }; +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: vi.fn(), + MemoryRouter: vi.fn(() => ), + useSearchParams: useSearchParamsMock, +})); + +vi.mock('@ovh-ux/manager-react-components', () => { + return { + useNotifications: vi.fn(() => ({ + addError: () => vi.fn(), + addSuccess: () => vi.fn(), + })), + }; +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('Organizations add and edit modal', () => { + it('if i have not editOrganizationId params', () => { + const { getByTestId } = render(); + const modal = getByTestId('modal'); + expect(modal).toHaveProperty( + 'headline', + organizationsAddAndEditTranslation.zimbra_organization_add_modal_title, + ); + }); + + it('if i have editOrganizationId params', () => { + useSearchParamsMock.mockImplementation( + vi.fn(() => [ + new URLSearchParams({ + editOrganizationId: '1903b491-4d10-4000-8b70-f474d1abe601', + }), + ]), + ); + const { getByTestId } = render(); + const modal = getByTestId('modal'); + expect(modal).toHaveProperty( + 'headline', + organizationsAddAndEditTranslation.zimbra_organization_edit_modal_title, + ); + }); + + it('check validity form', () => { + const { getByTestId } = render(); + + const button = getByTestId('confirm-btn'); + const input1 = getByTestId('input-name'); + const input2 = getByTestId('input-label'); + + expect(getByTestId('confirm-btn')).not.toBeEnabled(); + + act(() => { + input1.odsInputBlur.emit({ name: 'name', value: '' }); + }); + + expect(input1).toHaveAttribute('color', 'error'); + expect(getByTestId('field-name')).toHaveAttribute( + 'error', + organizationsAddAndEditTranslation.zimbra_organization_add_form_input_name_error, + ); + + act(() => { + fireEvent.change(input1, { target: { value: 'Name' } }); + fireEvent.change(input2, { target: { value: 'Label' } }); + + // it seems we have to manually trigger the ods event + input1.odsValueChange.emit({ name: 'name', value: 'Name' }); + input2.odsValueChange.emit({ name: 'label', value: 'Label' }); + }); + + expect(input1).toHaveAttribute('color', 'default'); + expect(input2).toHaveAttribute('color', 'default'); + expect(button).toBeEnabled(); + + act(() => { + fireEvent.change(input1, { target: { value: 'Name' } }); + fireEvent.change(input2, { target: { value: 'Label' } }); + + // it seems we have to manually trigger the ods event + input1.odsValueChange.emit({ name: 'name', value: 'Name' }); + input2.odsValueChange.emit({ + name: 'label', + value: 'NoValidLabelWithMore12Digit', + }); + }); + + expect(input1).toHaveAttribute('color', 'default'); + expect(input2).toHaveAttribute('color', 'error'); + expect(getByTestId('field-label')).toHaveAttribute( + 'error', + organizationsAddAndEditTranslation.zimbra_organization_add_form_input_label_error.replace( + '{{ value }}', + 12, + ), + ); + + expect(button).not.toBeEnabled(); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalDeleteOrganization.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalDeleteOrganization.spec.tsx new file mode 100644 index 000000000000..8b93e747f8e9 --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/ModalDeleteOrganization.spec.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import 'element-internals-polyfill'; +import '@testing-library/jest-dom'; +import { vi, describe, expect } from 'vitest'; +import { render } from '@/utils/test.provider'; +import { platformMock, domainMock } from '@/api/_mock_'; +import ModalDeleteOrganization from '../ModalDeleteOrganization'; +import organizationsDeleteTranslation from '@/public/translations/organizations/delete/Messages_fr_FR.json'; + +const { useDomainsMock } = vi.hoisted(() => ({ + useDomainsMock: vi.fn(() => ({ + data: domainMock, + isLoading: false, + })), +})); + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + })), + useGenerateUrl: vi.fn(), + useDomains: useDomainsMock, + }; +}); + +vi.mock('react-router-dom', () => ({ + useNavigate: vi.fn(), + MemoryRouter: vi.fn(() => ), + useSearchParams: vi.fn(() => [ + new URLSearchParams({ + deleteOrganizationId: '1903b491-4d10-4000-8b70-f474d1abe601', + }), + ]), +})); + +vi.mock('@ovh-ux/manager-react-components', () => { + return { + useNotifications: vi.fn(() => ({ + addError: () => vi.fn(), + addSuccess: () => vi.fn(), + })), + }; +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('Organizations delete modal', () => { + it('check if it is displayed', () => { + const { getByTestId } = render(); + const modal = getByTestId('modal'); + expect(modal).toHaveProperty( + 'headline', + organizationsDeleteTranslation.zimbra_organization_delete_modal_title, + ); + }); + + it('if there is domain in organization', () => { + const { getByTestId } = render(); + expect(getByTestId('banner-message')).toBeVisible(); + expect(getByTestId('delete-btn')).toBeDisabled(); + }); + + it('if there is not domain in organization', () => { + useDomainsMock.mockImplementation( + vi.fn(() => ({ + data: [], + isLoading: false, + })), + ); + const { getByTestId, queryByTestId } = render(); + expect(queryByTestId('banner-message')).toBeNull(); + expect(getByTestId('delete-btn')).not.toBeDisabled(); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/Organizations.spec.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/Organizations.spec.tsx new file mode 100644 index 000000000000..ff86d96dc3ac --- /dev/null +++ b/packages/manager/apps/zimbra/src/pages/dashboard/Organizations/__test__/Organizations.spec.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { vi, describe, expect } from 'vitest'; +import Organizations from '../Organizations'; +import { render } from '@/utils/test.provider'; +import organizationsTranslation from '@/public/translations/organizations/Messages_fr_FR.json'; +import { organizationListMock, platformMock } from '@/api/_mock_'; + +vi.mock('@/hooks', () => { + return { + usePlatform: vi.fn(() => ({ + platformId: platformMock[0].id, + platformUrn: platformMock[0].iam.urn, + })), + useOrganizationList: vi.fn(() => ({ + data: organizationListMock, + })), + useGenerateUrl: vi.fn( + () => '#/00000000-0000-0000-0000-000000000001/organizations/add?', + ), + }; +}); + +vi.mock('@ovh-ux/manager-react-components', async (importOriginal) => { + const actual: any = await importOriginal(); + return { + ...actual, + Notifications: vi.fn().mockReturnValue(
Notifications
), + Datagrid: vi.fn().mockReturnValue(
Datagrid
), + }; +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +describe('Organizations page', () => { + it('Page should display correctly', () => { + const { getByTestId } = render(); + const button = getByTestId('add-organization-btn'); + expect(button).toHaveAttribute( + 'href', + '#/00000000-0000-0000-0000-000000000001/organizations/add?', + ); + expect(button).toHaveTextContent( + organizationsTranslation.add_organisation_cta, + ); + }); +}); diff --git a/packages/manager/apps/zimbra/src/pages/dashboard/_layout.tsx b/packages/manager/apps/zimbra/src/pages/dashboard/_layout.tsx index 5edb703f23a8..f8baccebd418 100644 --- a/packages/manager/apps/zimbra/src/pages/dashboard/_layout.tsx +++ b/packages/manager/apps/zimbra/src/pages/dashboard/_layout.tsx @@ -5,10 +5,8 @@ import Loading from '@/components/Loading/Loading'; export default function DashboardPage() { return ( -
- }> - - -
+ }> + + ); } diff --git a/packages/manager/apps/zimbra/src/pages/layout.tsx b/packages/manager/apps/zimbra/src/pages/layout.tsx index c85fa09bc3fa..60d3463f7872 100644 --- a/packages/manager/apps/zimbra/src/pages/layout.tsx +++ b/packages/manager/apps/zimbra/src/pages/layout.tsx @@ -1,48 +1,34 @@ -import React, { useEffect, useContext } from 'react'; -import { defineCurrentPage } from '@ovh-ux/request-tagger'; -import { Outlet, useLocation, useMatches, Navigate } from 'react-router-dom'; -import { ShellContext, useRouting } from '@ovh-ux/manager-react-shell-client'; +import React, { useEffect } from 'react'; +import { Outlet, Navigate, useLocation } from 'react-router-dom'; +import { + useRouteSynchro, + useRouting, +} from '@ovh-ux/manager-react-shell-client'; -import { useQuery } from '@tanstack/react-query'; -import { getZimbraPlatform } from '@/api'; import Loading from '@/components/Loading/Loading'; import ErrorBanner from '@/components/Error/Error'; +import { usePlatform } from '@/hooks'; export default function Layout() { const location = useLocation(); const routing = useRouting(); - const { shell } = useContext(ShellContext); - const matches = useMatches(); - - useEffect(() => { - const match = matches.slice(-1); - defineCurrentPage(`app.zimbra-${match[0]?.id}`); - }, [location]); - - useEffect(() => { - shell.ux.hidePreloader(); - }, []); - - useEffect(() => { - routing.stopListenForHashChange(); - }, []); + const { platformId, isLoading, isError, error } = usePlatform(); useEffect(() => { routing.onHashChange(); }, [location]); - const { data, isError, isLoading, error }: any = useQuery({ - queryKey: ['get/zimbra/platform'], - queryFn: () => getZimbraPlatform(null), // The temp call to IAM api, because zimbra api isn't available - }); + useRouteSynchro(); return ( <> {isLoading && } {isError && } - {data?.data?.length === 0 && } - {data?.data?.length > 0 && } + {!platformId && !isLoading && } + {platformId && location.pathname === '/' && location.search === '' && ( + + )} ); } diff --git a/packages/manager/apps/zimbra/src/pages/onboarding/index.tsx b/packages/manager/apps/zimbra/src/pages/onboarding/index.tsx index 01b3630b0b32..03d932b26edc 100644 --- a/packages/manager/apps/zimbra/src/pages/onboarding/index.tsx +++ b/packages/manager/apps/zimbra/src/pages/onboarding/index.tsx @@ -1,57 +1,25 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; -import { Card, OnboardingLayout } from '@ovh-ux/manager-react-components'; +import { OnboardingLayout } from '@ovh-ux/manager-react-components'; import onboardingImgSrc from './onboarding-img.png'; export default function Onboarding() { const { t } = useTranslation('onboarding'); - const tileList = [ - { - id: 1, - texts: { - title: t('guide1Title'), - description: t('guide1Description'), - category: t('guideCategory'), - }, - href: 'https://ovh/com/link/1', - }, - { - id: 2, - texts: { - title: t('guide2Title'), - description: t('guide2Description'), - category: t('guideCategory'), - }, - href: 'https://ovh/com/link/2', - }, - { - id: 3, - texts: { - title: t('guide3Title'), - description: t('guide3Description'), - category: t('guideCategory'), - }, - href: 'https://ovh/com/link/3', - }, - ]; - const title: string = t('title'); const description: string = t('description'); + const onOrderButtonClick = () => { + window.open('https://labs.ovhcloud.com/en/', '_blank', 'noopener'); + }; + return ( - {tileList.map((tile) => ( - - ))} - + onOrderButtonClick={onOrderButtonClick} + > ); } diff --git a/packages/manager/apps/zimbra/src/pages/onboarding/onboarding-img.png b/packages/manager/apps/zimbra/src/pages/onboarding/onboarding-img.png index 1ac8d6473c95..3d844cce9c3a 100644 Binary files a/packages/manager/apps/zimbra/src/pages/onboarding/onboarding-img.png and b/packages/manager/apps/zimbra/src/pages/onboarding/onboarding-img.png differ diff --git a/packages/manager/apps/zimbra/src/components/Breadcrumb/constants.ts b/packages/manager/apps/zimbra/src/routes/routes.constants.ts similarity index 63% rename from packages/manager/apps/zimbra/src/components/Breadcrumb/constants.ts rename to packages/manager/apps/zimbra/src/routes/routes.constants.ts index 5c3a98e3bcff..1262570a2e18 100644 --- a/packages/manager/apps/zimbra/src/components/Breadcrumb/constants.ts +++ b/packages/manager/apps/zimbra/src/routes/routes.constants.ts @@ -4,8 +4,7 @@ export const urls = { dashboard: '/:serviceName', overview: '/:serviceName', organizations: '/:serviceName/organizations', - domain: '/:serviceName/domains', + organizationsDelete: '/:serviceName/organizations/delete', + domains: '/:serviceName/domains', email_accounts: '/:serviceName/email_accounts', - mailing_list: '/:serviceName/mailing_lists', - redirections: '/:serviceName/redirections', }; diff --git a/packages/manager/apps/zimbra/src/routes/routes.tsx b/packages/manager/apps/zimbra/src/routes/routes.tsx index f88edb49c798..2d3604f78a74 100644 --- a/packages/manager/apps/zimbra/src/routes/routes.tsx +++ b/packages/manager/apps/zimbra/src/routes/routes.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { RouteObject } from 'react-router-dom'; -import i18next from 'i18next'; import NotFound from '@/pages/404'; const lazyRouteConfig = (importFn: CallableFunction): Partial => { @@ -18,7 +17,6 @@ const lazyRouteConfig = (importFn: CallableFunction): Partial => { export const Routes: any = [ { path: '', - handle: { breadcrumb: (): string => 'Zimbra' }, ...lazyRouteConfig(() => import('@/pages/layout')), children: [ { @@ -28,32 +26,95 @@ export const Routes: any = [ { path: '', ...lazyRouteConfig(() => - import('@/pages/dashboard/GeneralInformation'), + import('@/pages/dashboard/GeneralInformation/GeneralInformation'), ), - handle: { - breadcrumb: (): null => null, - }, }, { path: 'organizations', - ...lazyRouteConfig(() => import('@/pages/dashboard/Organizations')), - handle: { - breadcrumb: (): string => i18next.t('dashboard:organization'), - }, + ...lazyRouteConfig(() => + import('@/pages/dashboard/Organizations/Organizations'), + ), + children: [ + { + path: 'add', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/Organizations/ModalAddAndEditOrganization' + ), + ), + }, + { + path: 'edit', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/Organizations/ModalAddAndEditOrganization' + ), + ), + }, + { + path: 'delete', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/Organizations/ModalDeleteOrganization' + ), + ), + }, + ], }, { path: 'domains', - ...lazyRouteConfig(() => import('@/pages/dashboard/Domains')), - handle: { - breadcrumb: (): string => i18next.t('dashboard:domain'), - }, + ...lazyRouteConfig(() => + import('@/pages/dashboard/Domains/Domains'), + ), + children: [ + { + path: 'add', + ...lazyRouteConfig(() => + import('@/pages/dashboard/Domains/AddDomain'), + ), + handle: { isOverridePage: true }, + }, + { + path: 'delete', + ...lazyRouteConfig(() => + import('@/pages/dashboard/Domains/ModalDeleteDomain'), + ), + }, + ], }, { path: 'email_accounts', - ...lazyRouteConfig(() => import('@/pages/dashboard/EmailAccounts')), - handle: { - breadcrumb: (): string => i18next.t('dashboard:email_accounts'), - }, + ...lazyRouteConfig(() => + import('@/pages/dashboard/EmailAccounts/EmailAccounts'), + ), + children: [ + { + path: 'add', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/EmailAccounts/AddAndEditEmailAccount' + ), + ), + handle: { isOverridePage: true }, + }, + { + path: 'edit', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/EmailAccounts/AddAndEditEmailAccount' + ), + ), + handle: { isOverridePage: true }, + }, + { + path: 'delete', + ...lazyRouteConfig(() => + import( + '@/pages/dashboard/EmailAccounts/ModalDeleteEmailAccount' + ), + ), + }, + ], }, ], }, diff --git a/packages/manager/apps/zimbra/src/utils/convertOctets.ts b/packages/manager/apps/zimbra/src/utils/convertOctets.ts new file mode 100644 index 000000000000..2545b38055d5 --- /dev/null +++ b/packages/manager/apps/zimbra/src/utils/convertOctets.ts @@ -0,0 +1,30 @@ +import { useTranslation } from 'react-i18next'; + +const units = [ + { value: 1024 ** 4, label: 'zimbra_account_datagrid_quota_to' }, + { value: 1024 ** 3, label: 'zimbra_account_datagrid_quota_go' }, + { value: 1024 ** 2, label: 'zimbra_account_datagrid_quota_mo' }, + { value: 1024, label: 'zimbra_account_datagrid_quota_ko' }, +]; + +const formatValue = ( + value: number, + unitValue: number, + label: string, +): string => { + const convertedValue = + unitValue === 1 ? value.toString() : (value / unitValue).toFixed(2); + return `${convertedValue} ${label}`; +}; + +export const convertOctets = (value: number): string => { + const { t } = useTranslation('accounts'); + + const unit = units.find((u) => value >= u.value); + const label = unit + ? t(unit.label) + : t('zimbra_account_datagrid_quota_octets'); + const unitValue = unit ? unit.value : 1; + + return formatValue(value, unitValue, label); +}; diff --git a/packages/manager/apps/zimbra/src/utils/iamAction.constants.ts b/packages/manager/apps/zimbra/src/utils/iamAction.constants.ts new file mode 100644 index 000000000000..76d37c4a144c --- /dev/null +++ b/packages/manager/apps/zimbra/src/utils/iamAction.constants.ts @@ -0,0 +1,27 @@ +const IAM_ACTIONS_PREFIX = 'zimbra:apiovh:platform/'; + +export const IAM_ACTIONS = { + account: { + create: `${IAM_ACTIONS_PREFIX}account/create`, + delete: `${IAM_ACTIONS_PREFIX}account/delete`, + edit: `${IAM_ACTIONS_PREFIX}account/edit`, + get: `${IAM_ACTIONS_PREFIX}account/get`, + }, + domain: { + create: `${IAM_ACTIONS_PREFIX}domain/create`, + delete: `${IAM_ACTIONS_PREFIX}domain/delete`, + }, + organization: { + create: `${IAM_ACTIONS_PREFIX}organization/create`, + delete: `${IAM_ACTIONS_PREFIX}organization/delete`, + edit: `${IAM_ACTIONS_PREFIX}organization/edit`, + }, + platform: { + get: `${IAM_ACTIONS_PREFIX}get`, + }, + task: { + get: `${IAM_ACTIONS_PREFIX}task/get`, + }, +}; + +export default { IAM_ACTIONS }; diff --git a/packages/manager/apps/zimbra/src/utils/index.ts b/packages/manager/apps/zimbra/src/utils/index.ts new file mode 100644 index 000000000000..a1a4923a9be1 --- /dev/null +++ b/packages/manager/apps/zimbra/src/utils/index.ts @@ -0,0 +1 @@ +export * from './convertOctets'; diff --git a/packages/manager/apps/zimbra/src/utils/test.provider.tsx b/packages/manager/apps/zimbra/src/utils/test.provider.tsx new file mode 100644 index 000000000000..4b23d1336e2a --- /dev/null +++ b/packages/manager/apps/zimbra/src/utils/test.provider.tsx @@ -0,0 +1,59 @@ +import { render, RenderOptions, RenderResult } from '@testing-library/react'; +import i18n from 'i18next'; +import React, { ComponentType } from 'react'; +import { I18nextProvider, initReactI18next } from 'react-i18next'; +import { MemoryRouter } from 'react-router-dom'; +import { QueryClientProvider } from '@tanstack/react-query'; +import dashboardTranslation from '@/public/translations/dashboard/Messages_fr_FR.json'; +import organizationsTranslation from '@/public/translations/organizations/Messages_fr_FR.json'; +import organizationsAddAndEditTranslation from '@/public/translations/organizations/addAndEdit/Messages_fr_FR.json'; +import organizationsDeleteTranslation from '@/public/translations/organizations/delete/Messages_fr_FR.json'; +import domainsTranslation from '@/public/translations/domains/Messages_fr_FR.json'; +import domainsAddDomainTranslation from '@/public/translations/domains/addDomain/Messages_fr_FR.json'; +import domainsDeleteTranslation from '@/public/translations/domains/delete/Messages_fr_FR.json'; +import accountTranslation from '@/public/translations/accounts/Messages_fr_FR.json'; +import accountAddAndEditTranslation from '@/public/translations/accounts/addAndEdit/Messages_fr_FR.json'; +import accountDeleteTranslation from '@/public/translations/accounts/delete/Messages_fr_FR.json'; +import queryClient from '@/queryClient'; +import '@testing-library/jest-dom'; +import 'element-internals-polyfill'; + +i18n.use(initReactI18next).init({ + lng: 'fr', + fallbackLng: 'fr', + resources: { + fr: { + dashboard: dashboardTranslation, + organizations: organizationsTranslation, + 'organizations/addAndEdit': organizationsAddAndEditTranslation, + 'organizations/delete': organizationsDeleteTranslation, + domains: domainsTranslation, + 'domains/addDomain': domainsAddDomainTranslation, + 'domains/delete': domainsDeleteTranslation, + accounts: accountTranslation, + 'accounts/addAndEdit': accountAddAndEditTranslation, + 'accounts/delete': accountDeleteTranslation, + }, + }, + ns: ['dashboard'], +}); + +const Wrappers = ({ children }: { children: React.ReactNode }) => { + return ( + + + {children} + + + ); +}; + +const customRender = ( + ui: React.JSX.Element, + options?: Omit, +): RenderResult => + render(ui, { wrapper: Wrappers as ComponentType, ...options }); + +export * from '@testing-library/react'; + +export { customRender as render }; diff --git a/packages/manager/apps/zimbra/tsconfig.json b/packages/manager/apps/zimbra/tsconfig.json index 9895f8a68b4c..8e9c91916e2a 100644 --- a/packages/manager/apps/zimbra/tsconfig.json +++ b/packages/manager/apps/zimbra/tsconfig.json @@ -19,10 +19,18 @@ "jsx": "react", "baseUrl": ".", "paths": { - "@/*": ["./src/*"], - "@playwright-helpers/*": ["../../../../playwright-helpers/*"] + "@/public/*": ["./public/*"], + "@/*": ["./src/*"] } }, "include": ["src"], - "exclude": ["node_modules", "dist", "types", "src/__tests__"] + "exclude": [ + "node_modules", + "dist", + "types", + "src/pages/dashboard/Organizations/__test__", + "src/pages/dashboard/Domains/__test__", + "src/pages/dashboard/EmailAccounts/__test__", + "src/hook/__test__" + ] } diff --git a/packages/manager/apps/zimbra/vitest.config.js b/packages/manager/apps/zimbra/vitest.config.js new file mode 100644 index 000000000000..ce6b3faa5017 --- /dev/null +++ b/packages/manager/apps/zimbra/vitest.config.js @@ -0,0 +1,37 @@ +import path from 'path'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + globals: true, + environment: 'jsdom', + coverage: { + include: ['src'], + exclude: [ + 'src/configInterface.ts', + 'src/api', + 'src/zimbra.config.ts', + 'src/__tests__', + 'src/vite-*.ts', + 'src/App.tsx', + 'src/hooks/__tests__', + 'src/hooks/index.ts', + 'src/hooks/types.ts', + 'src/index.tsx', + 'src/routes/routes.tsx', + 'src/utils/index.ts', + 'src/**/*constants.ts', + ], + }, + }, + resolve: { + alias: { + '@/public': path.resolve(__dirname, 'public'), + '@': path.resolve(__dirname, 'src'), + }, + mainFields: ['module'], + }, +}); diff --git a/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.controller.js b/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.controller.js index cfeeca5fefca..fe1cc2ce39c8 100644 --- a/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.controller.js +++ b/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.controller.js @@ -26,17 +26,47 @@ export default class FtthEligibilityCtrl { this.getAllServices(); } + static sortList(listToSort) { + const sorted = listToSort.sort((a, b) => { + if (a.accessType < b.accessType) { + return -1; + } + if (a.accessType > b.accessType) { + return 1; + } + + return 0; + }); + return sorted; + } + + static getAccessSorted(services) { + // Group by access type to display first ADSL and VDSL access + const groupBy = Object.groupBy(services, ({ accessType }) => { + return [ACCESS_TYPE.adsl, ACCESS_TYPE.vdsl].includes(accessType) + ? ELIGIBILITY.eligible + : ELIGIBILITY.not_eligible; + }); + const eligible = this.sortList(groupBy.eligible); + const notEligible = this.sortList(groupBy.not_eligible); + + const sorted = [...eligible, ...notEligible]; + return sorted; + } + getAllServices() { this.FtthEligibilityService.getAllServices() .then((data) => { this.servicesLength = data.length; - if (data.length <= this.amountServicesDisplayed) { - this.createServiceList(data).then((services) => { + + const sorted = this.constructor.getAccessSorted(data); + if (sorted.length <= this.amountServicesDisplayed) { + this.createServiceList(sorted).then((services) => { this.services = services; }); } else { // Get only this.amountServicesDisplayed elements from the list - const limitedServices = data.slice(0, this.amountServicesDisplayed); + const limitedServices = sorted.slice(0, this.amountServicesDisplayed); this.createServiceList(limitedServices).then((services) => { this.services = services; }); diff --git a/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.html b/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.html index b65569dd704c..6253bf1cb823 100644 --- a/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.html +++ b/packages/manager/modules/telecom-dashboard/src/ftth-eligibility/telecom-dashboard-ftth-eligibility.html @@ -23,7 +23,7 @@