From c6e752c7aa21e30a820bb2f1dddfc7bda656a5d4 Mon Sep 17 00:00:00 2001 From: Victor Ilyushchenko Date: Mon, 24 Feb 2025 17:13:35 +0300 Subject: [PATCH] EQMS-1451/1453/1455: reference tweaks for QMS documents (#8083) * EQMS-1451/1453/1455: reference tweaks for QMS documents Signed-off-by: Victor Ilyushchenko * fmt Signed-off-by: Victor Ilyushchenko --------- Signed-off-by: Victor Ilyushchenko --- models/controlled-documents/src/index.ts | 14 +++- models/controlled-documents/src/plugin.ts | 6 ++ models/view/src/index.ts | 7 ++ .../controlled-documents-assets/lang/cs.json | 4 +- .../controlled-documents-assets/lang/de.json | 4 +- .../controlled-documents-assets/lang/en.json | 4 +- .../controlled-documents-assets/lang/fr.json | 4 +- .../controlled-documents-assets/lang/it.json | 4 +- .../controlled-documents-assets/lang/ru.json | 4 +- .../controlled-documents-assets/lang/zh.json | 4 +- .../components/document/EditDocContent.svelte | 11 ++- .../document/popups/ChangeDocCodePopup.svelte | 6 +- .../src/index.ts | 6 ++ .../src/plugin.ts | 5 +- .../src/utils.ts | 72 +++++++++++++++++-- plugins/controlled-documents/src/docutils.ts | 2 +- plugins/controlled-documents/src/utils.ts | 25 ++++--- .../src/components/MentionPopup.svelte | 9 +-- .../src/components/extension/reference.ts | 22 +++++- plugins/view/src/index.ts | 2 + plugins/view/src/types.ts | 7 ++ .../src/index.ts | 13 ++-- 22 files changed, 195 insertions(+), 40 deletions(-) diff --git a/models/controlled-documents/src/index.ts b/models/controlled-documents/src/index.ts index 1b15efadc0..aaf04d5ed4 100644 --- a/models/controlled-documents/src/index.ts +++ b/models/controlled-documents/src/index.ts @@ -106,7 +106,7 @@ export function createModel (builder: Builder): void { }) builder.mixin(documents.class.DocumentMeta, core.class.Class, view.mixin.ObjectTitle, { - titleProvider: documents.function.ControlledDocumentTitleProvider + titleProvider: documents.function.DocumentMetaTitleProvider }) builder.mixin(documents.class.DocumentApprovalRequest, core.class.Class, view.mixin.ObjectPresenter, { @@ -406,6 +406,10 @@ export function createModel (builder: Builder): void { presenter: documents.component.DocumentPresenter }) + builder.mixin(documents.class.ControlledDocument, core.class.Class, view.mixin.LinkProvider, { + encode: documents.function.GetControlledDocumentLinkFragment + }) + builder.mixin(documents.class.Document, core.class.Class, view.mixin.IgnoreActions, { actions: [view.action.Delete] }) @@ -741,6 +745,14 @@ export function createModel (builder: Builder): void { provider: documents.function.DocumentIdentifierProvider }) + builder.mixin(documents.class.ControlledDocument, core.class.Class, view.mixin.ReferenceObjectProvider, { + provider: documents.function.ControlledDocumentReferenceObjectProvider + }) + + builder.mixin(documents.class.ProjectDocument, core.class.Class, view.mixin.ReferenceObjectProvider, { + provider: documents.function.ProjectDocumentReferenceObjectProvider + }) + createAction( builder, { diff --git a/models/controlled-documents/src/plugin.ts b/models/controlled-documents/src/plugin.ts index fdde0039ed..e0b5eca013 100644 --- a/models/controlled-documents/src/plugin.ts +++ b/models/controlled-documents/src/plugin.ts @@ -53,6 +53,12 @@ export default mergeIds(documentsId, documents, { DocumentIdentifierProvider: '' as Resource< (client: Client, ref: Ref, doc?: T) => Promise >, + ControlledDocumentReferenceObjectProvider: '' as Resource< + (client: Client, ref: Ref, doc?: T) => Promise + >, + ProjectDocumentReferenceObjectProvider: '' as Resource< + (client: Client, ref: Ref, doc?: T) => Promise + >, Comment: '' as Resource, IsCommentVisible: '' as Resource }, diff --git a/models/view/src/index.ts b/models/view/src/index.ts index e83609c617..9c9b73d2b5 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -89,6 +89,7 @@ import { type ViewletDescriptor, type ViewletPreference, type ObjectIdentifier, + type ReferenceObjectProvider, type ObjectIcon, type ObjectTooltip, type AttrPresenter, @@ -253,6 +254,11 @@ export class TObjectIdentifier extends TClass implements ObjectIdentifier { provider!: Resource<(client: Client, ref: Ref, doc?: T) => Promise> } +@Mixin(view.mixin.ReferenceObjectProvider, core.class.Class) +export class TReferenceObjectProvider extends TClass implements ReferenceObjectProvider { + provider!: Resource<(client: Client, ref: Ref, doc?: T) => Promise> +} + @Mixin(view.mixin.ObjectTooltip, core.class.Class) export class TObjectTooltip extends TClass implements ObjectTooltip { provider!: Resource<(client: Client, doc?: Doc | null) => Promise> @@ -465,6 +471,7 @@ export function createModel (builder: Builder): void { TAggregation, TGroupping, TObjectIdentifier, + TReferenceObjectProvider, TObjectTooltip, TObjectIcon, TAttrPresenter, diff --git a/plugins/controlled-documents-assets/lang/cs.json b/plugins/controlled-documents-assets/lang/cs.json index 34f47aca5f..4241ef4869 100644 --- a/plugins/controlled-documents-assets/lang/cs.json +++ b/plugins/controlled-documents-assets/lang/cs.json @@ -300,7 +300,9 @@ "Obsolete": "Zastaralé", "MakeDocumentObsolete": "Označit jako zastaralé", "MakeDocumentObsoleteDialog": "Označit {count, plural, one {dokument jako zastaralý} other {dokumenty jako zastaralé}}", - "MakeDocumentObsoleteConfirm": "Opravdu chcete označit následující dokumenty jako zastaralé: {titles}?" + "MakeDocumentObsoleteConfirm": "Opravdu chcete označit následující dokumenty jako zastaralé: {titles}?", + + "LatestVersionHint": "nejnovější" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/de.json b/plugins/controlled-documents-assets/lang/de.json index 0653e4b4c0..f1866edaf9 100644 --- a/plugins/controlled-documents-assets/lang/de.json +++ b/plugins/controlled-documents-assets/lang/de.json @@ -307,7 +307,9 @@ "Obsolete": "Veraltet", "MakeDocumentObsolete": "Als veraltet markieren", "MakeDocumentObsoleteDialog": "{count, plural, one {Dokument als veraltet markieren} other {Dokumente als veraltet markieren}}", - "MakeDocumentObsoleteConfirm": "Möchten Sie die folgenden Dokumente wirklich als veraltet markieren: {titles}?" + "MakeDocumentObsoleteConfirm": "Möchten Sie die folgenden Dokumente wirklich als veraltet markieren: {titles}?", + + "LatestVersionHint": "neueste" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/en.json b/plugins/controlled-documents-assets/lang/en.json index dbd49df4b7..a98bc2d854 100644 --- a/plugins/controlled-documents-assets/lang/en.json +++ b/plugins/controlled-documents-assets/lang/en.json @@ -309,7 +309,9 @@ "CreateFolder": "Create new folder", "RenameFolder": "Rename folder", - "CreateChildFolder": "Create child folder" + "CreateChildFolder": "Create child folder", + + "LatestVersionHint": "latest" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/fr.json b/plugins/controlled-documents-assets/lang/fr.json index 9b2ee9fe3f..82b93dbd9b 100644 --- a/plugins/controlled-documents-assets/lang/fr.json +++ b/plugins/controlled-documents-assets/lang/fr.json @@ -267,7 +267,9 @@ "Obsolete": "Obsolète", "MakeDocumentObsolete": "Marquer comme obsolète", "MakeDocumentObsoleteDialog": "Marquer {count, plural, one {le document comme obsolète} other {les documents comme obsolètes}}", - "MakeDocumentObsoleteConfirm": "Voulez-vous vraiment marquer les documents suivants comme obsolètes : {titles} ?" + "MakeDocumentObsoleteConfirm": "Voulez-vous vraiment marquer les documents suivants comme obsolètes : {titles} ?", + + "LatestVersionHint": "dernier" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/it.json b/plugins/controlled-documents-assets/lang/it.json index 1ec19f9672..79b28decd0 100644 --- a/plugins/controlled-documents-assets/lang/it.json +++ b/plugins/controlled-documents-assets/lang/it.json @@ -265,7 +265,9 @@ "Obsolete": "Obsoleto", "MakeDocumentObsolete": "Segna come obsoleto", "MakeDocumentObsoleteDialog": "Segna {count, plural, one {il documento come obsoleto} other {i documenti come obsoleti}}", - "MakeDocumentObsoleteConfirm": "Vuoi davvero segnare i seguenti documenti come obsoleti: {titles}?" + "MakeDocumentObsoleteConfirm": "Vuoi davvero segnare i seguenti documenti come obsoleti: {titles}?", + + "LatestVersionHint": "ultimo" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/ru.json b/plugins/controlled-documents-assets/lang/ru.json index dd99112ec0..37fc54813b 100644 --- a/plugins/controlled-documents-assets/lang/ru.json +++ b/plugins/controlled-documents-assets/lang/ru.json @@ -309,7 +309,9 @@ "Obsolete": "Устаревший", "MakeDocumentObsolete": "Пометить как устаревшее", "MakeDocumentObsoleteDialog": "Пометить {count, plural, one {документ как устаревший} other {документы как устаревшие}}", - "MakeDocumentObsoleteConfirm": "Вы действительно хотите пометить следующие документы как устаревшие: {titles}?" + "MakeDocumentObsoleteConfirm": "Вы действительно хотите пометить следующие документы как устаревшие: {titles}?", + + "LatestVersionHint": "последняя" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-assets/lang/zh.json b/plugins/controlled-documents-assets/lang/zh.json index d0b07eddbe..7b4c2f584e 100644 --- a/plugins/controlled-documents-assets/lang/zh.json +++ b/plugins/controlled-documents-assets/lang/zh.json @@ -306,7 +306,9 @@ "Obsolete": "已过时", "MakeDocumentObsolete": "标记为过时", "MakeDocumentObsoleteDialog": "标记 {count, plural, one {文档为过时} other {文档为过时}}", - "MakeDocumentObsoleteConfirm": "您确定要将以下文档标记为过时吗:{titles}?" + "MakeDocumentObsoleteConfirm": "您确定要将以下文档标记为过时吗:{titles}?", + + "LatestVersionHint": "最新" }, "controlledDocStates": { "Empty": "", diff --git a/plugins/controlled-documents-resources/src/components/document/EditDocContent.svelte b/plugins/controlled-documents-resources/src/components/document/EditDocContent.svelte index 5e404a3980..fe2e87ccfd 100644 --- a/plugins/controlled-documents-resources/src/components/document/EditDocContent.svelte +++ b/plugins/controlled-documents-resources/src/components/document/EditDocContent.svelte @@ -49,10 +49,12 @@ $documentComments as documentComments, documentCommentsDisplayRequested, documentCommentsHighlightUpdated, - documentCommentsLocationNavigateRequested + documentCommentsLocationNavigateRequested, + $documentReleasedVersions as documentReleasedVersions } from '../../stores/editors/document' import DocumentTitle from './DocumentTitle.svelte' import DocumentPrintTitlePage from '../print/DocumentPrintTitlePage.svelte' + import { syncDocumentMetaTitle } from '../../utils' const client = getClient() const hierarchy = client.getHierarchy() @@ -111,14 +113,17 @@ unsubscribeNavigateToLocation() }) - const handleUpdateTitle = () => { + const handleUpdateTitle = async () => { if (!$controlledDocument || !title) { return } const titleTrimmed = title.trim() if (titleTrimmed.length > 0 && titleTrimmed !== $controlledDocument.title) { - client.update($controlledDocument, { title: titleTrimmed }) + await client.update($controlledDocument, { title: titleTrimmed }) + if ($documentReleasedVersions.length === 0 && $controlledDocument.state === DocumentState.Draft) { + await syncDocumentMetaTitle(client, $controlledDocument.attachedTo, $controlledDocument.code, titleTrimmed) + } } } diff --git a/plugins/controlled-documents-resources/src/components/document/popups/ChangeDocCodePopup.svelte b/plugins/controlled-documents-resources/src/components/document/popups/ChangeDocCodePopup.svelte index 8459e97d04..aeea262934 100644 --- a/plugins/controlled-documents-resources/src/components/document/popups/ChangeDocCodePopup.svelte +++ b/plugins/controlled-documents-resources/src/components/document/popups/ChangeDocCodePopup.svelte @@ -15,14 +15,15 @@ diff --git a/plugins/controlled-documents-resources/src/index.ts b/plugins/controlled-documents-resources/src/index.ts index 40d379be40..e7d32d0c4b 100644 --- a/plugins/controlled-documents-resources/src/index.ts +++ b/plugins/controlled-documents-resources/src/index.ts @@ -106,7 +106,10 @@ import { createTemplate, deleteFolder, documentIdentifierProvider, + controlledDocumentReferenceObjectProvider, + projectDocumentReferenceObjectProvider, getAllDocumentStates, + getControlledDocumentLinkFragment, getControlledDocumentTitle, getDocumentMetaLinkFragment, getDocumentMetaTitle, @@ -450,6 +453,7 @@ export default async (): Promise => ({ DocumentStateSort: sortDocumentStates, GetAllDocumentStates: getAllDocumentStates, GetDocumentMetaLinkFragment: getDocumentMetaLinkFragment, + GetControlledDocumentLinkFragment: getControlledDocumentLinkFragment, CanDeleteDocument: canDeleteDocument, CanArchiveDocument: canArchiveDocument, CanMakeDocumentObsolete: canMakeDocumentObsolete, @@ -457,6 +461,8 @@ export default async (): Promise => ({ CanOpenDocument: canOpenDocument, CanPrintDocument: canPrintDocument, DocumentIdentifierProvider: documentIdentifierProvider, + ControlledDocumentReferenceObjectProvider: controlledDocumentReferenceObjectProvider, + ProjectDocumentReferenceObjectProvider: projectDocumentReferenceObjectProvider, ControlledDocumentTitleProvider: getControlledDocumentTitle, DocumentMetaTitleProvider: getDocumentMetaTitle, Comment: comment, diff --git a/plugins/controlled-documents-resources/src/plugin.ts b/plugins/controlled-documents-resources/src/plugin.ts index 85a569dad6..04a794ca23 100644 --- a/plugins/controlled-documents-resources/src/plugin.ts +++ b/plugins/controlled-documents-resources/src/plugin.ts @@ -212,7 +212,9 @@ export default mergeIds(documentsId, documents, { CreateDocumentFailed: '' as IntlString, CreateDocumentTemplateFailed: '' as IntlString, - TryAgain: '' as IntlString + TryAgain: '' as IntlString, + + LatestVersionHint: '' as IntlString }, controlledDocStates: { Empty: '' as IntlString, @@ -240,6 +242,7 @@ export default mergeIds(documentsId, documents, { GetAllDocumentStates: '' as Resource<() => Promise>, GetVisibleFilters: '' as Resource<(filters: KeyFilter[], space?: Ref) => Promise>, GetDocumentMetaLinkFragment: '' as Resource<(doc: Doc, props: Record) => Promise>, + GetControlledDocumentLinkFragment: '' as Resource<(doc: Doc, props: Record) => Promise>, CanDeleteDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanArchiveDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanMakeDocumentObsolete: '' as Resource<(doc?: Doc | Doc[]) => Promise>, diff --git a/plugins/controlled-documents-resources/src/utils.ts b/plugins/controlled-documents-resources/src/utils.ts index d238e18a3b..bd411abe75 100644 --- a/plugins/controlled-documents-resources/src/utils.ts +++ b/plugins/controlled-documents-resources/src/utils.ts @@ -16,6 +16,7 @@ import { type Employee, type Person, type PersonAccount } from '@hcengineering/c import documents, { type ControlledDocument, type Document, + type DocumentBundle, type DocumentCategory, type DocumentComment, type DocumentMeta, @@ -27,12 +28,12 @@ import documents, { type ProjectDocument, type ProjectMeta, ControlledDocumentState, - type DocumentBundle, DocumentState, + ProjectDocumentTree, + compareDocumentVersions, emptyBundle, getDocumentName, - getFirstRank, - ProjectDocumentTree + getFirstRank } from '@hcengineering/controlled-documents' import core, { type Class, @@ -195,6 +196,18 @@ export async function getDocumentMetaLinkFragment (document: Doc): Promise { + const client = getClient() + const targetDocument = await client.findOne(documents.class.ProjectDocument, { document: document._id }) + + if (targetDocument === undefined) { + throw new Error('Cannot resolve a ProjectDocument for document ' + document._id) + } + + const project = targetDocument.project ?? documents.ids.NoProject + return getProjectDocumentLink(document, project) +} + export interface TeamPopupData { controlledDoc: ControlledDocument requestClass: Ref> @@ -707,6 +720,41 @@ export async function documentIdentifierProvider (client: Client, ref: Ref, + doc?: ControlledDocument +): Promise { + const document = doc ?? (await client.findOne(documents.class.ControlledDocument, { _id: ref })) + if (document === undefined) return + + const meta = await client.findOne(documents.class.DocumentMeta, { _id: document.attachedTo }) + if (meta === undefined) return + + let documentSeq: ControlledDocument[] = await client.findAll(documents.class.ControlledDocument, { + attachedTo: meta._id + }) + + const allowStates = [DocumentState.Draft, DocumentState.Effective] + documentSeq = documentSeq.filter((d) => allowStates.includes(d.state)).sort(compareDocumentVersions) + + const effIndex = documentSeq.findIndex((d) => d.state === DocumentState.Effective) + const docIndex = documentSeq.findIndex((d) => d._id === document._id) + + return docIndex >= 0 && (docIndex <= effIndex || effIndex < 0) ? meta : document +} + +export async function projectDocumentReferenceObjectProvider ( + client: Client, + ref: Ref, + doc?: ProjectDocument +): Promise { + const prjdoc = doc ?? (await client.findOne(documents.class.ProjectDocument, { _id: ref })) + if (prjdoc === undefined) return + + return await controlledDocumentReferenceObjectProvider(client, prjdoc.document as Ref) +} + export function documentCompareFn (doc1: Document, doc2: Document): number { return doc1.major - doc2.major !== 0 ? doc1.major - doc2.major : doc1.minor - doc2.minor } @@ -724,7 +772,7 @@ export async function getControlledDocumentTitle ( if (object === undefined) return '' - return object.title + return object.title + ` (${getDocumentVersionString(object)})` } export async function getDocumentMetaTitle ( @@ -736,7 +784,9 @@ export async function getDocumentMetaTitle ( if (object === undefined) return '' - return object.title + const hint = await translate(documentsResources.string.LatestVersionHint, {}) + + return object.title + ` (${hint})` } export const getCurrentEmployee = (): Ref | undefined => { @@ -932,3 +982,15 @@ export class DocumentHiearchyQuery { export function createDocumentHierarchyQuery (): DocumentHiearchyQuery { return new DocumentHiearchyQuery() } + +export async function syncDocumentMetaTitle ( + client: Client & TxOperations, + _id: Ref, + code: string, + title: string +): Promise { + const meta = await client.findOne(documents.class.DocumentMeta, { _id }) + if (meta !== undefined) { + await client.update(meta, { title: `${code} ${title}` }) + } +} diff --git a/plugins/controlled-documents/src/docutils.ts b/plugins/controlled-documents/src/docutils.ts index d1346c0356..9a13d9fb9f 100644 --- a/plugins/controlled-documents/src/docutils.ts +++ b/plugins/controlled-documents/src/docutils.ts @@ -166,7 +166,7 @@ export async function createControlledDocMetadata ( space, { documents: 0, - title: `${prefix}-${seqNumber} ${specTitle}` + title: `${specCode} ${specTitle}` }, metaId ) diff --git a/plugins/controlled-documents/src/utils.ts b/plugins/controlled-documents/src/utils.ts index 0e093632e1..f080cf494f 100644 --- a/plugins/controlled-documents/src/utils.ts +++ b/plugins/controlled-documents/src/utils.ts @@ -156,17 +156,25 @@ export function isFolder (doc: ProjectDocument | undefined): boolean { return doc !== undefined && doc.document === documents.ids.Folder } +function getDocumentSortSequence (doc: ControlledDocument | undefined): number[] { + return doc !== undefined ? [doc.seqNumber, doc.major, doc.minor, doc.createdOn ?? 0] : [0, 0, 0, 0] +} + +export function compareDocumentVersions ( + doc1: ControlledDocument | undefined, + doc2: ControlledDocument | undefined +): number { + const s0 = getDocumentSortSequence(doc1) + const s1 = getDocumentSortSequence(doc2) + return s0.reduce((r, v, i) => (r !== 0 ? r : s1[i] - v), 0) +} + function extractPresentableStateFromDocumentBundle (bundle: DocumentBundle, prjmeta: ProjectMeta): DocumentBundle { bundle = { ...bundle } const person = getCurrentAccount().person as Ref const documentById = toIdMap(bundle.ControlledDocument) - const getSortSequence = (prjdoc: ProjectDocument): number[] => { - const doc = documentById.get(prjdoc.document as Ref) - return doc !== undefined ? [doc.seqNumber, doc.major, doc.minor, doc.createdOn ?? 0] : [0, 0, 0, 0] - } - const prjdoc = bundle.ProjectDocument.filter((prjdoc) => { if (prjdoc.attachedTo !== prjmeta._id) return false if (isFolder(prjdoc)) return true @@ -174,9 +182,10 @@ function extractPresentableStateFromDocumentBundle (bundle: DocumentBundle, prjm const isPublicState = doc?.state === DocumentState.Effective || doc?.state === DocumentState.Archived return doc !== undefined && (isPublicState || isCollaborator(doc, person)) }).sort((a, b) => { - const s0 = getSortSequence(a) - const s1 = getSortSequence(b) - return s0.reduce((r, v, i) => (r !== 0 ? r : s1[i] - v), 0) + return compareDocumentVersions( + documentById.get(a.document as Ref), + documentById.get(b.document as Ref) + ) })[0] const doc = prjdoc !== undefined ? documentById.get(prjdoc.document as Ref) : undefined diff --git a/plugins/text-editor-resources/src/components/MentionPopup.svelte b/plugins/text-editor-resources/src/components/MentionPopup.svelte index c43b03241d..f57ea3e9dd 100644 --- a/plugins/text-editor-resources/src/components/MentionPopup.svelte +++ b/plugins/text-editor-resources/src/components/MentionPopup.svelte @@ -18,7 +18,7 @@ import presentation, { SearchResult, reduceCalls, searchFor, type SearchItem } from '@hcengineering/presentation' import { Label, ListView, resizeObserver } from '@hcengineering/ui' import { createEventDispatcher } from 'svelte' - import { getReferenceLabel } from './extension/reference' + import { getReferenceLabel, getReferenceObject } from './extension/reference' export let query: string = '' @@ -31,11 +31,12 @@ let selection = 0 async function handleSelectItem (item: SearchResultDoc): Promise { - const label = await getReferenceLabel(item.doc._class, item.doc._id) + const obj = (await getReferenceObject(item.doc._class, item.doc._id)) ?? item.doc + const label = await getReferenceLabel(obj._class, obj._id) dispatch('close', { - id: item.id, + id: obj._id, label, - objectclass: item.doc._class + objectclass: obj._class }) } diff --git a/plugins/text-editor-resources/src/components/extension/reference.ts b/plugins/text-editor-resources/src/components/extension/reference.ts index 8c1b69165a..f66c9fa3cf 100644 --- a/plugins/text-editor-resources/src/components/extension/reference.ts +++ b/plugins/text-editor-resources/src/components/extension/reference.ts @@ -344,10 +344,30 @@ export async function getReferenceLabel ( return label } +export async function getReferenceObject ( + objectclass: Ref>, + id: Ref, + doc?: T +): Promise { + const client = getClient() + const hierarchy = client.getHierarchy() + + const referenceObjectProvider = hierarchy.classHierarchyMixin( + objectclass as Ref>, + view.mixin.ReferenceObjectProvider + ) + const referenceObjectProviderFn = + referenceObjectProvider !== undefined ? await getResource(referenceObjectProvider.provider) : undefined + + return await referenceObjectProviderFn?.(client, id, doc) +} + export async function getReferenceFromUrl (urlString: string): Promise { - const target = await getTargetObjectFromUrl(urlString) + let target = await getTargetObjectFromUrl(urlString) if (target === undefined) return + target = (await getReferenceObject(target._class, target._id)) ?? target + const label = await getReferenceLabel(target._class, target._id) if (label === '') return diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 5cee522138..2b567833ac 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -52,6 +52,7 @@ import { ObjectTitle, ObjectTooltip, ObjectValidator, + ReferenceObjectProvider, AttrPresenter, PreviewPresenter, SpaceHeader, @@ -96,6 +97,7 @@ const view = plugin(viewId, { ObjectFactory: '' as Ref>, ObjectTitle: '' as Ref>, ObjectIdentifier: '' as Ref>, + ReferenceObjectProvider: '' as Ref>, ObjectTooltip: '' as Ref>, SpaceHeader: '' as Ref>, SpaceName: '' as Ref>, diff --git a/plugins/view/src/types.ts b/plugins/view/src/types.ts index b77614f365..063be94678 100644 --- a/plugins/view/src/types.ts +++ b/plugins/view/src/types.ts @@ -290,6 +290,13 @@ export interface ObjectIdentifier extends Class { provider: Resource<(client: Client, ref: Ref, doc?: T) => Promise> } +/** + * @public + */ +export interface ReferenceObjectProvider extends Class { + provider: Resource<(client: Client, ref: Ref, doc?: T) => Promise> +} + /** * @public */ diff --git a/server-plugins/controlled-documents-resources/src/index.ts b/server-plugins/controlled-documents-resources/src/index.ts index 2349ca95ac..a078023fb2 100644 --- a/server-plugins/controlled-documents-resources/src/index.ts +++ b/server-plugins/controlled-documents-resources/src/index.ts @@ -9,31 +9,30 @@ import documents, { DocumentApprovalRequest, DocumentState, DocumentTemplate, - getDocumentId, getEffectiveDocUpdate, type DocumentRequest, type DocumentTraining } from '@hcengineering/controlled-documents' import core, { AccountRole, + combineAttributes, + Doc, DocumentQuery, Ref, SortingOrder, Tx, TxCreateDoc, + TxCUD, TxFactory, TxUpdateDoc, type Account, type RolesAssignment, - type Timestamp, - Doc, - combineAttributes, - TxCUD + type Timestamp } from '@hcengineering/core' +import { NotificationType } from '@hcengineering/notification' import { RequestStatus } from '@hcengineering/request' import { TriggerControl } from '@hcengineering/server-core' import training, { TrainingState, type TrainingRequest } from '@hcengineering/training' -import { NotificationType } from '@hcengineering/notification' async function getDocs ( control: TriggerControl, @@ -77,7 +76,7 @@ function archiveDocs (docs: ControlledDocument[], txFactory: TxFactory): Tx[] { function updateMeta (doc: ControlledDocument, txFactory: TxFactory): Tx[] { return [ txFactory.createTxUpdateDoc(doc.attachedToClass, doc.space, doc.attachedTo, { - title: `${getDocumentId(doc)} ${doc.title}` + title: `${doc.code} ${doc.title}` }) ] }