From 6a5f1ed4791f0a7d74e51ad548e91ef9b839fb35 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Sat, 14 Jan 2023 16:54:54 +0600 Subject: [PATCH] List extract (#2505) --- models/attachment/src/index.ts | 2 +- models/board/src/index.ts | 6 +- models/calendar/src/index.ts | 4 +- models/chunter/src/index.ts | 6 +- models/contact/src/index.ts | 38 +- models/contact/src/plugin.ts | 3 + models/document/src/index.ts | 4 +- models/hr/src/index.ts | 2 +- models/inventory/src/index.ts | 17 +- models/inventory/src/plugin.ts | 1 + models/lead/src/index.ts | 40 +- models/lead/src/plugin.ts | 4 +- models/recruit/src/index.ts | 12 +- models/recruit/src/review.ts | 4 +- models/request/src/index.ts | 2 +- models/tags/src/index.ts | 4 +- models/task/src/index.ts | 31 +- models/task/src/plugin.ts | 4 +- models/tracker/src/index.ts | 105 ++++-- models/tracker/src/plugin.ts | 3 +- models/view/src/index.ts | 50 ++- models/view/src/plugin.ts | 8 +- models/workbench/src/index.ts | 2 +- packages/kanban/src/components/Kanban.svelte | 56 +-- packages/presentation/lang/en.json | 3 +- packages/presentation/lang/ru.json | 3 +- packages/presentation/src/plugin.ts | 3 +- packages/presentation/src/utils.ts | 4 +- packages/ui/src/components/TimeSince.svelte | 4 +- .../src/components/KanbanView.svelte | 10 +- .../src/components/TableView.svelte | 2 +- .../src/components/CalendarView.svelte | 11 +- plugins/contact-assets/lang/en.json | 3 +- plugins/contact-assets/lang/ru.json | 3 +- .../src/components/ContactRefPresenter.svelte | 33 ++ .../src/components/EmployeePresenter.svelte | 15 +- .../components/EmployeeRefPresenter.svelte | 39 ++ .../src/components/PersonPresenter.svelte | 47 ++- .../src/components/PersonRefPresenter.svelte | 59 +++ plugins/contact-resources/src/index.ts | 21 +- plugins/contact-resources/src/plugin.ts | 7 +- plugins/contact-resources/src/utils.ts | 36 +- .../components/CategoryRefPresenter.svelte | 33 ++ plugins/inventory-resources/src/index.ts | 2 + plugins/lead-assets/lang/en.json | 3 +- plugins/lead-assets/lang/ru.json | 5 +- .../src/components/CreateLead.svelte | 29 +- .../src/components/Leads.svelte | 4 +- .../src/components/LeadsPopup.svelte | 6 +- plugins/lead-resources/src/plugin.ts | 4 +- .../src/components/Applications.svelte | 4 +- .../src/components/ApplicationsPopup.svelte | 2 +- .../VacancyApplicationsPopup.svelte | 2 +- .../src/components/AssignedTasks.svelte | 11 +- .../src/components/Dashboard.svelte | 14 +- .../src/components/StatusTableView.svelte | 35 +- .../src/components/kanban/KanbanView.svelte | 18 +- .../state/DoneStateRefPresenter.svelte | 33 ++ .../components/state/StateRefPresenter.svelte | 31 ++ plugins/task-resources/src/index.ts | 4 + .../src/components/issues/Active.svelte | 2 +- .../issues/AssigneePresenter.svelte | 21 +- .../src/components/issues/Backlog.svelte | 2 +- .../src/components/issues/Issues.svelte | 2 +- .../components/issues/IssuesContent.svelte | 19 +- .../src/components/issues/IssuesList.svelte | 355 ------------------ .../issues/IssuesListBrowser.svelte | 82 ---- .../src/components/issues/IssuesView.svelte | 23 +- .../src/components/issues/KanbanView.svelte | 114 +++--- .../src/components/issues/ListView.svelte | 83 ---- .../issues/PriorityRefPresenter.svelte | 74 ++++ .../issues/StatusRefPresenter.svelte | 32 ++ .../components/issues/edit/EditIssue.svelte | 87 +---- .../issues/edit/SubIssueList.svelte | 4 +- .../issues/edit/SubIssueSelector.svelte | 4 +- .../issues/edit/SubIssuesSelector.svelte | 55 ++- .../issues/timereport/ReportsPopup.svelte | 2 +- .../src/components/myissues/MyIssues.svelte | 6 +- .../components/projects/EditProject.svelte | 2 +- .../src/components/sprints/EditSprint.svelte | 2 +- .../components/sprints/IssueStatistics.svelte | 10 +- .../components/sprints/SprintEditor.svelte | 9 +- .../sprints/SprintRefPresenter.svelte | 76 ++++ .../templates/IssueTemplatesContent.svelte | 23 +- .../templates/IssueTemplatesView.svelte | 7 +- .../components/templates/TemplatesList.svelte | 65 ---- plugins/tracker-resources/src/index.ts | 22 +- plugins/tracker-resources/src/plugin.ts | 15 +- plugins/tracker-resources/src/types.ts | 2 +- plugins/tracker-resources/src/utils.ts | 193 +++------- plugins/tracker/src/index.ts | 2 +- plugins/view-assets/lang/en.json | 8 +- plugins/view-assets/lang/ru.json | 8 +- .../src/components/ClassRefPresenter.svelte | 26 ++ .../src/components/FixedColumn.svelte | 17 +- .../src/components/ObjectPresenter.svelte | 2 +- .../src/components/TableView.svelte | 5 +- .../src/components/UpDownNavigator.svelte | 5 +- .../src/components/ViewOptions.svelte | 91 +++++ .../src/components/ViewOptionsButton.svelte | 72 ---- .../src/components/ViewOptionsPopup.svelte | 37 -- .../src/components/ViewletSetting.svelte | 67 ++-- .../components/ViewletSettingButton.svelte | 38 +- .../src/components/list}/GrowPresenter.svelte | 0 .../src/components/list/List.svelte | 211 +++++++++++ .../src/components/list/ListCategory.svelte | 140 +++++++ .../src/components/list/ListHeader.svelte | 135 +++++++ .../src/components/list/ListItem.svelte | 223 +++++++++++ .../src/components/list/ListView.svelte | 74 ++++ plugins/view-resources/src/index.ts | 10 +- plugins/view-resources/src/plugin.ts | 7 +- plugins/view-resources/src/selection.ts | 49 ++- plugins/view-resources/src/utils.ts | 58 ++- plugins/view-resources/src/viewOptions.ts | 34 +- plugins/view/src/index.ts | 103 ++++- .../src/components/Archive.svelte | 2 +- .../src/components/SpaceBrowser.svelte | 2 +- .../src/components/SpaceContent.svelte | 19 +- .../src/components/SpaceHeader.svelte | 10 +- .../src/components/SpaceView.svelte | 6 +- server/core/src/fulltext.ts | 2 +- tests/docker-compose.yaml | 4 +- tests/sanity/tests/tracker.layout.spec.ts | 10 +- tests/sanity/tests/tracker.spec.ts | 6 +- 124 files changed, 2382 insertions(+), 1445 deletions(-) create mode 100644 plugins/contact-resources/src/components/ContactRefPresenter.svelte create mode 100644 plugins/contact-resources/src/components/EmployeeRefPresenter.svelte create mode 100644 plugins/contact-resources/src/components/PersonRefPresenter.svelte create mode 100644 plugins/inventory-resources/src/components/CategoryRefPresenter.svelte create mode 100644 plugins/task-resources/src/components/state/DoneStateRefPresenter.svelte create mode 100644 plugins/task-resources/src/components/state/StateRefPresenter.svelte delete mode 100644 plugins/tracker-resources/src/components/issues/IssuesList.svelte delete mode 100644 plugins/tracker-resources/src/components/issues/IssuesListBrowser.svelte delete mode 100644 plugins/tracker-resources/src/components/issues/ListView.svelte create mode 100644 plugins/tracker-resources/src/components/issues/PriorityRefPresenter.svelte create mode 100644 plugins/tracker-resources/src/components/issues/StatusRefPresenter.svelte create mode 100644 plugins/tracker-resources/src/components/sprints/SprintRefPresenter.svelte delete mode 100644 plugins/tracker-resources/src/components/templates/TemplatesList.svelte create mode 100644 plugins/view-resources/src/components/ClassRefPresenter.svelte create mode 100644 plugins/view-resources/src/components/ViewOptions.svelte delete mode 100644 plugins/view-resources/src/components/ViewOptionsButton.svelte delete mode 100644 plugins/view-resources/src/components/ViewOptionsPopup.svelte rename plugins/{tracker-resources/src/components/issues => view-resources/src/components/list}/GrowPresenter.svelte (100%) create mode 100644 plugins/view-resources/src/components/list/List.svelte create mode 100644 plugins/view-resources/src/components/list/ListCategory.svelte create mode 100644 plugins/view-resources/src/components/list/ListHeader.svelte create mode 100644 plugins/view-resources/src/components/list/ListItem.svelte create mode 100644 plugins/view-resources/src/components/list/ListView.svelte diff --git a/models/attachment/src/index.ts b/models/attachment/src/index.ts index 700933b867..87dd56f0e3 100644 --- a/models/attachment/src/index.ts +++ b/models/attachment/src/index.ts @@ -77,7 +77,7 @@ export class TSavedAttachments extends TPreference implements SavedAttachments { export function createModel (builder: Builder): void { builder.createModel(TAttachment, TPhoto, TSavedAttachments) - builder.mixin(attachment.class.Attachment, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(attachment.class.Attachment, core.class.Class, view.mixin.ObjectPresenter, { presenter: attachment.component.AttachmentPresenter }) diff --git a/models/board/src/index.ts b/models/board/src/index.ts index bfcbb00c33..cd55f2d18e 100644 --- a/models/board/src/index.ts +++ b/models/board/src/index.ts @@ -212,15 +212,15 @@ export function createModel (builder: Builder): void { editor: board.component.EditCard }) - builder.mixin(board.class.Card, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(board.class.Card, core.class.Class, view.mixin.ObjectPresenter, { presenter: board.component.CardPresenter }) - builder.mixin(board.class.Board, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(board.class.Board, core.class.Class, view.mixin.ObjectPresenter, { presenter: board.component.BoardPresenter }) - builder.mixin(board.class.CardCover, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(board.class.CardCover, core.class.Class, view.mixin.ObjectPresenter, { presenter: board.component.CardCoverPresenter }) diff --git a/models/calendar/src/index.ts b/models/calendar/src/index.ts index ff1d25b307..d0bc1d0ab8 100644 --- a/models/calendar/src/index.ts +++ b/models/calendar/src/index.ts @@ -187,7 +187,7 @@ export function createModel (builder: Builder): void { calendar.action.SaveEventReminder ) - builder.mixin(calendar.mixin.Reminder, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(calendar.mixin.Reminder, core.class.Class, view.mixin.ObjectPresenter, { presenter: calendar.component.ReminderPresenter }) @@ -195,7 +195,7 @@ export function createModel (builder: Builder): void { editor: calendar.component.EditEvent }) - builder.mixin(calendar.class.Event, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(calendar.class.Event, core.class.Class, view.mixin.ObjectPresenter, { presenter: calendar.component.EventPresenter }) } diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index beeea80e80..00c36b7145 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -190,11 +190,11 @@ export function createModel (builder: Builder, options = { addApplication: true getName: chunter.function.GetDmName }) - builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(chunter.class.DirectMessage, core.class.Class, view.mixin.ObjectPresenter, { presenter: chunter.component.DmPresenter }) - builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.ObjectPresenter, { presenter: chunter.component.ChannelPresenter }) @@ -404,7 +404,7 @@ export function createModel (builder: Builder, options = { addApplication: true ) } - builder.mixin(chunter.class.Comment, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(chunter.class.Comment, core.class.Class, view.mixin.ObjectPresenter, { presenter: chunter.component.CommentPresenter }) diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index f454c0b98a..55d297c384 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -48,7 +48,7 @@ import attachment from '@hcengineering/model-attachment' import chunter from '@hcengineering/model-chunter' import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@hcengineering/model-core' import presentation from '@hcengineering/model-presentation' -import view, { actionTemplates, createAction, ViewAction } from '@hcengineering/model-view' +import view, { actionTemplates, createAction, ViewAction, Viewlet } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import type { Asset, IntlString, Resource } from '@hcengineering/platform' import setting from '@hcengineering/setting' @@ -204,7 +204,7 @@ export function createModel (builder: Builder): void { contact.app.Contacts ) - builder.createDoc( + builder.createDoc( view.class.Viewlet, core.space.Model, { @@ -229,7 +229,7 @@ export function createModel (builder: Builder): void { pinned: true }) - builder.createDoc( + builder.createDoc( view.class.Viewlet, core.space.Model, { @@ -237,7 +237,7 @@ export function createModel (builder: Builder): void { descriptor: view.viewlet.Table, config: [ '', - '$lookup._class', + '_class', 'city', 'attachments', 'modifiedOn', @@ -280,7 +280,7 @@ export function createModel (builder: Builder): void { inlineEditor: contact.component.EmployeeArrayEditor }) - builder.mixin(contact.class.Member, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Member, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.MemberPresenter }) @@ -292,7 +292,7 @@ export function createModel (builder: Builder): void { inlineEditor: contact.component.EmployeeEditor }) - builder.mixin(contact.class.Channel, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Channel, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.ChannelsPresenter }) @@ -401,7 +401,7 @@ export function createModel (builder: Builder): void { contact.avatarProvider.Gravatar ) - builder.mixin(contact.class.Person, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Person, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.PersonPresenter }) @@ -413,22 +413,38 @@ export function createModel (builder: Builder): void { inlineEditor: contact.component.AccountArrayEditor }) - builder.mixin(core.class.Account, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(core.class.Account, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.EmployeeAccountPresenter }) - builder.mixin(contact.class.Organization, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Organization, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.OrganizationPresenter }) - builder.mixin(contact.class.Contact, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Contact, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.ContactPresenter }) - builder.mixin(contact.class.Employee, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(contact.class.Employee, core.class.Class, view.mixin.ObjectPresenter, { presenter: contact.component.EmployeePresenter }) + builder.mixin(contact.class.Employee, core.class.Class, view.mixin.SortFuncs, { + func: contact.function.EmployeeSort + }) + + builder.mixin(contact.class.Person, core.class.Class, view.mixin.AttributePresenter, { + presenter: contact.component.PersonRefPresenter + }) + + builder.mixin(contact.class.Contact, core.class.Class, view.mixin.AttributePresenter, { + presenter: contact.component.ContactRefPresenter + }) + + builder.mixin(contact.class.Employee, core.class.Class, view.mixin.AttributePresenter, { + presenter: contact.component.EmployeeRefPresenter + }) + builder.mixin(contact.class.Employee, core.class.Class, view.mixin.IgnoreActions, { actions: [view.action.Delete] }) diff --git a/models/contact/src/plugin.ts b/models/contact/src/plugin.ts index be462d919e..6a06fe4a7c 100644 --- a/models/contact/src/plugin.ts +++ b/models/contact/src/plugin.ts @@ -25,6 +25,7 @@ import { Action, ActionCategory, ViewAction } from '@hcengineering/view' export default mergeIds(contactId, contact, { component: { PersonPresenter: '' as AnyComponent, + ContactRefPresenter: '' as AnyComponent, ContactPresenter: '' as AnyComponent, EditPerson: '' as AnyComponent, EditOrganization: '' as AnyComponent, @@ -35,6 +36,8 @@ export default mergeIds(contactId, contact, { EmployeeAccountPresenter: '' as AnyComponent, OrganizationEditor: '' as AnyComponent, EmployeePresenter: '' as AnyComponent, + EmployeeRefPresenter: '' as AnyComponent, + PersonRefPresenter: '' as AnyComponent, PersonEditor: '' as AnyComponent, Members: '' as AnyComponent, MemberPresenter: '' as AnyComponent, diff --git a/models/document/src/index.ts b/models/document/src/index.ts index 0e823e8f4c..2aaba67af3 100644 --- a/models/document/src/index.ts +++ b/models/document/src/index.ts @@ -224,10 +224,10 @@ export function createModel (builder: Builder): void { editor: document.component.EditDoc }) - builder.mixin(document.class.Document, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(document.class.Document, core.class.Class, view.mixin.ObjectPresenter, { presenter: document.component.DocumentPresenter }) - builder.mixin(document.class.DocumentVersion, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(document.class.DocumentVersion, core.class.Class, view.mixin.ObjectPresenter, { presenter: document.component.DocumentVersionPresenter }) diff --git a/models/hr/src/index.ts b/models/hr/src/index.ts index a429a30263..a4018c6256 100644 --- a/models/hr/src/index.ts +++ b/models/hr/src/index.ts @@ -387,7 +387,7 @@ export function createModel (builder: Builder): void { } }) - builder.mixin(hr.class.Request, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(hr.class.Request, core.class.Class, view.mixin.ObjectPresenter, { presenter: hr.component.RequestPresenter }) } diff --git a/models/inventory/src/index.ts b/models/inventory/src/index.ts index 2197be9468..c091dbe6bd 100644 --- a/models/inventory/src/index.ts +++ b/models/inventory/src/index.ts @@ -22,8 +22,7 @@ import { createAction } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' import setting from '@hcengineering/setting' -import type {} from '@hcengineering/view' -import view from '@hcengineering/view' +import view, { Viewlet } from '@hcengineering/view' import inventory from './plugin' export const DOMAIN_INVENTORY = 'inventory' as Domain @@ -75,15 +74,19 @@ export class TVariant extends TAttachedDoc implements Variant { export function createModel (builder: Builder): void { builder.createModel(TCategory, TProduct, TVariant) - builder.mixin(inventory.class.Category, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(inventory.class.Category, core.class.Class, view.mixin.ObjectPresenter, { presenter: inventory.component.CategoryPresenter }) - builder.mixin(inventory.class.Product, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(inventory.class.Category, core.class.Class, view.mixin.AttributePresenter, { + presenter: inventory.component.CategoryRefPresenter + }) + + builder.mixin(inventory.class.Product, core.class.Class, view.mixin.ObjectPresenter, { presenter: inventory.component.ProductPresenter }) - builder.mixin(inventory.class.Variant, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(inventory.class.Variant, core.class.Class, view.mixin.ObjectPresenter, { presenter: inventory.component.VariantPresenter }) @@ -99,13 +102,13 @@ export function createModel (builder: Builder): void { value: true }) - builder.createDoc( + builder.createDoc( view.class.Viewlet, core.space.Model, { attachTo: inventory.class.Product, descriptor: view.viewlet.Table, - config: ['', '$lookup.attachedTo', 'modifiedOn'] + config: ['', 'attachedTo', 'modifiedOn'] }, inventory.viewlet.TableProduct ) diff --git a/models/inventory/src/plugin.ts b/models/inventory/src/plugin.ts index c97fbe3c69..a5d1d9dc2e 100644 --- a/models/inventory/src/plugin.ts +++ b/models/inventory/src/plugin.ts @@ -36,6 +36,7 @@ export default mergeIds(inventoryId, inventory, { CreateProduct: '' as AnyComponent, EditProduct: '' as AnyComponent, CategoryPresenter: '' as AnyComponent, + CategoryRefPresenter: '' as AnyComponent, Variants: '' as AnyComponent, ProductPresenter: '' as AnyComponent, VariantPresenter: '' as AnyComponent diff --git a/models/lead/src/index.ts b/models/lead/src/index.ts index 3c4d20f78a..8aa973dd97 100644 --- a/models/lead/src/index.ts +++ b/models/lead/src/index.ts @@ -189,7 +189,7 @@ export function createModel (builder: Builder): void { descriptor: view.viewlet.Table, config: [ '', - '$lookup._class', + '_class', 'leads', 'modifiedOn', { @@ -212,9 +212,9 @@ export function createModel (builder: Builder): void { config: [ '', 'title', - '$lookup.attachedTo', - '$lookup.state', - '$lookup.doneState', + 'attachedTo', + 'state', + 'doneState', 'attachments', 'comments', 'modifiedOn', @@ -227,6 +227,36 @@ export function createModel (builder: Builder): void { lead.viewlet.TableLead ) + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: lead.class.Lead, + descriptor: view.viewlet.List, + config: [ + { key: '', props: { fixed: 'left' } }, + { key: 'title', props: { fixed: 'left' } }, + { key: 'state', props: { fixed: 'left' } }, + { key: 'doneState', props: { fixed: 'left' } }, + { key: '', presenter: view.component.GrowPresenter }, + 'attachments', + 'comments', + 'assignee' + ], + viewOptions: { + groupBy: ['assignee', 'state', 'attachedTo'], + orderBy: [ + ['assignee', -1], + ['state', 1], + ['attachedTo', 1], + ['modifiedOn', -1] + ], + other: [] + } + }, + lead.viewlet.ListLead + ) + builder.createDoc(view.class.Viewlet, core.space.Model, { attachTo: lead.class.Lead, descriptor: task.viewlet.Kanban, @@ -254,7 +284,7 @@ export function createModel (builder: Builder): void { editor: lead.component.EditLead }) - builder.mixin(lead.class.Lead, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(lead.class.Lead, core.class.Class, view.mixin.ObjectPresenter, { presenter: lead.component.LeadPresenter }) diff --git a/models/lead/src/plugin.ts b/models/lead/src/plugin.ts index 5223da1052..77b1e4a7be 100644 --- a/models/lead/src/plugin.ts +++ b/models/lead/src/plugin.ts @@ -30,7 +30,6 @@ export default mergeIds(leadId, lead, { LeadApplication: '' as IntlString, Lead: '' as IntlString, Title: '' as IntlString, - Assignee: '' as IntlString, ManageFunnelStatuses: '' as IntlString, FunnelBrowser: '' as IntlString, GotoLeadApplication: '' as IntlString @@ -52,7 +51,8 @@ export default mergeIds(leadId, lead, { }, viewlet: { TableCustomer: '' as Ref, - TableLead: '' as Ref + TableLead: '' as Ref, + ListLead: '' as Ref }, category: { Lead: '' as Ref diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 0e0769c006..c2b896260c 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -351,10 +351,10 @@ export function createModel (builder: Builder): void { descriptor: task.viewlet.StatusTable, config: [ '', - '$lookup.attachedTo', - '$lookup.assignee', - '$lookup.state', - '$lookup.doneState', + 'attachedTo', + 'assignee', + 'state', + 'doneState', 'attachments', 'comments', 'modifiedOn', @@ -415,7 +415,7 @@ export function createModel (builder: Builder): void { editor: recruit.component.EditVacancy }) - builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ObjectPresenter, { presenter: recruit.component.ApplicationPresenter }) @@ -423,7 +423,7 @@ export function createModel (builder: Builder): void { presenter: recruit.component.ApplicationsPresenter }) - builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ObjectPresenter, { presenter: recruit.component.VacancyPresenter }) diff --git a/models/recruit/src/review.ts b/models/recruit/src/review.ts index 219fe2ef31..8fb186ec33 100644 --- a/models/recruit/src/review.ts +++ b/models/recruit/src/review.ts @@ -60,11 +60,11 @@ export function createReviewModel (builder: Builder): void { editor: recruit.component.EditReview }) - builder.mixin(recruit.class.Review, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(recruit.class.Review, core.class.Class, view.mixin.ObjectPresenter, { presenter: recruit.component.ReviewPresenter }) - builder.mixin(recruit.class.Opinion, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(recruit.class.Opinion, core.class.Class, view.mixin.ObjectPresenter, { presenter: recruit.component.OpinionPresenter }) diff --git a/models/request/src/index.ts b/models/request/src/index.ts index c7ed836ae7..84434f1520 100644 --- a/models/request/src/index.ts +++ b/models/request/src/index.ts @@ -56,7 +56,7 @@ export function createModel (builder: Builder): void { editor: request.component.EditRequest }) - builder.mixin(request.class.Request, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(request.class.Request, core.class.Class, view.mixin.ObjectPresenter, { presenter: request.component.RequestPresenter }) diff --git a/models/tags/src/index.ts b/models/tags/src/index.ts index 2209c7f27e..8224f782f5 100644 --- a/models/tags/src/index.ts +++ b/models/tags/src/index.ts @@ -106,10 +106,10 @@ export function createModel (builder: Builder): void { inlineEditor: tags.component.TagsAttributeEditor }) - builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.ObjectPresenter, { presenter: tags.component.TagReferencePresenter }) - builder.mixin(tags.class.TagElement, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tags.class.TagElement, core.class.Class, view.mixin.ObjectPresenter, { presenter: tags.component.TagElementPresenter }) diff --git a/models/task/src/index.ts b/models/task/src/index.ts index e9c51c579e..5bee6066f8 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -366,29 +366,20 @@ export function createModel (builder: Builder): void { { attachTo: task.class.Issue, descriptor: task.viewlet.StatusTable, - config: [ - '', - 'name', - '$lookup.assignee', - '$lookup.state', - '$lookup.doneState', - 'attachments', - 'comments', - 'modifiedOn' - ] + config: ['', 'name', 'assignee', 'state', 'doneState', 'attachments', 'comments', 'modifiedOn'] }, task.viewlet.TableIssue ) - builder.mixin(task.class.Task, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.Task, core.class.Class, view.mixin.ObjectPresenter, { presenter: view.component.ObjectPresenter }) - builder.mixin(task.class.Issue, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.Issue, core.class.Class, view.mixin.ObjectPresenter, { presenter: task.component.TaskPresenter }) - builder.mixin(task.class.KanbanTemplate, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.KanbanTemplate, core.class.Class, view.mixin.ObjectPresenter, { presenter: task.component.KanbanTemplatePresenter }) @@ -462,10 +453,14 @@ export function createModel (builder: Builder): void { inlineEditor: task.component.StateEditor }) - builder.mixin(task.class.State, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.State, core.class.Class, view.mixin.ObjectPresenter, { presenter: task.component.StatePresenter }) + builder.mixin(task.class.State, core.class.Class, view.mixin.AttributePresenter, { + presenter: task.component.StateRefPresenter + }) + builder.mixin(task.class.State, core.class.Class, view.mixin.IgnoreActions, { actions: [view.action.Delete] }) @@ -474,10 +469,14 @@ export function createModel (builder: Builder): void { inlineEditor: task.component.DoneStateEditor }) - builder.mixin(task.class.DoneState, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.DoneState, core.class.Class, view.mixin.ObjectPresenter, { presenter: task.component.DoneStatePresenter }) + builder.mixin(task.class.DoneState, core.class.Class, view.mixin.AttributePresenter, { + presenter: task.component.DoneStateRefPresenter + }) + builder.createDoc( view.class.ViewletDescriptor, core.space.Model, @@ -504,7 +503,7 @@ export function createModel (builder: Builder): void { editor: task.component.Todos }) - builder.mixin(task.class.TodoItem, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(task.class.TodoItem, core.class.Class, view.mixin.ObjectPresenter, { presenter: task.component.TodoItemPresenter }) diff --git a/models/task/src/plugin.ts b/models/task/src/plugin.ts index a2c71d1761..671b7ac249 100644 --- a/models/task/src/plugin.ts +++ b/models/task/src/plugin.ts @@ -58,7 +58,9 @@ export default mergeIds(taskId, task, { TodoItemPresenter: '' as AnyComponent, StatusTableView: '' as AnyComponent, TaskHeader: '' as AnyComponent, - Dashboard: '' as AnyComponent + Dashboard: '' as AnyComponent, + StateRefPresenter: '' as AnyComponent, + DoneStateRefPresenter: '' as AnyComponent }, space: { TasksPublic: '' as Ref diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index 9b2778c187..563c55f191 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -73,7 +73,7 @@ import { trackerId, WorkDayLength } from '@hcengineering/tracker' -import { KeyBinding } from '@hcengineering/view' +import { KeyBinding, ViewOptionsModel } from '@hcengineering/view' import tracker from './plugin' import presentation from '@hcengineering/model-presentation' @@ -467,9 +467,31 @@ export function createModel (builder: Builder): void { TTypeReportedTime ) + const issuesOptions: ViewOptionsModel = { + groupBy: ['status', 'assignee', 'priority', 'project', 'sprint'], + orderBy: [ + ['status', SortingOrder.Ascending], + ['priority', SortingOrder.Ascending], + ['modifiedOn', SortingOrder.Descending], + ['dueDate', SortingOrder.Descending], + ['rank', SortingOrder.Ascending] + ], + other: [ + { + key: 'shouldShowSubIssues', + type: 'toggle', + defaultValue: false, + actionTartget: 'query', + action: tracker.function.SubIssueQuery, + label: tracker.string.SubIssues + } + ] + } + builder.createDoc(view.class.Viewlet, core.space.Model, { attachTo: tracker.class.Issue, - descriptor: tracker.viewlet.List, + descriptor: view.viewlet.List, + viewOptions: issuesOptions, config: [ { key: '', @@ -484,7 +506,7 @@ export function createModel (builder: Builder): void { }, { key: '', presenter: tracker.component.TitlePresenter, props: { shouldUseMargin: true } }, { key: '', presenter: tracker.component.SubIssuesSelector, props: {} }, - { key: '', presenter: tracker.component.GrowPresenter, props: { type: 'grow' } }, + { key: '', presenter: view.component.GrowPresenter, props: { type: 'grow' } }, { key: '', presenter: tracker.component.DueDatePresenter, props: { kind: 'list' } }, { key: '', @@ -530,11 +552,21 @@ export function createModel (builder: Builder): void { builder.createDoc(view.class.Viewlet, core.space.Model, { attachTo: tracker.class.IssueTemplate, - descriptor: tracker.viewlet.List, + descriptor: view.viewlet.List, + viewOptions: { + groupBy: ['assignee', 'priority', 'project', 'sprint'], + orderBy: [ + ['priority', SortingOrder.Ascending], + ['modifiedOn', SortingOrder.Descending], + ['dueDate', SortingOrder.Descending], + ['rank', SortingOrder.Ascending] + ], + other: [] + }, config: [ // { key: '', presenter: tracker.component.PriorityEditor, props: { kind: 'list', size: 'small' } }, { key: '', presenter: tracker.component.IssueTemplatePresenter, props: { type: 'issue', shouldUseMargin: true } }, - { key: '', presenter: tracker.component.GrowPresenter, props: { type: 'grow' } }, + { key: '', presenter: view.component.GrowPresenter, props: { type: 'grow' } }, // { key: '', presenter: tracker.component.DueDatePresenter, props: { kind: 'list' } }, { key: '', @@ -556,20 +588,10 @@ export function createModel (builder: Builder): void { ] }) - builder.createDoc( - view.class.ViewletDescriptor, - core.space.Model, - { - label: tracker.string.List, - icon: view.icon.Table, - component: tracker.component.ListView - }, - tracker.viewlet.List - ) - builder.createDoc(view.class.Viewlet, core.space.Model, { attachTo: tracker.class.Issue, descriptor: tracker.viewlet.Kanban, + viewOptions: issuesOptions, config: [] }) @@ -657,11 +679,11 @@ export function createModel (builder: Builder): void { const sprintsId = 'sprints' const templatesId = 'templates' - builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.IssuePresenter }) - builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.IssueTemplatePresenter }) @@ -669,7 +691,7 @@ export function createModel (builder: Builder): void { presenter: tracker.component.IssuePreview }) - builder.mixin(tracker.class.TimeSpendReport, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.TimeSpendReport, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.TimeSpendReport }) @@ -677,7 +699,23 @@ export function createModel (builder: Builder): void { titleProvider: tracker.function.IssueTitleProvider }) - builder.mixin(tracker.class.TypeIssuePriority, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.ListHeaderExtra, { + presenters: [tracker.component.IssueStatistics] + }) + + builder.mixin(tracker.class.IssueStatus, core.class.Class, view.mixin.SortFuncs, { + func: tracker.function.IssueStatusSort + }) + + builder.mixin(tracker.class.TypeIssuePriority, core.class.Class, view.mixin.SortFuncs, { + func: tracker.function.IssuePrioritySort + }) + + builder.mixin(tracker.class.Sprint, core.class.Class, view.mixin.SortFuncs, { + func: tracker.function.SprintSort + }) + + builder.mixin(tracker.class.TypeIssuePriority, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.PriorityPresenter }) @@ -685,33 +723,40 @@ export function createModel (builder: Builder): void { component: view.component.ValueFilter }) - builder.mixin(tracker.class.IssueStatus, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.IssueStatus, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.StatusPresenter }) - builder.mixin(tracker.class.Project, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.IssueStatus, core.class.Class, view.mixin.AttributePresenter, { + presenter: tracker.component.StatusRefPresenter + }) + + builder.mixin(tracker.class.TypeIssuePriority, core.class.Class, view.mixin.AttributePresenter, { + presenter: tracker.component.PriorityRefPresenter + }) + + builder.mixin(tracker.class.Project, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.ProjectTitlePresenter }) - builder.mixin(tracker.class.Team, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.Team, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.TeamPresenter }) - classPresenter( - builder, - tracker.class.Project, - tracker.component.ProjectTitlePresenter, - tracker.component.ProjectSelector - ) + classPresenter(builder, tracker.class.Project, tracker.component.ProjectSelector, tracker.component.ProjectSelector) builder.mixin(tracker.class.Project, core.class.Class, view.mixin.AttributeEditor, { inlineEditor: tracker.component.ProjectSelector }) - builder.mixin(tracker.class.Sprint, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(tracker.class.Sprint, core.class.Class, view.mixin.ObjectPresenter, { presenter: tracker.component.SprintTitlePresenter }) + builder.mixin(tracker.class.Sprint, core.class.Class, view.mixin.AttributePresenter, { + presenter: tracker.component.SprintRefPresenter + }) + builder.mixin(tracker.class.Issue, core.class.Class, setting.mixin.Editable, { value: true }) diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index 03450215b7..74153e7ad9 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -41,7 +41,8 @@ export default mergeIds(trackerId, tracker, { // Required to pass build without errorsF Nope: '' as AnyComponent, SprintSelector: '' as AnyComponent, - SubIssuesSelector: '' as AnyComponent + SubIssuesSelector: '' as AnyComponent, + IssueStatistics: '' as AnyComponent }, app: { Tracker: '' as Ref diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 688cca9b9f..6aaa838188 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -29,6 +29,7 @@ import type { AttributePresenter, BuildModelKey, ClassFilters, + ClassSortFuncs, CollectionEditor, CollectionPresenter, Filter, @@ -38,13 +39,16 @@ import type { KeyBinding, KeyFilter, LinkPresenter, + ListHeaderExtra, + ListItemPresenter, ObjectEditor, ObjectEditorHeader, ObjectFactory, + ObjectPresenter, ObjectTitle, ObjectValidator, PreviewPresenter, - ListItemPresenter, + SortFunc, SpaceHeader, SpaceName, ViewAction, @@ -52,7 +56,8 @@ import type { ViewContext, Viewlet, ViewletDescriptor, - ViewletPreference + ViewletPreference, + ViewOptionsModel } from '@hcengineering/view' import view from './plugin' @@ -134,6 +139,11 @@ export class TAttributePresenter extends TClass implements AttributePresenter { presenter!: AnyComponent } +@Mixin(view.mixin.ObjectPresenter, core.class.Class) +export class TObjectPresenter extends TClass implements ObjectPresenter { + presenter!: AnyComponent +} + @Mixin(view.mixin.ListItemPresenter, core.class.Class) export class TListItemPresenter extends TClass implements ListItemPresenter { presenter!: AnyComponent @@ -176,6 +186,16 @@ export class TObjectTitle extends TClass implements ObjectTitle { titleProvider!: Resource<(client: Client, ref: Ref) => Promise> } +@Mixin(view.mixin.ListHeaderExtra, core.class.Class) +export class TListHeaderExtra extends TClass implements ListHeaderExtra { + presenters!: AnyComponent[] +} + +@Mixin(view.mixin.SortFuncs, core.class.Class) +export class TSortFuncs extends TClass implements ClassSortFuncs { + func!: SortFunc +} + @Model(view.class.ViewletPreference, preference.class.Preference) export class TViewletPreference extends TPreference implements ViewletPreference { attachedTo!: Ref @@ -190,11 +210,12 @@ export class TViewletDescriptor extends TDoc implements ViewletDescriptor { @Model(view.class.Viewlet, core.class.Doc, DOMAIN_MODEL) export class TViewlet extends TDoc implements Viewlet { - attachTo!: Ref> + attachTo!: Ref> descriptor!: Ref open!: AnyComponent config!: (BuildModelKey | string)[] hiddenKeys?: string[] + viewOptions?: ViewOptionsModel } @Model(view.class.Action, core.class.Doc, DOMAIN_MODEL) @@ -279,6 +300,9 @@ export function createModel (builder: Builder): void { TCollectionEditor, TCollectionPresenter, TObjectEditor, + TObjectPresenter, + TSortFuncs, + TListHeaderExtra, TViewletPreference, TViewletDescriptor, TViewlet, @@ -330,7 +354,14 @@ export function createModel (builder: Builder): void { classPresenter(builder, core.class.TypeTimestamp, view.component.TimestampPresenter) classPresenter(builder, core.class.TypeDate, view.component.DatePresenter, view.component.DateEditor) classPresenter(builder, core.class.Space, view.component.ObjectPresenter) - classPresenter(builder, core.class.Class, view.component.ClassPresenter) + classPresenter(builder, core.class.Class, view.component.ClassRefPresenter) + builder.mixin(core.class.Space, core.class.Class, view.mixin.ObjectPresenter, { + presenter: view.component.SpacePresenter + }) + + builder.mixin(core.class.Class, core.class.Class, view.mixin.ObjectPresenter, { + presenter: view.component.ClassPresenter + }) classPresenter(builder, core.class.TypeRelatedDocument, view.component.ObjectPresenter) @@ -376,6 +407,17 @@ export function createModel (builder: Builder): void { view.viewlet.Table ) + builder.createDoc( + view.class.ViewletDescriptor, + core.space.Model, + { + label: view.string.Table, + icon: view.icon.Table, + component: view.component.ListView + }, + view.viewlet.List + ) + createAction( builder, { diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index 21cf16a468..1658fba407 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -58,10 +58,13 @@ export default mergeIds(viewId, view, { YoutubePresenter: '' as AnyComponent, GithubPresenter: '' as AnyComponent, ClassPresenter: '' as AnyComponent, + ClassRefPresenter: '' as AnyComponent, EnumEditor: '' as AnyComponent, HTMLEditor: '' as AnyComponent, MarkupEditor: '' as AnyComponent, - MarkupEditorPopup: '' as AnyComponent + MarkupEditorPopup: '' as AnyComponent, + ListView: '' as AnyComponent, + GrowPresenter: '' as AnyComponent }, string: { Table: '' as IntlString, @@ -84,7 +87,8 @@ export default mergeIds(viewId, view, { General: '' as IntlString, Navigation: '' as IntlString, Editor: '' as IntlString, - MarkdownFormatting: '' as IntlString + MarkdownFormatting: '' as IntlString, + List: '' as IntlString }, function: { FilterObjectInResult: '' as Resource<(filter: Filter, onUpdate: () => void) => Promise>>, diff --git a/models/workbench/src/index.ts b/models/workbench/src/index.ts index ed480a6850..3dae7993cb 100644 --- a/models/workbench/src/index.ts +++ b/models/workbench/src/index.ts @@ -48,7 +48,7 @@ export class TSpaceView extends TClass implements SpaceView { export function createModel (builder: Builder): void { builder.createModel(TApplication, TSpaceView, THiddenApplication) - builder.mixin(workbench.class.Application, core.class.Class, view.mixin.AttributePresenter, { + builder.mixin(workbench.class.Application, core.class.Class, view.mixin.ObjectPresenter, { presenter: workbench.component.ApplicationPresenter }) } diff --git a/packages/kanban/src/components/Kanban.svelte b/packages/kanban/src/components/Kanban.svelte index 70c1c12aed..aa2cb89a5b 100644 --- a/packages/kanban/src/components/Kanban.svelte +++ b/packages/kanban/src/components/Kanban.svelte @@ -13,7 +13,7 @@ // limitations under the License. --> { listProvider.update(evt.detail) }} diff --git a/plugins/board-resources/src/components/TableView.svelte b/plugins/board-resources/src/components/TableView.svelte index 5e2dffbb87..60ab06b427 100644 --- a/plugins/board-resources/src/components/TableView.svelte +++ b/plugins/board-resources/src/components/TableView.svelte @@ -23,7 +23,7 @@ {_class} config={[ 'title', - '$lookup.state', + 'state', { key: '', presenter: tags.component.TagsPresenter, diff --git a/plugins/calendar-resources/src/components/CalendarView.svelte b/plugins/calendar-resources/src/components/CalendarView.svelte index 0363286494..07295e43a6 100644 --- a/plugins/calendar-resources/src/components/CalendarView.svelte +++ b/plugins/calendar-resources/src/components/CalendarView.svelte @@ -40,7 +40,6 @@ export let options: FindOptions | undefined = undefined export let baseMenuClass: Ref> | undefined = undefined export let config: (string | BuildModelKey)[] - export let search: string = '' export let createComponent: AnyComponent | undefined = undefined const mondayStart = true @@ -49,10 +48,6 @@ let currentDate: Date = new Date() let selectedDate: Date = new Date() - let resultQuery: DocumentQuery - $: spaceOpt = space ? { space } : {} - $: resultQuery = search === '' ? { ...query, ...spaceOpt } : { ...query, $search: search, ...spaceOpt } - let objects: Event[] = [] const q = createQuery() @@ -67,7 +62,7 @@ { sort: { date: SortingOrder.Ascending }, ...options } ) } - $: update(_class, resultQuery, options) + $: update(_class, query, options) function areDatesLess (firstDate: Date, secondDate: Date): boolean { return ( @@ -256,7 +251,7 @@ {today} {selected} {wrongMonth} - query={resultQuery} + {query} /> @@ -276,7 +271,7 @@ {today} {selected} {wrongMonth} - query={resultQuery} + {query} on:select={(e) => { currentDate = e.detail if (areDatesEqual(selectedDate, currentDate)) { diff --git a/plugins/contact-assets/lang/en.json b/plugins/contact-assets/lang/en.json index 78857cb726..a872e2eeee 100644 --- a/plugins/contact-assets/lang/en.json +++ b/plugins/contact-assets/lang/en.json @@ -72,6 +72,7 @@ "Birthday": "Birthday", "UseImage": "Upload an image", "UseGravatar": "Use Gravatar", - "UseColor": "Use color" + "UseColor": "Use color", + "NotSpecified": "Not specified" } } \ No newline at end of file diff --git a/plugins/contact-assets/lang/ru.json b/plugins/contact-assets/lang/ru.json index 9848e3fd3c..86ff8d8d88 100644 --- a/plugins/contact-assets/lang/ru.json +++ b/plugins/contact-assets/lang/ru.json @@ -72,6 +72,7 @@ "Birthday": "День рождения", "UseImage": "Загрузить фото", "UseGravatar": "Использовать Gravatar", - "UseColor": "Использовать цвет" + "UseColor": "Использовать цвет", + "NotSpecified": "Не указан" } } \ No newline at end of file diff --git a/plugins/contact-resources/src/components/ContactRefPresenter.svelte b/plugins/contact-resources/src/components/ContactRefPresenter.svelte new file mode 100644 index 0000000000..6d2469a9e1 --- /dev/null +++ b/plugins/contact-resources/src/components/ContactRefPresenter.svelte @@ -0,0 +1,33 @@ + + + +{#if doc} + +{/if} diff --git a/plugins/contact-resources/src/components/EmployeePresenter.svelte b/plugins/contact-resources/src/components/EmployeePresenter.svelte index 117fb87a49..2b92f3ae03 100644 --- a/plugins/contact-resources/src/components/EmployeePresenter.svelte +++ b/plugins/contact-resources/src/components/EmployeePresenter.svelte @@ -2,21 +2,14 @@ import { Employee } from '@hcengineering/contact' import { WithLookup } from '@hcengineering/core' import { IntlString } from '@hcengineering/platform' - import type { AnyComponent, AnySvelteComponent } from '@hcengineering/ui' import { showPopup } from '@hcengineering/ui' + import { PersonLabelTooltip } from '..' import PersonPresenter from '../components/PersonPresenter.svelte' import EmployeePreviewPopup from './EmployeePreviewPopup.svelte' import EmployeeStatusPresenter from './EmployeeStatusPresenter.svelte' export let value: WithLookup | null | undefined - export let tooltipLabels: - | { - personLabel?: IntlString - placeholderLabel?: IntlString - component?: AnySvelteComponent | AnyComponent - props?: any - } - | undefined = undefined + export let tooltipLabels: PersonLabelTooltip | undefined = undefined export let shouldShowAvatar: boolean = true export let shouldShowName: boolean = true export let shouldShowPlaceholder = false @@ -25,6 +18,7 @@ export let isInteractive = true export let inline = false export let disableClick = false + export let defaultName: IntlString | undefined = undefined let container: HTMLElement @@ -48,7 +42,7 @@ $: handlePersonEdit = onEmployeeEdit ?? onEdit -
+
{#if value?.$lookup?.statuses?.length} diff --git a/plugins/contact-resources/src/components/EmployeeRefPresenter.svelte b/plugins/contact-resources/src/components/EmployeeRefPresenter.svelte new file mode 100644 index 0000000000..74b22852a9 --- /dev/null +++ b/plugins/contact-resources/src/components/EmployeeRefPresenter.svelte @@ -0,0 +1,39 @@ + + + diff --git a/plugins/contact-resources/src/components/PersonPresenter.svelte b/plugins/contact-resources/src/components/PersonPresenter.svelte index 1596f45f2b..1f2b37b8cd 100644 --- a/plugins/contact-resources/src/components/PersonPresenter.svelte +++ b/plugins/contact-resources/src/components/PersonPresenter.svelte @@ -15,8 +15,10 @@ {#if value || shouldShowPlaceholder} + + + diff --git a/plugins/contact-resources/src/index.ts b/plugins/contact-resources/src/index.ts index e9af7cf6d4..4f705088e6 100644 --- a/plugins/contact-resources/src/index.ts +++ b/plugins/contact-resources/src/index.ts @@ -17,9 +17,9 @@ import { Channel, Contact, Employee, formatName, getGravatarUrl } from '@hcengineering/contact' import { Class, Client, DocumentQuery, Ref, RelatedDocument, WithLookup } from '@hcengineering/core' import { leaveWorkspace } from '@hcengineering/login-resources' -import { Resources } from '@hcengineering/platform' +import { IntlString, Resources } from '@hcengineering/platform' import { Avatar, getClient, MessageBox, ObjectSearchResult, UserInfo, getFileUrl } from '@hcengineering/presentation' -import { showPopup } from '@hcengineering/ui' +import { AnyComponent, AnySvelteComponent, showPopup } from '@hcengineering/ui' import Channels from './components/Channels.svelte' import ChannelsDropdown from './components/ChannelsDropdown.svelte' import ChannelsEditor from './components/ChannelsEditor.svelte' @@ -48,7 +48,11 @@ import OrganizationPresenter from './components/OrganizationPresenter.svelte' import PersonEditor from './components/PersonEditor.svelte' import PersonPresenter from './components/PersonPresenter.svelte' import SocialEditor from './components/SocialEditor.svelte' +import ContactRefPresenter from './components/ContactRefPresenter.svelte' +import PersonRefPresenter from './components/PersonRefPresenter.svelte' +import EmployeeRefPresenter from './components/EmployeeRefPresenter.svelte' import contact from './plugin' +import { employeeSort } from './utils' export { Channels, @@ -117,6 +121,13 @@ async function openChannelURL (doc: Channel): Promise { } } +export interface PersonLabelTooltip { + personLabel?: IntlString + placeholderLabel?: IntlString + component?: AnySvelteComponent | AnyComponent + props?: any +} + export default async (): Promise => ({ actionImpl: { KickEmployee: kickEmployee, @@ -126,6 +137,8 @@ export default async (): Promise => ({ PersonEditor, OrganizationEditor, ContactPresenter, + ContactRefPresenter, + PersonRefPresenter, PersonPresenter, OrganizationPresenter, ChannelsPresenter, @@ -139,6 +152,7 @@ export default async (): Promise => ({ Contacts, EmployeeAccountPresenter, EmployeePresenter, + EmployeeRefPresenter, Members, MemberPresenter, EditMember, @@ -164,6 +178,7 @@ export default async (): Promise => ({ function: { GetFileUrl: getFileUrl, GetGravatarUrl: getGravatarUrl, - GetColorUrl: (uri: string) => uri + GetColorUrl: (uri: string) => uri, + EmployeeSort: employeeSort } }) diff --git a/plugins/contact-resources/src/plugin.ts b/plugins/contact-resources/src/plugin.ts index 626203795b..0315607ec5 100644 --- a/plugins/contact-resources/src/plugin.ts +++ b/plugins/contact-resources/src/plugin.ts @@ -16,6 +16,7 @@ import contact, { contactId } from '@hcengineering/contact' import { IntlString, mergeIds } from '@hcengineering/platform' +import { SortFunc } from '@hcengineering/view' export default mergeIds(contactId, contact, { string: { @@ -61,6 +62,10 @@ export default mergeIds(contactId, contact, { KickEmployeeDescr: '' as IntlString, Email: '' as IntlString, CreateEmployee: '' as IntlString, - Inactive: '' as IntlString + Inactive: '' as IntlString, + NotSpecified: '' as IntlString + }, + function: { + EmployeeSort: '' as SortFunc } }) diff --git a/plugins/contact-resources/src/utils.ts b/plugins/contact-resources/src/utils.ts index a85f4ccbc9..8645e62e32 100644 --- a/plugins/contact-resources/src/utils.ts +++ b/plugins/contact-resources/src/utils.ts @@ -14,9 +14,9 @@ // limitations under the License. // -import contact, { ChannelProvider } from '@hcengineering/contact' +import contact, { ChannelProvider, Employee, formatName } from '@hcengineering/contact' import { Ref, Timestamp } from '@hcengineering/core' -import { getClient } from '@hcengineering/presentation' +import { createQuery, getClient } from '@hcengineering/presentation' const client = getClient() const channelProviders = client.findAll(contact.class.ChannelProvider, {}) @@ -38,3 +38,35 @@ export function formatDate (dueDateMs: Timestamp): string { minute: '2-digit' }) } + +export async function employeeSort (value: Array>): Promise>> { + return await new Promise((resolve) => { + const query = createQuery(true) + query.query(contact.class.Employee, { _id: { $in: value } }, (res) => { + const employees = new Map(res.map((x) => [x._id, x])) + value.sort((a, b) => { + const employeeId1 = a as Ref | null | undefined + const employeeId2 = b as Ref | null | undefined + + if (employeeId1 == null && employeeId2 != null) { + return 1 + } + + if (employeeId1 != null && employeeId2 == null) { + return -1 + } + + if (employeeId1 != null && employeeId2 != null) { + const name1 = formatName(employees.get(employeeId1)?.name ?? '') + const name2 = formatName(employees.get(employeeId2)?.name ?? '') + + return name1.localeCompare(name2) + } + + return 0 + }) + resolve(value) + query.unsubscribe() + }) + }) +} diff --git a/plugins/inventory-resources/src/components/CategoryRefPresenter.svelte b/plugins/inventory-resources/src/components/CategoryRefPresenter.svelte new file mode 100644 index 0000000000..8a890f7bb2 --- /dev/null +++ b/plugins/inventory-resources/src/components/CategoryRefPresenter.svelte @@ -0,0 +1,33 @@ + + + +{#if category} + +{/if} diff --git a/plugins/inventory-resources/src/index.ts b/plugins/inventory-resources/src/index.ts index 5a4eaa0795..0b42013626 100644 --- a/plugins/inventory-resources/src/index.ts +++ b/plugins/inventory-resources/src/index.ts @@ -19,6 +19,7 @@ import { Resources } from '@hcengineering/platform' import { showPopup } from '@hcengineering/ui' import Categories from './components/Categories.svelte' import CategoryPresenter from './components/CategoryPresenter.svelte' +import CategoryRefPresenter from './components/CategoryRefPresenter.svelte' import CreateCategory from './components/CreateCategory.svelte' import EditProduct from './components/EditProduct.svelte' import ProductPresenter from './components/ProductPresenter.svelte' @@ -37,6 +38,7 @@ export default async (): Promise => ({ component: { Categories, CategoryPresenter, + CategoryRefPresenter, ProductPresenter, EditProduct, Variants, diff --git a/plugins/lead-assets/lang/en.json b/plugins/lead-assets/lang/en.json index 4e88c24c17..2066b53837 100644 --- a/plugins/lead-assets/lang/en.json +++ b/plugins/lead-assets/lang/en.json @@ -30,6 +30,7 @@ "Description": "Description", "FullDescription": "Full description", "FunnelPlaceholder": "The simple funnel", - "Members": "Members" + "Members": "Members", + "UnAssign": "Unassign" } } \ No newline at end of file diff --git a/plugins/lead-assets/lang/ru.json b/plugins/lead-assets/lang/ru.json index cb2a8cd3d4..a360fa5f5d 100644 --- a/plugins/lead-assets/lang/ru.json +++ b/plugins/lead-assets/lang/ru.json @@ -17,7 +17,7 @@ "Leads": "Сделки", "SelectCustomer": "Выбрать клиента", "Lead": "Сделка", - "Assignee": "Назначена", + "Assignee": "Исполнитель", "Title": "Загаловок", "LeadPlaceholder": "Простая сделка", "ManageFunnelStatuses": "Управление статусами воронки", @@ -30,6 +30,7 @@ "Description": "Описание", "FullDescription": "Детальное описание", "FunnelPlaceholder": "Простая воронка", - "Members": "Пользователи" + "Members": "Пользователи", + "UnAssign": "Отменить назначение" } } \ No newline at end of file diff --git a/plugins/lead-resources/src/components/CreateLead.svelte b/plugins/lead-resources/src/components/CreateLead.svelte index b736e5405e..10247aab73 100644 --- a/plugins/lead-resources/src/components/CreateLead.svelte +++ b/plugins/lead-resources/src/components/CreateLead.svelte @@ -14,11 +14,11 @@ // limitations under the License. --> - +
diff --git a/plugins/lead-resources/src/plugin.ts b/plugins/lead-resources/src/plugin.ts index 7f0de9b44a..45c802d638 100644 --- a/plugins/lead-resources/src/plugin.ts +++ b/plugins/lead-resources/src/plugin.ts @@ -41,7 +41,9 @@ export default mergeIds(leadId, lead, { Description: '' as IntlString, FullDescription: '' as IntlString, FunnelPlaceholder: '' as IntlString, - Members: '' as IntlString + Members: '' as IntlString, + Assignee: '' as IntlString, + UnAssign: '' as IntlString }, component: { CreateCustomer: '' as AnyComponent, diff --git a/plugins/recruit-resources/src/components/Applications.svelte b/plugins/recruit-resources/src/components/Applications.svelte index 6a9addde42..9cbbd56031 100644 --- a/plugins/recruit-resources/src/components/Applications.svelte +++ b/plugins/recruit-resources/src/components/Applications.svelte @@ -35,8 +35,8 @@ '', '$lookup.space.name', '$lookup.space.$lookup.company', - '$lookup.state', - '$lookup.doneState' + 'state', + 'doneState' ] let wSection: number diff --git a/plugins/recruit-resources/src/components/ApplicationsPopup.svelte b/plugins/recruit-resources/src/components/ApplicationsPopup.svelte index d1f7fc8f51..ba06b5ec80 100644 --- a/plugins/recruit-resources/src/components/ApplicationsPopup.svelte +++ b/plugins/recruit-resources/src/components/ApplicationsPopup.svelte @@ -23,7 +23,7 @@
diff --git a/plugins/recruit-resources/src/components/VacancyApplicationsPopup.svelte b/plugins/recruit-resources/src/components/VacancyApplicationsPopup.svelte index 44aa7471d5..2c23eda46b 100644 --- a/plugins/recruit-resources/src/components/VacancyApplicationsPopup.svelte +++ b/plugins/recruit-resources/src/components/VacancyApplicationsPopup.svelte @@ -35,7 +35,7 @@
diff --git a/plugins/task-resources/src/components/Dashboard.svelte b/plugins/task-resources/src/components/Dashboard.svelte index bcf9b71d7d..74a68d62ac 100644 --- a/plugins/task-resources/src/components/Dashboard.svelte +++ b/plugins/task-resources/src/components/Dashboard.svelte @@ -18,11 +18,11 @@ import type { DoneState, SpaceWithStates, State, Task } from '@hcengineering/task' import task from '@hcengineering/task' import { BarDashboard, DashboardItem } from '@hcengineering/ui' - import { FilterBar } from '@hcengineering/view-resources' import CreateFilter from './CreateFilter.svelte' export let _class: Ref> export let space: Ref + export let query: DocumentQuery const client = getClient() const hieararchy = client.getHierarchy() @@ -85,15 +85,12 @@ const docQuery = createQuery() - $: query = modified + $: resultQuery = modified ? { - space, - _id: { $in: ids } + _id: { $in: ids }, + ...query } - : { space } - let resultQuery = { - space - } + : query function updateDocs (_class: Ref>, states: State[], query: DocumentQuery): void { if (states.length === 0) { @@ -146,7 +143,6 @@ - (resultQuery = e.detail)} />
diff --git a/plugins/task-resources/src/components/StatusTableView.svelte b/plugins/task-resources/src/components/StatusTableView.svelte index 9d7e2a8e4d..90ac588ce6 100644 --- a/plugins/task-resources/src/components/StatusTableView.svelte +++ b/plugins/task-resources/src/components/StatusTableView.svelte @@ -15,7 +15,7 @@ --> {#await cardPresenter then presenter} @@ -105,22 +104,13 @@ mode: 'browser' }} /> - { - resultQuery = e.detail - }} - /> + + +{#if state} + +{/if} diff --git a/plugins/task-resources/src/components/state/StateRefPresenter.svelte b/plugins/task-resources/src/components/state/StateRefPresenter.svelte new file mode 100644 index 0000000000..1f87f9d577 --- /dev/null +++ b/plugins/task-resources/src/components/state/StateRefPresenter.svelte @@ -0,0 +1,31 @@ + + + +{#if state} + +{/if} diff --git a/plugins/task-resources/src/index.ts b/plugins/task-resources/src/index.ts index 53176fdc5d..e77a0c1086 100644 --- a/plugins/task-resources/src/index.ts +++ b/plugins/task-resources/src/index.ts @@ -39,6 +39,8 @@ import TodoItemsPopup from './components/todos/TodoItemsPopup.svelte' import Todos from './components/todos/Todos.svelte' import TodoStatePresenter from './components/todos/TodoStatePresenter.svelte' import Dashboard from './components/Dashboard.svelte' +import DoneStateRefPresenter from './components/state/DoneStateRefPresenter.svelte' +import StateRefPresenter from './components/state/StateRefPresenter.svelte' export { default as AssigneePresenter } from './components/AssigneePresenter.svelte' @@ -70,6 +72,8 @@ export default async (): Promise => ({ KanbanTemplateEditor, KanbanTemplateSelector, AssignedTasks, + DoneStateRefPresenter, + StateRefPresenter, TodoItemsPopup }, actionImpl: { diff --git a/plugins/tracker-resources/src/components/issues/Active.svelte b/plugins/tracker-resources/src/components/issues/Active.svelte index ffd3add93f..fc78389d5f 100644 --- a/plugins/tracker-resources/src/components/issues/Active.svelte +++ b/plugins/tracker-resources/src/components/issues/Active.svelte @@ -35,4 +35,4 @@ ) - + diff --git a/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte b/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte index 0692d0960f..f78fdd186c 100644 --- a/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte +++ b/plugins/tracker-resources/src/components/issues/AssigneePresenter.svelte @@ -15,17 +15,16 @@ - + diff --git a/plugins/tracker-resources/src/components/issues/Issues.svelte b/plugins/tracker-resources/src/components/issues/Issues.svelte index 3fb24a33e6..e3cf25c876 100644 --- a/plugins/tracker-resources/src/components/issues/Issues.svelte +++ b/plugins/tracker-resources/src/components/issues/Issues.svelte @@ -23,4 +23,4 @@ $: query = { space: currentSpace } - + diff --git a/plugins/tracker-resources/src/components/issues/IssuesContent.svelte b/plugins/tracker-resources/src/components/issues/IssuesContent.svelte index 7aef539589..86790a7ad4 100644 --- a/plugins/tracker-resources/src/components/issues/IssuesContent.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuesContent.svelte @@ -1,23 +1,32 @@ {#if viewlet?.$lookup?.descriptor?.component} {/if} diff --git a/plugins/tracker-resources/src/components/issues/IssuesList.svelte b/plugins/tracker-resources/src/components/issues/IssuesList.svelte deleted file mode 100644 index c902d2f4d3..0000000000 --- a/plugins/tracker-resources/src/components/issues/IssuesList.svelte +++ /dev/null @@ -1,355 +0,0 @@ - - - -
- {#each categories as category} - {@const items = groupedIssues[category] ?? []} - {@const limited = limitGroup(category, groupedIssues, categoryLimit) ?? []} - {#if headerComponent || groupByKey === 'assignee' || category === undefined} - -
handleCollapseCategory(toCat(category))}> -
- - {#if groupByKey === 'assignee' && personPresenter} - x?._id === category)} - defaultName={tracker.string.NoAssignee} - shouldShowPlaceholder={true} - isInteractive={false} - avatarSize={'small'} - enlargedText - {currentSpace} - /> - {:else if !groupByKey} - - - {:else if headerComponent} - - {/if} - - - - - {#if limited.length < items.length} -
- {limited.length} -
/
- {items.length} -
- { - categoryLimit[toCat(category)] = limited.length + 20 - }} - /> - {:else} - {items.length} - {/if} -
-
- {/if} - - {#if itemModels} - {#if groupedIssues[category]} - {#each limited as docObject (docObject._id)} - x === docObject)]} - {docObject} - model={itemModels} - {groupByKey} - selected={selectedRowIndex === combinedGroupedIssues.findIndex((x) => x === docObject)} - checked={selectedObjectIdsSet.has(docObject._id)} - {statuses} - {currentTeam} - on:check={(ev) => dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })} - on:contextmenu={(event) => - handleMenuOpened( - event, - docObject, - combinedGroupedIssues.findIndex((x) => x === docObject) - )} - on:focus={() => {}} - on:mouseover={() => handleRowFocused(docObject)} - /> - {/each} - {:else if loadingProps !== undefined} - {#each Array(getLoadingElementsLength(loadingProps, options)) as _, rowIndex} -
-
-
- -
- -
-
-
-
- {/each} - {/if} - {/if} -
- {/each} -
- - diff --git a/plugins/tracker-resources/src/components/issues/IssuesListBrowser.svelte b/plugins/tracker-resources/src/components/issues/IssuesListBrowser.svelte deleted file mode 100644 index 39e11009d0..0000000000 --- a/plugins/tracker-resources/src/components/issues/IssuesListBrowser.svelte +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - { - listProvider.updateFocus(event.detail ?? undefined) - }} - on:check={(event) => { - listProvider.updateSelection(event.detail.docs, event.detail.value) - }} -/> diff --git a/plugins/tracker-resources/src/components/issues/IssuesView.svelte b/plugins/tracker-resources/src/components/issues/IssuesView.svelte index 59c0223de9..65859e7227 100644 --- a/plugins/tracker-resources/src/components/issues/IssuesView.svelte +++ b/plugins/tracker-resources/src/components/issues/IssuesView.svelte @@ -1,21 +1,20 @@ @@ -78,7 +71,7 @@ {#if viewlet} - + {/if} {#if asideFloat && $$slots.aside}
@@ -98,7 +91,7 @@ (resultQuery = e.detail)} />
{#if viewlet} - + {/if} {#if $$slots.aside !== undefined && asideShown}
diff --git a/plugins/tracker-resources/src/components/issues/KanbanView.svelte b/plugins/tracker-resources/src/components/issues/KanbanView.svelte index 0859b1cdc4..cc8733ef04 100644 --- a/plugins/tracker-resources/src/components/issues/KanbanView.svelte +++ b/plugins/tracker-resources/src/components/issues/KanbanView.svelte @@ -17,7 +17,8 @@ import { Class, Doc, DocumentQuery, Lookup, Ref, SortingOrder, WithLookup } from '@hcengineering/core' import { Kanban, TypeState } from '@hcengineering/kanban' import notification from '@hcengineering/notification' - import { createQuery } from '@hcengineering/presentation' + import { getResource } from '@hcengineering/platform' + import { createQuery, getClient } from '@hcengineering/presentation' import tags from '@hcengineering/tags' import { Issue, IssuesGrouping, IssuesOrdering, IssueStatus, Team } from '@hcengineering/tracker' import { @@ -30,18 +31,20 @@ showPopup, tooltip } from '@hcengineering/ui' - import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '@hcengineering/view-resources' + import { ViewOptionModel, ViewOptions, ViewQueryOption } from '@hcengineering/view' + import { + focusStore, + ListSelectionProvider, + noCategory, + SelectDirection, + selectionStore, + viewOptionsStore + } from '@hcengineering/view-resources' import ActionContext from '@hcengineering/view-resources/src/components/ActionContext.svelte' import Menu from '@hcengineering/view-resources/src/components/Menu.svelte' import { onMount } from 'svelte' import tracker from '../../plugin' - import { - getIssueStatusStates, - getKanbanStatuses, - getPriorityStates, - issuesGroupBySorting, - issuesSortOrderMap - } from '../../utils' + import { getIssueStatusStates, getKanbanStatuses, getPriorityStates, issuesGroupBySorting } from '../../utils' import CreateIssue from '../CreateIssue.svelte' import ProjectEditor from '../projects/ProjectEditor.svelte' import AssigneePresenter from './AssigneePresenter.svelte' @@ -53,24 +56,16 @@ import StatusEditor from './StatusEditor.svelte' import EstimationEditor from './timereport/EstimationEditor.svelte' - export let currentSpace: Ref = tracker.team.DefaultTeam + export let space: Ref | undefined = undefined export let baseMenuClass: Ref> | undefined = undefined export let query: DocumentQuery = {} - export let viewOptions: { - groupBy: IssuesGrouping - orderBy: IssuesOrdering - shouldShowEmptyGroups: boolean - shouldShowSubIssues: boolean - } + export let viewOptions: ViewOptionModel[] | undefined - $: currentSpace = typeof query.space === 'string' ? query.space : tracker.team.DefaultTeam - $: ({ groupBy, orderBy, shouldShowEmptyGroups, shouldShowSubIssues } = viewOptions) - $: sort = { [orderBy]: issuesSortOrderMap[orderBy] } - $: rankFieldName = orderBy === IssuesOrdering.Manual ? orderBy : undefined - $: resultQuery = { - ...(shouldShowSubIssues ? {} : { attachedTo: tracker.ids.NoParent }), - ...query - } as any + $: currentSpace = space || tracker.team.DefaultTeam + $: groupBy = ($viewOptionsStore.groupBy ?? noCategory) as IssuesGrouping + $: orderBy = $viewOptionsStore.orderBy + $: sort = { [orderBy[0]]: orderBy[1] } + $: dontUpdateRank = orderBy[0] !== IssuesOrdering.Manual const spaceQuery = createQuery() const statusesQuery = createQuery() @@ -80,6 +75,28 @@ currentTeam = res.shift() }) + let resultQuery: DocumentQuery = query + $: getResultQuery(query, viewOptions, $viewOptionsStore).then((p) => (resultQuery = p)) + + const client = getClient() + const hierarchy = client.getHierarchy() + + async function getResultQuery ( + query: DocumentQuery, + viewOptions: ViewOptionModel[] | undefined, + viewOptionsStore: ViewOptions + ): Promise> { + if (viewOptions === undefined) return query + let result = hierarchy.clone(query) + for (const viewOption of viewOptions) { + if (viewOption.actionTartget !== 'query') continue + const queryOption = viewOption as ViewQueryOption + const f = await getResource(queryOption.action) + result = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, query) + } + return result + } + let issueStatuses: WithLookup[] | undefined $: issueStatusStates = getIssueStatusStates(issueStatuses) $: statusesQuery.query( @@ -122,6 +139,12 @@ } const issuesQuery = createQuery() let issueStates: TypeState[] = [] + const lookupIssue: Lookup = { + status: [tracker.class.IssueStatus, { category: tracker.class.IssueStatusCategory }], + project: tracker.class.Project, + sprint: tracker.class.Sprint, + assignee: contact.class.Employee + } $: issuesQuery.query( tracker.class.Issue, resultQuery, @@ -129,12 +152,7 @@ issueStates = await getKanbanStatuses(groupBy, result) }, { - lookup: { - status: [tracker.class.IssueStatus, { category: tracker.class.IssueStatusCategory }], - project: tracker.class.Project, - sprint: tracker.class.Sprint, - assignee: contact.class.Employee - }, + lookup: lookupIssue, sort: issuesGroupBySorting[groupBy] } ) @@ -145,17 +163,16 @@ }) function getIssueStates ( groupBy: IssuesGrouping, - showEmptyGroups: boolean, states: TypeState[], statusStates: TypeState[], priorityStates: TypeState[] ) { - if (!showEmptyGroups && states.length > 0) return states + if (states.length > 0) return states if (groupBy === IssuesGrouping.Status) return statusStates if (groupBy === IssuesGrouping.Priority) return priorityStates return [] } - $: states = getIssueStates(groupBy, shouldShowEmptyGroups, issueStates, issueStatusStates, priorityStates) + $: states = getIssueStates(groupBy, issueStates, issueStatusStates, priorityStates) const fullFilled: { [key: string]: boolean } = {} const getState = (state: any): WithLookup | undefined => { @@ -174,12 +191,11 @@ { listProvider.update(evt.detail) }} @@ -202,18 +218,16 @@ {state.title} {count}
- {#if groupBy === IssuesGrouping.Status} -
-
- {/if} +
+
@@ -244,7 +258,7 @@
@@ -252,8 +266,8 @@
- {#if issue && issueStatuses && issue.subIssues > 0} - + {#if issue && issue.subIssues > 0} + {/if} - import contact, { Employee } from '@hcengineering/contact' - import { Class, Doc, DocumentQuery, Ref, SortingOrder, WithLookup } from '@hcengineering/core' - import { createQuery } from '@hcengineering/presentation' - import { Issue, IssueStatus, ViewOptions } from '@hcengineering/tracker' - import { issueSP, Scroller } from '@hcengineering/ui' - import { BuildModelKey } from '@hcengineering/view' - import tracker from '../../plugin' - import { - getCategories, - groupBy as groupByFunc, - issuesGroupKeyMap, - issuesOrderKeyMap, - issuesSortOrderMap - } from '../../utils' - import IssuesListBrowser from './IssuesListBrowser.svelte' - - export let _class: Ref> - export let config: (string | BuildModelKey)[] - export let query: DocumentQuery = {} - export let viewOptions: ViewOptions - - $: currentSpace = typeof query.space === 'string' ? query.space : tracker.team.DefaultTeam - $: ({ groupBy, orderBy, shouldShowEmptyGroups, shouldShowSubIssues } = viewOptions) - $: groupByKey = issuesGroupKeyMap[groupBy] - $: orderByKey = issuesOrderKeyMap[orderBy] - $: subIssuesQuery = shouldShowSubIssues ? {} : { attachedTo: tracker.ids.NoParent } - - const statusesQuery = createQuery() - let statuses: IssueStatus[] = [] - $: statusesQuery.query( - tracker.class.IssueStatus, - { attachedTo: currentSpace }, - (result) => { - statuses = [...result] - }, - { - lookup: { category: tracker.class.IssueStatusCategory }, - sort: { rank: SortingOrder.Ascending } - } - ) - $: groupedIssues = groupByFunc(issues, groupBy) - $: categories = getCategories(groupByKey, issues, !!shouldShowEmptyGroups, statuses, employees) - $: employees = issues.map((x) => x.$lookup?.assignee).filter(Boolean) as Employee[] - - const issuesQuery = createQuery() - let issues: WithLookup[] = [] - $: issuesQuery.query( - tracker.class.Issue, - { ...subIssuesQuery, ...query }, - (result) => { - issues = result - }, - { - sort: { [orderByKey]: issuesSortOrderMap[orderByKey] }, - lookup: { - assignee: contact.class.Employee, - status: tracker.class.IssueStatus, - space: tracker.class.Team, - sprint: tracker.class.Sprint, - _id: { - subIssues: tracker.class.Issue - } - } - } - ) - - -
- - - -
diff --git a/plugins/tracker-resources/src/components/issues/PriorityRefPresenter.svelte b/plugins/tracker-resources/src/components/issues/PriorityRefPresenter.svelte new file mode 100644 index 0000000000..72ed7e7e8d --- /dev/null +++ b/plugins/tracker-resources/src/components/issues/PriorityRefPresenter.svelte @@ -0,0 +1,74 @@ + + + +{#if kind === 'list' || kind === 'list-header'} +
+
+ {#if issuePriorities[value]?.icon}{/if} +
+ + +
+{:else} +
diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte index cbafb72968..77552ce933 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssueSelector.svelte @@ -31,6 +31,7 @@ import tracker from '../../../plugin' import { getIssueId } from '../../../issues' import IssueStatusIcon from '../IssueStatusIcon.svelte' + import { ListSelectionProvider } from '@hcengineering/view-resources' export let issue: WithLookup @@ -48,6 +49,7 @@ function openParentIssue () { if (parentIssue) { closeTooltip() + ListSelectionProvider.Pop() openIssue(parentIssue._id) } } @@ -138,7 +140,7 @@ bind:this={subIssuesElement} class="flex-center sub-issues cursor-pointer" use:tooltip={{ label: tracker.string.OpenSubIssues, direction: 'bottom' }} - on:click|preventDefault={areSubIssuesLoading ? undefined : showSubIssues} + on:click|preventDefault={showSubIssues} > {subIssues?.length}
diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte index 8a54597693..46836d35e7 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssuesSelector.svelte @@ -13,17 +13,26 @@ // limitations under the License. --> - + diff --git a/plugins/tracker-resources/src/components/projects/EditProject.svelte b/plugins/tracker-resources/src/components/projects/EditProject.svelte index a63ba6e600..e75ab432aa 100644 --- a/plugins/tracker-resources/src/components/projects/EditProject.svelte +++ b/plugins/tracker-resources/src/components/projects/EditProject.svelte @@ -34,7 +34,7 @@ }) - + - - diff --git a/plugins/view-resources/src/components/ViewOptionsPopup.svelte b/plugins/view-resources/src/components/ViewOptionsPopup.svelte deleted file mode 100644 index 1b2cbd7ee6..0000000000 --- a/plugins/view-resources/src/components/ViewOptionsPopup.svelte +++ /dev/null @@ -1,37 +0,0 @@ - - -
-
- {#each config as model} - -
- {#if isToggleType(model)} - dispatch('update', { key: model.key, value: !viewOptions[model.key] })} - /> - {:else if isDropdownType(model)} - {@const items = model.values.filter(({ hidden }) => !hidden?.(viewOptions))} - dispatch('update', { key: model.key, value: e.detail })} - /> - {/if} -
- {/each} - -
-
diff --git a/plugins/view-resources/src/components/ViewletSetting.svelte b/plugins/view-resources/src/components/ViewletSetting.svelte index 671a946fe1..4544e84545 100644 --- a/plugins/view-resources/src/components/ViewletSetting.svelte +++ b/plugins/view-resources/src/components/ViewletSetting.svelte @@ -13,16 +13,16 @@ // limitations under the License. --> {#if viewlet} @@ -30,9 +58,7 @@ size={'small'} showTooltip={{ label: view.string.CustomizeView }} bind:input={btn} - on:click={() => { - showPopup(ViewletSetting, { viewlet }, btn) - }} + on:click={clickHandler} >
diff --git a/plugins/tracker-resources/src/components/issues/GrowPresenter.svelte b/plugins/view-resources/src/components/list/GrowPresenter.svelte similarity index 100% rename from plugins/tracker-resources/src/components/issues/GrowPresenter.svelte rename to plugins/view-resources/src/components/list/GrowPresenter.svelte diff --git a/plugins/view-resources/src/components/list/List.svelte b/plugins/view-resources/src/components/list/List.svelte new file mode 100644 index 0000000000..4a03f05563 --- /dev/null +++ b/plugins/view-resources/src/components/list/List.svelte @@ -0,0 +1,211 @@ + + + +
+ {#each categories as category, i} + {@const items = groupedDocs[category] ?? []} + + {/each} +
+ + diff --git a/plugins/view-resources/src/components/list/ListCategory.svelte b/plugins/view-resources/src/components/list/ListCategory.svelte new file mode 100644 index 0000000000..9aced6c6e6 --- /dev/null +++ b/plugins/view-resources/src/components/list/ListCategory.svelte @@ -0,0 +1,140 @@ + + + + { + limit += 20 + }} + on:collapse={() => { + collapsed = !collapsed + }} +/> + + {#if itemModels} + {#if limited} + {#each limited as docObject, i (docObject._id)} + dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })} + on:contextmenu={(event) => handleMenuOpened(event, docObject, initIndex + i)} + on:focus={() => {}} + on:mouseover={() => handleRowFocused(docObject)} + /> + {/each} + {/if} + {:else if loadingPropsLength !== undefined} + {#each Array(Math.max(loadingPropsLength, limit)) as _, rowIndex} +
+
+
+ +
+ +
+
+
+
+ {/each} + {/if} +
+ + diff --git a/plugins/view-resources/src/components/list/ListHeader.svelte b/plugins/view-resources/src/components/list/ListHeader.svelte new file mode 100644 index 0000000000..414ab6530d --- /dev/null +++ b/plugins/view-resources/src/components/list/ListHeader.svelte @@ -0,0 +1,135 @@ + + + +{#if headerComponent || groupByKey === noCategory} + +
dispatch('collapse')}> +
+ + {#if groupByKey === noCategory} + + + {:else if headerComponent} + + {/if} + + {#if extraHeaders} + {#each extraHeaders as extra} + + + + {/each} + {/if} + {#if limited < items.length} +
+ {limited} +
/
+ {items.length} +
+ { + dispatch('more') + }} + /> + {:else} + {items.length} + {/if} +
+ {#if createItemDialog !== undefined && createItemLabel !== undefined} +
+{/if} + + diff --git a/plugins/view-resources/src/components/list/ListItem.svelte b/plugins/view-resources/src/components/list/ListItem.svelte new file mode 100644 index 0000000000..2e66c6b42a --- /dev/null +++ b/plugins/view-resources/src/components/list/ListItem.svelte @@ -0,0 +1,223 @@ + + + +
+
+
+
+ { + dispatch('check', { docs: [docObject], value: event.detail }) + }} + /> +
+ +
+
+ {#each model as attributeModel} + {#if attributeModel.props?.type === 'grow'} + + {:else if (!groupByKey || attributeModel.props?.excludeByKey !== groupByKey) && !(attributeModel.props?.optional && compactMode)} + {#if attributeModel.props?.fixed} + + + + {:else} + + {/if} + {/if} + {/each} + {#if compactMode} +
+ +
+ +
+
+
+ +
+ +
+
+ {#each model as attributeModel} + {@const value = getObjectValue(attributeModel.key, docObject)} + {#if attributeModel.props?.optional && attributeModel.props?.excludeByKey !== groupByKey && value !== undefined} + + {/if} + {/each} +
+
+ {/if} +
+ + diff --git a/plugins/view-resources/src/components/list/ListView.svelte b/plugins/view-resources/src/components/list/ListView.svelte new file mode 100644 index 0000000000..075117a217 --- /dev/null +++ b/plugins/view-resources/src/components/list/ListView.svelte @@ -0,0 +1,74 @@ + + + + +
+ + { + listProvider.updateFocus(event.detail ?? undefined) + }} + on:check={(event) => { + listProvider.updateSelection(event.detail.docs, event.detail.value) + }} + on:content={(evt) => { + listProvider.update(evt.detail) + }} + /> + +
diff --git a/plugins/view-resources/src/index.ts b/plugins/view-resources/src/index.ts index aec7dfb475..7cad0c61a8 100644 --- a/plugins/view-resources/src/index.ts +++ b/plugins/view-resources/src/index.ts @@ -22,6 +22,7 @@ import BooleanPresenter from './components/BooleanPresenter.svelte' import BooleanTruePresenter from './components/BooleanTruePresenter.svelte' import ClassAttributeBar from './components/ClassAttributeBar.svelte' import ClassPresenter from './components/ClassPresenter.svelte' +import ClassRefPresenter from './components/ClassRefPresenter.svelte' import ColorsPopup from './components/ColorsPopup.svelte' import DateEditor from './components/DateEditor.svelte' import DatePresenter from './components/DatePresenter.svelte' @@ -58,6 +59,9 @@ import MarkupEditor from './components/MarkupEditor.svelte' import MarkupEditorPopup from './components/MarkupEditorPopup.svelte' import SortableList from './components/list/SortableList.svelte' import SortableListItem from './components/list/SortableListItem.svelte' +import ListView from './components/list/ListView.svelte' +import GrowPresenter from './components/list/GrowPresenter.svelte' + import { afterResult, beforeResult, @@ -81,7 +85,6 @@ export { default as LinkPresenter } from './components/LinkPresenter.svelte' export { default as ContextMenu } from './components/Menu.svelte' export { default as TableBrowser } from './components/TableBrowser.svelte' export { default as FixedColumn } from './components/FixedColumn.svelte' -export { default as ViewOptionsButton } from './components/ViewOptionsButton.svelte' export { default as ValueSelector } from './components/ValueSelector.svelte' export { default as ObjectBox } from './components/ObjectBox.svelte' export { default as ObjectPresenter } from './components/ObjectPresenter.svelte' @@ -128,6 +131,7 @@ export default async (): Promise => ({ actionImpl, component: { ClassPresenter, + ClassRefPresenter, ObjectFilter, ValueFilter, TimestampFilter, @@ -158,7 +162,9 @@ export default async (): Promise => ({ EnumEditor, FilterTypePopup, ValueSelector, - HTMLEditor + HTMLEditor, + ListView, + GrowPresenter }, popup: { PositionElementAlignment diff --git a/plugins/view-resources/src/plugin.ts b/plugins/view-resources/src/plugin.ts index 1659f53fe1..0fd62c06cd 100644 --- a/plugins/view-resources/src/plugin.ts +++ b/plugins/view-resources/src/plugin.ts @@ -55,6 +55,11 @@ export default mergeIds(viewId, view, { AllFilters: '' as IntlString, MatchCriteria: '' as IntlString, DontMatchCriteria: '' as IntlString, - MarkupEditor: '' as IntlString + MarkupEditor: '' as IntlString, + Select: '' as IntlString, + NoGrouping: '' as IntlString, + Grouping: '' as IntlString, + Ordering: '' as IntlString, + Manual: '' as IntlString } }) diff --git a/plugins/view-resources/src/selection.ts b/plugins/view-resources/src/selection.ts index 9da690ae2b..1b38164c59 100644 --- a/plugins/view-resources/src/selection.ts +++ b/plugins/view-resources/src/selection.ts @@ -1,7 +1,7 @@ import { Doc } from '@hcengineering/core' import { panelstore } from '@hcengineering/ui' import { onDestroy } from 'svelte' -import { writable } from 'svelte/store' +import { Unsubscriber, writable } from 'svelte/store' /** * @public @@ -85,22 +85,52 @@ export function updateFocus (selection?: FocusSelection): void { } } +const providers: ListSelectionProvider[] = [] + /** * @public * * List selection provider */ export class ListSelectionProvider implements SelectionFocusProvider { - _docs: Doc[] = [] + private _docs: Doc[] = [] _current?: FocusSelection - constructor (private readonly delegate: (offset: 1 | -1 | 0, of?: Doc, direction?: SelectDirection) => void) { - const unsubscribe = focusStore.subscribe((doc) => { + private readonly unsubscribe: Unsubscriber + constructor ( + private readonly delegate: (offset: 1 | -1 | 0, of?: Doc, direction?: SelectDirection) => void, + autoDestroy = true + ) { + this.unsubscribe = focusStore.subscribe((doc) => { this._current = doc }) - onDestroy(() => { - unsubscribe() - updateFocus(undefined) - }) + providers.push(this) + if (autoDestroy) { + onDestroy(() => { + this.destroy() + }) + } + } + + static Pop (): void { + if (providers.length === 0) return + const last = providers[providers.length - 1] + last.destroy() + } + + destroy (): void { + const thisIndex = providers.findIndex((p) => p === this) + providers.splice(thisIndex, 1) + if (thisIndex === providers.length) { + if (providers.length > 0) { + const current = providers[providers.length - 1] + const index = current.current() + const target = index !== undefined ? current.docs()[index] : undefined + updateFocus({ focus: target, provider: current }) + } else { + updateFocus() + } + } + this.unsubscribe() } select (offset: 1 | -1 | 0, of?: Doc, direction?: SelectDirection): void { @@ -143,6 +173,7 @@ export class ListSelectionProvider implements SelectionFocusProvider { } current (doc?: FocusSelection): number | undefined { - return this._docs.findIndex((it) => it._id === doc?.focus?._id) + const index = this._docs.findIndex((it) => it._id === (doc?.focus?._id ?? this._current?.focus?._id)) + return index === -1 ? undefined : index } } diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index 6c6dbcadb4..f8693ef456 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -41,6 +41,7 @@ import type { BuildModelOptions, Viewlet } from '@hcengineering/view' import view, { AttributeModel, BuildModelKey } from '@hcengineering/view' import { writable } from 'svelte/store' import plugin from './plugin' +import { noCategory } from './viewOptions' /** * Define some properties to be used to show component until data is properly loaded. @@ -59,7 +60,7 @@ export async function getObjectPresenter ( isCollectionAttr: boolean = false ): Promise { const hierarchy = client.getHierarchy() - const mixin = isCollectionAttr ? view.mixin.CollectionPresenter : view.mixin.AttributePresenter + const mixin = isCollectionAttr ? view.mixin.CollectionPresenter : view.mixin.ObjectPresenter const clazz = hierarchy.getClass(_class) let mixinClazz = hierarchy.getClass(_class) let presenterMixin = hierarchy.as(clazz, mixin) @@ -157,7 +158,7 @@ async function getAttributePresenter ( _class: presenterClass.attrClass, label: preserveKey.label ?? attribute.shortLabel ?? attribute.label, presenter, - props: {}, + props: preserveKey.props, icon: presenterMixin.icon, attribute, collectionAttr: isCollectionAttr @@ -180,7 +181,7 @@ export async function getPresenter ( _class, label: label as IntlString, presenter: typeof presenter === 'string' ? await getResource(presenter) : presenter, - props: key.props, + props: preserveKey.props, collectionAttr: isCollectionAttr } } @@ -497,3 +498,54 @@ export function getActiveViewletId (): Ref | null { export type FixedWidthStore = Record export const fixedWidthStore = writable({}) + +export const groupBy = (docs: Doc[], key: string): { [key: string]: Doc[] } => { + return docs.reduce((storage: { [key: string]: Doc[] }, item: Doc) => { + const group = (item as any)[key] ?? undefined + + storage[group] = storage[group] ?? [] + + storage[group].push(item) + + return storage + }, {}) +} + +export async function getCategories ( + client: TxOperations, + _class: Ref>, + docs: Doc[], + key: string +): Promise { + if (key === noCategory) return [undefined] + const hierarchy = client.getHierarchy() + const existingCategories = Array.from(new Set(docs.map((x: any) => x[key] ?? undefined))) + const attr = hierarchy.getAttribute(_class, key) + console.log(attr) + if (attr === undefined) return existingCategories + const attrClass = getAttributePresenterClass(hierarchy, attr).attrClass + console.log(attrClass) + const clazz = hierarchy.getClass(attrClass) + const sortFunc = hierarchy.as(clazz, view.mixin.SortFuncs) + if (sortFunc?.func === undefined) return existingCategories + const f = await getResource(sortFunc.func) + + return await f(existingCategories) +} + +export function getKeyLabel ( + client: TxOperations, + _class: Ref>, + key: string, + lookup: Lookup | undefined +): IntlString { + if (key.startsWith('$lookup') && lookup !== undefined) { + const lookupClass = getLookupClass(key, lookup, _class) + const lookupProperty = getLookupProperty(key) + const lookupKey = { key: lookupProperty[0] } + return getLookupLabel(client, lookupClass[1], lookupClass[0], lookupKey, lookupProperty[1]) + } else { + const attribute = client.getHierarchy().getAttribute(_class, key) + return attribute.label + } +} diff --git a/plugins/view-resources/src/viewOptions.ts b/plugins/view-resources/src/viewOptions.ts index c52dd76551..8f15ec8f57 100644 --- a/plugins/view-resources/src/viewOptions.ts +++ b/plugins/view-resources/src/viewOptions.ts @@ -1,10 +1,16 @@ -import { IntlString } from '@hcengineering/platform' +import { SortingOrder } from '@hcengineering/core' import { getCurrentLocation, locationToUrl } from '@hcengineering/ui' +import { DropdownViewOption, ToggleViewOption, ViewOptionModel, ViewOptions } from '@hcengineering/view' import { writable } from 'svelte/store' -export type ViewOptions = Record +export const noCategory = '#no_category' -export const viewOptionsStore = writable({}) +export const defaulOptions: ViewOptions = { + groupBy: noCategory, + orderBy: ['modifiedBy', SortingOrder.Descending] +} + +export const viewOptionsStore = writable(defaulOptions) export function isToggleType (viewOption: ViewOptionModel): viewOption is ToggleViewOption { return viewOption.type === 'toggle' @@ -32,25 +38,3 @@ export function getViewOptions (prefix: string): ViewOptions | null { if (options === null) return null return JSON.parse(options) } - -export interface ViewOption { - type: string - key: string - defaultValue: any - label: IntlString - group?: string - hidden?: (viewOptions: ViewOptions) => boolean -} - -export interface ToggleViewOption extends ViewOption { - type: 'toggle' - defaultValue: boolean -} - -export interface DropdownViewOption extends ViewOption { - type: 'dropdown' - defaultValue: string - values: Array<{ label: IntlString, id: string, hidden?: (viewOptions: ViewOptions) => boolean }> -} - -export type ViewOptionModel = ToggleViewOption | DropdownViewOption diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 179e37f3fb..06d68ce239 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -26,6 +26,7 @@ import type { Obj, ObjQueryType, Ref, + SortingOrder, Space, Type, UXObject @@ -128,6 +129,13 @@ export interface AttributePresenter extends Class { presenter: AnyComponent } +/** + * @public + */ +export interface ObjectPresenter extends Class { + presenter: AnyComponent +} + /** * @public */ @@ -185,15 +193,35 @@ export interface ViewletDescriptor extends Doc, UXObject { component: AnyComponent } +/** + * @public + */ +export interface ListHeaderExtra extends Class { + presenters: AnyComponent[] +} + +/** + * @public + */ +export type SortFunc = Resource<(values: any[]) => Promise> + +/** + * @public + */ +export interface ClassSortFuncs extends Class { + func: SortFunc +} + /** * @public */ export interface Viewlet extends Doc { - attachTo: Ref> + attachTo: Ref> descriptor: Ref options?: FindOptions config: (BuildModelKey | string)[] hiddenKeys?: string[] + viewOptions?: ViewOptionsModel } /** @@ -395,6 +423,71 @@ export interface ViewletPreference extends Preference { config: (BuildModelKey | string)[] } +/** + * @public + */ +export type ViewOptions = { + groupBy: string + orderBy: OrderOption +} & Record + +/** + * @public + */ +export interface ViewOption { + type: string + key: string + defaultValue: any + label: IntlString + hidden?: (viewOptions: ViewOptions) => boolean + actionTartget?: 'query' + action?: Resource<(value: any, ...params: any) => any> +} + +/** + * @public + */ +export interface ViewQueryOption extends ViewOption { + actionTartget: 'query' + action: Resource<(value: any, query: DocumentQuery) => DocumentQuery> +} + +/** + * @public + */ +export interface ToggleViewOption extends ViewOption { + type: 'toggle' + defaultValue: boolean +} + +/** + * @public + */ +export interface DropdownViewOption extends ViewOption { + type: 'dropdown' + defaultValue: string + values: Array<{ label: IntlString, id: string, hidden?: (viewOptions: ViewOptions) => boolean }> +} + +/** + * @public + */ +export type ViewOptionModel = ToggleViewOption | DropdownViewOption + +/** + * @public + */ +export type OrderOption = [string, SortingOrder] + +/** + * @public + */ +export interface ViewOptionsModel { + groupBy: string[] + orderBy: OrderOption[] + other: ViewOptionModel[] +} + /** * @public */ @@ -410,6 +503,7 @@ const view = plugin(viewId, { AttributePresenter: '' as Ref>, ListItemPresenter: '' as Ref>, ObjectEditor: '' as Ref>, + ObjectPresenter: '' as Ref>, ObjectEditorHeader: '' as Ref>, ObjectValidator: '' as Ref>, ObjectFactory: '' as Ref>, @@ -417,7 +511,9 @@ const view = plugin(viewId, { SpaceHeader: '' as Ref>, SpaceName: '' as Ref>, IgnoreActions: '' as Ref>, - PreviewPresenter: '' as Ref> + PreviewPresenter: '' as Ref>, + ListHeaderExtra: '' as Ref>, + SortFuncs: '' as Ref> }, class: { ViewletPreference: '' as Ref>, @@ -449,7 +545,8 @@ const view = plugin(viewId, { Open: '' as Ref }, viewlet: { - Table: '' as Ref + Table: '' as Ref, + List: '' as Ref }, component: { ObjectPresenter: '' as AnyComponent, diff --git a/plugins/workbench-resources/src/components/Archive.svelte b/plugins/workbench-resources/src/components/Archive.svelte index cd4ebe7fca..cf9a1fea77 100644 --- a/plugins/workbench-resources/src/components/Archive.svelte +++ b/plugins/workbench-resources/src/components/Archive.svelte @@ -33,7 +33,7 @@ {#if model} = { name: SortingOrder.Ascending } diff --git a/plugins/workbench-resources/src/components/SpaceContent.svelte b/plugins/workbench-resources/src/components/SpaceContent.svelte index deee83454c..bd914441d1 100644 --- a/plugins/workbench-resources/src/components/SpaceContent.svelte +++ b/plugins/workbench-resources/src/components/SpaceContent.svelte @@ -14,20 +14,28 @@ // limitations under the License. -->