diff --git a/@vates/types/src/common.mts b/@vates/types/src/common.mts index 9eafeaed92..e576854828 100644 --- a/@vates/types/src/common.mts +++ b/@vates/types/src/common.mts @@ -755,9 +755,9 @@ export type TrafficRuleDirection = 'from' | 'to' | 'from/to' export type RawTrafficRule = { allow: boolean - protocol: string + protocol: TrafficRuleProtocol ipRange: string - direction: string + direction: TrafficRuleDirection port?: string } diff --git a/@xen-orchestra/web-core/docs/i18n-weblate.md b/@xen-orchestra/web-core/docs/i18n-weblate.md index ba5ec2fc78..ab070fbecb 100644 --- a/@xen-orchestra/web-core/docs/i18n-weblate.md +++ b/@xen-orchestra/web-core/docs/i18n-weblate.md @@ -153,3 +153,10 @@ If the translation in your language for this new key is the same as an already e ``` This provides the option to override the `save-changes` translation in some locales if needed, while keeping the same translation as `save` by default. + +Some translations use modifiers on linked translations, such as `@.lower:` (lowercase) or `@.capitalize:`. + +These modifiers automatically transform the casing of the referenced translation. + +> [!IMPORTANT] +> When translating a key that is referenced with a modifier, keep in mind that the output will be automatically transformed. Make sure the result is correct in your language, and override the referencing key with a direct translation if needed. diff --git a/@xen-orchestra/web-core/docs/i18n.md b/@xen-orchestra/web-core/docs/i18n.md index 30078b70e0..9b51b79ce9 100644 --- a/@xen-orchestra/web-core/docs/i18n.md +++ b/@xen-orchestra/web-core/docs/i18n.md @@ -295,3 +295,21 @@ If you really need to **exceptionally** include a literal string, you can either For other locales added by contributors, some keys might be missing when we add new translations. This can result in ESLint errors when some translation keys are missing. To avoid this, remember to add the locale to the list of excluded files in `.eslintrc.js` at the root of the project (rule is `'@intlify/vue-i18n/no-missing-keys-in-other-locales': ['error', { ignoreLocales: ['de', 'fa'] }]`), and update the `@xen-orchestra/web-core/lib/i18n.ts` file to include the new locale. + +### Linked translations with modifiers + +Vue-i18n provides built-in modifiers that can be applied to linked translations, such as @.lower:, @.upper:, or @.capitalize:. + +These modifiers transform the referenced translation (e.g., forcing it to lowercase). + +> \[!IMPORTANT\] +> Case transformation rules vary across languages (e.g., German capitalizes all nouns, Turkish has specific `I`/`ı` casing rules). When using a modifier, the referenced key SHOULD contain a simple, standalone word - not a sentence or phrase. + +#### Example + +```json +{ + "vif": "VIF", + "on-vif": "on {'@.lower:vif'}" +} +``` diff --git a/@xen-orchestra/web-core/lib/locales/en.json b/@xen-orchestra/web-core/lib/locales/en.json index 8c7d8c08d5..38780d7c2a 100644 --- a/@xen-orchestra/web-core/lib/locales/en.json +++ b/@xen-orchestra/web-core/lib/locales/en.json @@ -71,6 +71,7 @@ "action:duplicate-n-vms": "Duplicate 1 VM | Duplicate {n} VMs", "action:edit": "Edit", "action:edit-config": "Edit config", + "action:edit-traffic-rule": "@:action:edit @.lower:traffic-rule", "action:enable": "Enable", "action:enable-host": "Enable host", "action:enable-light-mode": "Enable light mode", @@ -391,6 +392,7 @@ "fast-clone-available": "Fast clone is available only for halted VMs.", "fetching-fresh-data": "Fetching fresh data", "field:exceeds-max-characters": "Field value must be {max} characters or less.", + "field:required": "Field is required.", "file": "File", "filter-actions": "Filter actions", "following-hosts-unreachable": "The following hosts are unreachable", @@ -505,6 +507,7 @@ "job:delete:in-progress": "Delete in progress…", "job:disable:in-progress": "Disable in progress…", "job:disconnect:in-progress": "Disconnect in progress…", + "job:edit:in-progress": "Edit in progress…", "job:enable:in-progress": "Enable in progress…", "job:export:in-progress": "Export in progress…", "job:host-detach:in-progress": "Host detach in progress…", diff --git a/@xen-orchestra/web-core/lib/locales/fr.json b/@xen-orchestra/web-core/lib/locales/fr.json index be6a4d26fa..4dc2d1675f 100644 --- a/@xen-orchestra/web-core/lib/locales/fr.json +++ b/@xen-orchestra/web-core/lib/locales/fr.json @@ -71,6 +71,7 @@ "action:duplicate-n-vms": "Dupliquer 1 VM | Dupliquer {n} VMs", "action:edit": "Modifier", "action:edit-config": "Modifier config", + "action:edit-traffic-rule": "@:action:edit la @.lower:traffic-rule", "action:enable": "Activer", "action:enable-host": "Activer l'hôte", "action:enable-light-mode": "Activer le mode clair", @@ -391,6 +392,7 @@ "fast-clone-available": "Clonage rapide disponible uniquement pour les VMs arrêtées.", "fetching-fresh-data": "Récupération de données à jour", "field:exceeds-max-characters": "Le champ doit contenir {max} caractères ou moins.", + "field:required": "Champ obligatoire.", "file": "Fichier", "filter-actions": "Actions du filtre", "following-hosts-unreachable": "Les hôtes suivants sont inaccessibles", @@ -504,6 +506,7 @@ "job:delete:in-progress": "Suppression en cours…", "job:disable:in-progress": "Désactivation en cours…", "job:disconnect:in-progress": "Déconnexion en cours…", + "job:edit:in-progress": "Modification en cours…", "job:enable:in-progress": "Activation en cours…", "job:export:in-progress": "Export en cours…", "job:host-detach:in-progress": "Détachement de l'hôte en cours…", diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/TrafficRulesTable.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/TrafficRulesTable.vue index 4f2cfd6356..03857563d5 100644 --- a/@xen-orchestra/web/src/modules/traffic-rules/components/TrafficRulesTable.vue +++ b/@xen-orchestra/web/src/modules/traffic-rules/components/TrafficRulesTable.vue @@ -52,6 +52,7 @@ import type { FrontXoPool } from '@/modules/pool/remote-resources/use-xo-pool-co import { useDirectionLabels } from '@/modules/traffic-rules/composables/direction-labels.composable.ts' import { useTrafficRuleTarget } from '@/modules/traffic-rules/composables/traffic-rule-target.composable.ts' import { useTrafficRuleDelete } from '@/modules/traffic-rules/composables/use-traffic-rule-delete.composable.ts' +import { useTrafficRuleEdit } from '@/modules/traffic-rules/composables/use-traffic-rule-edit.composable.ts' import type { EnrichedTrafficRule } from '@/modules/traffic-rules/types.ts' import { XO_LINKS } from '@/shared/constants.ts' import VtsQueryBuilder from '@core/components/query-builder/VtsQueryBuilder.vue' @@ -154,6 +155,8 @@ const { HeadCells, BodyCells } = useTrafficRulesColumns({ const { deleteTrafficRules, canDeleteTrafficRules, isDeletingTrafficRules, deleteTrafficRulesErrorMessage } = useTrafficRuleDelete(() => [rule]) + const { editTrafficRule, canEditTrafficRule, isEditingTrafficRule } = useTrafficRuleEdit(() => rule) + return { order: r => r(rule.order), policy: r => r(t(rule.allow ? 'allow' : 'drop'), rule.allow ? 'success' : 'danger'), @@ -166,6 +169,13 @@ const { HeadCells, BodyCells } = useTrafficRulesColumns({ r({ onClick: () => (selectedRuleId.value = rule.id), actions: [ + { + label: t('action:edit'), + icon: 'action:edit', + onClick: () => editTrafficRule(), + busy: isEditingTrafficRule.value, + disabled: !canEditTrafficRule.value, + }, { label: t('action:delete'), icon: 'action:delete', diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/actions/TrafficRuleActions.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/actions/TrafficRuleActions.vue index 0e681a201f..98acd5ff72 100644 --- a/@xen-orchestra/web/src/modules/traffic-rules/components/actions/TrafficRuleActions.vue +++ b/@xen-orchestra/web/src/modules/traffic-rules/components/actions/TrafficRuleActions.vue @@ -1,15 +1,33 @@ diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/drawer/TrafficRuleEditDrawer.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/drawer/TrafficRuleEditDrawer.vue new file mode 100644 index 0000000000..be1e848b7b --- /dev/null +++ b/@xen-orchestra/web/src/modules/traffic-rules/components/drawer/TrafficRuleEditDrawer.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/form/edit/EditTrafficRuleForm.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/form/edit/EditTrafficRuleForm.vue new file mode 100644 index 0000000000..100d758785 --- /dev/null +++ b/@xen-orchestra/web/src/modules/traffic-rules/components/form/edit/EditTrafficRuleForm.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormNumberInput.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormNumberInput.vue similarity index 100% rename from @xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormNumberInput.vue rename to @xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormNumberInput.vue diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormSelect.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormSelect.vue similarity index 100% rename from @xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormSelect.vue rename to @xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormSelect.vue diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormTextInput.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormTextInput.vue similarity index 100% rename from @xen-orchestra/web/src/modules/traffic-rules/components/form/new/inputs/TrafficRuleFormTextInput.vue rename to @xen-orchestra/web/src/modules/traffic-rules/components/form/inputs/TrafficRuleFormTextInput.vue diff --git a/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/NewTrafficRuleForm.vue b/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/NewTrafficRuleForm.vue index 86462ee733..0fa5e2df73 100644 --- a/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/NewTrafficRuleForm.vue +++ b/@xen-orchestra/web/src/modules/traffic-rules/components/form/new/NewTrafficRuleForm.vue @@ -66,12 +66,12 @@