mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
feat: implement reference versioning functionality across various com… (#10941)
* feat: implement reference versioning functionality across various components and plugins Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * fix: simplify provider function calls and label retrieval in MentionPopup component Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * refactor: improve readability of version selection and reference handling in MentionVersionPopup and reference.ts Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * feat: add CardReferenceObjectProvider and integrate into card model and resources Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> --------- Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -22,6 +22,7 @@ export interface ReferenceNodeProps {
|
||||
id: Ref<Doc>
|
||||
objectclass: Ref<Class<Doc>>
|
||||
label: string
|
||||
fixed?: boolean
|
||||
}
|
||||
|
||||
export interface ReferenceOptions {
|
||||
@@ -42,7 +43,19 @@ export const ReferenceNode = Node.create<ReferenceOptions>({
|
||||
return {
|
||||
id: getDataAttribute('id'),
|
||||
objectclass: getDataAttribute('objectclass'),
|
||||
label: getDataAttribute('label')
|
||||
label: getDataAttribute('label'),
|
||||
fixed: {
|
||||
default: null,
|
||||
parseHTML: (element) => element.getAttribute('data-fixed') === 'true',
|
||||
renderHTML: (attributes) => {
|
||||
if (attributes.fixed !== true) {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
'data-fixed': 'true'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -91,6 +104,7 @@ function getAttrs (el: HTMLSpanElement): Attrs | false {
|
||||
const id = el.dataset.id?.trim()
|
||||
const label = el.dataset.label?.trim()
|
||||
const objectclass = el.dataset.objectclass?.trim()
|
||||
const fixed = el.getAttribute('data-fixed') === 'true'
|
||||
|
||||
if (id == null || label == null || objectclass == null) {
|
||||
return false
|
||||
@@ -99,6 +113,7 @@ function getAttrs (el: HTMLSpanElement): Attrs | false {
|
||||
return {
|
||||
id,
|
||||
label,
|
||||
objectclass
|
||||
objectclass,
|
||||
fixed: fixed || null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,6 +963,10 @@ export function createModel (builder: Builder): void {
|
||||
titleProvider: card.function.CardTitleProvider
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.ReferenceObjectProvider, {
|
||||
provider: card.function.CardReferenceObjectProvider
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.LinkProvider, {
|
||||
encode: card.function.GetCardLink
|
||||
})
|
||||
|
||||
@@ -471,6 +471,10 @@ export function createModel (builder: Builder): void {
|
||||
titleProvider: documents.function.DocumentMetaTitleProvider
|
||||
})
|
||||
|
||||
builder.mixin(documents.class.DocumentMeta, core.class.Class, view.mixin.ReferenceVersionsProvider, {
|
||||
provider: documents.function.DocumentMetaReferenceVersionsProvider
|
||||
})
|
||||
|
||||
builder.mixin(documents.class.DocumentMeta, core.class.Class, view.mixin.LinkProvider, {
|
||||
encode: documents.function.GetDocumentMetaLinkFragment
|
||||
})
|
||||
|
||||
@@ -92,6 +92,8 @@ import {
|
||||
type ObjectValidator,
|
||||
type PreviewPresenter,
|
||||
type ReferenceObjectProvider,
|
||||
type ReferenceVersion,
|
||||
type ReferenceVersionsProvider,
|
||||
type SortFunc,
|
||||
type SpaceHeader,
|
||||
type SpaceName,
|
||||
@@ -275,6 +277,11 @@ export class TReferenceObjectProvider extends TClass implements ReferenceObjectP
|
||||
provider!: Resource<<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<Doc | undefined>>
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.ReferenceVersionsProvider, core.class.Class)
|
||||
export class TReferenceVersionsProvider extends TClass implements ReferenceVersionsProvider {
|
||||
provider!: Resource<<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<ReferenceVersion[]>>
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.ObjectTooltip, core.class.Class)
|
||||
export class TObjectTooltip extends TClass implements ObjectTooltip {
|
||||
provider!: Resource<(client: Client, doc?: Doc | null) => Promise<LabelAndProps | undefined>>
|
||||
@@ -523,6 +530,7 @@ export function createModel (builder: Builder): void {
|
||||
TGroupping,
|
||||
TObjectIdentifier,
|
||||
TReferenceObjectProvider,
|
||||
TReferenceVersionsProvider,
|
||||
TObjectTooltip,
|
||||
TObjectIcon,
|
||||
TAttrPresenter,
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
editSpace,
|
||||
cardCustomLinkEncode,
|
||||
cardCustomLinkMatch,
|
||||
cardReferenceObjectProvider,
|
||||
openCardInSidebar,
|
||||
checkRelationsSectionVisibility,
|
||||
checkOldMessagesSectionVisibility,
|
||||
@@ -169,6 +170,7 @@ export default async (): Promise<Resources> => ({
|
||||
},
|
||||
function: {
|
||||
CardTitleProvider: getCardTitle,
|
||||
CardReferenceObjectProvider: cardReferenceObjectProvider,
|
||||
GetCardLink: getCardLink,
|
||||
CardCustomLinkMatch: cardCustomLinkMatch,
|
||||
CardCustomLinkEncode: cardCustomLinkEncode,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import card, { type Card, cardId } from '@hcengineering/card'
|
||||
import { type Permission, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type Client, type Permission, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineering/presentation'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
@@ -62,6 +62,9 @@ export default mergeIds(cardId, card, {
|
||||
},
|
||||
function: {
|
||||
CardFactory: '' as Resource<(props?: Record<string, any>) => Promise<Ref<Doc> | undefined>>,
|
||||
CardReferenceObjectProvider: '' as Resource<
|
||||
<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<Doc | undefined>
|
||||
>,
|
||||
FormatCardMarkdownValue: '' as Resource<ValueFormatter>,
|
||||
CheckChildrenSectionVisibility: '' as Resource<(doc: Card) => Promise<boolean>>
|
||||
},
|
||||
|
||||
@@ -486,6 +486,26 @@ export async function getCardTitle (client: TxOperations, ref: Ref<Card>, doc?:
|
||||
return ids + ' ' + object.title + ' ' + version
|
||||
}
|
||||
|
||||
export async function cardReferenceObjectProvider<T extends Doc> (
|
||||
client: Client,
|
||||
ref: Ref<T>,
|
||||
doc?: T
|
||||
): Promise<Doc | undefined> {
|
||||
const object =
|
||||
(doc as unknown as Card | undefined) ?? (await client.findOne(card.class.Card, { _id: ref as any as Ref<Card> }))
|
||||
if (object === undefined) return
|
||||
|
||||
const versioningEnabled = client
|
||||
.getHierarchy()
|
||||
.classHierarchyMixin(object._class, core.mixin.VersionableClass)?.enabled
|
||||
if (versioningEnabled !== true) return object
|
||||
|
||||
const baseId = object.baseId ?? object._id
|
||||
if (object.isLatest === true) return object
|
||||
|
||||
return (await client.findOne(object._class, { baseId, isLatest: true } as any)) ?? object
|
||||
}
|
||||
|
||||
export async function getCardLink (doc: Card): Promise<Location> {
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path.length = 2
|
||||
|
||||
@@ -103,6 +103,7 @@ import {
|
||||
createFolder,
|
||||
createTemplate,
|
||||
deleteFolder,
|
||||
documentMetaReferenceVersionsProvider,
|
||||
documentIdentifierProvider,
|
||||
controlledDocumentReferenceObjectProvider,
|
||||
projectDocumentReferenceObjectProvider,
|
||||
@@ -442,6 +443,7 @@ export default async (): Promise<Resources> => ({
|
||||
DocumentIdentifierProvider: documentIdentifierProvider,
|
||||
ControlledDocumentReferenceObjectProvider: controlledDocumentReferenceObjectProvider,
|
||||
ProjectDocumentReferenceObjectProvider: projectDocumentReferenceObjectProvider,
|
||||
DocumentMetaReferenceVersionsProvider: documentMetaReferenceVersionsProvider,
|
||||
ControlledDocumentTitleProvider: getControlledDocumentTitle,
|
||||
DocumentMetaTitleProvider: getDocumentMetaTitle,
|
||||
FormatDocumentMarkdownValue: formatControlledDocumentValue,
|
||||
|
||||
@@ -21,7 +21,7 @@ import documents, {
|
||||
import { type Client, type Doc, type Ref, type Space } from '@hcengineering/core'
|
||||
import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform'
|
||||
import { type AnyComponent, type Location } from '@hcengineering/ui/src/types'
|
||||
import type { KeyFilter, SortFunc, ViewActionAvailabilityFunction } from '@hcengineering/view'
|
||||
import type { KeyFilter, ReferenceVersion, SortFunc, ViewActionAvailabilityFunction } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(documentsId, documents, {
|
||||
component: {
|
||||
@@ -256,6 +256,9 @@ export default mergeIds(documentsId, documents, {
|
||||
CanPrintDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
||||
CanTransferDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise<boolean>>,
|
||||
ControlledDocumentTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>,
|
||||
DocumentMetaTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>
|
||||
DocumentMetaTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>,
|
||||
DocumentMetaReferenceVersionsProvider: '' as Resource<
|
||||
(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<ReferenceVersion[]>
|
||||
>
|
||||
}
|
||||
})
|
||||
|
||||
@@ -64,7 +64,7 @@ import { createQuery, getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import request, { type Request, RequestStatus } from '@hcengineering/request'
|
||||
import { isEmptyMarkup } from '@hcengineering/text'
|
||||
import { type Location, getUserTimezone, showPopup } from '@hcengineering/ui'
|
||||
import { type KeyFilter } from '@hcengineering/view'
|
||||
import { type KeyFilter, type ReferenceVersion } from '@hcengineering/view'
|
||||
|
||||
import { makeRank } from '@hcengineering/rank'
|
||||
import { getProjectDocumentLink } from './navigation'
|
||||
@@ -842,6 +842,29 @@ export async function getDocumentMetaTitle (
|
||||
return object.title + ` (${hint})`
|
||||
}
|
||||
|
||||
export async function documentMetaReferenceVersionsProvider (
|
||||
client: Client,
|
||||
ref: Ref<DocumentMeta>
|
||||
): Promise<ReferenceVersion[]> {
|
||||
const versions = await client.findAll(
|
||||
documents.class.ControlledDocument,
|
||||
{ attachedTo: ref },
|
||||
{
|
||||
sort: {
|
||||
major: SortingOrder.Descending,
|
||||
minor: SortingOrder.Descending
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return versions.map((doc) => ({
|
||||
id: doc._id,
|
||||
objectclass: doc._class,
|
||||
label: `${doc.title} (${getDocumentVersionString(doc)})`,
|
||||
fixed: true
|
||||
}))
|
||||
}
|
||||
|
||||
export async function controlledDocumentReferenceObjectProvider (
|
||||
client: Client,
|
||||
ref: Ref<ControlledDocument>,
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
"UnableToLoadEmbeddedContent": "Link preview couldn't be loaded due to permission settings or unsupported content",
|
||||
"CannotConnectToCollaborationService": "Cannot connect to collaboration service",
|
||||
"SourceURL": "Source URL",
|
||||
"SelectedDocuments": "Selected documents ({count, plural, =1 {1 item} other {# items}})"
|
||||
"SelectedDocuments": "Selected documents ({count, plural, =1 {1 item} other {# items}})",
|
||||
"LatestVersion": "Latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +82,11 @@
|
||||
"CannotConnectToCollaborationService": "Не удалось подключиться к сервису совместной работы",
|
||||
"SourceURL": "Исходный URL",
|
||||
"SelectedDocuments": "Выбранные документы ({count, plural, =1 {1 элемент} other {# элементов}})",
|
||||
"Highlight": "Highlight",
|
||||
"Subscript": "Subscript",
|
||||
"Superscript": "Superscript",
|
||||
"Mathematics": "Mathematics",
|
||||
"MathematicsBlock": "Mathematics block"
|
||||
"Highlight": "Выделение",
|
||||
"Subscript": "Нижний индекс",
|
||||
"Superscript": "Верхний индекс",
|
||||
"Mathematics": "Формула",
|
||||
"MathematicsBlock": "Блок формул",
|
||||
"LatestVersion": "Последняя"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,22 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import core, { SearchResultDoc, Ref, Class, Doc } from '@hcengineering/core'
|
||||
import contact from '@hcengineering/contact'
|
||||
import core, { Class, Doc, Ref, SearchResultDoc, SortingOrder, type VersionableDoc } from '@hcengineering/core'
|
||||
import { getResource, translate } from '@hcengineering/platform'
|
||||
import presentation, {
|
||||
SearchResult,
|
||||
getClient,
|
||||
reduceCalls,
|
||||
searchFor,
|
||||
type SearchItem,
|
||||
getClient
|
||||
SearchResult,
|
||||
type SearchItem
|
||||
} from '@hcengineering/presentation'
|
||||
import { Label, ListView, resizeObserver } from '@hcengineering/ui'
|
||||
import { Label, ListView, resizeObserver, Submenu } from '@hcengineering/ui'
|
||||
import view, { type ReferenceVersion, type ReferenceVersionsProvider } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import contact from '@hcengineering/contact'
|
||||
import { getReferenceLabel, getReferenceObject } from './extension/reference'
|
||||
import { translate } from '@hcengineering/platform'
|
||||
|
||||
import MentionVersionPopup from './MentionVersionPopup.svelte'
|
||||
|
||||
export let query: string = ''
|
||||
export let multipleMentions: boolean = false
|
||||
@@ -34,6 +37,62 @@
|
||||
|
||||
let items: SearchItem[] = []
|
||||
|
||||
function getReferenceVersionsProvider (doc: SearchResultDoc['doc']): ReferenceVersionsProvider | undefined {
|
||||
return client.getHierarchy().classHierarchyMixin(doc._class, view.mixin.ReferenceVersionsProvider)
|
||||
}
|
||||
|
||||
function getVersionableDoc (doc: SearchResultDoc['doc']): VersionableDoc | undefined {
|
||||
const enabled = client.getHierarchy().classHierarchyMixin(doc._class, core.mixin.VersionableClass)?.enabled
|
||||
if (enabled !== true) return
|
||||
|
||||
const versionedDoc = doc as VersionableDoc
|
||||
if (versionedDoc.baseId === undefined) return
|
||||
if (versionedDoc.isLatest === true && versionedDoc.baseId === versionedDoc._id) return
|
||||
return versionedDoc
|
||||
}
|
||||
|
||||
function hasReferenceVersions (doc: SearchResultDoc['doc']): boolean {
|
||||
return getReferenceVersionsProvider(doc) !== undefined || getVersionableDoc(doc) !== undefined
|
||||
}
|
||||
|
||||
async function getReferenceVersions (doc: SearchResultDoc['doc']): Promise<ReferenceVersion[]> {
|
||||
const provider = getReferenceVersionsProvider(doc)
|
||||
if (provider !== undefined) {
|
||||
const providerFn = await getResource(provider.provider)
|
||||
return await providerFn(client, doc._id)
|
||||
}
|
||||
|
||||
const versionedDoc = getVersionableDoc(doc)
|
||||
if (versionedDoc === undefined) return []
|
||||
|
||||
const versions = await client.findAll(
|
||||
doc._class,
|
||||
{ baseId: versionedDoc.baseId } as any,
|
||||
{ sort: { version: SortingOrder.Descending } } as any
|
||||
)
|
||||
|
||||
return await Promise.all(
|
||||
versions.map(async (version) => ({
|
||||
id: version._id,
|
||||
objectclass: version._class,
|
||||
label: await getReferenceLabel(version._class, version._id, version),
|
||||
fixed: true
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
async function getLatestReference (item: SearchResultDoc): Promise<ReferenceVersion> {
|
||||
return {
|
||||
id: item.doc._id,
|
||||
objectclass: item.doc._class,
|
||||
label: await getReferenceLabel(item.doc._class, item.doc._id)
|
||||
}
|
||||
}
|
||||
|
||||
function selectReference (props: ReferenceVersion): void {
|
||||
dispatch('close', props)
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
@@ -107,6 +166,11 @@
|
||||
return
|
||||
}
|
||||
|
||||
if (getReferenceVersionsProvider(item.doc) !== undefined) {
|
||||
dispatch('close', await getLatestReference(item))
|
||||
return
|
||||
}
|
||||
|
||||
const obj = (await getReferenceObject(item.doc._class, item.doc._id)) ?? item.doc
|
||||
const label = await getReferenceLabel(obj._class, obj._id)
|
||||
dispatch('close', {
|
||||
@@ -183,15 +247,36 @@
|
||||
<svelte:fragment slot="item" let:item={num}>
|
||||
{@const item = items[num]}
|
||||
{@const doc = item.item}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="ap-menuItem withComp h-8"
|
||||
on:click={() => {
|
||||
void handleSelectItem(doc)
|
||||
}}
|
||||
>
|
||||
<SearchResult value={doc} />
|
||||
</div>
|
||||
{#if hasReferenceVersions(doc.doc)}
|
||||
<Submenu
|
||||
withoutMargin
|
||||
withHover
|
||||
props={{
|
||||
latest: {
|
||||
id: doc.doc._id,
|
||||
objectclass: doc.doc._class,
|
||||
label: doc.title ?? ''
|
||||
},
|
||||
versions: getReferenceVersions(doc.doc),
|
||||
onSelect: selectReference
|
||||
}}
|
||||
options={{ component: MentionVersionPopup }}
|
||||
>
|
||||
<div slot="item" class="mention-version-item">
|
||||
<SearchResult value={doc} />
|
||||
</div>
|
||||
</Submenu>
|
||||
{:else}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="ap-menuItem withComp h-8"
|
||||
on:click={() => {
|
||||
void handleSelectItem(doc)
|
||||
}}
|
||||
>
|
||||
<SearchResult value={doc} />
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</ListView>
|
||||
{/if}
|
||||
@@ -213,6 +298,14 @@
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.mention-version-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mentonCategory {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.625rem;
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<!--
|
||||
// Copyright © 2026 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { ReferenceVersion } from '@hcengineering/view'
|
||||
import { Label, Scroller, resizeObserver } from '@hcengineering/ui'
|
||||
|
||||
import textEditor from '../plugin'
|
||||
|
||||
export let latest: ReferenceVersion
|
||||
export let versions: Promise<ReferenceVersion[]>
|
||||
export let onSelect: (props: ReferenceVersion) => void
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function selectLatest (): void {
|
||||
onSelect(latest)
|
||||
dispatch('close')
|
||||
}
|
||||
|
||||
function selectVersion (version: ReferenceVersion): void {
|
||||
onSelect(version)
|
||||
dispatch('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="selectPopup dropdown" use:resizeObserver={() => dispatch('changeContent')}>
|
||||
<div class="menu-space" />
|
||||
<Scroller>
|
||||
<button class="px-1 py-2 menu-item" on:click={selectLatest}>
|
||||
<div class="w-full flex-between">
|
||||
<div class="mr-2 ml-4 flex-row-center">
|
||||
<span class="title mr-1-5">{latest.label}</span>
|
||||
<span class="version mr-1-5"><Label label={textEditor.string.LatestVersion} /></span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{#await versions then versionItems}
|
||||
{#if versionItems.length > 0}
|
||||
<div class="menu-separator" />
|
||||
{#each versionItems as version}
|
||||
<button
|
||||
class="px-1 py-2 menu-item"
|
||||
on:click={() => {
|
||||
selectVersion(version)
|
||||
}}
|
||||
>
|
||||
<div class="w-full flex-between">
|
||||
<div class="mr-2 ml-4 flex-row-center">
|
||||
<span class="title mr-1-5">{version.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
{/await}
|
||||
</Scroller>
|
||||
<div class="menu-space" />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.dropdown {
|
||||
min-width: 25rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.version {
|
||||
font-weight: 500;
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
@@ -200,15 +200,21 @@ export const ReferenceExtension = ReferenceNode.extend<ReferenceExtensionOptions
|
||||
void renderLabel({ id, objectclass, label: node.attrs.label })
|
||||
resetTooltipHandle(undefined)
|
||||
} else {
|
||||
const label = await getReferenceLabel(objectclass, id, obj)
|
||||
const targetObj =
|
||||
node.attrs.fixed === true ? obj : ((await getReferenceObject(objectclass, id, obj)) ?? obj)
|
||||
const label = await getReferenceLabel(targetObj._class, targetObj._id, targetObj)
|
||||
if (label === '') return
|
||||
|
||||
let tooltipOptions: LabelAndProps | undefined = await getReferenceTooltip(objectclass, id, obj)
|
||||
let tooltipOptions: LabelAndProps | undefined = await getReferenceTooltip(
|
||||
targetObj._class,
|
||||
targetObj._id,
|
||||
targetObj
|
||||
)
|
||||
if (tooltipOptions.component === undefined) {
|
||||
tooltipOptions = undefined
|
||||
}
|
||||
resetTooltipHandle(tooltip(root, tooltipOptions))
|
||||
void renderLabel({ id, objectclass, label })
|
||||
void renderLabel({ id: targetObj._id, objectclass: targetObj._class, label })
|
||||
}
|
||||
})
|
||||
} else if (withoutDoc) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { type IntlString, plugin } from '@hcengineering/platform'
|
||||
export default plugin(textEditorId, {
|
||||
string: {
|
||||
CannotConnectToCollaborationService: '' as IntlString,
|
||||
SourceURL: '' as IntlString
|
||||
SourceURL: '' as IntlString,
|
||||
LatestVersion: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
OpenDocumentFunction,
|
||||
PreviewPresenter,
|
||||
ReferenceObjectProvider,
|
||||
ReferenceVersionsProvider,
|
||||
SpaceHeader,
|
||||
SpaceName,
|
||||
SpacePresenter,
|
||||
@@ -103,6 +104,7 @@ const view = plugin(viewId, {
|
||||
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
|
||||
ObjectIdentifier: '' as Ref<Mixin<ObjectIdentifier>>,
|
||||
ReferenceObjectProvider: '' as Ref<Mixin<ReferenceObjectProvider>>,
|
||||
ReferenceVersionsProvider: '' as Ref<Mixin<ReferenceVersionsProvider>>,
|
||||
ObjectTooltip: '' as Ref<Mixin<ObjectTooltip>>,
|
||||
SpaceHeader: '' as Ref<Mixin<SpaceHeader>>,
|
||||
SpaceName: '' as Ref<Mixin<SpaceName>>,
|
||||
|
||||
@@ -308,6 +308,23 @@ export interface ReferenceObjectProvider extends Class<Doc> {
|
||||
provider: Resource<<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<Doc | undefined>>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ReferenceVersion {
|
||||
id: Ref<Doc>
|
||||
objectclass: Ref<Class<Doc>>
|
||||
label: string
|
||||
fixed?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface ReferenceVersionsProvider extends Class<Doc> {
|
||||
provider: Resource<<T extends Doc>(client: Client, ref: Ref<T>, doc?: T) => Promise<ReferenceVersion[]>>
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user