From ecadcc6814af19b33501fad85203c6bead2078d9 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Sun, 1 Mar 2026 00:38:01 +0500 Subject: [PATCH] feat: implement field locking and unlocking functionality, including UI, backend logic, and i18n. Signed-off-by: Denis Bykhov --- models/process/src/actions.ts | 28 ++++ models/server-process/src/index.ts | 8 ++ .../src/components/CardAttributes.svelte | 2 +- .../src/components/EditCardNew.svelte | 2 +- plugins/card/src/index.ts | 1 + plugins/process-assets/lang/cs.json | 4 +- plugins/process-assets/lang/de.json | 4 +- plugins/process-assets/lang/en.json | 4 +- plugins/process-assets/lang/es.json | 4 +- plugins/process-assets/lang/fr.json | 4 +- plugins/process-assets/lang/it.json | 4 +- plugins/process-assets/lang/ja.json | 4 +- plugins/process-assets/lang/pt-br.json | 4 +- plugins/process-assets/lang/pt.json | 4 +- plugins/process-assets/lang/ru.json | 4 +- plugins/process-assets/lang/tr.json | 4 +- plugins/process-assets/lang/zh.json | 4 +- .../settings/LockFieldEditor.svelte | 122 ++++++++++++++++++ .../settings/LockFieldPresenter.svelte | 37 ++++++ .../settings/UnLockFieldPresenter.svelte | 24 ++++ plugins/process-resources/src/index.ts | 8 +- plugins/process-resources/src/plugin.ts | 5 + plugins/process/src/index.ts | 4 +- .../process-resources/src/functions.ts | 73 ++++++++++- server-plugins/process-resources/src/index.ts | 8 +- server-plugins/process/src/index.ts | 2 + 26 files changed, 350 insertions(+), 22 deletions(-) create mode 100644 plugins/process-resources/src/components/settings/LockFieldEditor.svelte create mode 100644 plugins/process-resources/src/components/settings/LockFieldPresenter.svelte create mode 100644 plugins/process-resources/src/components/settings/UnLockFieldPresenter.svelte diff --git a/models/process/src/actions.ts b/models/process/src/actions.ts index 16dbbe6d1ab..38fc53629aa 100644 --- a/models/process/src/actions.ts +++ b/models/process/src/actions.ts @@ -199,4 +199,32 @@ export function defineMethods (builder: Builder): void { }, process.method.UnlockSection ) + + builder.createDoc( + process.class.Method, + core.space.Model, + { + label: process.string.LockField, + objectClass: card.class.Card, + editor: process.component.LockFieldEditor, + presenter: process.component.LockFieldPresenter, + requiredParams: ['value'], + createdContext: null + }, + process.method.LockField + ) + + builder.createDoc( + process.class.Method, + core.space.Model, + { + label: process.string.UnlockField, + objectClass: card.class.Card, + editor: process.component.LockFieldEditor, + presenter: process.component.UnLockFieldPresenter, + requiredParams: ['value'], + createdContext: null + }, + process.method.UnlockField + ) } diff --git a/models/server-process/src/index.ts b/models/server-process/src/index.ts index 5311e13197b..0db998cf3d0 100644 --- a/models/server-process/src/index.ts +++ b/models/server-process/src/index.ts @@ -155,6 +155,14 @@ export function createModel (builder: Builder): void { func: serverProcess.func.UnlockSection }) + builder.mixin(process.method.LockField, process.class.Method, serverProcess.mixin.MethodImpl, { + func: serverProcess.func.LockField + }) + + builder.mixin(process.method.UnlockField, process.class.Method, serverProcess.mixin.MethodImpl, { + func: serverProcess.func.UnlockField + }) + builder.mixin(process.function.FirstValue, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, { func: serverProcess.transform.FirstValue }) diff --git a/plugins/card-resources/src/components/CardAttributes.svelte b/plugins/card-resources/src/components/CardAttributes.svelte index b847b206927..4cb11f1e0e3 100644 --- a/plugins/card-resources/src/components/CardAttributes.svelte +++ b/plugins/card-resources/src/components/CardAttributes.svelte @@ -75,7 +75,7 @@ {_class} {object} {showHeader} - readonly={readonly || !canChange(key.attr, $permissionsStore)} + readonly={readonly || !canChange(key.attr, $permissionsStore) || object.readonlyFields?.includes(key.key)} withIcon on:update /> diff --git a/plugins/card-resources/src/components/EditCardNew.svelte b/plugins/card-resources/src/components/EditCardNew.svelte index 34682e7ad66..7ebe1514dda 100644 --- a/plugins/card-resources/src/components/EditCardNew.svelte +++ b/plugins/card-resources/src/components/EditCardNew.svelte @@ -153,7 +153,7 @@ } }) - $: _readonly = (readonly || doc?.readonly) ?? false + $: _readonly = (readonly || doc?.readonly || doc?.readonlyFields?.includes('title')) ?? false $: updatePermissionForbidden = doc && !canChangeDoc(doc?._class, doc?.space, $permissionsStore) diff --git a/plugins/card/src/index.ts b/plugins/card/src/index.ts index 67b563c0ed3..be58e4bcbf8 100644 --- a/plugins/card/src/index.ts +++ b/plugins/card/src/index.ts @@ -61,6 +61,7 @@ export interface Card extends Doc, IconProps, VersionableDoc { peerId?: string readonlySections?: Ref[] + readonlyFields?: string[] } export interface CardSpace extends TypedSpace { diff --git a/plugins/process-assets/lang/cs.json b/plugins/process-assets/lang/cs.json index a2eb5b9f162..52761a54542 100644 --- a/plugins/process-assets/lang/cs.json +++ b/plugins/process-assets/lang/cs.json @@ -150,7 +150,9 @@ "ActionType": "Typ", "ApproveAction": "Schválit", "ReviewAction": "Zkontrolovat", - "Review": "Zkontrolovat" + "Review": "Zkontrolovat", + "LockField": "Zamknout pole", + "UnlockField": "Odemknout pole" }, "error": { "MethodNotFound": "Metoda nenalezena: {methodId}", diff --git a/plugins/process-assets/lang/de.json b/plugins/process-assets/lang/de.json index 372510e39b0..1d605074b34 100644 --- a/plugins/process-assets/lang/de.json +++ b/plugins/process-assets/lang/de.json @@ -150,7 +150,9 @@ "ActionType": "Typ", "ApproveAction": "Genehmigen", "ReviewAction": "Prüfen", - "Review": "Prüfen" + "Review": "Prüfen", + "LockField": "Feld sperren", + "UnlockField": "Feld entsperren" }, "error": { "MethodNotFound": "Methode nicht gefunden: {methodId}", diff --git a/plugins/process-assets/lang/en.json b/plugins/process-assets/lang/en.json index 6da4d6741d5..35fb1c3fd38 100644 --- a/plugins/process-assets/lang/en.json +++ b/plugins/process-assets/lang/en.json @@ -155,7 +155,9 @@ "ActionType": "Type", "ApproveAction": "Approve", "ReviewAction": "Review", - "Review": "Review" + "Review": "Review", + "LockField": "Lock field", + "UnlockField": "Unlock field" }, "error": { "MethodNotFound": "Method not found: {methodId}", diff --git a/plugins/process-assets/lang/es.json b/plugins/process-assets/lang/es.json index ec7823a3cb5..1166a2fdef1 100644 --- a/plugins/process-assets/lang/es.json +++ b/plugins/process-assets/lang/es.json @@ -155,7 +155,9 @@ "ActionType": "Tipo", "ApproveAction": "Aprobar", "ReviewAction": "Revisar", - "Review": "Revisar" + "Review": "Revisar", + "LockField": "Bloquear campo", + "UnlockField": "Desbloquear campo" }, "error": { "MethodNotFound": "Método no encontrado: {methodId}", diff --git a/plugins/process-assets/lang/fr.json b/plugins/process-assets/lang/fr.json index 157b78ba8c1..03187830d51 100644 --- a/plugins/process-assets/lang/fr.json +++ b/plugins/process-assets/lang/fr.json @@ -155,7 +155,9 @@ "ActionType": "Type", "ApproveAction": "Approuver", "ReviewAction": "Revoir", - "Review": "Revoir" + "Review": "Revoir", + "LockField": "Verrouiller le champ", + "UnlockField": "Déverrouiller le champ" }, "error": { "MethodNotFound": "Méthode introuvable : {methodId}", diff --git a/plugins/process-assets/lang/it.json b/plugins/process-assets/lang/it.json index 0a6c05f1cc1..9aeccb2b83d 100644 --- a/plugins/process-assets/lang/it.json +++ b/plugins/process-assets/lang/it.json @@ -155,7 +155,9 @@ "ActionType": "Tipo", "ApproveAction": "Approva", "ReviewAction": "Revisa", - "Review": "Revisa" + "Review": "Revisa", + "LockField": "Blocca campo", + "UnlockField": "Sblocca campo" }, "error": { "MethodNotFound": "Metodo non trovato: {methodId}", diff --git a/plugins/process-assets/lang/ja.json b/plugins/process-assets/lang/ja.json index 3f2aacc4c07..c0f302bbdd6 100644 --- a/plugins/process-assets/lang/ja.json +++ b/plugins/process-assets/lang/ja.json @@ -154,7 +154,9 @@ "ActionType": "タイプ", "ApproveAction": "承認", "ReviewAction": "レビュー", - "Review": "レビュー" + "Review": "レビュー", + "LockField": "フィールドをロック", + "UnlockField": "フィールドのロックを解除" }, "error": { "MethodNotFound": "メソッドが見つかりません: {methodId}", diff --git a/plugins/process-assets/lang/pt-br.json b/plugins/process-assets/lang/pt-br.json index 74b2a6658e1..df361c1fa71 100644 --- a/plugins/process-assets/lang/pt-br.json +++ b/plugins/process-assets/lang/pt-br.json @@ -143,7 +143,9 @@ "ActionType": "Tipo", "ApproveAction": "Aprovar", "ReviewAction": "Revisar", - "Review": "Revisar" + "Review": "Revisar", + "LockField": "Bloquear campo", + "UnlockField": "Desbloquear campo" }, "error": { "MethodNotFound": "Método não encontrado: {methodId}", diff --git a/plugins/process-assets/lang/pt.json b/plugins/process-assets/lang/pt.json index c47ec498672..e0444f822ec 100644 --- a/plugins/process-assets/lang/pt.json +++ b/plugins/process-assets/lang/pt.json @@ -155,7 +155,9 @@ "ActionType": "Tipo", "ApproveAction": "Aprovar", "ReviewAction": "Revisar", - "Review": "Revisar" + "Review": "Revisar", + "LockField": "Bloquear campo", + "UnlockField": "Desbloquear campo" }, "error": { "MethodNotFound": "Método não encontrado: {methodId}", diff --git a/plugins/process-assets/lang/ru.json b/plugins/process-assets/lang/ru.json index 1f7902e0963..db744471136 100644 --- a/plugins/process-assets/lang/ru.json +++ b/plugins/process-assets/lang/ru.json @@ -155,7 +155,9 @@ "ActionType": "Тип", "ApproveAction": "Утверждение", "ReviewAction": "Рецензирование", - "Review": "Рецензировать" + "Review": "Рецензировать", + "LockField": "Заблокировать поле", + "UnlockField": "Разблокировать поле" }, "error": { "MethodNotFound": "Метод не найден: {methodId}", diff --git a/plugins/process-assets/lang/tr.json b/plugins/process-assets/lang/tr.json index 80fa74fba6b..77876e86eda 100644 --- a/plugins/process-assets/lang/tr.json +++ b/plugins/process-assets/lang/tr.json @@ -152,7 +152,9 @@ "ActionType": "Tür", "ApproveAction": "Onayla", "ReviewAction": "Gözden geçir", - "Review": "Gözden geçir" + "Review": "Gözden geçir", + "LockField": "Alanı kilitle", + "UnlockField": "Alanı kilitle" }, "error": { "MethodNotFound": "Metod bulunamadı: {methodId}", diff --git a/plugins/process-assets/lang/zh.json b/plugins/process-assets/lang/zh.json index 09731eef387..bbd15db200f 100644 --- a/plugins/process-assets/lang/zh.json +++ b/plugins/process-assets/lang/zh.json @@ -155,7 +155,9 @@ "ActionType": "类型", "ApproveAction": "批准", "ReviewAction": "审查", - "Review": "审查" + "Review": "审查", + "LockField": "锁定字段", + "UnlockField": "解锁字段" }, "error": { "MethodNotFound": "找不到方法:{methodId}", diff --git a/plugins/process-resources/src/components/settings/LockFieldEditor.svelte b/plugins/process-resources/src/components/settings/LockFieldEditor.svelte new file mode 100644 index 00000000000..b2b16016141 --- /dev/null +++ b/plugins/process-resources/src/components/settings/LockFieldEditor.svelte @@ -0,0 +1,122 @@ + + + +
+ {#each keys as key (key)} + {@const attribute = allAttrs.find((attr) => attr.name === key)} + {#if attribute} + + +
+
+ {/if} + {/each} +
+{#if possibleAttrs.length > 0} +
+
+{/if} + + diff --git a/plugins/process-resources/src/components/settings/LockFieldPresenter.svelte b/plugins/process-resources/src/components/settings/LockFieldPresenter.svelte new file mode 100644 index 00000000000..c0d8b6012dc --- /dev/null +++ b/plugins/process-resources/src/components/settings/LockFieldPresenter.svelte @@ -0,0 +1,37 @@ + + + + +