diff --git a/models/card/src/index.ts b/models/card/src/index.ts index 49ef99b7fb..7ea4a85c38 100644 --- a/models/card/src/index.ts +++ b/models/card/src/index.ts @@ -749,6 +749,10 @@ export function createModel (builder: Builder): void { }, card.ids.CardWidget ) + builder.mixin(card.class.Card, core.class.Class, view.mixin.CustomObjectLinkProvider, { + match: card.function.CardCustomLinkMatch, + encode: card.function.CardCustomLinkEncode + }) } function defineTabs (builder: Builder): void { diff --git a/models/card/src/plugin.ts b/models/card/src/plugin.ts index 2ad28cbb61..02aaa141ab 100644 --- a/models/card/src/plugin.ts +++ b/models/card/src/plugin.ts @@ -52,7 +52,9 @@ export default mergeIds(cardId, card, { function: { CardTitleProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise>, CardIdProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise>, - GetCardLink: '' as Resource<(doc: Doc, props: Record) => Promise> + GetCardLink: '' as Resource<(doc: Doc, props: Record) => Promise>, + CardCustomLinkMatch: '' as Resource<(doc: Doc) => boolean>, + CardCustomLinkEncode: '' as Resource<(doc: Doc) => Location> }, label: { Subscribed: '' as Ref, diff --git a/models/chat/src/index.ts b/models/chat/src/index.ts index a592e532e3..96a1c520b1 100644 --- a/models/chat/src/index.ts +++ b/models/chat/src/index.ts @@ -39,7 +39,8 @@ export function createModel (builder: Builder): void { hidden: true, component: chat.component.ChatApplication, locationResolver: chat.resolver.Location, - locationDataResolver: chat.resolver.LocationData + locationDataResolver: chat.resolver.LocationData, + type: 'cards' }, chat.app.Chat ) diff --git a/models/view/src/index.ts b/models/view/src/index.ts index d5166ff5af..edc91bea68 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -96,7 +96,8 @@ import { type ObjectTooltip, type AttrPresenter, type AttributeCategory, - type LinkIdProvider + type LinkIdProvider, + type CustomObjectLinkProvider } from '@hcengineering/view' import view from './plugin' @@ -390,6 +391,12 @@ export class TAttrPresenter extends TDoc implements AttrPresenter { component!: AnyComponent } +@Mixin(view.mixin.CustomObjectLinkProvider, core.class.Class) +export class TCustomObjectLinkProvider extends TClass implements CustomObjectLinkProvider { + match!: Resource<(doc: Doc) => boolean> + encode!: Resource<(doc: Doc) => Location> +} + export type ActionTemplate = Partial> /** @@ -478,7 +485,8 @@ export function createModel (builder: Builder): void { TObjectTooltip, TObjectIcon, TAttrPresenter, - TLinkIdProvider + TLinkIdProvider, + TCustomObjectLinkProvider ) classPresenter( diff --git a/plugins/card-resources/src/index.ts b/plugins/card-resources/src/index.ts index bd3cb97137..93102e2afa 100644 --- a/plugins/card-resources/src/index.ts +++ b/plugins/card-resources/src/index.ts @@ -25,7 +25,9 @@ import { getCardLink, queryCard, deleteMasterTag, - editSpace + editSpace, + cardCustomLinkEncode, + cardCustomLinkMatch } from './utils' import ManageMasterTagsContent from './components/settings/ManageMasterTagsContent.svelte' import ManageMasterTagsTools from './components/settings/ManageMasterTagsTools.svelte' @@ -115,6 +117,8 @@ export default async (): Promise => ({ function: { CardTitleProvider: getCardTitle, CardIdProvider: getCardId, - GetCardLink: getCardLink + GetCardLink: getCardLink, + CardCustomLinkMatch: cardCustomLinkMatch, + CardCustomLinkEncode: cardCustomLinkEncode } }) diff --git a/plugins/card-resources/src/utils.ts b/plugins/card-resources/src/utils.ts index 0f98279c2c..c734762cf5 100644 --- a/plugins/card-resources/src/utils.ts +++ b/plugins/card-resources/src/utils.ts @@ -36,7 +36,7 @@ import { type ResolvedLocation, showPopup } from '@hcengineering/ui' -import view from '@hcengineering/view' +import view, { encodeObjectURI } from '@hcengineering/view' import { accessDeniedStore } from '@hcengineering/view-resources' import workbench, { type LocationData } from '@hcengineering/workbench' import { translate } from '@hcengineering/platform' @@ -252,3 +252,20 @@ export async function openCardInSidebar (cardId: Ref, doc?: Card, tabId?: openWidget(widget, data) } + +export function cardCustomLinkMatch (doc: Card): boolean { + const loc = getCurrentResolvedLocation() + const client = getClient() + const alias = loc.path[2] + const app = client.getModel().findAllSync(workbench.class.Application, { + alias + })[0] + + return app.type === 'cards' +} + +export function cardCustomLinkEncode (doc: Card): Location { + const loc = getCurrentResolvedLocation() + loc.path[3] = encodeObjectURI(doc._id, card.class.Card) + return loc +} diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index b29641268e..7b20f381ba 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -1141,6 +1141,20 @@ export async function getObjectLinkFragment ( props: Record = {}, component: AnyComponent = view.component.EditDoc ): Promise { + const customProvider = hierarchy.classHierarchyMixin( + Hierarchy.mixinOrClass(object), + view.mixin.CustomObjectLinkProvider, + (m) => hasResource(m.encode) ?? false + ) + if (customProvider !== undefined) { + const matchFn = await getResource(customProvider.match) + if (matchFn(object)) { + const encodeFn = await getResource(customProvider.encode) + + return encodeFn(object) + } + } + const provider = hierarchy.classHierarchyMixin( Hierarchy.mixinOrClass(object), view.mixin.LinkProvider, diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index a6d964fd90..cbb7e3f68e 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -62,7 +62,8 @@ import { Viewlet, ViewletDescriptor, ViewletPreference, - LinkIdProvider + LinkIdProvider, + CustomObjectLinkProvider } from './types' export * from './types' @@ -113,7 +114,8 @@ const view = plugin(viewId, { AttributeFilterPresenter: '' as Ref>, Aggregation: '' as Ref>, Groupping: '' as Ref>, - ObjectIcon: '' as Ref> + ObjectIcon: '' as Ref>, + CustomObjectLinkProvider: '' as Ref> }, class: { ViewletPreference: '' as Ref>, diff --git a/plugins/view/src/types.ts b/plugins/view/src/types.ts index a16efc331e..bbe98b3919 100644 --- a/plugins/view/src/types.ts +++ b/plugins/view/src/types.ts @@ -812,6 +812,12 @@ export interface ObjectPanel extends Class { component: AnyComponent } +// Temp workaround for cards-based apps navigation +export interface CustomObjectLinkProvider extends Class { + match: Resource<(doc: Doc) => boolean> + encode: Resource<(doc: Doc) => Location> +} + /** * @public */ diff --git a/plugins/workbench/src/types.ts b/plugins/workbench/src/types.ts index 420a5ec4a7..1ec3fb743d 100644 --- a/plugins/workbench/src/types.ts +++ b/plugins/workbench/src/types.ts @@ -38,6 +38,7 @@ export interface Application extends Doc { icon: Asset hidden: boolean position?: 'top' | 'mid' + type?: string // temporary workaround for navigation in card-based application // Also attached ApplicationNavModel will be joined after this one main. navigatorModel?: NavigatorModel