Add workaround to open card in current application

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina Fefelova 2025-05-07 08:53:31 +04:00
parent 0127b10d5f
commit efdb261387
No known key found for this signature in database
GPG Key ID: 750D35EF042F0690
10 changed files with 68 additions and 9 deletions

View File

@ -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 {

View File

@ -52,7 +52,9 @@ export default mergeIds(cardId, card, {
function: {
CardTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>,
CardIdProvider: '' as Resource<(client: Client, ref: Ref<Doc>, doc?: Doc) => Promise<string>>,
GetCardLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>
GetCardLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
CardCustomLinkMatch: '' as Resource<(doc: Doc) => boolean>,
CardCustomLinkEncode: '' as Resource<(doc: Doc) => Location>
},
label: {
Subscribed: '' as Ref<TagElement>,

View File

@ -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
)

View File

@ -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<Data<Action>>
/**
@ -478,7 +485,8 @@ export function createModel (builder: Builder): void {
TObjectTooltip,
TObjectIcon,
TAttrPresenter,
TLinkIdProvider
TLinkIdProvider,
TCustomObjectLinkProvider
)
classPresenter(

View File

@ -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<Resources> => ({
function: {
CardTitleProvider: getCardTitle,
CardIdProvider: getCardId,
GetCardLink: getCardLink
GetCardLink: getCardLink,
CardCustomLinkMatch: cardCustomLinkMatch,
CardCustomLinkEncode: cardCustomLinkEncode
}
})

View File

@ -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<Card>, 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
}

View File

@ -1141,6 +1141,20 @@ export async function getObjectLinkFragment (
props: Record<string, any> = {},
component: AnyComponent = view.component.EditDoc
): Promise<Location> {
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,

View File

@ -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<Mixin<AttributeFilterPresenter>>,
Aggregation: '' as Ref<Mixin<Aggregation>>,
Groupping: '' as Ref<Mixin<Groupping>>,
ObjectIcon: '' as Ref<Mixin<ObjectIcon>>
ObjectIcon: '' as Ref<Mixin<ObjectIcon>>,
CustomObjectLinkProvider: '' as Ref<Mixin<CustomObjectLinkProvider>>
},
class: {
ViewletPreference: '' as Ref<Class<ViewletPreference>>,

View File

@ -812,6 +812,12 @@ export interface ObjectPanel extends Class<Doc> {
component: AnyComponent
}
// Temp workaround for cards-based apps navigation
export interface CustomObjectLinkProvider extends Class<Doc> {
match: Resource<(doc: Doc) => boolean>
encode: Resource<(doc: Doc) => Location>
}
/**
* @public
*/

View File

@ -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