diff --git a/models/document/src/index.ts b/models/document/src/index.ts index dcea580104..f731f14beb 100644 --- a/models/document/src/index.ts +++ b/models/document/src/index.ts @@ -96,6 +96,10 @@ export class TDocument extends TAttachedDoc implements Document { @Hidden() content!: CollaborativeDoc + @Prop(TypeRef(core.class.Account), document.string.LockedBy) + @Hidden() + lockedBy?: Ref + @Prop(Collection(document.class.Document), document.string.ChildDocument) children!: CollectionSize @@ -373,6 +377,44 @@ function defineDocument (builder: Builder): void { document.action.CopyDocumentLink ) + createAction( + builder, + { + action: document.actionImpl.LockContent, + label: document.string.Lock, + icon: document.icon.Lock, + input: 'focus', + category: document.category.Document, + target: document.class.Document, + context: { + mode: ['context', 'browser'], + application: document.app.Documents, + group: 'copy' + }, + visibilityTester: document.function.CanLockDocument + }, + document.action.LockContent + ) + + createAction( + builder, + { + action: document.actionImpl.UnlockContent, + label: document.string.Unlock, + icon: document.icon.Unlock, + input: 'focus', + category: document.category.Document, + target: document.class.Document, + context: { + mode: ['context', 'browser'], + application: document.app.Documents, + group: 'copy' + }, + visibilityTester: document.function.CanUnlockDocument + }, + document.action.UnlockContent + ) + // Notifications builder.mixin(document.class.Document, core.class.Class, activity.mixin.ActivityDoc, {}) diff --git a/models/document/src/plugin.ts b/models/document/src/plugin.ts index 3f7a6a0252..b300742654 100644 --- a/models/document/src/plugin.ts +++ b/models/document/src/plugin.ts @@ -40,10 +40,18 @@ export default mergeIds(documentId, document, { actionImpl: { CreateChildDocument: '' as ViewAction, CreateDocument: '' as ViewAction, - EditTeamspace: '' as ViewAction + EditTeamspace: '' as ViewAction, + LockContent: '' as ViewAction, + UnlockContent: '' as ViewAction }, action: { - PublicLink: '' as Ref> + PublicLink: '' as Ref>, + LockContent: '' as Ref>, + UnlockContent: '' as Ref> + }, + function: { + CanLockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, + CanUnlockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise> }, viewlet: { TeamspaceTable: '' as Ref @@ -55,6 +63,7 @@ export default mergeIds(documentId, document, { string: { ConfigDescription: '' as IntlString, ParentDocument: '' as IntlString, - ChildDocument: '' as IntlString + ChildDocument: '' as IntlString, + LockedBy: '' as IntlString } }) diff --git a/plugins/document-assets/assets/icons.svg b/plugins/document-assets/assets/icons.svg index b85c321278..53644afe7f 100644 --- a/plugins/document-assets/assets/icons.svg +++ b/plugins/document-assets/assets/icons.svg @@ -18,6 +18,12 @@ + + + + + + diff --git a/plugins/document-assets/lang/en.json b/plugins/document-assets/lang/en.json index 5618afd99a..488c3d094a 100644 --- a/plugins/document-assets/lang/en.json +++ b/plugins/document-assets/lang/en.json @@ -48,6 +48,10 @@ "Star": "Star", "Unstar": "Unstar", + "Lock": "Lock", + "Unlock": "Unlock", + "Locked": "Locked", + "ConfigLabel": "Documents", "ConfigDescription": "Extension for collaborative document editing", diff --git a/plugins/document-assets/lang/es.json b/plugins/document-assets/lang/es.json index a244ba12e3..3a22b65b14 100644 --- a/plugins/document-assets/lang/es.json +++ b/plugins/document-assets/lang/es.json @@ -43,6 +43,9 @@ "CompareTo": "Comparar con...", "Star": "Destacar", "Unstar": "Quitar destacado", + "Lock": "Bloquear", + "Unlock": "Desbloquear", + "Locked": "Bloqueado", "ConfigLabel": "Documentos", "ConfigDescription": "Extensión para edición colaborativo de documentos", "UnassignToDo": "Eliminar tarea asignada", diff --git a/plugins/document-assets/lang/pt.json b/plugins/document-assets/lang/pt.json index 888c916d4d..53bf53cd24 100644 --- a/plugins/document-assets/lang/pt.json +++ b/plugins/document-assets/lang/pt.json @@ -43,6 +43,9 @@ "CompareTo": "Comparar com...", "Star": "Destacar", "Unstar": "Remover destaque", + "Lock": "Bloquear", + "Unlock": "Desbloquear", + "Locked": "Bloqueado", "ConfigLabel": "Documentos", "ConfigDescription": "Extensão para edição colaborativa de documentos", "UnassignToDo": "Remover tarefa atribuída", diff --git a/plugins/document-assets/lang/ru.json b/plugins/document-assets/lang/ru.json index aaaeca73f9..913ea2afc7 100644 --- a/plugins/document-assets/lang/ru.json +++ b/plugins/document-assets/lang/ru.json @@ -48,6 +48,10 @@ "Star": "Добавить в закладки", "Unstar": "Удалить из закладок", + "Lock": "Запретить изменения", + "Unlock": "Разрешить изменения", + "Locked": "Защищино от изменений", + "ConfigLabel": "Документы", "ConfigDescription": "Расширение по работе с текстовыми документами", diff --git a/plugins/document-assets/src/index.ts b/plugins/document-assets/src/index.ts index 20212cdb0d..64a0197dc9 100644 --- a/plugins/document-assets/src/index.ts +++ b/plugins/document-assets/src/index.ts @@ -24,6 +24,8 @@ loadMetadata(document.icon, { Teamspace: `${icons}#teamspace`, References: `${icons}#references`, History: `${icons}#history`, + Lock: `${icons}#lock`, + Unlock: `${icons}#unlock`, Star: `${icons}#star`, Starred: `${icons}#starred` }) diff --git a/plugins/document-resources/src/components/EditDoc.svelte b/plugins/document-resources/src/components/EditDoc.svelte index 1466451f02..db690996ca 100644 --- a/plugins/document-resources/src/components/EditDoc.svelte +++ b/plugins/document-resources/src/components/EditDoc.svelte @@ -50,7 +50,7 @@ } from '@hcengineering/view-resources' import { createEventDispatcher, onDestroy, onMount } from 'svelte' - import { starDocument, unstarDocument } from '..' + import { starDocument, unstarDocument, unlockContent } from '..' import document from '../plugin' import { getDocumentUrl } from '../utils' import DocumentEditor from './DocumentEditor.svelte' @@ -64,7 +64,8 @@ export let embedded: boolean = false export let kind: 'default' | 'modern' = 'default' - $: readonly = $restrictionStore.readonly + $: locked = doc?.lockedBy != null + $: readonly = $restrictionStore.readonly || locked export function canClose (): boolean { return false @@ -248,6 +249,23 @@ + {#if locked} +
+
+ {/if}
diff --git a/plugins/document-resources/src/index.ts b/plugins/document-resources/src/index.ts index 52e9e45d6b..28292f5f02 100644 --- a/plugins/document-resources/src/index.ts +++ b/plugins/document-resources/src/index.ts @@ -15,6 +15,7 @@ import { generateId, + getCurrentAccount, type Class, type Client, type DocumentQuery, @@ -122,6 +123,35 @@ export async function unstarDocument (doc: Document): Promise { } } +export async function lockContent (doc: Document | Document[]): Promise { + const client = getClient() + const me = getCurrentAccount() + + const arr = Array.isArray(doc) ? doc : [doc] + for (const doc of arr) { + await client.diffUpdate(doc, { lockedBy: me._id }) + } +} + +export async function unlockContent (doc: Document | Document[]): Promise { + const client = getClient() + + const arr = Array.isArray(doc) ? doc : [doc] + for (const doc of arr) { + await client.diffUpdate(doc, { lockedBy: null }) + } +} + +export async function canLockDocument (doc: Document | Document[]): Promise { + const arr = Array.isArray(doc) ? doc : [doc] + return arr.some((p) => p.lockedBy == null) +} + +export async function canUnlockDocument (doc: Document | Document[]): Promise { + const arr = Array.isArray(doc) ? doc : [doc] + return arr.some((p) => p.lockedBy != null) +} + export default async (): Promise => ({ component: { CreateDocument, @@ -148,12 +178,16 @@ export default async (): Promise => ({ actionImpl: { CreateChildDocument: createChildDocument, CreateDocument: createDocument, - EditTeamspace: editTeamspace + EditTeamspace: editTeamspace, + LockContent: lockContent, + UnlockContent: unlockContent }, function: { GetDocumentLink: getDocumentUrl, GetObjectLinkFragment: getDocumentLink, - DocumentTitleProvider: documentTitleProvider + DocumentTitleProvider: documentTitleProvider, + CanLockDocument: canLockDocument, + CanUnlockDocument: canUnlockDocument }, resolver: { Location: resolveLocation diff --git a/plugins/document-resources/src/plugin.ts b/plugins/document-resources/src/plugin.ts index c779ce41af..2bb41765aa 100644 --- a/plugins/document-resources/src/plugin.ts +++ b/plugins/document-resources/src/plugin.ts @@ -71,6 +71,10 @@ export default mergeIds(documentId, document, { Unstar: '' as IntlString, CopyDocumentUrl: '' as IntlString, + Lock: '' as IntlString, + Unlock: '' as IntlString, + Locked: '' as IntlString, + ViewMode: '' as IntlString, EditMode: '' as IntlString, SuggestMode: '' as IntlString, diff --git a/plugins/document/src/plugin.ts b/plugins/document/src/plugin.ts index 900a3f63ae..426030f1c6 100644 --- a/plugins/document/src/plugin.ts +++ b/plugins/document/src/plugin.ts @@ -58,7 +58,9 @@ export const documentPlugin = plugin(documentId, { References: '' as Asset, History: '' as Asset, Star: '' as Asset, - Starred: '' as Asset + Starred: '' as Asset, + Lock: '' as Asset, + Unlock: '' as Asset }, app: { Documents: '' as Ref diff --git a/plugins/document/src/types.ts b/plugins/document/src/types.ts index 1b7e8ffc5f..ab2b64d3e5 100644 --- a/plugins/document/src/types.ts +++ b/plugins/document/src/types.ts @@ -14,7 +14,7 @@ // import { Attachment } from '@hcengineering/attachment' -import { AttachedDoc, Class, CollaborativeDoc, Ref, TypedSpace } from '@hcengineering/core' +import { Account, AttachedDoc, Class, CollaborativeDoc, Ref, TypedSpace } from '@hcengineering/core' import { Preference } from '@hcengineering/preference' import { IconProps } from '@hcengineering/view' @@ -28,6 +28,8 @@ export interface Document extends AttachedDoc, name: string content: CollaborativeDoc + lockedBy?: Ref | null + snapshots?: number attachments?: number children?: number