diff --git a/packages/presentation/lang/en.json b/packages/presentation/lang/en.json index dd99f49374..4ef5b5816b 100644 --- a/packages/presentation/lang/en.json +++ b/packages/presentation/lang/en.json @@ -28,6 +28,12 @@ "Edit": "Edit", "SelectAvatar": "Select avatar", "GravatarsManaged": "Gravatars are managed through", + "CategoryCurrentUser": "Current user", + "Assigned": "Assigned", + "CategoryPreviousAssigned": "Previously assigned", + "CategoryProjectLead": "Project lead", + "CategoryProjectMembers": "Project members", + "CategoryOther": "Other", "InltPropsValue": "{value}" } } diff --git a/packages/presentation/lang/ru.json b/packages/presentation/lang/ru.json index 3381d3950b..b92cabd03e 100644 --- a/packages/presentation/lang/ru.json +++ b/packages/presentation/lang/ru.json @@ -22,12 +22,18 @@ "NumberSpaces": "{count, plural, =0 {В} =1 {В 1 месте} other {В # местах}}", "InThis": "В этом {space}", "NoMatchesInThis": "В этом {space} совпадения не обнаружены", - "NoMatchesFound": "Не найдено соответсвий", + "NoMatchesFound": "Не найдено соответствий", "NotInThis": "Не в этом {space}", "Add": "Добавить", "Edit": "Редактировать", "SelectAvatar": "Выбрать аватар", "GravatarsManaged": "Граватары управляются через", + "CategoryCurrentUser": "Текущий пользователь", + "Assigned": "Назначен", + "CategoryPreviousAssigned": "Ранее назначенные", + "CategoryProjectLead": "Руководитель проекта", + "CategoryProjectMembers": "Участники проекта", + "CategoryOther": "Прочие", "InltPropsValue": "{value}" } } diff --git a/packages/presentation/src/components/AssigneeBox.svelte b/packages/presentation/src/components/AssigneeBox.svelte new file mode 100644 index 0000000000..d4462e97b8 --- /dev/null +++ b/packages/presentation/src/components/AssigneeBox.svelte @@ -0,0 +1,177 @@ + + + + +
+ {#if $$slots.content} +
+ +
+ {:else} + + {/if} +
diff --git a/packages/presentation/src/components/AssigneePopup.svelte b/packages/presentation/src/components/AssigneePopup.svelte new file mode 100644 index 0000000000..12954fd421 --- /dev/null +++ b/packages/presentation/src/components/AssigneePopup.svelte @@ -0,0 +1,285 @@ + + + + + +
{ + dispatch('changeContent') + }} +> +
+ +
+ {#if cHeight === 1} +
+ {/if} +
updateLocation(scrollDiv, selectedDiv, contacts, selected)} + bind:this={scrollDiv} + > +
+ + + {#if showCategories} + {@const obj = toAny(contacts[item])} + {@const category = categorizedPersons.get(obj._id)} + {@const cl = hierarchy.getClass(contacts[item]._class)} + {#if item === 0 || (item > 0 && categorizedPersons.get(toAny(contacts[item - 1])._id) !== categorizedPersons.get(obj._id))} + +
+
+ + {#if cl.icon} + + {/if} + +
+
+ {/if} + {/if} +
+ + {@const obj = contacts[item]} + + +
+
+
+ {#if cHeight === -1} +
+ {/if} +
+ + diff --git a/packages/presentation/src/index.ts b/packages/presentation/src/index.ts index 707e27c579..20b8116fab 100644 --- a/packages/presentation/src/index.ts +++ b/packages/presentation/src/index.ts @@ -21,6 +21,7 @@ export { default as AttributeBarEditor } from './components/AttributeBarEditor.s export { default as AttributeEditor } from './components/AttributeEditor.svelte' export { default as AttributesBar } from './components/AttributesBar.svelte' export { default as Avatar } from './components/Avatar.svelte' +export { default as AssigneeBox } from './components/AssigneeBox.svelte' export { default as Card } from './components/Card.svelte' export { default as CombineAvatars } from './components/CombineAvatars.svelte' export { default as EditableAvatar } from './components/EditableAvatar.svelte' @@ -41,6 +42,7 @@ export { default as EmployeeBox } from './components/EmployeeBox.svelte' export { default as UsersPopup } from './components/UsersPopup.svelte' export { default as MembersBox } from './components/MembersBox.svelte' export { default as IconMembers } from './components/icons/Members.svelte' +export { default as IconPerson } from './components/icons/Person.svelte' export { default as IconMembersOutline } from './components/icons/MembersOutline.svelte' export { default as ObjectSearchPopup } from './components/ObjectSearchPopup.svelte' export { default as IndexedDocumentPreview } from './components/IndexedDocumentPreview.svelte' diff --git a/packages/presentation/src/plugin.ts b/packages/presentation/src/plugin.ts index 4356153cad..09292049f6 100644 --- a/packages/presentation/src/plugin.ts +++ b/packages/presentation/src/plugin.ts @@ -57,6 +57,12 @@ export default plugin(presentationId, { Edit: '' as IntlString, SelectAvatar: '' as IntlString, GravatarsManaged: '' as IntlString, + CategoryCurrentUser: '' as IntlString, + Assigned: '' as IntlString, + CategoryPreviousAssigned: '' as IntlString, + CategoryProjectLead: '' as IntlString, + CategoryProjectMembers: '' as IntlString, + CategoryOther: '' as IntlString, InltPropsValue: '' as IntlString }, metadata: { diff --git a/packages/presentation/src/utils.ts b/packages/presentation/src/utils.ts index a1311ac2c6..a0c6681824 100644 --- a/packages/presentation/src/utils.ts +++ b/packages/presentation/src/utils.ts @@ -34,12 +34,13 @@ import core, { TxResult } from '@hcengineering/core' import login from '@hcengineering/login' -import { getMetadata } from '@hcengineering/platform' +import { getMetadata, IntlString } from '@hcengineering/platform' import { LiveQuery as LQ } from '@hcengineering/query' import { onDestroy } from 'svelte' import { deepEqual } from 'fast-equals' import { IconSize, DropdownIntlItem } from '@hcengineering/ui' import contact, { AvatarType, AvatarProvider } from '@hcengineering/contact' +import presentation from '..' let liveQuery: LQ let client: TxOperations @@ -272,3 +273,43 @@ export function getAvatarProviderId (avatar?: string | null): Ref = Object.freeze({ + CurrentUser: presentation.string.CategoryCurrentUser, + Assigned: presentation.string.Assigned, + PreviouslyAssigned: presentation.string.CategoryPreviousAssigned, + ProjectLead: presentation.string.CategoryProjectLead, + ProjectMembers: presentation.string.CategoryProjectMembers, + Other: presentation.string.CategoryOther +}) + +/** + * @public + */ +export const assigneeCategoryOrder: AssigneeCategory[] = [ + 'CurrentUser', + 'Assigned', + 'PreviouslyAssigned', + 'ProjectLead', + 'ProjectMembers', + 'Other' +] + +/** + * @public + */ +export function getCategorytitle (category: AssigneeCategory | undefined): IntlString { + const cat: AssigneeCategory = category ?? 'Other' + return assigneeCategoryTitleMap[cat] +} diff --git a/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte b/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte index d000639779..6b8bbe71f5 100644 --- a/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte +++ b/plugins/tracker-resources/src/components/issues/AssigneeEditor.svelte @@ -15,11 +15,12 @@ {#if value} - import contact from '@hcengineering/contact' import { Ref } from '@hcengineering/core' - import { UserBox } from '@hcengineering/presentation' + import { AssigneeBox } from '@hcengineering/presentation' import { Issue, Team } from '@hcengineering/tracker' import { deviceOptionsStore as deviceInfo, getEventPositionElement, ListView, showPopup } from '@hcengineering/ui' import { ContextMenu, FixedColumn, ListSelectionProvider } from '@hcengineering/view-resources' @@ -60,21 +60,19 @@
-
- - - - - - -
+ + + + + +
diff --git a/plugins/tracker-resources/src/utils.ts b/plugins/tracker-resources/src/utils.ts index e36911b07c..ac6b973303 100644 --- a/plugins/tracker-resources/src/utils.ts +++ b/plugins/tracker-resources/src/utils.ts @@ -13,7 +13,19 @@ // limitations under the License. // -import { Doc, DocumentQuery, Ref, SortingOrder, toIdMap, TxOperations, WithLookup } from '@hcengineering/core' +import { Employee } from '@hcengineering/contact' +import core, { + AttachedData, + Doc, + DocumentQuery, + Ref, + SortingOrder, + toIdMap, + TxCollectionCUD, + TxOperations, + TxUpdateDoc, + WithLookup +} from '@hcengineering/core' import { TypeState } from '@hcengineering/kanban' import { Asset, IntlString, translate } from '@hcengineering/platform' import { createQuery } from '@hcengineering/presentation' @@ -24,6 +36,7 @@ import { IssuesGrouping, IssuesOrdering, IssueStatus, + IssueTemplateData, ProjectStatus, Sprint, SprintStatus, @@ -592,3 +605,25 @@ export function subIssueListProvider (subIssues: Issue[], target: Ref): v listProvider.updateFocus(selectedIssue) } } + +export async function getPreviousAssignees ( + issue: Issue | AttachedData | IssueTemplateData +): Promise>> { + return await new Promise((resolve) => { + const query = createQuery(true) + query.query( + core.class.Tx, + { + 'tx.objectId': (issue as Issue)._id, + 'tx.operations.assignee': { $exists: true } + }, + (res) => { + const prevAssignee = res + .map((t) => ((t as TxCollectionCUD).tx as TxUpdateDoc).operations.assignee) + .filter((p) => !(p == null)) as Array> + resolve(prevAssignee) + query.unsubscribe() + } + ) + }) +}