diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index f66f7daef8..92cb19a6ba 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -783,4 +783,67 @@ export function createModel (builder: Builder): void { }, tracker.action.SetDueDate ) + createAction( + builder, + { + action: tracker.actionImpl.CopyToClipboard, + actionProps: { + type: 'id' + }, + label: tracker.string.CopyIssueId, + icon: tracker.icon.CopyID, + keyBinding: [], + input: 'none', + category: tracker.category.Tracker, + target: tracker.class.Issue, + context: { + mode: ['context', 'browser'], + application: tracker.app.Tracker, + group: 'copy' + } + }, + tracker.action.CopyIssueId + ) + createAction( + builder, + { + action: tracker.actionImpl.CopyToClipboard, + actionProps: { + type: 'title' + }, + label: tracker.string.CopyIssueTitle, + icon: tracker.icon.CopyBranch, + keyBinding: [], + input: 'none', + category: tracker.category.Tracker, + target: tracker.class.Issue, + context: { + mode: ['context', 'browser'], + application: tracker.app.Tracker, + group: 'copy' + } + }, + tracker.action.CopyIssueTitle + ) + createAction( + builder, + { + action: tracker.actionImpl.CopyToClipboard, + actionProps: { + type: 'link' + }, + label: tracker.string.CopyIssueUrl, + icon: tracker.icon.CopyURL, + keyBinding: [], + input: 'none', + category: tracker.category.Tracker, + target: tracker.class.Issue, + context: { + mode: ['context', 'browser'], + application: tracker.app.Tracker, + group: 'copy' + } + }, + tracker.action.CopyIssueLink + ) } diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index 9df8c9518e..cc24aebeb6 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -20,7 +20,7 @@ import { IntlString, mergeIds, Resource } from '@anticrm/platform' import { trackerId } from '@anticrm/tracker' import tracker from '@anticrm/tracker-resources/src/plugin' import type { AnyComponent } from '@anticrm/ui/src/types' -import { ViewletDescriptor } from '@anticrm/view' +import { ViewAction, ViewletDescriptor } from '@anticrm/view' import { Application } from '@anticrm/workbench' export default mergeIds(trackerId, tracker, { @@ -49,5 +49,8 @@ export default mergeIds(trackerId, tracker, { completion: { IssueQuery: '' as Resource, IssueCategory: '' as Ref + }, + actionImpl: { + CopyToClipboard: '' as ViewAction } }) diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json index 31220f627d..eb3bacccf1 100644 --- a/plugins/tracker-assets/lang/en.json +++ b/plugins/tracker-assets/lang/en.json @@ -112,6 +112,7 @@ "CopyIssueUrl": "Copy Issue URL to clipboard", "CopyIssueId": "Copy Issue ID to clipboard", "CopyIssueBranch": "Copy Git branch name to clipboard", + "CopyIssueTitle": "Copy Issue title to clipboard", "AssetLabel": "Asset", "AddToProject": "Add to project\u2026", "MoveToProject": "Move to project\u2026", diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json index 0f5b037056..4c742600b3 100644 --- a/plugins/tracker-assets/lang/ru.json +++ b/plugins/tracker-assets/lang/ru.json @@ -112,6 +112,7 @@ "CopyIssueUrl": "Копировать URL-адрес задачи в буфер обмена", "CopyIssueId": "Копировать ID задачи в буфер обмена", "CopyIssueBranch": "Копировать имя ветки Git в буфер обмена", + "CopyIssueTitle": "Копировать имя задачи в буфер обмена", "AssetLabel": "Asset", "AddToProject": "Добавить в проект\u2026", "MoveToProject": "Переместить в проект\u2026", diff --git a/plugins/tracker-resources/src/index.ts b/plugins/tracker-resources/src/index.ts index 58948eea6d..e7a4b6100d 100644 --- a/plugins/tracker-resources/src/index.ts +++ b/plugins/tracker-resources/src/index.ts @@ -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, getIssueTitle } from './utils' +import { copyToClipboard, getIssueId, getIssueTitle } from './utils' import CreateIssue from './components/CreateIssue.svelte' export async function queryIssue ( @@ -107,6 +107,7 @@ export async function queryIssue ( component: IssueItem })) } + export default async (): Promise => ({ component: { NopeComponent, @@ -153,5 +154,8 @@ export default async (): Promise => ({ }, function: { IssueTitleProvider: getIssueTitle + }, + actionImpl: { + CopyToClipboard: copyToClipboard } }) diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index 837e1bb5cb..65988c9c6f 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -148,6 +148,7 @@ export default mergeIds(trackerId, tracker, { CopyIssueUrl: '' as IntlString, CopyIssueId: '' as IntlString, CopyIssueBranch: '' as IntlString, + CopyIssueTitle: '' as IntlString, FilterIs: '' as IntlString, FilterIsNot: '' as IntlString, diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index 11d0a75f4c..34eb98f67e 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -17,6 +17,7 @@ import contact, { Employee, formatName } from '@anticrm/contact' import { Doc, DocumentQuery, Ref, SortingOrder, TxOperations } from '@anticrm/core' import { TypeState } from '@anticrm/kanban' import { Asset, IntlString, translate } from '@anticrm/platform' +import { getClient } from '@anticrm/presentation' import { Issue, IssuesDateModificationPeriod, @@ -26,7 +27,13 @@ import { ProjectStatus, Team } from '@anticrm/tracker' -import { AnyComponent, AnySvelteComponent, getMillisecondsInMonth, MILLISECONDS_IN_WEEK } from '@anticrm/ui' +import { + AnyComponent, + AnySvelteComponent, + getMillisecondsInMonth, + getPanelURI, + MILLISECONDS_IN_WEEK +} from '@anticrm/ui' import tracker from './plugin' import { defaultPriorities, defaultProjectStatuses, issuePriorities } from './types' @@ -461,3 +468,23 @@ export async function getIssueTitle (client: TxOperations, ref: Ref): Promi if (object?.$lookup?.space === undefined) throw new Error(`Issue Team not found, _id: ${ref}`) return getIssueId(object.$lookup.space, object) } + +export async function copyToClipboard (object: Issue, ev: Event, { type }: { type: string }): Promise { + const client = getClient() + let text: string + switch (type) { + case 'id': + text = await getIssueTitle(client, object._id) + break + case 'title': + text = object.title + break + case 'link': + // TODO: fix when short link is available + text = `${window.location.href}#${getPanelURI(tracker.component.EditIssue, object._id, object._class, 'content')}` + break + default: + return + } + await navigator.clipboard.writeText(text) +} diff --git a/plugins/tracker/src/index.ts b/plugins/tracker/src/index.ts index b4a96fde4d..78d4d33a16 100644 --- a/plugins/tracker/src/index.ts +++ b/plugins/tracker/src/index.ts @@ -280,7 +280,10 @@ export default plugin(trackerId, { SetStatus: '' as Ref, SetPriority: '' as Ref, SetAssignee: '' as Ref, - SetProject: '' as Ref + SetProject: '' as Ref, + CopyIssueId: '' as Ref, + CopyIssueTitle: '' as Ref, + CopyIssueLink: '' as Ref }, team: { DefaultTeam: '' as Ref