From 69384ad4a1621e0ebe5d25b2522eca35138f0e79 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Fri, 14 Feb 2025 22:32:41 +0500 Subject: [PATCH 1/3] Fix create employee case senstive (#8004) Signed-off-by: Denis Bykhov --- .../src/components/CreateEmployee.svelte | 10 +++++----- tests/sanity/tests/contacts.spec.ts | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/contact-resources/src/components/CreateEmployee.svelte b/plugins/contact-resources/src/components/CreateEmployee.svelte index 32472b7fa4..ec906813e7 100644 --- a/plugins/contact-resources/src/components/CreateEmployee.svelte +++ b/plugins/contact-resources/src/components/CreateEmployee.svelte @@ -72,10 +72,10 @@ await client.createDoc(contact.class.Person, contact.space.Contacts, person, id) await client.createMixin(id, contact.class.Person, contact.space.Contacts, contact.mixin.Employee, { - active: true + active: false }) - const mail = email.trim() + const mail = email.trim().toLowerCase() await client.createDoc(contact.class.PersonAccount, core.space.Model, { email: mail, @@ -84,7 +84,7 @@ }) const sendInvite = await getResource(login.function.SendInvite) - await sendInvite(email.trim(), id, AccountRole.User) + await sendInvite(mail, id, AccountRole.User) for (const channel of channels) { await client.addCollection( @@ -116,7 +116,7 @@ $: query.query( contact.class.PersonAccount, { - email: email.trim() + email: email.trim().toLowerCase() }, (p) => { exists = p[0] @@ -128,7 +128,7 @@ function changeEmail () { const index = channels.findIndex((p) => p.provider === contact.channelProvider.Email) if (index !== -1) { - channels[index].value = email.trim() + channels[index].value = email.trim().toLowerCase() } else { channels.push({ provider: contact.channelProvider.Email, diff --git a/tests/sanity/tests/contacts.spec.ts b/tests/sanity/tests/contacts.spec.ts index 1cfeaad96e..f358b119ad 100644 --- a/tests/sanity/tests/contacts.spec.ts +++ b/tests/sanity/tests/contacts.spec.ts @@ -83,7 +83,8 @@ test.describe('contact tests', () => { await contractPage.fillEmailInput(mail) await contractPage.clickCreateButton() await contractPage.waitForFormAntiCardDetached() - await contractPage.kickEmployee(first, last) + // employee already inactive + // await contractPage.kickEmployee(first, last) // In non refactored code, the last assert just checks if the employee does exist, not if it has inactive status await contractPage.expectKickEmployeeShowsInactiveStatus(first, last) }) From 2fe638297c20eabb1dd4662e53a12d789c4af20a Mon Sep 17 00:00:00 2001 From: Victor Ilyushchenko Date: Mon, 17 Feb 2025 06:47:55 +0300 Subject: [PATCH 2/3] Live-sync for reference label (#8016) Signed-off-by: Victor Ilyushchenko --- models/controlled-documents/src/index.ts | 66 ++-- .../text/src/markup/__tests__/dsl.test.ts | 2 +- packages/text/src/nodes/reference.ts | 37 +- .../src/index.ts | 2 + .../src/plugin.ts | 3 +- .../src/utils.ts | 12 + .../text-editor-resources/src/Completion.ts | 179 --------- .../components/CollaborativeTextEditor.svelte | 8 +- .../src/components/MentionPopup.svelte | 28 +- .../src/components/ReferenceInput.svelte | 21 +- .../src/components/StyledTextArea.svelte | 9 +- .../src/components/StyledTextBox.svelte | 8 +- .../src/components/extension/link.ts | 159 +------- .../src/components/extension/reference.ts | 374 ++++++++++++++++++ .../src/components/extensions.ts | 54 +-- .../src/components/ObjectMention.svelte | 4 +- .../sanity/tests/documents/documents.spec.ts | 50 ++- 17 files changed, 523 insertions(+), 493 deletions(-) delete mode 100644 plugins/text-editor-resources/src/Completion.ts create mode 100644 plugins/text-editor-resources/src/components/extension/reference.ts diff --git a/models/controlled-documents/src/index.ts b/models/controlled-documents/src/index.ts index 0885da5aee..1b15efadc0 100644 --- a/models/controlled-documents/src/index.ts +++ b/models/controlled-documents/src/index.ts @@ -13,60 +13,60 @@ // limitations under the License. // -import documentsPlugin, { - documentsId, - type Document, - type DocumentSpace, - DocumentState -} from '@hcengineering/controlled-documents' import activity from '@hcengineering/activity' import contact from '@hcengineering/contact' +import documentsPlugin, { + documentsId, + DocumentState, + type Document, + type DocumentSpace +} from '@hcengineering/controlled-documents' import { type Builder } from '@hcengineering/model' import chunter from '@hcengineering/model-chunter' import core from '@hcengineering/model-core' +import { generateClassNotificationTypes } from '@hcengineering/model-notification' +import presentation from '@hcengineering/model-presentation' +import print from '@hcengineering/model-print' import request from '@hcengineering/model-request' import tracker from '@hcengineering/model-tracker' -import { generateClassNotificationTypes } from '@hcengineering/model-notification' import view, { classPresenter, createAction } from '@hcengineering/model-view' -import presentation from '@hcengineering/model-presentation' import workbench from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' import setting from '@hcengineering/setting' import tags from '@hcengineering/tags' -import print from '@hcengineering/model-print' import textEditor from '@hcengineering/text-editor' -import documents from './plugin' +import { type Class, type Doc, type Ref } from '@hcengineering/core' +import { type Action } from '@hcengineering/view' import { definePermissions } from './permissions' +import documents from './plugin' +import { defineSpaceType } from './spaceType' import { + TChangeControl, + TControlledDocument, + TControlledDocumentSnapshot, + TDocument, + TDocumentApprovalRequest, + TDocumentCategory, + TDocumentComment, + TDocumentMeta, + TDocumentRequest, + TDocumentReviewRequest, + TDocumentSnapshot, TDocumentSpace, TDocumentSpaceType, TDocumentSpaceTypeDescriptor, - TExternalSpace, - TOrgSpace, - TDocumentMeta, - TProjectDocument, - TProjectMeta, - TProject, - TDocument, - TDocumentSnapshot, - TControlledDocumentSnapshot, - THierarchyDocument, TDocumentTemplate, TDocumentTraining, - TDocumentCategory, - TControlledDocument, - TChangeControl, - TDocumentRequest, - TDocumentReviewRequest, - TDocumentApprovalRequest, - TTypeDocumentState, + TExternalSpace, + THierarchyDocument, + TOrgSpace, + TProject, + TProjectDocument, + TProjectMeta, TTypeControlledDocumentState, - TDocumentComment + TTypeDocumentState } from './types' -import { defineSpaceType } from './spaceType' -import { type Class, type Doc, type Ref } from '@hcengineering/core' -import { type Action } from '@hcengineering/view' export { documentsId } from '@hcengineering/controlled-documents/src/index' export * from './types' @@ -105,6 +105,10 @@ export function createModel (builder: Builder): void { titleProvider: documents.function.ControlledDocumentTitleProvider }) + builder.mixin(documents.class.DocumentMeta, core.class.Class, view.mixin.ObjectTitle, { + titleProvider: documents.function.ControlledDocumentTitleProvider + }) + builder.mixin(documents.class.DocumentApprovalRequest, core.class.Class, view.mixin.ObjectPresenter, { presenter: documents.component.DocumentApprovalRequestPresenter }) diff --git a/packages/text/src/markup/__tests__/dsl.test.ts b/packages/text/src/markup/__tests__/dsl.test.ts index 2458a48b36..69762fa291 100644 --- a/packages/text/src/markup/__tests__/dsl.test.ts +++ b/packages/text/src/markup/__tests__/dsl.test.ts @@ -21,7 +21,7 @@ describe('dsl', () => { ) ) expect(jsonToHTML(doc)).toEqual( - '

Hello, @World

Check out this link.

' + '

Hello, @World

Check out this link.

' ) }) }) diff --git a/packages/text/src/nodes/reference.ts b/packages/text/src/nodes/reference.ts index 6e75cfcffc..c333371095 100644 --- a/packages/text/src/nodes/reference.ts +++ b/packages/text/src/nodes/reference.ts @@ -15,10 +15,18 @@ import { Node, mergeAttributes } from '@tiptap/core' import { getDataAttribute } from './utils' +import { Class, Doc, Ref } from '@hcengineering/core' + +export interface ReferenceNodeProps { + id: Ref + objectclass: Ref> + label: string +} export interface ReferenceOptions { - renderLabel: (props: { options: ReferenceOptions, node: any }) => string - suggestion: { char: string } + renderLabel: (props: { options: ReferenceOptions, props: ReferenceNodeProps }) => string + suggestion: { char?: string } + HTMLAttributes: Record } /** @@ -28,23 +36,26 @@ export const ReferenceNode = Node.create({ name: 'reference', group: 'inline', inline: true, + selectable: true, + atom: true, + draggable: true, addAttributes () { return { id: getDataAttribute('id'), objectclass: getDataAttribute('objectclass'), - label: getDataAttribute('label'), - class: { default: null } + label: getDataAttribute('label') } }, addOptions () { return { - renderLabel ({ options, node }) { + renderLabel ({ options, props }) { // eslint-disable-next-line - return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}` + return `${options.suggestion.char}${props.label ?? props.id}` }, - suggestion: { char: '@' } + suggestion: { char: '@' }, + HTMLAttributes: {} } }, @@ -72,21 +83,25 @@ export const ReferenceNode = Node.create({ }, renderHTML ({ node, HTMLAttributes }) { - const options = this.options return [ 'span', mergeAttributes( { - 'data-type': this.name + 'data-type': this.name, + class: 'antiMention' }, + this.options.HTMLAttributes, HTMLAttributes ), - this.options.renderLabel({ options, node }) + this.options.renderLabel({ + options: this.options, + props: node.attrs as ReferenceNodeProps + }) ] }, renderText ({ node }) { const options = this.options - return options.renderLabel({ options, node }) + return options.renderLabel({ options, props: node.attrs as ReferenceNodeProps }) } }) diff --git a/plugins/controlled-documents-resources/src/index.ts b/plugins/controlled-documents-resources/src/index.ts index e0b32883c5..40d379be40 100644 --- a/plugins/controlled-documents-resources/src/index.ts +++ b/plugins/controlled-documents-resources/src/index.ts @@ -109,6 +109,7 @@ import { getAllDocumentStates, getControlledDocumentTitle, getDocumentMetaLinkFragment, + getDocumentMetaTitle, getVisibleFilters, isFolder, renameFolder, @@ -457,6 +458,7 @@ export default async (): Promise => ({ CanPrintDocument: canPrintDocument, DocumentIdentifierProvider: documentIdentifierProvider, ControlledDocumentTitleProvider: getControlledDocumentTitle, + DocumentMetaTitleProvider: getDocumentMetaTitle, Comment: comment, IsCommentVisible: isCommentVisible }, diff --git a/plugins/controlled-documents-resources/src/plugin.ts b/plugins/controlled-documents-resources/src/plugin.ts index 2c139b36c7..9e14aaa0cb 100644 --- a/plugins/controlled-documents-resources/src/plugin.ts +++ b/plugins/controlled-documents-resources/src/plugin.ts @@ -246,6 +246,7 @@ export default mergeIds(documentsId, documents, { CanOpenDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanPrintDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanTransferDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, - ControlledDocumentTitleProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise> + ControlledDocumentTitleProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise>, + DocumentMetaTitleProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise> } }) diff --git a/plugins/controlled-documents-resources/src/utils.ts b/plugins/controlled-documents-resources/src/utils.ts index bc3122a6d7..d238e18a3b 100644 --- a/plugins/controlled-documents-resources/src/utils.ts +++ b/plugins/controlled-documents-resources/src/utils.ts @@ -727,6 +727,18 @@ export async function getControlledDocumentTitle ( return object.title } +export async function getDocumentMetaTitle ( + client: Client, + ref: Ref, + doc?: DocumentMeta +): Promise { + const object = doc ?? (await client.findOne(documents.class.DocumentMeta, { _id: ref })) + + if (object === undefined) return '' + + return object.title +} + export const getCurrentEmployee = (): Ref | undefined => { const currentAccount = getCurrentAccount() const person = (currentAccount as PersonAccount)?.person diff --git a/plugins/text-editor-resources/src/Completion.ts b/plugins/text-editor-resources/src/Completion.ts deleted file mode 100644 index 061c752f46..0000000000 --- a/plugins/text-editor-resources/src/Completion.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { Node, mergeAttributes } from '@tiptap/core' -import { Plugin, PluginKey } from '@tiptap/pm/state' -import { getDataAttribute } from './utils' - -import Suggestion, { type SuggestionOptions } from './components/extension/suggestion' - -export interface CompletionOptions { - HTMLAttributes: Record - renderLabel: (props: { options: CompletionOptions, node: any }) => string - suggestion: Omit - showDoc?: (event: MouseEvent, _id: string, _class: string) => void -} - -export function clickHandler (opt: CompletionOptions): Plugin { - return new Plugin({ - key: new PluginKey('completion-handleClickLink'), - props: { - handleClick: (view, pos, event) => { - if (event.button !== 0) { - return false - } - - const link = (event.target as HTMLElement)?.closest('span') - if (link != null) { - const _class = link.getAttribute('data-objectclass') - const _id = link.getAttribute('data-id') - if (_id != null && _class != null) { - opt.showDoc?.(event, _id, _class) - } - } - - return false - } - } - }) -} - -export const Completion = Node.create({ - name: 'reference', - - addOptions () { - return { - HTMLAttributes: {}, - renderLabel ({ options, node }) { - // eslint-disable-next-line - return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}` - }, - suggestion: { - char: '@', - allowSpaces: true, - // pluginKey: CompletionPluginKey, - command: ({ editor, range, props }) => { - // increase range.to by one when the next node is of type "text" - // and starts with a space character - const nodeAfter = editor.view.state.selection.$to.nodeAfter - const overrideSpace = nodeAfter?.text?.startsWith(' ') - - if (overrideSpace !== undefined && overrideSpace) { - // eslint-disable-next-line - range.to += 1 - } - - if (props !== null) { - editor - .chain() - .focus() - .insertContentAt(range, [ - { - type: this.name, - attrs: props - }, - { - type: 'text', - text: ' ' - } - ]) - .run() - } - }, - allow: ({ editor, range }) => { - if (range.from > editor.state.doc.content.size) return false - const $from = editor.state.doc.resolve(range.from) - const type = editor.schema.nodes[this.name] - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - return !!$from.parent.type.contentMatch.matchType(type) - } - } - } - }, - - group: 'inline', - - inline: true, - - selectable: true, - - atom: true, - - draggable: true, - - addAttributes () { - return { - id: getDataAttribute('id'), - label: getDataAttribute('label'), - objectclass: getDataAttribute('objectclass') - } - }, - - parseHTML () { - return [ - { - tag: `span[data-type="${this.name}"]` - } - ] - }, - - renderHTML ({ node, HTMLAttributes }) { - return [ - 'span', - mergeAttributes( - { - 'data-type': this.name, - class: 'antiMention' - }, - this.options.HTMLAttributes, - HTMLAttributes - ), - this.options.renderLabel({ - options: this.options, - node - }) - ] - }, - - renderText ({ node }) { - return this.options.renderLabel({ - options: this.options, - node - }) - }, - - addKeyboardShortcuts () { - return { - Backspace: () => - this.editor.commands.command(({ tr, state }) => { - let isMention = false - const { selection } = state - const { empty, anchor } = selection - - if (!empty) { - return false - } - - state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => { - if (node.type.name === this.name) { - isMention = true - - // eslint-disable-next-line - tr.insertText(this.options.suggestion.char || '', pos, pos + node.nodeSize) - - return false - } - }) - - return isMention - }) - } - }, - - addProseMirrorPlugins () { - return [ - Suggestion({ - editor: this.editor, - ...this.options.suggestion - }), - clickHandler(this.options) - ] - } -}) diff --git a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte index f58f3936b5..b247fe201d 100644 --- a/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte +++ b/plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte @@ -66,7 +66,6 @@ TextEditorHandler } from '@hcengineering/text-editor' import { EditorKitOptions, getEditorKit } from '../../src/kits/editor-kit' - import { Completion } from '../Completion' import { deleteAttachment } from '../command/deleteAttachment' import { textEditorCommandHandler } from '../commands' import { Provider } from '../provider/types' @@ -84,8 +83,9 @@ import { InlineCommentCollaborationExtension } from './extension/inlineComment' import { LeftMenuExtension } from './extension/leftMenu' import { mermaidOptions } from './extension/mermaid' + import { ReferenceExtension, referenceConfig } from './extension/reference' import { type FileAttachFunction } from './extension/types' - import { completionConfig, inlineCommandsConfig } from './extensions' + import { inlineCommandsConfig } from './extensions' export let object: Doc export let attribute: KeyedAttribute @@ -495,8 +495,8 @@ render: renderCursor, selectionRender: noSelectionRender }), - Completion.configure({ - ...completionConfig, + ReferenceExtension.configure({ + ...referenceConfig, showDoc (event: MouseEvent, _id: string, _class: string) { dispatch('open-document', { event, _id, _class }) } diff --git a/plugins/text-editor-resources/src/components/MentionPopup.svelte b/plugins/text-editor-resources/src/components/MentionPopup.svelte index 6b9632b418..c43b03241d 100644 --- a/plugins/text-editor-resources/src/components/MentionPopup.svelte +++ b/plugins/text-editor-resources/src/components/MentionPopup.svelte @@ -15,23 +15,13 @@ --> {#if descriptor !== undefined} + {@const dIcon = descriptor.icon === '' ? settingRes.icon.Setting : descriptor.icon}
- + - - -{#if descriptor !== undefined} -
- - - {}} /> -
-{/if} diff --git a/plugins/task-resources/src/components/taskTypes/TaskKindSelector.svelte b/plugins/task-resources/src/components/taskTypes/TaskKindSelector.svelte index a1f18726fb..b6ca7bc33a 100644 --- a/plugins/task-resources/src/components/taskTypes/TaskKindSelector.svelte +++ b/plugins/task-resources/src/components/taskTypes/TaskKindSelector.svelte @@ -1,10 +1,13 @@ {#if projectType !== undefined && (items.length > 1 || showAlways)} - {/if} diff --git a/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte b/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte index 44a2bbfbac..5ee4d97302 100644 --- a/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte +++ b/plugins/task-resources/src/components/taskTypes/TaskTypeEditor.svelte @@ -14,28 +14,31 @@ // limitations under the License. --> {#if taskType !== undefined} @@ -157,15 +198,29 @@ /> {/if}
- +
+ { + showIssuesOfTaskType() + }} + /> + {#if canDelete} + + {/if} +
diff --git a/plugins/task-resources/src/components/taskTypes/TaskTypeListPresenter.svelte b/plugins/task-resources/src/components/taskTypes/TaskTypeListPresenter.svelte new file mode 100644 index 0000000000..09b67c5d26 --- /dev/null +++ b/plugins/task-resources/src/components/taskTypes/TaskTypeListPresenter.svelte @@ -0,0 +1,35 @@ + + + +{#if _value !== undefined && visible} + + + +{/if} diff --git a/plugins/task-resources/src/index.ts b/plugins/task-resources/src/index.ts index bcc7bdae4c..f3a8aac1b0 100644 --- a/plugins/task-resources/src/index.ts +++ b/plugins/task-resources/src/index.ts @@ -67,11 +67,11 @@ import ProjectTypeClassPresenter from './components/taskTypes/ProjectTypeClassPr import TaskKindSelector from './components/taskTypes/TaskKindSelector.svelte' import TaskTypeClassPresenter from './components/taskTypes/TaskTypeClassPresenter.svelte' import TaskTypePresenter from './components/taskTypes/TaskTypePresenter.svelte' +import TaskTypeListPresenter from './components/taskTypes/TaskTypeListPresenter.svelte' import { employeeByIdStore, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources' import CreateProjectType from './components/projectTypes/CreateProjectType.svelte' import ProjectTypeAutomationsSectionEditor from './components/projectTypes/ProjectTypeAutomationsSectionEditor.svelte' -import ProjectTypeCollectionsSectionEditor from './components/projectTypes/ProjectTypeCollectionsSectionEditor.svelte' import ProjectTypeGeneralSectionEditor from './components/projectTypes/ProjectTypeGeneralSectionEditor.svelte' import ProjectTypeSelector from './components/projectTypes/ProjectTypeSelector.svelte' import ProjectTypeTasksTypeSectionEditor from './components/projectTypes/ProjectTypeTasksTypeSectionEditor.svelte' @@ -198,6 +198,7 @@ export default async (): Promise => ({ StateIconPresenter, StatusFilter, TaskTypePresenter, + TaskTypeListPresenter, TaskTypeClassPresenter, ProjectTypeClassPresenter, ProjectTypePresenter, @@ -206,7 +207,6 @@ export default async (): Promise => ({ ProjectTypeGeneralSectionEditor, ProjectTypeTasksTypeSectionEditor, ProjectTypeAutomationsSectionEditor, - ProjectTypeCollectionsSectionEditor, TaskTypeEditor }, actionImpl: { diff --git a/plugins/task-resources/src/plugin.ts b/plugins/task-resources/src/plugin.ts index a27714a92d..88ef8abd84 100644 --- a/plugins/task-resources/src/plugin.ts +++ b/plugins/task-resources/src/plugin.ts @@ -104,7 +104,6 @@ export default mergeIds(taskId, task, { ProjectTypeGeneralSectionEditor: '' as AnyComponent, ProjectTypeTasksTypeSectionEditor: '' as AnyComponent, ProjectTypeAutomationsSectionEditor: '' as AnyComponent, - ProjectTypeCollectionsSectionEditor: '' as AnyComponent, TaskTypeEditor: '' as AnyComponent }, function: { diff --git a/plugins/task/src/index.ts b/plugins/task/src/index.ts index 7253e72476..a2ec1e99c6 100644 --- a/plugins/task/src/index.ts +++ b/plugins/task/src/index.ts @@ -94,6 +94,8 @@ export interface TaskTypeDescriptor extends Doc { // If specified, will allow to be created by users, system type overwise allowCreate: boolean statusCategoriesFunc?: Resource<(project: ProjectType) => Ref[]> + + openTasks?: Resource<(value: TaskType) => Promise> } /** diff --git a/plugins/tracker-resources/src/index.ts b/plugins/tracker-resources/src/index.ts index 3137774fef..4397654845 100644 --- a/plugins/tracker-resources/src/index.ts +++ b/plugins/tracker-resources/src/index.ts @@ -31,7 +31,14 @@ import { import { type Resources, type Status, translate } from '@hcengineering/platform' import { getClient, MessageBox, type ObjectSearchResult } from '@hcengineering/presentation' import { type Component, type Issue, type Milestone, type Project } from '@hcengineering/tracker' -import { closePanel, getCurrentLocation, navigate, showPopup, themeStore } from '@hcengineering/ui' +import { + closePanel, + getCurrentLocation, + getCurrentResolvedLocation, + navigate, + showPopup, + themeStore +} from '@hcengineering/ui' import ComponentEditor from './components/components/ComponentEditor.svelte' import ComponentFilterValuePresenter from './components/components/ComponentFilterValuePresenter.svelte' import ComponentPresenter from './components/components/ComponentPresenter.svelte' @@ -117,7 +124,13 @@ import ComponentSelector from './components/components/ComponentSelector.svelte' import IssueTemplatePresenter from './components/templates/IssueTemplatePresenter.svelte' import IssueTemplates from './components/templates/IssueTemplates.svelte' -import { AggregationManager, deleteObject, deleteObjects } from '@hcengineering/view-resources' +import { + AggregationManager, + buildFilterKey, + deleteObject, + deleteObjects, + setFilters +} from '@hcengineering/view-resources' import MoveAndDeleteMilestonePopup from './components/milestones/MoveAndDeleteMilestonePopup.svelte' import EditIssueTemplate from './components/templates/EditIssueTemplate.svelte' import TemplateEstimationEditor from './components/templates/EstimationEditor.svelte' @@ -160,6 +173,8 @@ import { settingId } from '@hcengineering/setting' import { getAllStates } from '@hcengineering/task-resources' import EstimationValueEditor from './components/issues/timereport/EstimationValueEditor.svelte' import TimePresenter from './components/issues/timereport/TimePresenter.svelte' +import type { TaskType } from '@hcengineering/task' +import view, { type Filter } from '@hcengineering/view' export { default as AssigneeEditor } from './components/issues/AssigneeEditor.svelte' export { default as SubIssueList } from './components/issues/edit/SubIssueList.svelte' @@ -346,6 +361,33 @@ function setStore (manager: DocManager): void { componentStore.set(manager) } +async function openIssuesOfTaskType (taskType: TaskType): Promise { + function setFilterTag (taskType: TaskType): void { + const client = getClient() + const hierarchy = client.getHierarchy() + const attribute = hierarchy.getAttribute(tracker.class.Issue, 'kind') + const key = buildFilterKey(hierarchy, tracker.class.Issue, 'kind', attribute) + const filter = { + key, + value: [taskType._id], + props: { level: 0 }, + modes: [view.filter.FilterObjectIn, view.filter.FilterObjectNin], + mode: view.filter.FilterObjectIn, + index: 1 + } as unknown as Filter + setFilters([filter]) + } + if (taskType === undefined) return + const loc = getCurrentResolvedLocation() + loc.path[2] = 'tracker' + loc.path[3] = 'all-issues' + loc.path.length = 4 + navigate(loc) + setTimeout(() => { + setFilterTag(taskType) + }, 200) +} + export default async (): Promise => ({ activity: { PriorityIcon, @@ -467,7 +509,8 @@ export default async (): Promise => ({ IsProjectJoined: async (project: Project) => project.members.includes(getCurrentAccount()._id), GetIssueStatusCategories: getIssueStatusCategories, SetComponentStore: setStore, - ComponentFilterFunction: filterComponents + ComponentFilterFunction: filterComponents, + OpenIssuesOfTaskType: openIssuesOfTaskType }, actionImpl: { Move: move, diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts index d2e6ac7112..35c2619bde 100644 --- a/plugins/tracker-resources/src/plugin.ts +++ b/plugins/tracker-resources/src/plugin.ts @@ -16,7 +16,7 @@ import { type StatusCategory, type Client, type Doc, type Ref, type Space } from import type { Asset, IntlString, Metadata, Resource } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import type { ObjectSearchCategory, ObjectSearchFactory } from '@hcengineering/presentation' -import { type ProjectType } from '@hcengineering/task' +import { type ProjectType, type TaskType } from '@hcengineering/task' import tracker, { trackerId, type IssueDraft, type Issue } from '@hcengineering/tracker' import { type AnyComponent, type Location } from '@hcengineering/ui' import { @@ -398,7 +398,8 @@ export default mergeIds(trackerId, tracker, { IsProjectJoined: '' as Resource<(space: Space) => Promise>, IssueChatTitleProvider: '' as Resource<(object: Doc) => string>, GetIssueStatusCategories: '' as Resource<(project: ProjectType) => Array>>, - GetIssueIdByIdentifier: '' as Resource<(id: string) => Promise | undefined>> + GetIssueIdByIdentifier: '' as Resource<(id: string) => Promise | undefined>>, + OpenIssuesOfTaskType: '' as Resource<(taskType: TaskType) => Promise> }, aggregation: { CreateComponentAggregationManager: '' as CreateAggregationManagerFunc,