UBERF-6486 Lock document content (#5799)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov
2024-06-13 13:27:59 +07:00
committed by GitHub
parent bf969fb27d
commit a409cfafb3
13 changed files with 142 additions and 9 deletions
+42
View File
@@ -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<Account>
@Prop(Collection(document.class.Document), document.string.ChildDocument)
children!: CollectionSize<Document>
@@ -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, {})
+12 -3
View File
@@ -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<Action<Doc, any>>
PublicLink: '' as Ref<Action<Doc, any>>,
LockContent: '' as Ref<Action<Doc, any>>,
UnlockContent: '' as Ref<Action<Doc, any>>
},
function: {
CanLockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
CanUnlockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>
},
viewlet: {
TeamspaceTable: '' as Ref<Viewlet>
@@ -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
}
})
+6
View File
@@ -18,6 +18,12 @@
<path d="M29.25 6.75997C28.6926 6.20061 28.0302 5.75679 27.3009 5.45396C26.5716 5.15112 25.7897 4.99524 25 4.99524C24.2103 4.99524 23.4284 5.15112 22.6991 5.45396C22.278 5.62881 21.8792 5.85065 21.5101 6.1146C21.0614 6.43545 21.0693 7.07931 21.4594 7.46935C21.8499 7.85988 22.4827 7.84994 22.9575 7.5679C23.1218 7.47029 23.2933 7.38434 23.4707 7.31086C23.9571 7.10938 24.4785 7.00567 25.005 7.00567C25.5315 7.00567 26.0528 7.10938 26.5393 7.31086C27.0257 7.51235 27.4677 7.80767 27.84 8.17997C28.2123 8.55227 28.5076 8.99425 28.7091 9.48068C28.9106 9.96711 29.0143 10.4885 29.0143 11.015C29.0143 11.5415 28.9106 12.0628 28.7091 12.5493C28.5076 13.0357 28.2123 13.4777 27.84 13.85L19.84 21.85C19.0894 22.6019 18.0709 23.0248 17.0085 23.0257C15.9461 23.0267 14.9269 22.6055 14.175 21.855C13.4231 21.1044 13.0001 20.0859 12.9992 19.0235C12.9983 17.9611 13.4194 16.9419 14.17 16.19L14.8803 15.4746C15.2675 15.0846 15.2659 14.4537 14.8787 14.0637C14.4886 13.6709 13.8519 13.6681 13.4604 14.0596L12.75 14.77C12.1906 15.3274 11.7468 15.9897 11.444 16.7191C11.1411 17.4484 10.9852 18.2303 10.9852 19.02C10.9852 19.8097 11.1411 20.5916 11.444 21.3209C11.7468 22.0502 12.1906 22.7125 12.75 23.27C13.8815 24.387 15.41 25.0092 17 25C17.7927 25.0032 18.5782 24.8494 19.3111 24.5473C20.044 24.2452 20.7098 23.8009 21.27 23.24L29.27 15.24C30.3909 14.1123 31.0184 12.5858 31.0147 10.9958C31.0109 9.40582 30.3762 7.88232 29.25 6.75997Z" />
<path d="M4.18997 24.82C3.81656 24.4483 3.52026 24.0065 3.31807 23.52C3.11589 23.0335 3.01181 22.5118 3.01181 21.985C3.01181 21.4581 3.11589 20.9365 3.31807 20.4499C3.52026 19.9634 3.81656 19.5216 4.18997 19.15L12.19 11.15C12.5616 10.7766 13.0034 10.4803 13.4899 10.2781C13.9765 10.0759 14.4981 9.97181 15.025 9.97181C15.5518 9.97181 16.0735 10.0759 16.56 10.2781C17.0465 10.4803 17.4883 10.7766 17.86 11.15C18.231 11.5246 18.5231 11.9698 18.7189 12.4594C18.9147 12.9489 19.0103 13.4728 19 14C19.003 14.5288 18.9012 15.0529 18.7004 15.5421C18.4995 16.0313 18.2037 16.4758 17.83 16.85L16.4072 18.2929C16.0213 18.6842 16.0289 19.3189 16.4175 19.7075C16.808 20.098 17.4466 20.1034 17.8371 19.7129L19.25 18.3C20.3785 17.1715 21.0124 15.6409 21.0124 14.045C21.0124 12.449 20.3785 10.9185 19.25 9.78997C18.1215 8.66147 16.5909 8.02749 14.995 8.02749C13.399 8.02749 11.8685 8.66147 10.74 9.78997L2.73997 17.79C2.17911 18.3476 1.73401 19.0106 1.43029 19.7408C1.12657 20.471 0.970215 21.2541 0.970215 22.045C0.970215 22.8358 1.12657 23.6189 1.43029 24.3492C1.73401 25.0794 2.17911 25.7424 2.73997 26.3C3.87879 27.4084 5.41087 28.0198 6.99997 28C8.26594 28.0012 9.49169 27.6069 10.5118 26.885C10.964 26.5651 10.961 25.921 10.5693 25.5293C10.1781 25.1381 9.54699 25.1518 9.0717 25.4348C8.90786 25.5324 8.73689 25.6184 8.56 25.6919C8.07349 25.8941 7.55182 25.9981 7.02497 25.9981C6.49812 25.9981 5.97645 25.8941 5.48994 25.6919C5.00342 25.4897 4.56164 25.1934 4.18997 24.82Z" />
</symbol>
<symbol id="lock" viewBox="0 0 16 16">
<path d="M4.69141 14.6338H11.3018C12.2178 14.6338 12.6689 14.1826 12.6689 13.1914V8.08496C12.6689 7.18945 12.293 6.72461 11.541 6.64941V4.96094C11.541 2.36328 9.81152 1.1123 7.99316 1.1123C6.18164 1.1123 4.45215 2.36328 4.45215 4.96094V6.67676C3.74805 6.78613 3.32422 7.2373 3.32422 8.08496V13.1914C3.32422 14.1826 3.77539 14.6338 4.69141 14.6338ZM5.75098 4.83105C5.75098 3.22461 6.76953 2.35645 7.99316 2.35645C9.2168 2.35645 10.2422 3.22461 10.2422 4.83105V6.64258L5.75098 6.64941V4.83105Z" />
</symbol>
<symbol id="unlock" viewBox="0 0 16 16">
<path d="M2.33301 14.6338H8.94336C9.85938 14.6338 10.3105 14.1826 10.3105 13.1914V8.08496C10.3105 7.2168 9.95508 6.75195 9.24414 6.65625V4.83105C9.24414 3.22461 10.2627 2.35645 11.4863 2.35645C12.71 2.35645 13.7354 3.22461 13.7354 4.83105V6.28711C13.7354 6.76562 14.0156 7.01855 14.3848 7.01855C14.7471 7.01855 15.0273 6.7793 15.0273 6.28711V4.96094C15.0273 2.36328 13.2979 1.1123 11.4863 1.1123C9.6748 1.1123 7.94531 2.36328 7.94531 4.96094V6.64258L2.44922 6.64941C1.5332 6.64941 0.96582 7.10742 0.96582 8.08496V13.1914C0.96582 14.1826 1.41699 14.6338 2.33301 14.6338Z" />
</symbol>
<symbol id="star" viewBox="0 0 20 20">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 1.25C10.2357 1.25 10.4504 1.38744 10.5518 1.60323L12.9271 6.65845L18.2297 7.46775C18.4573 7.50249 18.6464 7.66396 18.7189 7.88551C18.7914 8.10707 18.735 8.35113 18.573 8.51698L14.7234 12.4583L15.6331 18.0288C15.6712 18.2626 15.5747 18.498 15.3842 18.6353C15.1938 18.7726 14.9429 18.7878 14.7377 18.6745L10 16.0584L5.2623 18.6745C5.0571 18.7878 4.80616 18.7726 4.61575 18.6353C4.42534 18.498 4.32878 18.2626 4.36695 18.0288L5.27657 12.4583L1.42699 8.51698C1.26501 8.35113 1.20863 8.10707 1.28112 7.88551C1.35361 7.66396 1.54269 7.50249 1.7703 7.46775L7.07289 6.65845L9.44819 1.60323C9.54958 1.38744 9.76429 1.25 10 1.25ZM10 3.31093L8.0368 7.48908C7.94945 7.67499 7.77676 7.80476 7.57596 7.83541L3.14286 8.51201L6.36491 11.8109C6.50295 11.9522 6.56572 12.1521 6.53368 12.3484L5.77765 16.9783L9.70769 14.8081C9.88993 14.7075 10.1101 14.7075 10.2923 14.8081L14.2223 16.9783L13.4663 12.3484C13.4343 12.1521 13.497 11.9522 13.6351 11.8109L16.8571 8.51201L12.424 7.83541C12.2232 7.80476 12.0505 7.67499 11.9632 7.48908L10 3.31093Z" />
</symbol>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

+4
View File
@@ -48,6 +48,10 @@
"Star": "Star",
"Unstar": "Unstar",
"Lock": "Lock",
"Unlock": "Unlock",
"Locked": "Locked",
"ConfigLabel": "Documents",
"ConfigDescription": "Extension for collaborative document editing",
+3
View File
@@ -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",
+3
View File
@@ -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",
+4
View File
@@ -48,6 +48,10 @@
"Star": "Добавить в закладки",
"Unstar": "Удалить из закладок",
"Lock": "Запретить изменения",
"Unlock": "Разрешить изменения",
"Locked": "Защищино от изменений",
"ConfigLabel": "Документы",
"ConfigDescription": "Расширение по работе с текстовыми документами",
+2
View File
@@ -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`
})
@@ -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 @@
<svelte:fragment slot="title">
<ParentsNavigator element={doc} />
<DocumentPresenter value={doc} breadcrumb noUnderline />
{#if locked}
<div class="ml-2">
<Button
icon={document.icon.Lock}
iconProps={{ size: 'x-small' }}
label={document.string.Locked}
kind={'link-bordered'}
size={'small'}
noFocus
on:click={async () => {
if (doc !== undefined) {
await unlockContent(doc)
}
}}
/>
</div>
{/if}
</svelte:fragment>
<svelte:fragment slot="utils">
+36 -2
View File
@@ -15,6 +15,7 @@
import {
generateId,
getCurrentAccount,
type Class,
type Client,
type DocumentQuery,
@@ -122,6 +123,35 @@ export async function unstarDocument (doc: Document): Promise<void> {
}
}
export async function lockContent (doc: Document | Document[]): Promise<void> {
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<void> {
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<boolean> {
const arr = Array.isArray(doc) ? doc : [doc]
return arr.some((p) => p.lockedBy == null)
}
export async function canUnlockDocument (doc: Document | Document[]): Promise<boolean> {
const arr = Array.isArray(doc) ? doc : [doc]
return arr.some((p) => p.lockedBy != null)
}
export default async (): Promise<Resources> => ({
component: {
CreateDocument,
@@ -148,12 +178,16 @@ export default async (): Promise<Resources> => ({
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
+4
View File
@@ -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,
+3 -1
View File
@@ -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<Doc>
+3 -1
View File
@@ -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<Document, 'children', Teamspace>,
name: string
content: CollaborativeDoc
lockedBy?: Ref<Account> | null
snapshots?: number
attachments?: number
children?: number