diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 0d01744fff..d5d0d1eb47 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -213,7 +213,8 @@ export function createModel (builder: Builder): void { ['assigned', view.string.Assigned, {}], ['created', view.string.Created, {}], ['subscribed', view.string.Subscribed, {}] - ] + ], + descriptors: [view.viewlet.List, view.viewlet.Table, task.viewlet.Kanban] } }, { diff --git a/plugins/task-resources/src/components/AssignedTasks.svelte b/plugins/task-resources/src/components/AssignedTasks.svelte index 55baae4ca0..755767e184 100644 --- a/plugins/task-resources/src/components/AssignedTasks.svelte +++ b/plugins/task-resources/src/components/AssignedTasks.svelte @@ -14,11 +14,10 @@ --> <script lang="ts"> import { PersonAccount } from '@hcengineering/contact' - import { Class, Doc, DocumentQuery, getCurrentAccount, Ref, Status } from '@hcengineering/core' + import { Class, Doc, DocumentQuery, getCurrentAccount, Ref, Status, WithLookup } from '@hcengineering/core' import { IntlString, Asset } from '@hcengineering/platform' import { createQuery, getClient } from '@hcengineering/presentation' import tags, { TagCategory, TagElement } from '@hcengineering/tags' - import { selectedTagElements } from '@hcengineering/tags-resources' import { Task } from '@hcengineering/task' import { Component, @@ -30,12 +29,11 @@ SearchInput, Header } from '@hcengineering/ui' - import { Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view' + import { Viewlet, ViewletDescriptor, ViewletPreference, ViewOptions } from '@hcengineering/view' import { FilterBar, FilterButton, statusStore, - TableBrowser, ViewletSelector, ViewletSettingButton } from '@hcengineering/view-resources' @@ -46,6 +44,7 @@ export let labelTasks = task.string.Tasks export let icon: Asset export let config: [string, IntlString, object][] = [] + export let descriptors: Ref<ViewletDescriptor>[] | undefined = undefined let search = '' const dispatch = createEventDispatcher() @@ -69,43 +68,22 @@ const client = getClient() - let category: Ref<TagCategory> | undefined = undefined + const category: Ref<TagCategory> | undefined = undefined let loading = true let preference: ViewletPreference | undefined - let documentIds: Ref<Task>[] = [] - function updateResultQuery ( - search: string, - documentIds: Ref<Task>[], - doneStates: Status[], - mode: string | undefined - ): void { + function updateResultQuery (search: string, doneStates: Status[], mode: string | undefined): void { if (mode === 'assigned') { resultQuery.status = { $nin: doneStates.map((it) => it._id) } } - if (documentIds.length > 0) { - resultQuery._id = { $in: documentIds } - } } $: doneStates = $statusStore.array.filter( (it) => it.category === task.statusCategory.Lost || it.category === task.statusCategory.Won ) - // Find all tags for object class with matched elements - const query = createQuery() - - $: query.query(tags.class.TagReference, { tag: { $in: $selectedTagElements } }, (result) => { - documentIds = Array.from( - new Set<Ref<Task>>( - result - .filter((it) => client.getHierarchy().isDerived(it.attachedToClass, _class)) - .map((it) => it.attachedTo as Ref<Task>) - ).values() - ) - }) const subscribedQuery = createQuery() - function getSubscribed () { + function getSubscribed (): void { subscribedQuery.query( _class, { 'notification:mixin:Collaborators.collaborators': getCurrentAccount()._id }, @@ -132,31 +110,31 @@ } } - $: updateResultQuery(search, documentIds, doneStates, mode) + $: updateResultQuery(search, doneStates, mode) - let viewlet: Viewlet | undefined + let viewlet: WithLookup<Viewlet> | undefined let viewOptions: ViewOptions | undefined - function updateCategory (detail: { category: Ref<TagCategory> | null, elements: TagElement[] }) { - category = detail.category ?? undefined - selectedTagElements.set(Array.from(detail.elements ?? []).map((it) => it._id)) - } - const handleChange = (evt: any) => { - updateCategory(evt.detail) - } + $: viewOptionsConfig = + mode === 'assigned' + ? viewlet?.viewOptions?.other + : (viewlet?.viewOptions?.other ?? []).filter((it) => it.actionTarget !== 'query') </script> <Header adaptive={'freezeActions'} hideActions={modeSelectorProps === undefined}> <svelte:fragment slot="beforeTitle"> <ViewletSelector - hidden bind:viewlet bind:preference bind:loading - viewletQuery={{ attachTo: _class, descriptor: task.viewlet.StatusTable }} + viewletQuery={{ + attachTo: _class, + variant: { $exists: false }, + ...(descriptors !== undefined ? { descriptor: { $in: descriptors } } : {}) + }} /> - <ViewletSettingButton bind:viewOptions bind:viewlet /> + <ViewletSettingButton bind:viewOptions bind:viewlet {viewOptionsConfig} /> </svelte:fragment> <Breadcrumb {icon} label={labelTasks} size={'large'} isCurrent /> @@ -166,7 +144,7 @@ bind:value={search} collapsed on:change={() => { - updateResultQuery(search, documentIds, doneStates, mode) + updateResultQuery(search, doneStates, mode) }} /> <FilterButton {_class} adaptive={doubleRow} /> @@ -179,18 +157,19 @@ </Header> <FilterBar {_class} query={searchQuery} space={undefined} {viewOptions} on:change={(e) => (resultQuery = e.detail)} /> -<Component is={tags.component.TagsCategoryBar} props={{ targetClass: _class, category }} on:change={handleChange} /> - -{#if viewlet} - {#if loading} - <Loading /> - {:else} - <TableBrowser - {_class} - config={preference?.config ?? viewlet.config} - options={viewlet.options} - query={resultQuery} - showNotification - /> - {/if} +{#if loading || !viewlet || !viewlet?.$lookup?.descriptor?.component} + <Loading /> +{:else} + <Component + is={viewlet.$lookup.descriptor.component} + props={{ + _class, + options: viewlet.options, + config: preference?.config ?? viewlet.config, + viewlet, + viewOptions, + viewOptionsConfig, + query: resultQuery + }} + /> {/if} diff --git a/plugins/task-resources/src/components/kanban/KanbanView.svelte b/plugins/task-resources/src/components/kanban/KanbanView.svelte index c3b9054f34..f9868b5bac 100644 --- a/plugins/task-resources/src/components/kanban/KanbanView.svelte +++ b/plugins/task-resources/src/components/kanban/KanbanView.svelte @@ -56,7 +56,7 @@ export let space: Ref<Project> | undefined = undefined export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined export let query: DocumentQuery<Task> = {} - export let viewOptionsConfig: ViewOptionModel[] | undefined + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let viewOptions: ViewOptions export let viewlet: Viewlet export let config: (string | BuildModelKey)[] diff --git a/plugins/tracker-resources/src/components/issues/KanbanView.svelte b/plugins/tracker-resources/src/components/issues/KanbanView.svelte index 15826b4aa8..8091bc9d3f 100644 --- a/plugins/tracker-resources/src/components/issues/KanbanView.svelte +++ b/plugins/tracker-resources/src/components/issues/KanbanView.svelte @@ -85,7 +85,7 @@ export let space: Ref<Project> | undefined = undefined export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined export let query: DocumentQuery<Issue> = {} - export let viewOptionsConfig: ViewOptionModel[] | undefined + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let viewOptions: ViewOptions export let viewlet: Viewlet export let config: (string | BuildModelKey)[] diff --git a/plugins/view-resources/src/components/TableBrowser.svelte b/plugins/view-resources/src/components/TableBrowser.svelte index 2189876f7b..c7870cc746 100644 --- a/plugins/view-resources/src/components/TableBrowser.svelte +++ b/plugins/view-resources/src/components/TableBrowser.svelte @@ -16,7 +16,7 @@ import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@hcengineering/core' import { ActionContext } from '@hcengineering/presentation' import { FadeOptions, Scroller, tableSP } from '@hcengineering/ui' - import { BuildModelKey, ViewOptions, Viewlet } from '@hcengineering/view' + import { BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view' import { onMount } from 'svelte' import { focusStore, ListSelectionProvider, SelectDirection } from '../selection' import { LoadingProps } from '../utils' @@ -35,6 +35,7 @@ export let fade: FadeOptions = tableSP export let prefferedSorting: string = 'modifiedOn' export let viewOptions: ViewOptions | undefined = undefined + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let viewlet: Viewlet | undefined = undefined export let readonly = false @@ -83,7 +84,7 @@ {prefferedSorting} {tableId} {viewOptions} - viewOptionsConfig={viewlet?.viewOptions?.other} + viewOptionsConfig={viewOptionsConfig ?? viewlet?.viewOptions?.other} selection={listProvider.current($focusStore)} {readonly} on:row-focus={(evt) => { diff --git a/plugins/view-resources/src/components/ViewOptionsButton.svelte b/plugins/view-resources/src/components/ViewOptionsButton.svelte index 781e27f369..b80dbafa82 100644 --- a/plugins/view-resources/src/components/ViewOptionsButton.svelte +++ b/plugins/view-resources/src/components/ViewOptionsButton.svelte @@ -15,7 +15,7 @@ <script lang="ts"> import { getClient } from '@hcengineering/presentation' import { ButtonIcon, showPopup, closeTooltip, IconOptions } from '@hcengineering/ui' - import { ViewOptions, ViewOptionsModel, Viewlet } from '@hcengineering/view' + import { ViewOptionModel, ViewOptions, ViewOptionsModel, Viewlet } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' import view from '../plugin' import { focusStore } from '../selection' @@ -27,6 +27,7 @@ export let kind: 'primary' | 'secondary' | 'tertiary' | 'negative' = 'secondary' export let viewOptions: ViewOptions export let disabled: boolean = false + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined const dispatch = createEventDispatcher() const client = getClient() @@ -89,6 +90,9 @@ mergedModel.orderBy = mergedModel.orderBy.filter((it, idx, arr) => arr.findIndex((q) => it[0] === q[0]) === idx) mergedModel.other = mergedModel.other.filter((it, idx, arr) => arr.findIndex((q) => q.key === it.key) === idx) + if (viewOptionsConfig !== undefined) { + mergedModel.other = viewOptionsConfig + } showPopup( ViewOptionsEditor, { viewlet, config: mergedModel, viewOptions: getClient().getHierarchy().clone(viewOptions) }, diff --git a/plugins/view-resources/src/components/ViewletSettingButton.svelte b/plugins/view-resources/src/components/ViewletSettingButton.svelte index 2bd34d1150..85c4e2baf6 100644 --- a/plugins/view-resources/src/components/ViewletSettingButton.svelte +++ b/plugins/view-resources/src/components/ViewletSettingButton.svelte @@ -14,9 +14,9 @@ --> <script lang="ts"> import { ButtonIcon, showPopup, closeTooltip } from '@hcengineering/ui' - import { ViewOptions, Viewlet } from '@hcengineering/view' + import { ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view' import view from '../plugin' - import { getViewOptions, viewOptionStore } from '../viewOptions' + import { getViewOptions, viewOptionStore, defaultOptions } from '../viewOptions' import ViewOptionsButton from './ViewOptionsButton.svelte' import ViewletSetting from './ViewletSetting.svelte' import { restrictionStore } from '../utils' @@ -25,6 +25,7 @@ export let viewOptions: ViewOptions | undefined = undefined export let viewlet: Viewlet | undefined = undefined export let disabled: boolean = false + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined let btn: HTMLButtonElement let pressed: boolean = false @@ -37,14 +38,14 @@ }) } - $: viewOptions = getViewOptions(viewlet, $viewOptionStore) + $: viewOptions = getViewOptions(viewlet, $viewOptionStore, defaultOptions) $: disabled = $restrictionStore.readonly </script> {#if viewlet} {#if viewOptions} - <ViewOptionsButton {viewlet} {kind} {viewOptions} /> + <ViewOptionsButton {viewlet} {kind} {viewOptions} {viewOptionsConfig} /> {/if} <ButtonIcon icon={view.icon.Configure} diff --git a/plugins/view-resources/src/components/list/ListCategories.svelte b/plugins/view-resources/src/components/list/ListCategories.svelte index 570407038d..ab7af4db69 100644 --- a/plugins/view-resources/src/components/list/ListCategories.svelte +++ b/plugins/view-resources/src/components/list/ListCategories.svelte @@ -72,7 +72,7 @@ export let level: number export let initIndex = 0 export let newObjectProps: (doc: Doc | undefined) => Record<string, any> | undefined - export let viewOptionsConfig: ViewOptionModel[] | undefined + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let dragItem: { doc?: Doc revert?: () => void diff --git a/plugins/view-resources/src/components/list/ListCategory.svelte b/plugins/view-resources/src/components/list/ListCategory.svelte index 3c616e6dce..a44a8da2f4 100644 --- a/plugins/view-resources/src/components/list/ListCategory.svelte +++ b/plugins/view-resources/src/components/list/ListCategory.svelte @@ -67,7 +67,7 @@ export let configurationsVersion: number export let viewOptions: ViewOptions export let newObjectProps: (doc: Doc | undefined) => Record<string, any> | undefined - export let viewOptionsConfig: ViewOptionModel[] | undefined + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let dragItem: { doc?: Doc revert?: () => void diff --git a/plugins/view-resources/src/components/list/ListView.svelte b/plugins/view-resources/src/components/list/ListView.svelte index e1495cc494..ebd437c797 100644 --- a/plugins/view-resources/src/components/list/ListView.svelte +++ b/plugins/view-resources/src/components/list/ListView.svelte @@ -17,7 +17,7 @@ import { IntlString } from '@hcengineering/platform' import { ActionContext } from '@hcengineering/presentation' import { AnyComponent, Scroller, resizeObserver } from '@hcengineering/ui' - import { BuildModelKey, ViewOptions, Viewlet } from '@hcengineering/view' + import { BuildModelKey, ViewOptionModel, ViewOptions, Viewlet } from '@hcengineering/view' import { onMount } from 'svelte' import { ListSelectionProvider, SelectDirection, focusStore } from '../..' @@ -37,6 +37,7 @@ export let createItemLabel: IntlString | undefined export let createItemEvent: string | undefined export let viewOptions: ViewOptions + export let viewOptionsConfig: ViewOptionModel[] | undefined = undefined export let props: Record<string, any> = {} let list: List @@ -94,7 +95,7 @@ {props} {listProvider} compactMode={listWidth <= 800} - viewOptionsConfig={viewlet.viewOptions?.other} + viewOptionsConfig={viewOptionsConfig ?? viewlet.viewOptions?.other} selectedObjectIds={$selection ?? []} selection={listProvider.current($focusStore)} on:row-focus={(event) => { diff --git a/plugins/view-resources/src/viewOptions.ts b/plugins/view-resources/src/viewOptions.ts index 66855b0530..38eba41617 100644 --- a/plugins/view-resources/src/viewOptions.ts +++ b/plugins/view-resources/src/viewOptions.ts @@ -18,7 +18,7 @@ import { groupByCategory } from './utils' export const noCategory = '#no_category' -export const defaulOptions: ViewOptions = { +export const defaultOptions: ViewOptions = { groupBy: [noCategory], orderBy: ['modifiedBy', SortingOrder.Descending] } @@ -75,8 +75,8 @@ function _getViewOptions (viewlet: Viewlet, viewOptionStore: Map<string, ViewOpt function getDefaults (viewOptions: ViewOptionsModel): ViewOptions { const res: ViewOptions = { - groupBy: [viewOptions.groupBy[0] ?? defaulOptions.groupBy[0]], - orderBy: viewOptions.orderBy?.[0] ?? defaulOptions.orderBy + groupBy: [viewOptions.groupBy[0] ?? defaultOptions.groupBy[0]], + orderBy: viewOptions.orderBy?.[0] ?? defaultOptions.orderBy } for (const opt of viewOptions.other) { res[opt.key] = opt.defaultValue @@ -87,7 +87,7 @@ function getDefaults (viewOptions: ViewOptionsModel): ViewOptions { export function getViewOptions ( viewlet: Viewlet | undefined, viewOptionStore: Map<string, ViewOptions>, - defaults = defaulOptions + defaults = defaultOptions ): ViewOptions { if (viewlet === undefined) { return { ...defaults } diff --git a/pods/server/package.json b/pods/server/package.json index e09a5a206d..a3dc2127fe 100644 --- a/pods/server/package.json +++ b/pods/server/package.json @@ -9,6 +9,7 @@ "license": "EPL-2.0", "scripts": { "start": "rush bundle --to @hcengineering/pod-server && cross-env NODE_ENV=production MODEL_VERSION=$(node ../../common/scripts/show_version.js) ACCOUNTS_URL=http://localhost:3000 REKONI_URL=http://localhost:4004 MONGO_URL=mongodb://localhost:27017 DB_URL=mongodb://localhost:27017 FRONT_URL=http://localhost:8087 UPLOAD_URL=/upload MINIO_ENDPOINT=localhost MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin METRICS_CONSOLE=true SERVER_SECRET=secret OPERATION_PROFILING=false MODEL_JSON=../../models/all/bundle/model.json STATS_URL=http://host.docker.internal:4900 node --inspect bundle/bundle.js", + "start-cr": "rush bundle --to @hcengineering/pod-server && cross-env NODE_ENV=production MODEL_VERSION=$(node ../../common/scripts/show_version.js) ACCOUNTS_URL=http://localhost:3000 REKONI_URL=http://localhost:4004 DB_URL=postgresql://root@host.docker.internal:26257/defaultdb?sslmode=disable FRONT_URL=http://localhost:8087 UPLOAD_URL=/upload MINIO_ENDPOINT=localhost MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin METRICS_CONSOLE=true SERVER_SECRET=secret OPERATION_PROFILING=false MODEL_JSON=../../models/all/bundle/model.json STATS_URL=http://host.docker.internal:4900 FULLTEXT_URL=http://host.docker.internal:4702 SERVER_PORT=3332 node --inspect bundle/bundle.js", "start-flame": "rush bundle --to @hcengineering/pod-server && cross-env NODE_ENV=production MODEL_VERSION=$(node ../../common/scripts/show_version.js) ACCOUNTS_URL=http://localhost:3000 REKONI_URL=http://localhost:4004 MONGO_URL=mongodb://localhost:27017 FRONT_URL=http://localhost:8087 UPLOAD_URL=/upload MINIO_ENDPOINT=localhost MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin METRICS_CONSOLE=true SERVER_SECRET=secret MODEL_JSON=../../models/all/bundle/model.json clinic flame --dest ./out -- node --nolazy -r ts-node/register --enable-source-maps src/__start.ts", "start-raw": "ts-node src/__start.ts", "build": "compile",