Update window title (#2138)

Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com>
This commit is contained in:
Alex 2022-06-24 14:46:53 +07:00 committed by GitHub
parent 32d2b6ed69
commit 6c3070c85d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 5 deletions

View File

@ -409,6 +409,10 @@ export function createModel (builder: Builder): void {
presenter: tracker.component.IssuePreview
})
builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.ObjectTitle, {
titleProvider: tracker.function.getIssueTitle
})
builder.mixin(tracker.class.TypeIssuePriority, core.class.Class, view.mixin.AttributePresenter, {
presenter: tracker.component.PriorityPresenter
})

View File

@ -40,6 +40,7 @@ import type {
ObjectEditor,
ObjectEditorHeader,
ObjectFactory,
ObjectTitle,
ObjectValidator,
PreviewPresenter,
SpaceHeader,
@ -158,6 +159,11 @@ export class TObjectFactory extends TClass implements ObjectFactory {
component!: AnyComponent
}
@Mixin(view.mixin.ObjectTitle, core.class.Class)
export class TObjectTitle extends TClass implements ObjectTitle {
titleProvider!: Resource<<T extends Doc>(client: Client, ref: Ref<T>) => Promise<string>>
}
@Model(view.class.ViewletPreference, preference.class.Preference)
export class TViewletPreference extends TPreference implements ViewletPreference {
attachedTo!: Ref<Viewlet>
@ -276,6 +282,7 @@ export function createModel (builder: Builder): void {
TActionCategory,
TObjectValidator,
TObjectFactory,
TObjectTitle,
TObjectEditorHeader,
THTMLPresenter,
TSpaceHeader,

View File

@ -56,7 +56,7 @@ import SetParentIssueActionPopup from './components/SetParentIssueActionPopup.sv
import Views from './components/views/Views.svelte'
import KanbanView from './components/issues/KanbanView.svelte'
import tracker from './plugin'
import { getIssueId } from './utils'
import { getIssueId, getIssueTitle } from './utils'
export async function queryIssue<D extends Issue> (
_class: Ref<Class<D>>,
@ -148,5 +148,8 @@ export default async (): Promise<Resources> => ({
},
completion: {
IssueQuery: async (client: Client, query: string) => await queryIssue(tracker.class.Issue, client, query)
},
function: {
getIssueTitle
}
})

View File

@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import type { IntlString, Resource } from '@anticrm/platform'
import { mergeIds } from '@anticrm/platform'
import tracker, { trackerId } from '../../tracker/lib'
import { AnyComponent } from '@anticrm/ui'
import { Client, Doc, Ref } from '@anticrm/core'
export default mergeIds(trackerId, tracker, {
string: {
@ -209,5 +210,8 @@ export default mergeIds(trackerId, tracker, {
Roadmap: '' as AnyComponent,
TeamProjects: '' as AnyComponent,
IssuePreview: '' as AnyComponent
},
function: {
getIssueTitle: '' as Resource<(client: Client, ref: Ref<Doc>) => Promise<string>>
}
})

View File

@ -14,7 +14,7 @@
//
import contact, { Employee, formatName } from '@anticrm/contact'
import { DocumentQuery, Ref, SortingOrder, TxOperations } from '@anticrm/core'
import { Doc, DocumentQuery, Ref, SortingOrder, TxOperations } from '@anticrm/core'
import { Asset, IntlString, translate } from '@anticrm/platform'
import {
IssuePriority,
@ -504,3 +504,13 @@ export async function getKanbanStatuses (
}
return []
}
export async function getIssueTitle (client: TxOperations, ref: Ref<Doc>): Promise<string> {
const issue = await client.findOne(
tracker.class.Issue,
{ _id: ref as Ref<Issue> },
{ lookup: { space: tracker.class.Team } }
)
if (issue?.$lookup?.space === undefined) throw new Error(`Issue Team not found, _id: ${ref}`)
return getIssueId(issue.$lookup.space, issue)
}

View File

@ -154,6 +154,13 @@ export interface ObjectValidator extends Class<Doc> {
validator: Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>
}
/**
* @public
*/
export interface ObjectTitle extends Class<Doc> {
titleProvider: Resource<<T extends Doc>(client: Client, ref: Ref<T>) => Promise<string>>
}
/**
* @public
*/
@ -384,6 +391,7 @@ const view = plugin(viewId, {
ObjectEditorHeader: '' as Ref<Mixin<ObjectEditorHeader>>,
ObjectValidator: '' as Ref<Mixin<ObjectValidator>>,
ObjectFactory: '' as Ref<Mixin<ObjectFactory>>,
ObjectTitle: '' as Ref<Mixin<ObjectTitle>>,
SpaceHeader: '' as Ref<Mixin<SpaceHeader>>,
SpaceName: '' as Ref<Mixin<SpaceName>>,
IgnoreActions: '' as Ref<Mixin<IgnoreActions>>,

View File

@ -15,10 +15,10 @@
<script lang="ts">
import calendar from '@anticrm/calendar'
import contact, { Employee, EmployeeAccount } from '@anticrm/contact'
import core, { Client, getCurrentAccount, Ref, Space } from '@anticrm/core'
import core, { Class, Client, Doc, getCurrentAccount, Ref, Space } from '@anticrm/core'
import notification, { NotificationStatus } from '@anticrm/notification'
import { NotificationClientImpl } from '@anticrm/notification-resources'
import { getMetadata, IntlString } from '@anticrm/platform'
import { getMetadata, getResource, IntlString } from '@anticrm/platform'
import { Avatar, createQuery, setClient } from '@anticrm/presentation'
import {
AnyComponent,
@ -26,6 +26,7 @@
closeTooltip,
Component,
DatePickerPopup,
fetchMetadataLocalStorage,
getCurrentLocation,
location,
Location,
@ -35,6 +36,8 @@
showPopup,
TooltipInstance
} from '@anticrm/ui'
import login from '@anticrm/login'
import view from '@anticrm/view'
import { ActionContext, ActionHandler } from '@anticrm/view-resources'
import type { Application, NavigatorModel, SpecialNavModel, ViewConfiguration } from '@anticrm/workbench'
import { onDestroy, tick } from 'svelte'
@ -125,9 +128,33 @@
closePopup()
await syncLoc(loc)
await updateWindowTitle(loc)
})
)
async function updateWindowTitle (loc: Location) {
const title = (await getWindowTitle(loc)) ?? getMetadata(workbench.metadata.PlatformTitle) ?? 'Platform'
const ws = fetchMetadataLocalStorage(login.metadata.CurrentWorkspace)
document.title = ws == null ? title : `${ws} - ${title}`
}
async function getWindowTitle (loc: Location) {
if (loc.fragment == null) return
const hierarchy = client.getHierarchy()
const [, _id, _class] = decodeURIComponent(loc.fragment).split('|')
if (_class == null) return
const clazz = hierarchy.getClass(_class as Ref<Class<Doc>>)
if (!hierarchy.hasMixin(clazz, view.mixin.ObjectTitle)) return
const mixin = hierarchy.as(clazz, view.mixin.ObjectTitle)
const titleProvider = await getResource(mixin.titleProvider)
try {
return await titleProvider(client, _id as Ref<Doc>)
} catch (err: any) {
console.error(err)
}
}
async function syncLoc (loc: Location): Promise<void> {
const app = loc.path.length > 1 ? (loc.path[1] as Ref<Application>) : undefined
const space = loc.path.length > 2 ? (loc.path[2] as Ref<Space>) : undefined