mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
TSK-865 Сделать красивый вид ссылок (#2771)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
bbfee8f39b
commit
ae84626521
@ -19,7 +19,7 @@ import chunter from '@hcengineering/chunter-resources/src/plugin'
|
||||
import type { Ref, Space, Doc } from '@hcengineering/core'
|
||||
import type { IntlString, Resource } from '@hcengineering/platform'
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
import type { AnyComponent, Location } from '@hcengineering/ui'
|
||||
import type { Action, ActionCategory, ViewAction, ViewletDescriptor } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(chunterId, chunter, {
|
||||
@ -98,7 +98,7 @@ export default mergeIds(chunterId, chunter, {
|
||||
function: {
|
||||
ChunterBrowserVisible: '' as Resource<(spaces: Space[]) => Promise<boolean>>,
|
||||
GetLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>
|
||||
GetFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>
|
||||
},
|
||||
filter: {
|
||||
CommentsFilter: '' as Resource<(tx: DisplayTx, _class?: Ref<Doc>) => boolean>,
|
||||
|
@ -19,7 +19,7 @@ import { mergeIds } from '@hcengineering/platform'
|
||||
import { recruitId } from '@hcengineering/recruit'
|
||||
import recruit from '@hcengineering/recruit-resources/src/plugin'
|
||||
import { KanbanTemplate } from '@hcengineering/task'
|
||||
import type { AnyComponent } from '@hcengineering/ui'
|
||||
import type { AnyComponent, Location } from '@hcengineering/ui'
|
||||
import type { Action, ActionCategory, ViewAction, Viewlet } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(recruitId, recruit, {
|
||||
@ -39,7 +39,7 @@ export default mergeIds(recruitId, recruit, {
|
||||
Recruit: '' as Ref<ActionCategory>
|
||||
},
|
||||
function: {
|
||||
GetObjectLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetObjectLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
GetObjectLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>
|
||||
},
|
||||
string: {
|
||||
|
@ -294,7 +294,7 @@ export class TLinkPresenter extends TDoc implements LinkPresenter {
|
||||
|
||||
@Mixin(view.mixin.LinkProvider, core.class.Class)
|
||||
export class TLinkProvider extends TClass implements LinkProvider {
|
||||
encode!: Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>
|
||||
encode!: Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>
|
||||
}
|
||||
|
||||
@Mixin(view.mixin.ObjectPanel, core.class.Class)
|
||||
|
@ -13,6 +13,8 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { navigate, parseLocation } from '@hcengineering/ui'
|
||||
|
||||
export let href: string | undefined
|
||||
export let disableClick = false
|
||||
export let onClick: ((event: MouseEvent) => void) | undefined = undefined
|
||||
@ -21,17 +23,28 @@
|
||||
|
||||
function clickHandler (e: MouseEvent) {
|
||||
if (disableClick) return
|
||||
onClick?.(e)
|
||||
if (onClick) {
|
||||
onClick(e)
|
||||
} else if (href !== undefined) {
|
||||
try {
|
||||
const url = new URL(href)
|
||||
|
||||
if (url.origin === window.location.origin) {
|
||||
e.preventDefault()
|
||||
navigate(parseLocation(url))
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if disableClick || onClick || href === undefined}
|
||||
{#if disableClick || href === undefined}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<span class:cursor-pointer={!disableClick} class:noUnderline class:inline on:click={clickHandler}>
|
||||
<slot />
|
||||
</span>
|
||||
{:else}
|
||||
<a {href} class:noUnderline class:inline>
|
||||
<a {href} class:noUnderline class:inline on:click={clickHandler}>
|
||||
<slot />
|
||||
</a>
|
||||
{/if}
|
||||
|
@ -13,8 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte'
|
||||
import { locationToUrl, navigate, location, getCurrentLocation } from '../location'
|
||||
import { location, locationToUrl, navigate } from '../location'
|
||||
import { Location } from '../types'
|
||||
|
||||
export let app: string | undefined = undefined
|
||||
@ -22,13 +21,7 @@
|
||||
export let special: string | undefined = undefined
|
||||
export let disabled = false
|
||||
|
||||
let loc = createLocation(getCurrentLocation(), app, space, special)
|
||||
|
||||
onDestroy(
|
||||
location.subscribe(async (res) => {
|
||||
loc = createLocation(res, app, space, special)
|
||||
})
|
||||
)
|
||||
$: loc = createLocation($location, app, space, special)
|
||||
|
||||
$: href = locationToUrl(loc)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { writable } from 'svelte/store'
|
||||
import { getCurrentLocation, navigate } from './location'
|
||||
import { get, writable } from 'svelte/store'
|
||||
import { location, navigate } from './location'
|
||||
import { AnyComponent, PopupAlignment } from './types'
|
||||
|
||||
export interface PanelProps {
|
||||
@ -29,10 +29,10 @@ export function showPanel (
|
||||
rightSection?: AnyComponent
|
||||
): void {
|
||||
openPanel(component, _id, _class, element, rightSection)
|
||||
const location = getCurrentLocation()
|
||||
if (location.fragment !== currentLocation) {
|
||||
location.fragment = currentLocation
|
||||
navigate(location)
|
||||
const loc = get(location)
|
||||
if (loc.fragment !== currentLocation) {
|
||||
loc.fragment = currentLocation
|
||||
navigate(loc)
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ export function closePanel (shoulRedirect: boolean = true): void {
|
||||
return { panel: undefined }
|
||||
})
|
||||
if (shoulRedirect) {
|
||||
const location = getCurrentLocation()
|
||||
location.fragment = undefined
|
||||
const loc = get(location)
|
||||
loc.fragment = undefined
|
||||
currentLocation = undefined
|
||||
navigate(location)
|
||||
navigate(loc)
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,12 @@ export interface Location {
|
||||
fragment?: string // a value of fragment
|
||||
}
|
||||
|
||||
export interface ResolvedLocation {
|
||||
loc: Location
|
||||
shouldNavigate: boolean
|
||||
defaultLocation: Location
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if locations are equal.
|
||||
*/
|
||||
|
@ -17,16 +17,9 @@
|
||||
import contact, { Employee, EmployeeAccount } from '@hcengineering/contact'
|
||||
import core, { Class, getCurrentAccount, Ref, Space } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import ui, {
|
||||
EditWithIcon,
|
||||
getCurrentLocation,
|
||||
IconSearch,
|
||||
Label,
|
||||
navigate,
|
||||
Loading,
|
||||
TabList
|
||||
} from '@hcengineering/ui'
|
||||
import ui, { EditWithIcon, IconSearch, Label, Loading, location, navigate, TabList } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { get } from 'svelte/store'
|
||||
import { dateFileBrowserFilters, FileBrowserSortMode, fileTypeFileBrowserFilters, sortModeToOptionObject } from '..'
|
||||
import attachment from '../plugin'
|
||||
import AttachmentsGalleryView from './AttachmentsGalleryView.svelte'
|
||||
@ -37,11 +30,11 @@
|
||||
export let withHeader: boolean = true
|
||||
|
||||
const client = getClient()
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
const spaceId: Ref<Space> | undefined = loc.query?.spaceId as Ref<Space> | undefined
|
||||
|
||||
$: if (spaceId !== undefined) {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
loc.query = undefined
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -19,7 +19,8 @@
|
||||
import { generateId, getCurrentAccount, Ref, Space } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, navigate } from '@hcengineering/ui'
|
||||
import { location, navigate } from '@hcengineering/ui'
|
||||
import { get } from 'svelte/store'
|
||||
import { createBacklinks } from '../backlinks'
|
||||
import chunter from '../plugin'
|
||||
import Channel from './Channel.svelte'
|
||||
@ -76,7 +77,7 @@
|
||||
}
|
||||
|
||||
function openThread (_id: Ref<Message>) {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
loc.path[4] = _id
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import { NotificationClientImpl } from '@hcengineering/notification-resources'
|
||||
import { IntlString, Resources, translate } from '@hcengineering/platform'
|
||||
import preference from '@hcengineering/preference'
|
||||
import { getClient, MessageBox } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, navigate, showPopup } from '@hcengineering/ui'
|
||||
import { location, navigate, showPopup } from '@hcengineering/ui'
|
||||
import TxBacklinkCreate from './components/activity/TxBacklinkCreate.svelte'
|
||||
import TxBacklinkReference from './components/activity/TxBacklinkReference.svelte'
|
||||
import TxCommentCreate from './components/activity/TxCommentCreate.svelte'
|
||||
@ -51,10 +51,10 @@ import SavedMessages from './components/SavedMessages.svelte'
|
||||
import Threads from './components/Threads.svelte'
|
||||
import ThreadView from './components/ThreadView.svelte'
|
||||
|
||||
import { writable } from 'svelte/store'
|
||||
import { get, writable } from 'svelte/store'
|
||||
import { DisplayTx } from '../../activity/lib'
|
||||
import { updateBacklinksList } from './backlinks'
|
||||
import { getDmName, getFragment, getLink, resolveLocation } from './utils'
|
||||
import { getDmName, getTitle, getLink, resolveLocation } from './utils'
|
||||
|
||||
export { default as Header } from './components/Header.svelte'
|
||||
export { classIcon } from './utils'
|
||||
@ -134,7 +134,7 @@ export async function ArchiveChannel (channel: Channel, evt: any, afterArchive?:
|
||||
client.update(channel, { archived: true })
|
||||
if (afterArchive != null) afterArchive()
|
||||
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
if (loc.path[3] === channel._id) {
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
@ -243,7 +243,7 @@ export default async (): Promise<Resources> => ({
|
||||
function: {
|
||||
GetDmName: getDmName,
|
||||
ChunterBrowserVisible: chunterBrowserVisible,
|
||||
GetFragment: getFragment,
|
||||
GetFragment: getTitle,
|
||||
GetLink: getLink
|
||||
},
|
||||
activity: {
|
||||
|
@ -4,7 +4,7 @@ import { employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import { Class, Client, Doc, getCurrentAccount, Obj, Ref, Space, Timestamp } from '@hcengineering/core'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { getCurrentLocation, getPanelURI, Location, navigate } from '@hcengineering/ui'
|
||||
import { getCurrentLocation, getPanelURI, location, Location, navigate, ResolvedLocation } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { workbenchId } from '@hcengineering/workbench'
|
||||
import { get, writable } from 'svelte/store'
|
||||
@ -70,7 +70,7 @@ export function getDay (time: Timestamp): Timestamp {
|
||||
}
|
||||
|
||||
export function openMessageFromSpecial (message: ChunterMessage): void {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
|
||||
if (message.attachedToClass === chunter.class.ChunterSpace) {
|
||||
loc.path.length = 4
|
||||
@ -84,7 +84,7 @@ export function openMessageFromSpecial (message: ChunterMessage): void {
|
||||
}
|
||||
|
||||
export function navigateToSpecial (specialId: string): void {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
loc.path[3] = specialId
|
||||
navigate(loc)
|
||||
}
|
||||
@ -120,14 +120,25 @@ export function scrollAndHighLight (): void {
|
||||
}
|
||||
|
||||
export async function getLink (doc: Doc): Promise<string> {
|
||||
const fragment = await getFragment(doc)
|
||||
const fragment = await getTitle(doc)
|
||||
const location = getCurrentLocation()
|
||||
return await Promise.resolve(
|
||||
`${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}/${chunterId}#${fragment}`
|
||||
)
|
||||
}
|
||||
|
||||
export async function getFragment (doc: Doc): Promise<string> {
|
||||
export async function getFragment (doc: Doc): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = chunterId
|
||||
loc.fragment = await getTitle(doc)
|
||||
|
||||
return loc
|
||||
}
|
||||
|
||||
export async function getTitle (doc: Doc): Promise<string> {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
let clazz = hierarchy.getClass(doc._class)
|
||||
@ -137,26 +148,25 @@ export async function getFragment (doc: Doc): Promise<string> {
|
||||
label = clazz.shortLabel
|
||||
}
|
||||
label = label ?? doc._class
|
||||
return `${chunterId}|${label}-${doc._id}`
|
||||
return `${label}-${doc._id}`
|
||||
}
|
||||
|
||||
export async function resolveLocation (loc: Location): Promise<Location | undefined> {
|
||||
const split = loc.fragment?.split('|') ?? []
|
||||
if (split[0] !== chunterId) {
|
||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
if (loc.path[2] !== chunterId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const shortLink = split[1]
|
||||
const shortLink = loc.fragment
|
||||
|
||||
// shortlink
|
||||
if (isShortId(shortLink)) {
|
||||
if (shortLink !== undefined && isShortId(shortLink)) {
|
||||
return await generateLocation(loc, shortLink)
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function generateLocation (loc: Location, shortLink: string): Promise<Location | undefined> {
|
||||
async function generateLocation (loc: Location, shortLink: string): Promise<ResolvedLocation | undefined> {
|
||||
const tokens = shortLink.split('-')
|
||||
if (tokens.length < 2) {
|
||||
return undefined
|
||||
@ -187,8 +197,15 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Loca
|
||||
|
||||
if (hierarchy.isDerived(doc._class, chunter.class.Message)) {
|
||||
return {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
loc: {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
},
|
||||
shouldNavigate: true,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hierarchy.isDerived(doc._class, chunter.class.Comment)) {
|
||||
@ -197,15 +214,29 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Loca
|
||||
const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel)
|
||||
const component = panelComponent.component ?? view.component.EditDoc
|
||||
return {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, comment.attachedTo, comment.attachedToClass, 'content')
|
||||
loc: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, comment.attachedTo, comment.attachedToClass, 'content')
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, comment.attachedTo, comment.attachedToClass, 'content')
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hierarchy.isDerived(doc._class, chunter.class.ThreadMessage)) {
|
||||
const msg = doc as ThreadMessage
|
||||
return {
|
||||
path: [appComponent, workspace, chunterId, doc.space, msg.attachedTo],
|
||||
fragment: doc._id
|
||||
loc: {
|
||||
path: [appComponent, workspace, chunterId, doc.space, msg.attachedTo],
|
||||
fragment: doc._id
|
||||
},
|
||||
shouldNavigate: true,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, chunterId, doc.space],
|
||||
fragment: doc._id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import type { Employee } from '@hcengineering/contact'
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { IntlString, plugin } from '@hcengineering/platform'
|
||||
import type { Preference } from '@hcengineering/preference'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import { AnyComponent, ResolvedLocation } from '@hcengineering/ui'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -158,7 +158,7 @@ export default plugin(chunterId, {
|
||||
ConvertToPrivate: '' as IntlString
|
||||
},
|
||||
resolver: {
|
||||
Location: '' as Resource<(loc: Location) => Promise<Location | undefined>>
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
app: {
|
||||
Chunter: '' as Ref<Doc>
|
||||
|
@ -17,6 +17,7 @@
|
||||
import contact, { contactId } from '@hcengineering/contact'
|
||||
import { Doc } from '@hcengineering/core'
|
||||
import { IntlString, mergeIds, Resource } from '@hcengineering/platform'
|
||||
import { Location } from '@hcengineering/ui'
|
||||
import { FilterFunction, SortFunc } from '@hcengineering/view'
|
||||
|
||||
export default mergeIds(contactId, contact, {
|
||||
@ -66,7 +67,7 @@ export default mergeIds(contactId, contact, {
|
||||
DisplayName: '' as IntlString
|
||||
},
|
||||
function: {
|
||||
GetContactLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetContactLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
EmployeeSort: '' as SortFunc,
|
||||
FilterChannelInResult: '' as FilterFunction,
|
||||
FilterChannelNinResult: '' as FilterFunction
|
||||
|
@ -26,7 +26,7 @@ import {
|
||||
import { Doc, getCurrentAccount, IdMap, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { TemplateDataProvider } from '@hcengineering/templates'
|
||||
import { getPanelURI, Location } from '@hcengineering/ui'
|
||||
import { getCurrentLocation, getPanelURI, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import view, { Filter } from '@hcengineering/view'
|
||||
import { FilterQuery } from '@hcengineering/view-resources'
|
||||
import { get, writable } from 'svelte/store'
|
||||
@ -136,69 +136,51 @@ export async function getContactName (provider: TemplateDataProvider): Promise<s
|
||||
}
|
||||
}
|
||||
|
||||
export async function getContactLink (doc: Doc): Promise<string> {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
let clazz = hierarchy.getClass(doc._class)
|
||||
let label = clazz.shortLabel
|
||||
while (label === undefined && clazz.extends !== undefined) {
|
||||
clazz = hierarchy.getClass(clazz.extends)
|
||||
label = clazz.shortLabel
|
||||
}
|
||||
label = label ?? 'CONT'
|
||||
export async function getContactLink (doc: Doc): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = contactId
|
||||
loc.path[3] = doc._id
|
||||
|
||||
const id = doc._id
|
||||
|
||||
return `${contactId}|${label}-${id}`
|
||||
return loc
|
||||
}
|
||||
|
||||
function isShortId (shortLink: string): boolean {
|
||||
return /^\w+-\w+$/.test(shortLink)
|
||||
function isId (id: Ref<Contact>): boolean {
|
||||
return /^[0-9a-z]{24}$/.test(id)
|
||||
}
|
||||
|
||||
export async function resolveLocation (loc: Location): Promise<Location | undefined> {
|
||||
const split = loc.fragment?.split('|') ?? []
|
||||
if (split[0] !== contactId) {
|
||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
if (loc.path[2] !== contactId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const shortLink = split[1]
|
||||
|
||||
// shortlink
|
||||
if (isShortId(shortLink)) {
|
||||
return await generateLocation(loc, shortLink)
|
||||
const id = loc.path[3] as Ref<Contact>
|
||||
if (isId(id)) {
|
||||
return await generateLocation(loc, id)
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function generateLocation (loc: Location, shortLink: string): Promise<Location | undefined> {
|
||||
const tokens = shortLink.split('-')
|
||||
if (tokens.length < 2) {
|
||||
return undefined
|
||||
}
|
||||
const classLabel = tokens[0]
|
||||
const lastId = tokens[1] as Ref<Contact>
|
||||
async function generateLocation (loc: Location, id: Ref<Contact>): Promise<ResolvedLocation | undefined> {
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
const classes = hierarchy.getDescendants(contact.class.Contact)
|
||||
let _class = contact.class.Contact
|
||||
for (const clazz of classes) {
|
||||
if (hierarchy.getClass(clazz).shortLabel === classLabel) {
|
||||
_class = clazz
|
||||
break
|
||||
}
|
||||
}
|
||||
const doc = await client.findOne(_class, { _id: lastId })
|
||||
const doc = await client.findOne(contact.class.Contact, { _id: id })
|
||||
if (doc === undefined) {
|
||||
console.error(`Could not find contact ${lastId}.`)
|
||||
console.error(`Could not find contact ${id}.`)
|
||||
return undefined
|
||||
}
|
||||
const appComponent = loc.path[0] ?? ''
|
||||
const workspace = loc.path[1] ?? ''
|
||||
return {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
loc: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, contactId],
|
||||
fragment: getPanelURI(view.component.EditDoc, doc._id, doc._class, 'content')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import { Account, AttachedDoc, Class, Doc, Ref, Space, Timestamp, UXObject } fro
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { IntlString, plugin } from '@hcengineering/platform'
|
||||
import { TemplateField, TemplateFieldCategory } from '@hcengineering/templates'
|
||||
import type { AnyComponent, IconSize } from '@hcengineering/ui'
|
||||
import type { AnyComponent, IconSize, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { FilterMode, ViewAction, Viewlet } from '@hcengineering/view'
|
||||
|
||||
/**
|
||||
@ -250,7 +250,7 @@ export const contactPlugin = plugin(contactId, {
|
||||
FilterChannelNin: '' as Ref<FilterMode>
|
||||
},
|
||||
resolver: {
|
||||
Location: '' as Resource<(loc: Location) => Promise<Location | undefined>>
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
templateFieldCategory: {
|
||||
CurrentEmployee: '' as Ref<TemplateFieldCategory>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Class, Client, Doc, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Applicant, recruitId, Review, Vacancy } from '@hcengineering/recruit'
|
||||
import { getCurrentLocation, getPanelURI, Location } from '@hcengineering/ui'
|
||||
import { getCurrentLocation, getPanelURI, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { workbenchId } from '@hcengineering/workbench'
|
||||
import recruit from './plugin'
|
||||
@ -11,9 +11,9 @@ type RecruitDocument = Vacancy | Applicant | Review
|
||||
export async function objectLinkProvider (doc: RecruitDocument): Promise<string> {
|
||||
const location = getCurrentLocation()
|
||||
return await Promise.resolve(
|
||||
`${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}#${await getSequenceLink(
|
||||
doc
|
||||
)}`
|
||||
`${window.location.protocol}//${window.location.host}/${workbenchId}/${
|
||||
location.path[1]
|
||||
}/${recruitId}/${await getSequenceId(doc)}`
|
||||
)
|
||||
}
|
||||
|
||||
@ -21,13 +21,12 @@ function isShortId (shortLink: string): boolean {
|
||||
return /^\w+-\d+$/.test(shortLink)
|
||||
}
|
||||
|
||||
export async function resolveLocation (loc: Location): Promise<Location | undefined> {
|
||||
const split = loc.fragment?.split('|') ?? []
|
||||
if (split[0] !== recruitId) {
|
||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
if (loc.path[2] !== recruitId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const shortLink = split[1]
|
||||
const shortLink = loc.path[3]
|
||||
|
||||
// shortlink
|
||||
if (isShortId(shortLink)) {
|
||||
@ -37,7 +36,7 @@ export async function resolveLocation (loc: Location): Promise<Location | undefi
|
||||
return undefined
|
||||
}
|
||||
|
||||
async function generateLocation (loc: Location, shortLink: string): Promise<Location | undefined> {
|
||||
async function generateLocation (loc: Location, shortLink: string): Promise<ResolvedLocation | undefined> {
|
||||
const tokens = shortLink.split('-')
|
||||
if (tokens.length < 2) {
|
||||
return undefined
|
||||
@ -68,14 +67,34 @@ async function generateLocation (loc: Location, shortLink: string): Promise<Loca
|
||||
const targetClass = hierarchy.getClass(_class)
|
||||
const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel)
|
||||
const component = panelComponent.component ?? view.component.EditDoc
|
||||
const defaultPath = [appComponent, workspace, recruitId]
|
||||
if (_class === recruit.class.Vacancy) {
|
||||
defaultPath.push('vacancies')
|
||||
} else if (_class === recruit.class.Applicant) {
|
||||
defaultPath.push('candidates')
|
||||
}
|
||||
return {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, doc._id, doc._class, 'content')
|
||||
loc: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: getPanelURI(component, doc._id, doc._class, 'content')
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: defaultPath,
|
||||
fragment: getPanelURI(component, doc._id, doc._class, 'content')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSequenceLink (doc: RecruitDocument): Promise<string> {
|
||||
return `${recruitId}|${await getSequenceId(doc)}`
|
||||
export async function getSequenceLink (doc: RecruitDocument): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = recruitId
|
||||
loc.path[3] = await getSequenceId(doc)
|
||||
|
||||
return loc
|
||||
}
|
||||
|
||||
async function getTitle<T extends RecruitDocument> (
|
||||
|
@ -19,7 +19,7 @@ import type { AttachedData, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestam
|
||||
import type { Asset, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { KanbanTemplateSpace, SpaceWithStates, Task } from '@hcengineering/task'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import { AnyComponent, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
|
||||
/**
|
||||
@ -175,7 +175,7 @@ const recruit = plugin(recruitId, {
|
||||
Issue: '' as Asset
|
||||
},
|
||||
resolver: {
|
||||
Location: '' as Resource<(loc: Location) => Promise<Location | undefined>>
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
space: {
|
||||
VacancyTemplates: '' as Ref<KanbanTemplateSpace>,
|
||||
|
@ -16,7 +16,8 @@
|
||||
import core, { Class, Doc, Obj, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { AnySvelteComponent, getCurrentLocation, Icon, Label, navigate } from '@hcengineering/ui'
|
||||
import { AnySvelteComponent, location, Icon, Label, navigate } from '@hcengineering/ui'
|
||||
import { get } from 'svelte/store'
|
||||
import setting from '../plugin'
|
||||
import { filterDescendants } from '../utils'
|
||||
import ClassAttributes from './ClassAttributes.svelte'
|
||||
@ -32,14 +33,14 @@
|
||||
| undefined
|
||||
export let withoutHeader = false
|
||||
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
let _class: Ref<Class<Doc>> | undefined = ofClass ?? (loc.query?._class as Ref<Class<Doc>> | undefined)
|
||||
|
||||
$: if (_class !== undefined && ofClass === undefined) {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
loc.query = undefined
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Doc, DocumentUpdate, Ref, RelatedDocument, TxOperations } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Issue, Component, Sprint, Project, trackerId } from '@hcengineering/tracker'
|
||||
import { getCurrentLocation, getPanelURI, Location, navigate } from '@hcengineering/ui'
|
||||
import { Component, Issue, Project, Sprint, trackerId } from '@hcengineering/tracker'
|
||||
import { getCurrentLocation, getPanelURI, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { workbenchId } from '@hcengineering/workbench'
|
||||
import { writable } from 'svelte/store'
|
||||
import tracker from './plugin'
|
||||
@ -43,8 +43,15 @@ export async function issueIdProvider (doc: Doc): Promise<string> {
|
||||
return await getTitle(doc)
|
||||
}
|
||||
|
||||
export async function issueLinkFragmentProvider (doc: Doc): Promise<string> {
|
||||
return await getTitle(doc).then((p) => `${trackerId}|${p}`)
|
||||
export async function issueLinkFragmentProvider (doc: Doc): Promise<Location> {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path.length = 2
|
||||
loc.fragment = undefined
|
||||
loc.query = undefined
|
||||
loc.path[2] = trackerId
|
||||
loc.path[3] = await getTitle(doc)
|
||||
|
||||
return loc
|
||||
}
|
||||
|
||||
export async function issueTitleProvider (doc: Issue): Promise<string> {
|
||||
@ -57,10 +64,10 @@ export async function issueLinkProvider (doc: Doc): Promise<string> {
|
||||
|
||||
export function generateIssueShortLink (issueId: string): string {
|
||||
const location = getCurrentLocation()
|
||||
return `${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}/${trackerId}#${trackerId}|${issueId}`
|
||||
return `${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}/${trackerId}/${issueId}`
|
||||
}
|
||||
|
||||
export async function generateIssueLocation (loc: Location, issueId: string): Promise<Location | undefined> {
|
||||
export async function generateIssueLocation (loc: Location, issueId: string): Promise<ResolvedLocation | undefined> {
|
||||
const tokens = issueId.split('-')
|
||||
if (tokens.length < 2) {
|
||||
return undefined
|
||||
@ -83,32 +90,25 @@ export async function generateIssueLocation (loc: Location, issueId: string): Pr
|
||||
const appComponent = loc.path[0] ?? ''
|
||||
const workspace = loc.path[1] ?? ''
|
||||
return {
|
||||
path: [appComponent, workspace],
|
||||
fragment: generateIssuePanelUri(issue)
|
||||
loc: {
|
||||
path: [appComponent, workspace],
|
||||
fragment: generateIssuePanelUri(issue)
|
||||
},
|
||||
shouldNavigate: false,
|
||||
defaultLocation: {
|
||||
path: [appComponent, workspace, trackerId, project._id, 'issues'],
|
||||
fragment: generateIssuePanelUri(issue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkOld (loc: Location): void {
|
||||
const short = loc.path[3]
|
||||
if (isIssueId(short)) {
|
||||
loc.fragment = short
|
||||
loc.path.length = 3
|
||||
navigate(loc)
|
||||
}
|
||||
}
|
||||
|
||||
export async function resolveLocation (loc: Location): Promise<Location | undefined> {
|
||||
const split = loc.fragment?.split('|') ?? []
|
||||
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
const app = loc.path[2]
|
||||
if (app !== trackerId && split[0] !== trackerId) {
|
||||
if (app !== trackerId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const shortLink = split[1] ?? loc.fragment
|
||||
if (shortLink === undefined || shortLink === null || shortLink.trim() === '') {
|
||||
checkOld(loc)
|
||||
return undefined
|
||||
}
|
||||
const shortLink = loc.path[3]
|
||||
|
||||
// issue shortlink
|
||||
if (isIssueId(shortLink)) {
|
||||
|
@ -16,7 +16,7 @@ import { Client, Doc, Ref, Space } from '@hcengineering/core'
|
||||
import type { IntlString, Metadata, Resource } from '@hcengineering/platform'
|
||||
import { mergeIds } from '@hcengineering/platform'
|
||||
import { IssueDraft } from '@hcengineering/tracker'
|
||||
import { AnyComponent } from '@hcengineering/ui'
|
||||
import { AnyComponent, Location } from '@hcengineering/ui'
|
||||
import { SortFunc, Viewlet, ViewQueryAction } from '@hcengineering/view'
|
||||
import tracker, { trackerId } from '../../tracker/lib'
|
||||
|
||||
@ -376,7 +376,7 @@ export default mergeIds(trackerId, tracker, {
|
||||
IssueTitleProvider: '' as Resource<(client: Client, ref: Ref<Doc>) => Promise<string>>,
|
||||
GetIssueId: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetIssueLink: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetIssueLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
GetIssueLinkFragment: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>,
|
||||
GetIssueTitle: '' as Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>,
|
||||
IssueStatusSort: '' as SortFunc,
|
||||
IssuePrioritySort: '' as SortFunc,
|
||||
|
@ -18,7 +18,7 @@ import type { AttachedDoc, Class, Doc, Markup, Ref, RelatedDocument, Space, Time
|
||||
import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import type { TagCategory, TagElement } from '@hcengineering/tags'
|
||||
import { AnyComponent, Location } from '@hcengineering/ui'
|
||||
import { AnyComponent, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { Action, ActionCategory } from '@hcengineering/view'
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
|
||||
@ -527,7 +527,7 @@ export default plugin(trackerId, {
|
||||
DefaultProject: '' as Ref<Project>
|
||||
},
|
||||
resolver: {
|
||||
Location: '' as Resource<(loc: Location) => Promise<Location | undefined>>
|
||||
Location: '' as Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
},
|
||||
string: {
|
||||
NewRelatedIssue: '' as IntlString
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { Doc, Hierarchy } from '@hcengineering/core'
|
||||
import { getClient, NavLink } from '@hcengineering/presentation'
|
||||
import { AnyComponent, getPanelURI } from '@hcengineering/ui'
|
||||
import { AnyComponent, getPanelURI, locationToUrl } from '@hcengineering/ui'
|
||||
import view from '../plugin'
|
||||
import { getObjectLinkFragment } from '../utils'
|
||||
|
||||
@ -37,7 +37,8 @@
|
||||
href = undefined
|
||||
return
|
||||
}
|
||||
href = `#${await getObjectLinkFragment(hierarchy, object, props, component)}`
|
||||
const loc = await getObjectLinkFragment(hierarchy, object, props, component)
|
||||
href = `${window.location.origin}${locationToUrl(loc)}`
|
||||
}
|
||||
|
||||
$: getHref(object)
|
||||
|
@ -4,7 +4,6 @@
|
||||
import ui, {
|
||||
Button,
|
||||
closeTooltip,
|
||||
getCurrentLocation,
|
||||
IconDownOutline,
|
||||
IconNavPrev,
|
||||
IconUpOutline,
|
||||
@ -27,11 +26,7 @@
|
||||
const doc = await client.findOne($focusStore.focus._class, { _id: $focusStore.focus._id })
|
||||
if (doc !== undefined) {
|
||||
const link = await getObjectLinkFragment(client.getHierarchy(), doc, {}, $panelstore.panel.component)
|
||||
const location = getCurrentLocation()
|
||||
if (location.fragment !== link) {
|
||||
location.fragment = link
|
||||
navigate(location)
|
||||
}
|
||||
navigate(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -659,7 +659,7 @@ export async function getObjectLinkFragment (
|
||||
object: Doc,
|
||||
props: Record<string, any> = {},
|
||||
component: AnyComponent = view.component.EditDoc
|
||||
): Promise<string> {
|
||||
): Promise<Location> {
|
||||
let clazz = hierarchy.getClass(object._class)
|
||||
let provider = hierarchy.as(clazz, view.mixin.LinkProvider)
|
||||
while (provider.encode === undefined && clazz.extends !== undefined) {
|
||||
@ -673,5 +673,7 @@ export async function getObjectLinkFragment (
|
||||
return res
|
||||
}
|
||||
}
|
||||
return getPanelURI(component, object._id, Hierarchy.mixinOrClass(object), 'content')
|
||||
const loc = getCurrentLocation()
|
||||
loc.fragment = getPanelURI(component, object._id, Hierarchy.mixinOrClass(object), 'content')
|
||||
return loc
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ import type {
|
||||
AnySvelteComponent,
|
||||
PopupAlignment,
|
||||
PopupPosAlignment,
|
||||
Location as PlatformLocation
|
||||
Location as PlatformLocation,
|
||||
Location
|
||||
} from '@hcengineering/ui'
|
||||
|
||||
/**
|
||||
@ -551,7 +552,7 @@ export type OrderOption = [string, SortingOrder]
|
||||
* @public
|
||||
*/
|
||||
export interface LinkProvider extends Class<Doc> {
|
||||
encode: Resource<(doc: Doc, props: Record<string, any>) => Promise<string>>
|
||||
encode: Resource<(doc: Doc, props: Record<string, any>) => Promise<Location>>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,6 @@
|
||||
Component,
|
||||
DatePickerPopup,
|
||||
deviceOptionsStore as deviceInfo,
|
||||
getCurrentLocation,
|
||||
Label,
|
||||
location,
|
||||
Location,
|
||||
@ -41,6 +40,7 @@
|
||||
PopupAlignment,
|
||||
PopupPosAlignment,
|
||||
resizeObserver,
|
||||
ResolvedLocation,
|
||||
showPopup,
|
||||
TooltipInstance
|
||||
} from '@hcengineering/ui'
|
||||
@ -48,16 +48,17 @@
|
||||
import { ActionContext, ActionHandler, migrateViewOpttions } from '@hcengineering/view-resources'
|
||||
import type { Application, NavigatorModel, SpecialNavModel, ViewConfiguration } from '@hcengineering/workbench'
|
||||
import { getContext, onDestroy, onMount, tick } from 'svelte'
|
||||
import { get } from 'svelte/store'
|
||||
import { subscribeMobile } from '../mobile'
|
||||
import workbench from '../plugin'
|
||||
import AccountPopup from './AccountPopup.svelte'
|
||||
import AppItem from './AppItem.svelte'
|
||||
import Applications from './Applications.svelte'
|
||||
import Settings from './icons/Settings.svelte'
|
||||
import TopMenu from './icons/TopMenu.svelte'
|
||||
import NavHeader from './NavHeader.svelte'
|
||||
import Navigator from './Navigator.svelte'
|
||||
import SpaceView from './SpaceView.svelte'
|
||||
import Settings from './icons/Settings.svelte'
|
||||
|
||||
export let client: Client
|
||||
let contentPanel: HTMLElement
|
||||
@ -193,14 +194,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveShortLink (loc: Location): Promise<Location | undefined> {
|
||||
async function resolveShortLink (loc: Location): Promise<ResolvedLocation | undefined> {
|
||||
let locationResolver = currentApplication?.locationResolver
|
||||
if (loc.fragment !== undefined && loc.fragment.trim().length > 0) {
|
||||
const split = loc.fragment.split('|')
|
||||
if (loc.path[2] !== undefined && loc.path[2].trim().length > 0) {
|
||||
if (apps instanceof Promise) {
|
||||
apps = await apps
|
||||
}
|
||||
const app = apps.find((p) => p.alias === split[0])
|
||||
const app = apps.find((p) => p.alias === loc.path[2])
|
||||
if (app?.locationResolver) {
|
||||
locationResolver = app?.locationResolver
|
||||
}
|
||||
@ -211,27 +211,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function syncLoc (loc: Location): Promise<void> {
|
||||
let app = loc.path[2]
|
||||
let space = loc.path[3] as Ref<Space>
|
||||
let special = loc.path[4]
|
||||
let fragment = loc.fragment
|
||||
function mergeLoc (loc: Location, resolved: ResolvedLocation): Location {
|
||||
const resolvedApp = resolved.loc.path[2]
|
||||
const resolvedSpace = resolved.loc.path[3]
|
||||
const resolvedSpecial = resolved.loc.path[4]
|
||||
if (resolvedApp === undefined) {
|
||||
loc.path[2] = (currentAppAlias as string) ?? resolved.defaultLocation.path[2]
|
||||
loc.path[3] = currentSpace ?? (currentSpecial as string) ?? resolved.defaultLocation.path[3]
|
||||
if (currentSpace !== undefined) {
|
||||
loc.path[4] = currentSpecial ?? (asideId as string) ?? resolved.defaultLocation.path[4]
|
||||
} else {
|
||||
loc.path.length = 4
|
||||
}
|
||||
} else {
|
||||
loc.path[2] = resolvedApp
|
||||
if (resolvedSpace === undefined) {
|
||||
loc.path[3] = currentSpace ?? (currentSpecial as string) ?? resolved.defaultLocation.path[3]
|
||||
loc.path[4] = (currentSpecial as string) ?? resolved.defaultLocation.path[4]
|
||||
} else {
|
||||
loc.path[3] = resolvedSpace
|
||||
loc.path[4] = resolvedSpecial ?? currentSpecial ?? (asideId as string) ?? resolved.defaultLocation.path[4]
|
||||
}
|
||||
}
|
||||
for (let index = 0; index < loc.path.length; index++) {
|
||||
const path = loc.path[index]
|
||||
if (path === undefined) {
|
||||
loc.path.length = index
|
||||
break
|
||||
}
|
||||
}
|
||||
loc.fragment = resolved.loc.fragment ?? loc.fragment ?? resolved.defaultLocation.fragment
|
||||
return loc
|
||||
}
|
||||
|
||||
async function syncLoc (loc: Location): Promise<void> {
|
||||
const originalLoc = JSON.stringify(loc)
|
||||
// resolve short links
|
||||
const resolvedLocation = await resolveShortLink(loc)
|
||||
if (resolvedLocation && !areLocationsEqual(loc, resolvedLocation)) {
|
||||
if (app !== resolvedLocation.path[2] && resolvedLocation.path[2] !== undefined) {
|
||||
loc.path[2] = app = resolvedLocation.path[2] ?? app
|
||||
loc.path[3] = space = (resolvedLocation.path[3] as Ref<Space>) ?? space
|
||||
loc.path[4] = special = resolvedLocation.path[4] ?? special
|
||||
} else if (space !== (resolvedLocation.path[3] as Ref<Space>) && resolvedLocation.path[3] !== undefined) {
|
||||
loc.path[3] = space = (resolvedLocation.path[3] as Ref<Space>) ?? space
|
||||
loc.path[4] = special = resolvedLocation.path[4] ?? special
|
||||
if (resolvedLocation && !areLocationsEqual(loc, resolvedLocation.loc)) {
|
||||
loc = mergeLoc(loc, resolvedLocation)
|
||||
if (resolvedLocation.shouldNavigate) {
|
||||
navigate(loc)
|
||||
return
|
||||
}
|
||||
loc.path[4] = special = resolvedLocation.path[4] ?? special
|
||||
loc.fragment = fragment = resolvedLocation.fragment ?? fragment
|
||||
navigate(loc, false)
|
||||
}
|
||||
const app = loc.path[2]
|
||||
let space = loc.path[3] as Ref<Space>
|
||||
let special = loc.path[4]
|
||||
const fragment = loc.fragment
|
||||
|
||||
if (currentAppAlias !== app) {
|
||||
clear(1)
|
||||
@ -240,20 +267,25 @@
|
||||
navigatorModel = currentApplication?.navigatorModel
|
||||
}
|
||||
|
||||
if (space === undefined) {
|
||||
if (
|
||||
space === undefined &&
|
||||
((navigatorModel?.spaces?.length ?? 0) > 0 || (navigatorModel?.specials?.length ?? 0) > 0)
|
||||
) {
|
||||
const last = localStorage.getItem(`platform_last_loc_${app}`)
|
||||
if (last !== null) {
|
||||
const newLocation: Location = JSON.parse(last)
|
||||
if (newLocation.path[3] != null) {
|
||||
loc.path[3] = newLocation.path[3] as Ref<Space>
|
||||
loc.path[4] = newLocation.path[4]
|
||||
space = loc.path[3] = newLocation.path[3] as Ref<Space>
|
||||
special = loc.path[4] = newLocation.path[4]
|
||||
if (loc.path[4] == null) {
|
||||
loc.path.length = 4
|
||||
} else {
|
||||
loc.path.length = 5
|
||||
}
|
||||
navigate(loc)
|
||||
return
|
||||
if (fragment === undefined) {
|
||||
navigate(loc)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,7 +302,7 @@
|
||||
}
|
||||
}
|
||||
if (app !== undefined) {
|
||||
localStorage.setItem(`platform_last_loc_${app}`, JSON.stringify(loc))
|
||||
localStorage.setItem(`platform_last_loc_${app}`, originalLoc)
|
||||
}
|
||||
if (fragment !== currentFragment) {
|
||||
currentFragment = fragment
|
||||
@ -318,7 +350,7 @@
|
||||
}
|
||||
|
||||
function closeAside (): void {
|
||||
const loc = getCurrentLocation()
|
||||
const loc = get(location)
|
||||
loc.path.length = 4
|
||||
checkOnHide()
|
||||
navigate(loc)
|
||||
|
@ -64,6 +64,7 @@
|
||||
action: async (_id: Ref<Doc>): Promise<void> => {
|
||||
const loc = getCurrentLocation()
|
||||
loc.path[3] = 'spaceBrowser'
|
||||
loc.path.length = 4
|
||||
dispatch('open')
|
||||
navigate(loc)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
import type { Class, Doc, Mixin, Obj, Ref, Space } from '@hcengineering/core'
|
||||
import type { Asset, IntlString, Metadata, Plugin, Resource } from '@hcengineering/platform'
|
||||
import { plugin } from '@hcengineering/platform'
|
||||
import { AnyComponent, Location } from '@hcengineering/ui'
|
||||
import { AnyComponent, Location, ResolvedLocation } from '@hcengineering/ui'
|
||||
import { ViewAction } from '@hcengineering/view'
|
||||
import type { Preference } from '@hcengineering/preference'
|
||||
|
||||
@ -29,7 +29,7 @@ export interface Application extends Doc {
|
||||
icon: Asset
|
||||
hidden: boolean
|
||||
navigatorModel?: NavigatorModel
|
||||
locationResolver?: Resource<(loc: Location) => Promise<Location | undefined>>
|
||||
locationResolver?: Resource<(loc: Location) => Promise<ResolvedLocation | undefined>>
|
||||
|
||||
// Component will be displayed in case navigator model is not defined, or nothing is selected in navigator model
|
||||
component?: AnyComponent
|
||||
|
@ -270,26 +270,13 @@ export async function OnEmployeeUpdate (tx: Tx, control: TriggerControl): Promis
|
||||
return result
|
||||
}
|
||||
|
||||
async function getContactLink (doc: Doc, control: TriggerControl): Promise<string> {
|
||||
const hierarchy = control.hierarchy
|
||||
let clazz = hierarchy.getClass(doc._class)
|
||||
let label = clazz.shortLabel
|
||||
while (label === undefined && clazz.extends !== undefined) {
|
||||
clazz = hierarchy.getClass(clazz.extends)
|
||||
label = clazz.shortLabel
|
||||
}
|
||||
label = label ?? 'CONT'
|
||||
return `${contactId}|${label}-${doc._id}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function personHTMLPresenter (doc: Doc, control: TriggerControl): Promise<string> {
|
||||
const person = doc as Person
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
const fragment = await getContactLink(doc, control)
|
||||
const path = `${workbenchId}/${control.workspace.name}/${contactId}#${fragment}`
|
||||
const path = `${workbenchId}/${control.workspace.name}/${contactId}/${doc._id}`
|
||||
const link = concatLink(front, path)
|
||||
return `<a href="${link}">${getName(person)}</a>`
|
||||
}
|
||||
@ -308,8 +295,7 @@ export function personTextPresenter (doc: Doc): string {
|
||||
export async function organizationHTMLPresenter (doc: Doc, control: TriggerControl): Promise<string> {
|
||||
const organization = doc as Organization
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
const fragment = await getContactLink(doc, control)
|
||||
const path = `${workbenchId}/${control.workspace.name}/${contactId}#${fragment}`
|
||||
const path = `${workbenchId}/${control.workspace.name}/${contactId}/${doc._id}`
|
||||
const link = concatLink(front, path)
|
||||
return `<a href="${link}">${organization.name}</a>`
|
||||
}
|
||||
|
@ -51,10 +51,7 @@ function getSequenceId (doc: Vacancy | Applicant, control: TriggerControl): stri
|
||||
export async function vacancyHTMLPresenter (doc: Doc, control: TriggerControl): Promise<string> {
|
||||
const vacancy = doc as Vacancy
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${vacancy._id}/#${recruitId}|${getSequenceId(
|
||||
vacancy,
|
||||
control
|
||||
)}`
|
||||
const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${getSequenceId(vacancy, control)}`
|
||||
const link = concatLink(front, path)
|
||||
return `<a href="${link}">${vacancy.name}</a>`
|
||||
}
|
||||
@ -74,9 +71,9 @@ export async function applicationHTMLPresenter (doc: Doc, control: TriggerContro
|
||||
const applicant = doc as Applicant
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
const id = getSequenceId(applicant, control)
|
||||
const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${applicant.space}/#${recruitId}|${id}`
|
||||
const path = `${workbenchId}/${control.workspace.name}/${recruitId}/${id}`
|
||||
const link = concatLink(front, path)
|
||||
return `<a href="${link}">id</a>`
|
||||
return `<a href="${link}">${id}</a>`
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +57,7 @@ async function updateSubIssues (
|
||||
export async function issueHTMLPresenter (doc: Doc, control: TriggerControl): Promise<string> {
|
||||
const issueName = await issueTextPresenter(doc, control)
|
||||
const front = getMetadata(login.metadata.FrontUrl) ?? ''
|
||||
const path = `${workbenchId}/${control.workspace.name}/${trackerId}/${doc.space}/issues/#${trackerId}|${issueName}`
|
||||
const path = `${workbenchId}/${control.workspace.name}/${trackerId}/${issueName}`
|
||||
const link = concatLink(front, path)
|
||||
return `<a href="${link}">${issueName}</a>`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user