From 49bf38cf0aa7374b4dbb5a0c45070a7d6384ee1e Mon Sep 17 00:00:00 2001 From: Denis Bunakalya Date: Wed, 18 Jan 2023 11:53:37 +0400 Subject: [PATCH] Merge branch 'main' of github.com:hcengineering/anticrm into show-filter-items-current-space Signed-off-by: Denis Bunakalya --- .gitignore | 3 +- models/all/src/migration.ts | 4 +- 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 | 18 +- models/inventory/src/migration.ts | 21 ++ 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 | 173 +++++++-- models/tracker/src/plugin.ts | 3 +- models/view/package.json | 1 + models/view/src/index.ts | 50 ++- models/view/src/migration.ts | 45 ++- models/view/src/plugin.ts | 7 +- models/workbench/src/index.ts | 2 +- packages/core/src/hierarchy.ts | 10 +- packages/core/src/typeof.ts | 35 ++ packages/kanban/src/components/Kanban.svelte | 56 +-- packages/platform/src/event.ts | 6 +- packages/presentation/lang/en.json | 3 +- packages/presentation/lang/ru.json | 3 +- .../presentation/src/components/Avatar.svelte | 22 +- packages/presentation/src/connect.ts | 9 +- packages/presentation/src/plugin.ts | 3 +- packages/presentation/src/utils.ts | 4 +- .../src/components/ReferenceInput.svelte | 6 +- packages/theme/styles/_layouts.scss | 27 +- packages/theme/styles/common.scss | 3 + packages/theme/styles/dialogs.scss | 4 +- packages/ui/src/components/Chevron.svelte | 85 +++++ .../ui/src/components/ExpandCollapse.svelte | 2 +- packages/ui/src/components/Expandable.svelte | 73 ++-- packages/ui/src/components/Label.svelte | 18 +- packages/ui/src/components/ListView.svelte | 4 +- packages/ui/src/components/TimeSince.svelte | 4 +- .../src/components/icons/DownOutline.svelte | 2 +- packages/ui/src/index.ts | 1 + .../src/components/TxView.svelte | 42 ++- plugins/activity-resources/src/utils.ts | 41 +- plugins/attachment-resources/src/plugin.ts | 1 - plugins/attachment/src/index.ts | 3 +- .../src/components/EntityMapping.svelte | 4 +- .../FieldMappingSynchronizer.svelte | 69 ++-- .../src/components/KanbanView.svelte | 10 +- .../src/components/TableView.svelte | 2 +- .../src/components/CalendarView.svelte | 11 +- .../src/components/Events.svelte | 7 +- plugins/client-resources/src/index.ts | 2 +- plugins/contact-assets/lang/en.json | 3 +- plugins/contact-assets/lang/ru.json | 3 +- .../src/components/ContactRefPresenter.svelte | 33 ++ .../src/components/Contacts.svelte | 12 +- .../src/components/EmployeePresenter.svelte | 15 +- .../components/EmployeeRefPresenter.svelte | 39 ++ .../src/components/Members.svelte | 6 +- .../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 +- .../src/components/Documents.svelte | 12 +- .../src/components/DepartmentStaff.svelte | 6 +- .../components/schedule/MonthTableView.svelte | 6 +- .../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/InviteLink.svelte | 3 +- .../src/components/Applications.svelte | 4 +- .../src/components/ApplicationsPopup.svelte | 2 +- .../src/components/EditVacancy.svelte | 32 +- .../src/components/Vacancies.svelte | 6 +- .../VacancyApplicationsPopup.svelte | 2 +- .../src/components/Settings.svelte | 6 +- .../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 + plugins/tracker-resources/package.json | 1 + .../src/components/AccountPopup.svelte | 7 +- .../src/components/RelationsPopup.svelte | 6 +- .../issues/AssigneePresenter.svelte | 21 +- .../src/components/issues/Duration.svelte | 8 - .../issues/IssueNotification.svelte | 41 +- .../components/issues/IssuePresenter.svelte | 16 +- .../issues/IssueStatusActivity.svelte | 2 +- .../components/issues/IssueStatusIcon.svelte | 21 +- .../components/issues/IssuesContent.svelte | 26 +- .../components/issues/IssuesFilterMenu.svelte | 8 +- .../src/components/issues/IssuesList.svelte | 355 ------------------ .../issues/IssuesListBrowser.svelte | 82 ---- .../src/components/issues/IssuesView.svelte | 62 ++- .../src/components/issues/KanbanView.svelte | 115 +++--- .../src/components/issues/ListView.svelte | 83 ---- .../src/components/issues/ParentIssue.svelte | 1 + .../issues/ParentNamesPresenter.svelte | 1 + .../components/issues/PriorityEditor.svelte | 1 + .../issues/PriorityRefPresenter.svelte | 74 ++++ .../src/components/issues/StatusEditor.svelte | 42 ++- .../issues/StatusRefPresenter.svelte | 32 ++ .../components/issues/TitlePresenter.svelte | 12 +- .../components/issues/edit/EditIssue.svelte | 88 +---- .../issues/edit/SubIssueList.svelte | 206 ++-------- .../issues/edit/SubIssueSelector.svelte | 8 +- .../components/issues/edit/SubIssues.svelte | 143 ++++--- .../issues/edit/SubIssuesSelector.svelte | 55 ++- .../issues/related/RelatedIssues.svelte | 7 +- .../related/RelatedIssuesSection.svelte | 54 +++ .../issues/timereport/EstimationPopup.svelte | 23 +- .../timereport/EstimationSubIssueList.svelte | 82 ++-- .../timereport/ReportedTimeEditor.svelte | 1 + .../issues/timereport/ReportsPopup.svelte | 2 +- .../timereport/SubIssuesEstimations.svelte | 14 +- .../issues/timereport/TimePresenter.svelte | 1 + .../timereport/TimeReportDayDropdown.svelte | 4 +- .../timereport/TimeSpendReportPopup.svelte | 18 +- .../issues/timereport/TimeSpendReports.svelte | 18 +- .../timereport/TimeSpendReportsList.svelte | 99 ++--- .../src/components/myissues/MyIssues.svelte | 10 +- .../src/components/projects/NewProject.svelte | 9 - .../projects/ProjectPresenter.svelte | 1 + .../components/projects/ProjectsList.svelte | 10 +- .../src/components/sprints/EditSprint.svelte | 3 +- .../components/sprints/IssueStatistics.svelte | 10 +- .../src/components/sprints/NewSprint.svelte | 9 - .../components/sprints/SprintEditor.svelte | 12 +- .../src/components/sprints/SprintList.svelte | 1 + .../components/sprints/SprintPresenter.svelte | 1 + .../sprints/SprintRefPresenter.svelte | 76 ++++ .../templates/IssueTemplateChildList.svelte | 5 - .../templates/IssueTemplatePresenter.svelte | 1 + .../templates/IssueTemplatesContent.svelte | 23 +- .../templates/IssueTemplatesView.svelte | 9 +- .../templates/TemplateControlPanel.svelte | 12 +- .../components/templates/TemplatesList.svelte | 65 ---- .../components/workflow/StatusEditor.svelte | 1 + .../workflow/StatusPresenter.svelte | 6 +- .../src/components/workflow/Statuses.svelte | 1 + plugins/tracker-resources/src/index.ts | 26 +- plugins/tracker-resources/src/plugin.ts | 22 +- plugins/tracker-resources/src/types.ts | 2 +- plugins/tracker-resources/src/utils.ts | 194 +++------- plugins/tracker/src/index.ts | 3 +- plugins/view-assets/assets/icons.svg | 6 + plugins/view-assets/lang/en.json | 8 +- plugins/view-assets/lang/ru.json | 8 +- plugins/view-assets/src/index.ts | 1 + .../src/components/ClassRefPresenter.svelte | 26 ++ .../src/components/FixedColumn.svelte | 38 +- .../src/components/ObjectPresenter.svelte | 2 +- .../src/components/SpacePresenter.svelte | 4 +- .../src/components/TableBrowser.svelte | 8 +- .../src/components/TableView.svelte | 5 +- .../src/components/UpDownNavigator.svelte | 5 +- .../src/components/ViewOptions.svelte | 101 +++++ .../src/components/ViewOptionsButton.svelte | 72 ---- .../src/components/ViewOptionsPopup.svelte | 37 -- .../src/components/ViewletSetting.svelte | 67 ++-- .../components/ViewletSettingButton.svelte | 40 +- .../src/components/list}/GrowPresenter.svelte | 0 .../src/components/list/List.svelte | 230 ++++++++++++ .../src/components/list/ListCategory.svelte | 145 +++++++ .../src/components/list/ListHeader.svelte | 145 +++++++ .../src/components/list/ListItem.svelte | 227 +++++++++++ .../src/components/list/ListView.svelte | 78 ++++ .../src/components/list/SortableList.svelte | 11 +- plugins/view-resources/src/index.ts | 12 +- plugins/view-resources/src/plugin.ts | 7 +- plugins/view-resources/src/selection.ts | 49 ++- plugins/view-resources/src/utils.ts | 56 ++- plugins/view-resources/src/viewOptions.ts | 46 +-- plugins/view/src/index.ts | 108 +++++- .../src/components/AccountPopup.svelte | 4 +- .../src/components/Archive.svelte | 2 +- .../src/components/SelectWorkspaceMenu.svelte | 4 +- .../src/components/SpaceBrowser.svelte | 2 +- .../src/components/SpaceContent.svelte | 19 +- .../src/components/SpaceHeader.svelte | 19 +- .../src/components/SpaceView.svelte | 6 +- .../src/components/SpecialView.svelte | 86 +++-- .../src/components/Workbench.svelte | 1 + .../src/components/WorkbenchApp.svelte | 39 +- server-plugins/tracker-resources/src/index.ts | 6 +- server/core/src/fulltext.ts | 2 +- tests/docker-compose.yaml | 4 +- tests/sanity/package.json | 4 +- tests/sanity/tests/actions.spec.ts | 12 +- tests/sanity/tests/contact.duplicate.spec.ts | 2 +- tests/sanity/tests/contacts.spec.ts | 2 +- tests/sanity/tests/login.spec.ts | 2 +- tests/sanity/tests/org.members.spec.ts | 2 +- tests/sanity/tests/recruit.review.spec.ts | 2 +- tests/sanity/tests/recruit.spec.ts | 2 +- tests/sanity/tests/settings.spec.ts | 18 +- tests/sanity/tests/tags.spec.ts | 20 +- tests/sanity/tests/tracker.layout.spec.ts | 10 +- tests/sanity/tests/tracker.projects.spec.ts | 10 +- tests/sanity/tests/tracker.spec.ts | 6 +- tests/sanity/tests/tracker.utils.ts | 12 +- tests/sanity/tests/workbench.spec.ts | 14 +- vscode-profile-2022-12-30-12-56-33.cpuprofile | 1 - 221 files changed, 3593 insertions(+), 2272 deletions(-) create mode 100644 models/inventory/src/migration.ts create mode 100644 packages/core/src/typeof.ts create mode 100644 packages/ui/src/components/Chevron.svelte 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/issues/related/RelatedIssuesSection.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 delete mode 100644 vscode-profile-2022-12-30-12-56-33.cpuprofile diff --git a/.gitignore b/.gitignore index 206a281644..3bc7ee66c6 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,5 @@ dist_cache tsconfig.tsbuildinfo ingest-attachment-*.zip tsdoc-metadata.json -pods/front/dist \ No newline at end of file +pods/front/dist +*.cpuprofile diff --git a/models/all/src/migration.ts b/models/all/src/migration.ts index 1507bca477..9fab63b12a 100644 --- a/models/all/src/migration.ts +++ b/models/all/src/migration.ts @@ -27,6 +27,7 @@ import { settingOperation } from '@hcengineering/model-setting' import { recruitOperation } from '@hcengineering/model-recruit' import { tagsOperation } from '@hcengineering/model-tags' import { taskOperation } from '@hcengineering/model-task' +import { inventoryOperation } from '@hcengineering/model-inventory' import { telegramOperation } from '@hcengineering/model-telegram' import { templatesOperation } from '@hcengineering/model-templates' import { viewOperation } from '@hcengineering/model-view' @@ -58,5 +59,6 @@ export const migrateOperations: MigrateOperation[] = [ boardOperation, hrOperation, documentOperation, - bitrixOperation + bitrixOperation, + inventoryOperation ] 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..70ca065a64 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 ) @@ -173,4 +176,5 @@ export function createModel (builder: Builder): void { }) } +export { inventoryOperation } from './migration' export { default } from './plugin' diff --git a/models/inventory/src/migration.ts b/models/inventory/src/migration.ts new file mode 100644 index 0000000000..515ba8551b --- /dev/null +++ b/models/inventory/src/migration.ts @@ -0,0 +1,21 @@ +// +// Copyright © 2022 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model' + +export const inventoryOperation: MigrateOperation = { + async migrate (client: MigrationClient): Promise {}, + async upgrade (client: MigrationUpgradeClient): Promise {} +} 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..eba6f49259 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: '', @@ -528,13 +550,91 @@ export function createModel (builder: Builder): void { ] }) + const subIssuesOptions: ViewOptionsModel = { + groupBy: ['status', 'assignee', 'priority', 'sprint'], + orderBy: [ + ['status', SortingOrder.Ascending], + ['priority', SortingOrder.Ascending], + ['modifiedOn', SortingOrder.Descending], + ['dueDate', SortingOrder.Descending], + ['rank', SortingOrder.Ascending] + ], + other: [] + } + + builder.createDoc( + view.class.Viewlet, + core.space.Model, + { + attachTo: tracker.class.Issue, + descriptor: view.viewlet.List, + viewOptions: subIssuesOptions, + variant: 'subissue', + config: [ + { + key: '', + presenter: tracker.component.PriorityEditor, + props: { type: 'priority', kind: 'list', size: 'small' } + }, + { key: '', presenter: tracker.component.IssuePresenter, props: { type: 'issue', fixed: 'left' } }, + { + key: '', + presenter: tracker.component.StatusEditor, + props: { kind: 'list', size: 'small', justify: 'center' } + }, + { key: '', presenter: tracker.component.TitlePresenter, props: { shouldUseMargin: true, showParent: false } }, + { key: '', presenter: tracker.component.SubIssuesSelector, props: {} }, + { key: '', presenter: view.component.GrowPresenter, props: { type: 'grow' } }, + { key: '', presenter: tracker.component.DueDatePresenter, props: { kind: 'list' } }, + { + key: '', + presenter: tracker.component.SprintEditor, + props: { + kind: 'list', + size: 'small', + shape: 'round', + shouldShowPlaceholder: false, + excludeByKey: 'sprint', + optional: true + } + }, + { + key: '', + presenter: tracker.component.EstimationEditor, + props: { kind: 'list', size: 'small', optional: true } + }, + { + key: 'modifiedOn', + presenter: tracker.component.ModificationDatePresenter, + props: { fixed: 'right', optional: true } + }, + { + key: '$lookup.assignee', + presenter: tracker.component.AssigneePresenter, + props: { issueClass: tracker.class.Issue, defaultClass: contact.class.Employee, shouldShowLabel: false } + } + ] + }, + tracker.viewlet.SubIssues + ) + 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 +656,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 +747,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 +759,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 +767,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 +791,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/package.json b/models/view/package.json index 4f0ed39a7b..4cd48bbe21 100644 --- a/models/view/package.json +++ b/models/view/package.json @@ -32,6 +32,7 @@ "@hcengineering/view": "^0.6.2", "@hcengineering/view-resources": "^0.6.0", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/preference": "^0.6.2", "@hcengineering/model-preference": "^0.6.0" } } diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 688cca9b9f..20978a3523 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.List, + icon: view.icon.List, + component: view.component.ListView + }, + view.viewlet.List + ) + createAction( builder, { diff --git a/models/view/src/migration.ts b/models/view/src/migration.ts index 8bb162f702..f2a71dc5af 100644 --- a/models/view/src/migration.ts +++ b/models/view/src/migration.ts @@ -13,9 +13,52 @@ // limitations under the License. // +import { Ref } from '@hcengineering/core' import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model' +import { Viewlet, ViewletPreference } from '@hcengineering/view' +import { DOMAIN_PREFERENCE } from '@hcengineering/preference' + +async function migrateViewletPreference (client: MigrationClient): Promise { + const targets: Record = { + 'inventory:viewlet:TableProduct': ['attachedTo'], + 'lead:viewlet:TableCustomer': ['_class'], + 'lead:viewlet:TableLead': ['attachedTo', 'state', 'doneState'], + 'recruit.viewlet.TableApplicant': ['attachedTo', 'assignee', 'state', 'doneState'], + 'task.viewlet.TableIssue': ['assignee', 'state', 'doneState'] + } + for (const target in targets) { + const keys = targets[target] + const preferences = await client.find(DOMAIN_PREFERENCE, { + attachedTo: target as Ref + }) + for (const pref of preferences) { + let needUpdate = false + + for (const key of keys) { + const index = pref.config.findIndex((p) => p === `$lookup.${key}`) + if (index !== -1) { + pref.config.splice(index, 1, key) + needUpdate = true + } + } + if (needUpdate) { + await client.update( + DOMAIN_PREFERENCE, + { + _id: pref._id + }, + { + config: pref.config + } + ) + } + } + } +} export const viewOperation: MigrateOperation = { - async migrate (client: MigrationClient): Promise {}, + async migrate (client: MigrationClient): Promise { + await migrateViewletPreference(client) + }, async upgrade (client: MigrationUpgradeClient): Promise {} } diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index 21cf16a468..40470e8a7a 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -58,10 +58,12 @@ 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 }, string: { Table: '' as IntlString, @@ -84,7 +86,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/core/src/hierarchy.ts b/packages/core/src/hierarchy.ts index 14f0be4f1c..0c17e6031f 100644 --- a/packages/core/src/hierarchy.ts +++ b/packages/core/src/hierarchy.ts @@ -20,6 +20,7 @@ import core from './component' import { _createMixinProxy, _mixinClass, _toDoc } from './proxy' import type { Tx, TxCreateDoc, TxMixin, TxRemoveDoc, TxUpdateDoc } from './tx' import { TxProcessor } from './tx' +import getTypeOf from './typeof' /** * @public @@ -463,11 +464,12 @@ export class Hierarchy { if (typeof obj === 'function') { return obj } - const result: any = Array.isArray(obj) ? [] : {} + const isArray = Array.isArray(obj) + const result: any = isArray ? [] : Object.assign({}, obj) for (const key in obj) { // include prototype properties const value = obj[key] - const type = {}.toString.call(value).slice(8, -1) + const type = getTypeOf(value) if (type === 'Array') { result[key] = this.clone(value) } else if (type === 'Object') { @@ -477,7 +479,9 @@ export class Hierarchy { } else if (type === 'Date') { result[key] = new Date(value.getTime()) } else { - result[key] = value + if (isArray) { + result[key] = value + } } } return result diff --git a/packages/core/src/typeof.ts b/packages/core/src/typeof.ts new file mode 100644 index 0000000000..f9af5b1d25 --- /dev/null +++ b/packages/core/src/typeof.ts @@ -0,0 +1,35 @@ +const se = typeof Symbol !== 'undefined' +const ste = se && typeof Symbol.toStringTag !== 'undefined' + +export default function getTypeOf (obj: any): string { + const typeofObj = typeof obj + if (typeofObj !== 'object') { + return typeofObj + } + if (obj === null) { + return 'null' + } + + if (Array.isArray(obj) && (!ste || !(Symbol.toStringTag in obj))) { + return 'Array' + } + + const stringTag = ste && obj[Symbol.toStringTag] + if (typeof stringTag === 'string') { + return stringTag + } + + const objPrototype = Object.getPrototypeOf(obj) + + if (objPrototype === RegExp.prototype) { + return 'RegExp' + } + if (objPrototype === Date.prototype) { + return 'Date' + } + + if (objPrototype === null) { + return 'Object' + } + return {}.toString.call(obj).slice(8, -1) +} 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. --> + + +
+ {#if outline} + + {:else} + + + + {/if} +
+ + diff --git a/packages/ui/src/components/ExpandCollapse.svelte b/packages/ui/src/components/ExpandCollapse.svelte index 1ffcd64d1f..540be85b44 100644 --- a/packages/ui/src/components/ExpandCollapse.svelte +++ b/packages/ui/src/components/ExpandCollapse.svelte @@ -18,7 +18,7 @@ import { tweened } from 'svelte/motion' export let isExpanded = false - export let duration = 200 + export let duration = 150 export let easing: (t: number) => number = quintOut const dispatch = createEventDispatcher() diff --git a/packages/ui/src/components/Expandable.svelte b/packages/ui/src/components/Expandable.svelte index f23ddf82c7..98866f779f 100644 --- a/packages/ui/src/components/Expandable.svelte +++ b/packages/ui/src/components/Expandable.svelte @@ -17,51 +17,62 @@ import ExpandCollapse from './ExpandCollapse.svelte' import Icon from './Icon.svelte' import Label from './Label.svelte' + import Chevron from './Chevron.svelte' export let icon: Asset | undefined = undefined export let label: IntlString | undefined = undefined export let expanded: boolean = false + export let bordered: boolean = false export let expandable = true + export let contentColor = false - - -
-
{ - expanded = !expanded - }} - > -
-
+
+
+ +
{ + if (expandable) expanded = !expanded + }} + > + {#if icon} - +
+ +
{/if} + + {#if label}
- - {#if label} + {#if $$slots.tools} +
+ +
+ {/if}
- -
- -
+ -
-
+ +
diff --git a/packages/ui/src/components/Label.svelte b/packages/ui/src/components/Label.svelte index 14311808c6..46df0877e0 100644 --- a/packages/ui/src/components/Label.svelte +++ b/packages/ui/src/components/Label.svelte @@ -19,11 +19,19 @@ export let label: IntlString export let params: Record = {} - $: translation = translate(label, params) + let _value: string | undefined = undefined + + $: if (label !== undefined) { + translate(label, params ?? {}).then((r) => { + _value = r + }) + } else { + _value = label + } -{#await translation} +{#if _value} + {_value} +{:else} {label} -{:then text} - {text} -{/await} +{/if} diff --git a/packages/ui/src/components/ListView.svelte b/packages/ui/src/components/ListView.svelte index 36a1ab452b..b114942bad 100644 --- a/packages/ui/src/components/ListView.svelte +++ b/packages/ui/src/components/ListView.svelte @@ -18,6 +18,7 @@ export let selection: number = 0 export let count: number + export let addClass: string | undefined = undefined const refs: HTMLElement[] = [] @@ -66,8 +67,9 @@ > {#each Array(count) as _, row} +
onRow(row)} on:focus={() => {}} diff --git a/packages/ui/src/components/TimeSince.svelte b/packages/ui/src/components/TimeSince.svelte index 875dd26a09..34fe09ff39 100644 --- a/packages/ui/src/components/TimeSince.svelte +++ b/packages/ui/src/components/TimeSince.svelte @@ -32,7 +32,7 @@ let time: string = '' - async function formatTime (now: number) { + async function formatTime (now: number, value: number) { let passed = now - value if (passed < 0) passed = 0 if (passed < HOUR) { @@ -48,7 +48,7 @@ } } - $: formatTime($ticker) + $: formatTime($ticker, value) $: tooltipValue = new Date(value).toLocaleString('default', { minute: '2-digit', diff --git a/packages/ui/src/components/icons/DownOutline.svelte b/packages/ui/src/components/icons/DownOutline.svelte index ee3b5954f7..b8dcda616e 100644 --- a/packages/ui/src/components/icons/DownOutline.svelte +++ b/packages/ui/src/components/icons/DownOutline.svelte @@ -1,6 +1,6 @@ diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 269e7f083d..13dcc14e52 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -99,6 +99,7 @@ export { default as ErrorPresenter } from './components/ErrorPresenter.svelte' export { default as Scroller } from './components/Scroller.svelte' export { default as ScrollerBar } from './components/ScrollerBar.svelte' export { default as TabList } from './components/TabList.svelte' +export { default as Chevron } from './components/Chevron.svelte' export { default as IconAdd } from './components/icons/Add.svelte' export { default as IconBack } from './components/icons/Back.svelte' diff --git a/plugins/activity-resources/src/components/TxView.svelte b/plugins/activity-resources/src/components/TxView.svelte index 9445e4b801..5eda03639a 100644 --- a/plugins/activity-resources/src/components/TxView.svelte +++ b/plugins/activity-resources/src/components/TxView.svelte @@ -32,7 +32,7 @@ TimeSince } from '@hcengineering/ui' import type { AttributeModel } from '@hcengineering/view' - import { getActions } from '@hcengineering/view-resources' + import { getActions, ObjectPresenter } from '@hcengineering/view-resources' import { ActivityKey, DisplayTx } from '../activity' import activity from '../plugin' import TxViewTx from './TxViewTx.svelte' @@ -215,7 +215,11 @@
1}> {#each value.added as cvalue} - + {#if value.isObjectAdded} + + {:else} + + {/if} {/each}
@@ -234,11 +238,15 @@
1}> {#each value.removed as cvalue} - + {#if value.isObjectRemoved} + + {:else} + + {/if} {/each}
- {:else if value.set === null || value.set === undefined} + {:else if value.set === null || value.set === undefined || value.set === ''} {:else} @@ -251,11 +259,19 @@ {/if} {#if isMessageType(m.attribute)}
- + {#if value.isObjectSet} + + {:else} + + {/if}
{:else}
- + {#if value.isObjectSet} + + {:else} + + {/if}
{/if} {/if} @@ -264,7 +280,7 @@ {:else if viewlet === undefined && model.length > 0 && tx.mixinTx} {#each model as m} {#await getValue(client, m, tx) then value} - {#if value.set === null} + {#if value.set === null || value.set === ''} @@ -276,11 +292,19 @@
{#if isMessageType(m.attribute)}
- + {#if value.isObjectSet} + + {:else} + + {/if}
{:else}
- + {#if value.isObjectSet} + + {:else} + + {/if}
{/if} {/if} diff --git a/plugins/activity-resources/src/utils.ts b/plugins/activity-resources/src/utils.ts index 03ebebf847..ba25fa7e5b 100644 --- a/plugins/activity-resources/src/utils.ts +++ b/plugins/activity-resources/src/utils.ts @@ -224,10 +224,14 @@ async function buildRemovedDoc ( return doc } -async function getAllRealValues (client: TxOperations, values: any[], _class: Ref>): Promise { - if (values.length === 0) return [] +async function getAllRealValues ( + client: TxOperations, + values: any[], + _class: Ref> +): Promise<[any[], boolean]> { + if (values.length === 0) return [[], false] if (values.some((value) => typeof value !== 'string')) { - return values + return [values, false] } if ( _class === core.class.TypeString || @@ -235,12 +239,12 @@ async function getAllRealValues (client: TxOperations, values: any[], _class: Re _class === core.class.TypeNumber || _class === core.class.TypeDate ) { - return values + return [values, false] } const realValues = await client.findAll(_class, { _id: { $in: values } }) const realValuesIds = realValues.map(({ _id }) => _id) - return [ + const res = [ ...realValues, ...(await Promise.all( values @@ -248,6 +252,7 @@ async function getAllRealValues (client: TxOperations, values: any[], _class: Re .map(async (value) => await buildRemovedDoc(client, value, _class)) )) ].filter((v) => v != null) + return [res, true] } function combineAttributes (attributes: any[], key: string, operator: string, arrayKey: string): any[] { @@ -260,15 +265,31 @@ function combineAttributes (attributes: any[], key: string, operator: string, ar ).filter((v) => v != null) } -export async function getValue (client: TxOperations, m: AttributeModel, tx: DisplayTx): Promise { +interface TxAttributeValue { + set: any + isObjectSet: boolean + added: any[] + isObjectAdded: boolean + removed: any[] + isObjectRemoved: boolean +} + +export async function getValue (client: TxOperations, m: AttributeModel, tx: DisplayTx): Promise { const utxs = getModifiedAttributes(tx) - const value = { + const added = await getAllRealValues(client, combineAttributes(utxs, m.key, '$push', '$each'), m._class) + const removed = await getAllRealValues(client, combineAttributes(utxs, m.key, '$pull', '$in'), m._class) + const value: TxAttributeValue = { set: utxs[0][m.key], - added: await getAllRealValues(client, combineAttributes(utxs, m.key, '$push', '$each'), m._class), - removed: await getAllRealValues(client, combineAttributes(utxs, m.key, '$pull', '$in'), m._class) + isObjectSet: false, + added: added[0], + isObjectAdded: added[1], + removed: removed[0], + isObjectRemoved: removed[1] } if (value.set !== undefined) { - ;[value.set] = await getAllRealValues(client, [value.set], m._class) + const res = await getAllRealValues(client, [value.set], m._class) + value.set = res[0][0] + value.isObjectSet = res[1] } return value } diff --git a/plugins/attachment-resources/src/plugin.ts b/plugins/attachment-resources/src/plugin.ts index 1ec3d54e1b..6cf916e30b 100644 --- a/plugins/attachment-resources/src/plugin.ts +++ b/plugins/attachment-resources/src/plugin.ts @@ -23,7 +23,6 @@ export default mergeIds(attachmentId, attachment, { string: { NoAttachments: '' as IntlString, UploadDropFilesHere: '' as IntlString, - Attachments: '' as IntlString, Photos: '' as IntlString, FileBrowser: '' as IntlString, FileBrowserFileCounter: '' as IntlString, diff --git a/plugins/attachment/src/index.ts b/plugins/attachment/src/index.ts index 7386a9c96e..e93d94951b 100644 --- a/plugins/attachment/src/index.ts +++ b/plugins/attachment/src/index.ts @@ -86,6 +86,7 @@ export default plugin(attachmentId, { FileBrowserTypeFilterAudio: '' as IntlString, FileBrowserTypeFilterVideos: '' as IntlString, FileBrowserTypeFilterPDFs: '' as IntlString, - DeleteFile: '' as IntlString + DeleteFile: '' as IntlString, + Attachments: '' as IntlString } }) diff --git a/plugins/bitrix-resources/src/components/EntityMapping.svelte b/plugins/bitrix-resources/src/components/EntityMapping.svelte index 77257794d7..2d1824c7be 100644 --- a/plugins/bitrix-resources/src/components/EntityMapping.svelte +++ b/plugins/bitrix-resources/src/components/EntityMapping.svelte @@ -75,9 +75,7 @@
-
-
+
+
+
+
+ {state}
+
diff --git a/plugins/board-resources/src/components/KanbanView.svelte b/plugins/board-resources/src/components/KanbanView.svelte index fd796fd35b..5a76ffa3f9 100644 --- a/plugins/board-resources/src/components/KanbanView.svelte +++ b/plugins/board-resources/src/components/KanbanView.svelte @@ -15,7 +15,7 @@ --> { 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/calendar-resources/src/components/Events.svelte b/plugins/calendar-resources/src/components/Events.svelte index 2eefc81284..f41e0b76d7 100644 --- a/plugins/calendar-resources/src/components/Events.svelte +++ b/plugins/calendar-resources/src/components/Events.svelte @@ -30,7 +30,7 @@ TabList } from '@hcengineering/ui' import view, { Viewlet, ViewletPreference } from '@hcengineering/view' - import { FilterButton, ViewletSettingButton } from '@hcengineering/view-resources' + import { FilterButton, getViewOptions, ViewletSettingButton } from '@hcengineering/view-resources' import calendar from '../plugin' import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' @@ -101,6 +101,8 @@ }) $: twoRows = $deviceInfo.twoRows + + $: viewOptions = getViewOptions(selectedViewlet)
@@ -133,7 +135,7 @@ }} /> {/if} - +
@@ -148,6 +150,7 @@ space, options: selectedViewlet.options, config: preference?.config ?? selectedViewlet.config, + viewOptions, viewlet: selectedViewlet, query: resultQuery, search, diff --git a/plugins/client-resources/src/index.ts b/plugins/client-resources/src/index.ts index 3723df5148..204540deef 100644 --- a/plugins/client-resources/src/index.ts +++ b/plugins/client-resources/src/index.ts @@ -41,9 +41,9 @@ export default async () => { ): Promise => { if (client instanceof Promise) { client = await client - await client.close() } if (token !== _token && client !== undefined) { + await client.close() client = undefined } if (client === undefined) { 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/Contacts.svelte b/plugins/contact-resources/src/components/Contacts.svelte index ca9e74cc79..3e40664609 100644 --- a/plugins/contact-resources/src/components/Contacts.svelte +++ b/plugins/contact-resources/src/components/Contacts.svelte @@ -18,7 +18,13 @@ import { createQuery, getClient } from '@hcengineering/presentation' import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@hcengineering/ui' import view, { Viewlet, ViewletPreference } from '@hcengineering/view' - import { ActionContext, FilterButton, TableBrowser, ViewletSettingButton } from '@hcengineering/view-resources' + import { + ActionContext, + FilterButton, + getViewOptions, + TableBrowser, + ViewletSettingButton + } from '@hcengineering/view-resources' import contact from '../plugin' import CreateContact from './CreateContact.svelte' import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' @@ -64,6 +70,8 @@ } $: twoRows = $deviceInfo.twoRows + + $: viewOptions = getViewOptions(viewlet) showCreateDialog(ev)} /> - +
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/Members.svelte b/plugins/contact-resources/src/components/Members.svelte index 5166687b7e..d2666d3f7a 100644 --- a/plugins/contact-resources/src/components/Members.svelte +++ b/plugins/contact-resources/src/components/Members.svelte @@ -18,7 +18,7 @@ import { createQuery, getClient, UsersPopup, IconMembersOutline } from '@hcengineering/presentation' import { Button, IconAdd, Label, showPopup, Icon } from '@hcengineering/ui' import view, { Viewlet, ViewletPreference } from '@hcengineering/view' - import { Table, ViewletSettingButton } from '@hcengineering/view-resources' + import { getViewOptions, Table, ViewletSettingButton } from '@hcengineering/view-resources' import contact from '../plugin' export let objectId: Ref @@ -90,6 +90,7 @@ } }) } + $: viewOptions = getViewOptions(descr)
@@ -101,7 +102,7 @@
@@ -118,6 +119,7 @@ + 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/document-resources/src/components/Documents.svelte b/plugins/document-resources/src/components/Documents.svelte index 7e73ef61a2..ee1b9d176b 100644 --- a/plugins/document-resources/src/components/Documents.svelte +++ b/plugins/document-resources/src/components/Documents.svelte @@ -20,7 +20,13 @@ import { createQuery, getClient } from '@hcengineering/presentation' import { deviceOptionsStore as deviceInfo, Icon, Label, Loading, SearchEdit } from '@hcengineering/ui' import view, { Viewlet, ViewletPreference } from '@hcengineering/view' - import { ActionContext, FilterButton, TableBrowser, ViewletSettingButton } from '@hcengineering/view-resources' + import { + ActionContext, + FilterButton, + getViewOptions, + TableBrowser, + ViewletSettingButton + } from '@hcengineering/view-resources' import document from '../plugin' export let query: DocumentQuery = {} @@ -63,6 +69,8 @@ let twoRows: boolean $: twoRows = $deviceInfo.docWidth <= 680 + + $: viewOptions = getViewOptions(viewlet)
- +
diff --git a/plugins/hr-resources/src/components/DepartmentStaff.svelte b/plugins/hr-resources/src/components/DepartmentStaff.svelte index a1744091e9..181e55263a 100644 --- a/plugins/hr-resources/src/components/DepartmentStaff.svelte +++ b/plugins/hr-resources/src/components/DepartmentStaff.svelte @@ -19,7 +19,7 @@ import { createQuery, getClient, UsersPopup } from '@hcengineering/presentation' import { Button, eventToHTMLElement, IconAdd, Label, Scroller, showPopup } from '@hcengineering/ui' import view, { Viewlet, ViewletPreference } from '@hcengineering/view' - import { Table, ViewletSettingButton } from '@hcengineering/view-resources' + import { getViewOptions, Table, ViewletSettingButton } from '@hcengineering/view-resources' import hr from '../plugin' import { addMember } from '../utils' @@ -91,6 +91,8 @@ } }) } + + $: viewOptions = getViewOptions(descr)
@@ -99,7 +101,7 @@
diff --git a/plugins/hr-resources/src/components/schedule/MonthTableView.svelte b/plugins/hr-resources/src/components/schedule/MonthTableView.svelte index fd171687a8..653371ac28 100644 --- a/plugins/hr-resources/src/components/schedule/MonthTableView.svelte +++ b/plugins/hr-resources/src/components/schedule/MonthTableView.svelte @@ -20,7 +20,7 @@ import { createQuery, getClient } from '@hcengineering/presentation' import { Button, Label, Loading, Scroller, tableSP } from '@hcengineering/ui' import view, { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view' - import { Table, ViewletSettingButton } from '@hcengineering/view-resources' + import { getViewOptions, Table, ViewletSettingButton } from '@hcengineering/view-resources' import hr from '../../plugin' import { EmployeeReports, @@ -215,6 +215,8 @@ } return result } + + $: viewOptions = getViewOptions(descr) {#if departmentStaff.length} @@ -226,7 +228,7 @@ {:else}
- +