2022-09-21 08:08:25 +00:00
|
|
|
import { Doc, DocumentUpdate, Ref, RelatedDocument, TxOperations } from '@hcengineering/core'
|
2022-10-14 05:45:04 +00:00
|
|
|
import { getClient } from '@hcengineering/presentation'
|
2023-03-17 06:17:53 +00:00
|
|
|
import { Issue, Component, Sprint, Project, trackerId } from '@hcengineering/tracker'
|
2023-03-15 14:06:03 +00:00
|
|
|
import { getCurrentLocation, getPanelURI, Location, navigate } from '@hcengineering/ui'
|
2022-09-21 08:08:25 +00:00
|
|
|
import { workbenchId } from '@hcengineering/workbench'
|
2022-08-09 06:40:21 +00:00
|
|
|
import { writable } from 'svelte/store'
|
2022-06-30 03:46:46 +00:00
|
|
|
import tracker from './plugin'
|
|
|
|
|
2023-03-17 06:17:53 +00:00
|
|
|
export const activeComponent = writable<Ref<Component> | undefined>(undefined)
|
2022-08-09 06:40:21 +00:00
|
|
|
export const activeSprint = writable<Ref<Sprint> | undefined>(undefined)
|
|
|
|
|
2023-03-17 06:17:53 +00:00
|
|
|
export function getIssueId (project: Project, issue: Issue): string {
|
|
|
|
return `${project.identifier}-${issue.number}`
|
2022-06-30 03:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function isIssueId (shortLink: string): boolean {
|
|
|
|
return /^\w+-\d+$/.test(shortLink)
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getIssueTitle (client: TxOperations, ref: Ref<Doc>): Promise<string> {
|
|
|
|
const object = await client.findOne(
|
|
|
|
tracker.class.Issue,
|
|
|
|
{ _id: ref as Ref<Issue> },
|
2023-03-17 06:17:53 +00:00
|
|
|
{ lookup: { space: tracker.class.Project } }
|
2022-06-30 03:46:46 +00:00
|
|
|
)
|
2023-03-17 06:17:53 +00:00
|
|
|
if (object?.$lookup?.space === undefined) throw new Error(`Issue project not found, _id: ${ref}`)
|
2022-06-30 03:46:46 +00:00
|
|
|
return getIssueId(object.$lookup.space, object)
|
|
|
|
}
|
|
|
|
|
2023-03-16 09:52:19 +00:00
|
|
|
async function getTitle (doc: Doc): Promise<string> {
|
|
|
|
const client = getClient()
|
|
|
|
const issue = doc as Issue
|
2023-03-17 06:17:53 +00:00
|
|
|
const object = await client.findOne(tracker.class.Project, { _id: issue.space })
|
2023-03-16 09:52:19 +00:00
|
|
|
if (object === undefined) return `?-${issue.number}`
|
|
|
|
return getIssueId(object, issue)
|
|
|
|
}
|
|
|
|
|
2022-06-30 03:46:46 +00:00
|
|
|
export function generateIssuePanelUri (issue: Issue): string {
|
|
|
|
return getPanelURI(tracker.component.EditIssue, issue._id, issue._class, 'content')
|
|
|
|
}
|
|
|
|
|
2022-10-14 05:45:04 +00:00
|
|
|
export async function issueIdProvider (doc: Doc): Promise<string> {
|
2023-03-16 09:52:19 +00:00
|
|
|
return await getTitle(doc)
|
2022-10-14 05:45:04 +00:00
|
|
|
}
|
|
|
|
|
2023-03-15 14:06:03 +00:00
|
|
|
export async function issueLinkFragmentProvider (doc: Doc): Promise<string> {
|
2023-03-16 09:52:19 +00:00
|
|
|
return await getTitle(doc).then((p) => `${trackerId}|${p}`)
|
2023-03-15 14:06:03 +00:00
|
|
|
}
|
|
|
|
|
2022-10-14 05:45:04 +00:00
|
|
|
export async function issueTitleProvider (doc: Issue): Promise<string> {
|
|
|
|
return await Promise.resolve(doc.title)
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function issueLinkProvider (doc: Doc): Promise<string> {
|
2023-03-16 09:52:19 +00:00
|
|
|
return await getTitle(doc).then(generateIssueShortLink)
|
2022-06-30 03:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export function generateIssueShortLink (issueId: string): string {
|
2022-07-06 07:02:01 +00:00
|
|
|
const location = getCurrentLocation()
|
2023-03-15 14:06:03 +00:00
|
|
|
return `${window.location.protocol}//${window.location.host}/${workbenchId}/${location.path[1]}/${trackerId}#${trackerId}|${issueId}`
|
2022-06-30 03:46:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function generateIssueLocation (loc: Location, issueId: string): Promise<Location | undefined> {
|
|
|
|
const tokens = issueId.split('-')
|
|
|
|
if (tokens.length < 2) {
|
|
|
|
return undefined
|
|
|
|
}
|
2023-03-17 06:17:53 +00:00
|
|
|
const projectId = tokens[0]
|
2022-06-30 03:46:46 +00:00
|
|
|
const issueNumber = Number(tokens[1])
|
|
|
|
const client = getClient()
|
2023-03-17 06:17:53 +00:00
|
|
|
const project = await client.findOne(tracker.class.Project, { identifier: projectId })
|
|
|
|
if (project === undefined) {
|
2022-06-30 03:46:46 +00:00
|
|
|
console.error(
|
2023-03-17 06:17:53 +00:00
|
|
|
`Could not find project ${projectId}. Make sure you are in correct workspace and the project was not deleted or renamed.`
|
2022-06-30 03:46:46 +00:00
|
|
|
)
|
|
|
|
return undefined
|
|
|
|
}
|
2023-03-17 06:17:53 +00:00
|
|
|
const issue = await client.findOne(tracker.class.Issue, { number: issueNumber, space: project._id })
|
2022-06-30 03:46:46 +00:00
|
|
|
if (issue === undefined) {
|
|
|
|
console.error(`Could not find issue ${issueId}.`)
|
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
const appComponent = loc.path[0] ?? ''
|
2022-07-06 07:02:01 +00:00
|
|
|
const workspace = loc.path[1] ?? ''
|
2022-06-30 03:46:46 +00:00
|
|
|
return {
|
2023-03-16 03:44:21 +00:00
|
|
|
path: [appComponent, workspace],
|
2022-06-30 03:46:46 +00:00
|
|
|
fragment: generateIssuePanelUri(issue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-15 14:06:03 +00:00
|
|
|
function checkOld (loc: Location): void {
|
|
|
|
const short = loc.path[3]
|
|
|
|
if (isIssueId(short)) {
|
|
|
|
loc.fragment = short
|
|
|
|
loc.path.length = 3
|
|
|
|
navigate(loc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 03:46:46 +00:00
|
|
|
export async function resolveLocation (loc: Location): Promise<Location | undefined> {
|
2023-03-15 14:06:03 +00:00
|
|
|
const split = loc.fragment?.split('|') ?? []
|
|
|
|
const app = loc.path[2]
|
|
|
|
if (app !== trackerId && split[0] !== trackerId) {
|
2022-06-30 03:46:46 +00:00
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
|
2023-03-15 14:06:03 +00:00
|
|
|
const shortLink = split[1] ?? loc.fragment
|
|
|
|
if (shortLink === undefined || shortLink === null || shortLink.trim() === '') {
|
|
|
|
checkOld(loc)
|
2022-06-30 03:46:46 +00:00
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
// issue shortlink
|
|
|
|
if (isIssueId(shortLink)) {
|
|
|
|
return await generateIssueLocation(loc, shortLink)
|
|
|
|
}
|
|
|
|
|
|
|
|
return undefined
|
|
|
|
}
|
2022-07-01 06:14:31 +00:00
|
|
|
|
|
|
|
export async function updateIssueRelation (
|
|
|
|
client: TxOperations,
|
|
|
|
value: Issue,
|
2022-09-09 03:44:33 +00:00
|
|
|
id: RelatedDocument,
|
|
|
|
prop: 'blockedBy' | 'relations',
|
2022-07-01 06:14:31 +00:00
|
|
|
operation: '$push' | '$pull'
|
|
|
|
): Promise<void> {
|
2022-09-09 03:44:33 +00:00
|
|
|
let update: DocumentUpdate<Issue> = {}
|
|
|
|
switch (operation) {
|
|
|
|
case '$push':
|
|
|
|
update = { $push: { [prop]: { _id: id._id, _class: id._class } } }
|
|
|
|
break
|
|
|
|
case '$pull':
|
|
|
|
update = { $pull: { [prop]: { _id: id._id } } }
|
|
|
|
break
|
|
|
|
}
|
2022-07-01 06:14:31 +00:00
|
|
|
await client.update(value, update)
|
|
|
|
}
|