diff --git a/models/document/src/index.ts b/models/document/src/index.ts index 1e17d90d36f..29d0e74241d 100644 --- a/models/document/src/index.ts +++ b/models/document/src/index.ts @@ -217,8 +217,8 @@ function defineTeamspace (builder: Builder): void { key: 'hideArchived', type: 'toggle', defaultValue: true, - actionTarget: 'query', - action: document.function.HideArchivedTeamspaces, + actionTarget: 'options', + action: view.function.HideArchived, label: view.string.HideArchived } ] diff --git a/models/document/src/plugin.ts b/models/document/src/plugin.ts index 8f22ca83843..e83a4ff7c74 100644 --- a/models/document/src/plugin.ts +++ b/models/document/src/plugin.ts @@ -21,7 +21,7 @@ import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineer import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform' import { type TagCategory } from '@hcengineering/tags' import { type AnyComponent } from '@hcengineering/ui' -import type { Viewlet, Action, ActionCategory, ViewAction, ViewQueryAction } from '@hcengineering/view' +import type { Action, ActionCategory, ViewAction, Viewlet } from '@hcengineering/view' export default mergeIds(documentId, document, { component: { @@ -52,8 +52,7 @@ export default mergeIds(documentId, document, { }, function: { CanLockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, - CanUnlockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise>, - HideArchivedTeamspaces: '' as ViewQueryAction + CanUnlockDocument: '' as Resource<(doc?: Doc | Doc[]) => Promise> }, viewlet: { TeamspaceTable: '' as Ref diff --git a/models/drive/src/index.ts b/models/drive/src/index.ts index 6b4b762f384..4e2f5cbda39 100644 --- a/models/drive/src/index.ts +++ b/models/drive/src/index.ts @@ -277,8 +277,8 @@ function defineDrive (builder: Builder): void { key: 'hideArchived', type: 'toggle', defaultValue: true, - actionTarget: 'query', - action: drive.function.HideArchivedDrives, + actionTarget: 'options', + action: view.function.HideArchived, label: view.string.HideArchived } ] diff --git a/models/drive/src/plugin.ts b/models/drive/src/plugin.ts index 032df816a8a..533cb025d5e 100644 --- a/models/drive/src/plugin.ts +++ b/models/drive/src/plugin.ts @@ -25,7 +25,6 @@ import { type ActionCategory, type ViewAction, type ViewActionAvailabilityFunction, - type ViewQueryAction, type Viewlet, type ViewletDescriptor } from '@hcengineering/view' @@ -55,8 +54,7 @@ export default mergeIds(driveId, drive, { FolderLinkProvider: '' as Resource<(doc: Doc, props: Record) => Promise>, FileLinkProvider: '' as Resource<(doc: Doc, props: Record) => Promise>, CanRenameFile: '' as Resource, - CanRenameFolder: '' as Resource, - HideArchivedDrives: '' as ViewQueryAction + CanRenameFolder: '' as Resource }, completion: { FileQuery: '' as Resource, diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index d5d0d1eb47b..5804990126c 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -332,7 +332,9 @@ export function createModel (builder: Builder): void { key: 'hideArchived', type: 'toggle', defaultValue: true, - label: recruit.string.HideArchivedVacancies + actionTarget: 'options', + action: view.function.HideArchived, + label: view.string.HideArchived } builder.createDoc( @@ -452,8 +454,8 @@ export function createModel (builder: Builder): void { key: 'hideArchivedVacancies', type: 'toggle', defaultValue: true, - actionTarget: 'query', - action: recruit.function.HideArchivedVacancies, + actionTarget: 'options', + action: view.function.HideArchived, label: recruit.string.HideApplicantsFromArchivedVacancies } @@ -524,8 +526,7 @@ export function createModel (builder: Builder): void { } }, baseQuery: { - isDone: false, - '$lookup.space.archived': false + isDone: false } }, recruit.viewlet.TableApplicantMatch @@ -777,9 +778,6 @@ export function createModel (builder: Builder): void { strict: true, hiddenKeys: ['name', 'space', 'modifiedOn'] }, - baseQuery: { - '$lookup.space.archived': false - }, viewOptions: { groupBy: ['company', 'dueTo', 'createdBy'], orderBy: [ diff --git a/models/recruit/src/plugin.ts b/models/recruit/src/plugin.ts index 59af01b4aeb..86bfa59d639 100644 --- a/models/recruit/src/plugin.ts +++ b/models/recruit/src/plugin.ts @@ -13,13 +13,15 @@ // limitations under the License. // -import type { Status, Client, Doc, Ref } from '@hcengineering/core' +import { type DocUpdateMessageViewlet } from '@hcengineering/activity' +import { type ChatMessageViewlet } from '@hcengineering/chunter' +import type { Client, Doc, Ref, Status } from '@hcengineering/core' import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' -import type { IntlString, Resource, Status as OperationStatus } from '@hcengineering/platform' +import type { IntlString, Status as OperationStatus, Resource } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import { recruitId } from '@hcengineering/recruit' import recruit from '@hcengineering/recruit-resources/src/plugin' -import { type TaskTypeDescriptor, type ProjectType } from '@hcengineering/task' +import { type ProjectType, type TaskTypeDescriptor } from '@hcengineering/task' import type { AnyComponent, Location } from '@hcengineering/ui/src/types' import type { Action, @@ -29,8 +31,6 @@ import type { ViewQueryAction, Viewlet } from '@hcengineering/view' -import { type DocUpdateMessageViewlet } from '@hcengineering/activity' -import { type ChatMessageViewlet } from '@hcengineering/chunter' export default mergeIds(recruitId, recruit, { action: { @@ -57,7 +57,6 @@ export default mergeIds(recruitId, recruit, { GetObjectLink: '' as Resource<(doc: Doc, props: Record) => Promise>, GetTalentId: '' as Resource<(doc: Doc, props: Record) => Promise>, HideDoneState: '' as ViewQueryAction, - HideArchivedVacancies: '' as ViewQueryAction, ApplicantHasEmail: '' as Resource, ParseLinkId: '' as Resource<(id: string) => Promise | undefined>> }, diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts index ee25b631970..80bccfed6b5 100644 --- a/models/tracker/src/viewlets.ts +++ b/models/tracker/src/viewlets.ts @@ -545,7 +545,10 @@ export function defineViewlets (builder: Builder): void { presenter: tracker.component.ModificationDatePresenter, displayProps: { fixed: 'right', dividerBefore: true } } - ] + ], + options: { + showArchived: true + } }, tracker.viewlet.ProjectList ) diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index ef992371203..e70704a6681 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -16,7 +16,13 @@ import { type Blob, type Doc, type Ref } from '@hcengineering/core' import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui/src/types' -import { type FilterFunction, type ViewAction, type ViewCategoryAction, viewId } from '@hcengineering/view' +import { + type FilterFunction, + type ViewAction, + type ViewCategoryAction, + viewId, + type ViewOptionsAction +} from '@hcengineering/view' import { type BlobMetadata, type FileOrBlob, type FilePreviewExtension } from '@hcengineering/presentation/src/types' import { type PresentationMiddlewareFactory } from '@hcengineering/presentation/src/pipeline' import view from '@hcengineering/view-resources/src/plugin' @@ -135,6 +141,7 @@ export default mergeIds(viewId, view, { FilterDateNotSpecified: '' as FilterFunction, FilterDateCustom: '' as FilterFunction, ShowEmptyGroups: '' as ViewCategoryAction, + HideArchived: '' as ViewOptionsAction, CanDeleteObject: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanEditSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise>, CanArchiveSpace: '' as Resource<(doc?: Doc | Doc[]) => Promise>, diff --git a/packages/core/src/storage.ts b/packages/core/src/storage.ts index aca92d3a258..ef9f1ef41ec 100644 --- a/packages/core/src/storage.ts +++ b/packages/core/src/storage.ts @@ -128,6 +128,8 @@ export type FindOptions = { // If specified total will be returned total?: boolean + + showArchived?: boolean } /** diff --git a/plugins/document-resources/src/index.ts b/plugins/document-resources/src/index.ts index 2db4b0a18cf..04cfe530ba0 100644 --- a/plugins/document-resources/src/index.ts +++ b/plugins/document-resources/src/index.ts @@ -160,10 +160,6 @@ export async function canUnlockDocument (doc: Document | Document[]): Promise p.lockedBy != null) } -export function hideArchivedTeamspaces (value: boolean, query: DocumentQuery): DocumentQuery { - return value ? { ...query, archived: false } : query -} - export default async (): Promise => ({ component: { CreateDocument, @@ -202,8 +198,7 @@ export default async (): Promise => ({ CanLockDocument: canLockDocument, CanUnlockDocument: canUnlockDocument, GetDocumentLinkId: getDocumentLinkId, - ParseDocumentId: parseDocumentId, - HideArchivedTeamspaces: hideArchivedTeamspaces + ParseDocumentId: parseDocumentId }, resolver: { Location: resolveLocation diff --git a/plugins/drive-resources/src/index.ts b/plugins/drive-resources/src/index.ts index d41c7bffcbc..22343aa278f 100644 --- a/plugins/drive-resources/src/index.ts +++ b/plugins/drive-resources/src/index.ts @@ -160,10 +160,6 @@ export async function CanRenameFolder (doc: Folder | Folder[] | undefined): Prom return doc !== undefined && !Array.isArray(doc) } -export function HideArchivedDrives (value: boolean, query: DocumentQuery): DocumentQuery { - return value ? { ...query, archived: false } : query -} - export default async (): Promise => ({ component: { CreateDrive, @@ -204,8 +200,7 @@ export default async (): Promise => ({ FileLinkProvider, FolderLinkProvider, CanRenameFile, - CanRenameFolder, - HideArchivedDrives + CanRenameFolder }, resolver: { Location: resolveLocation diff --git a/plugins/recruit-resources/src/components/Vacancies.svelte b/plugins/recruit-resources/src/components/Vacancies.svelte index c1583df9f1e..c6b4e8cfd3c 100644 --- a/plugins/recruit-resources/src/components/Vacancies.svelte +++ b/plugins/recruit-resources/src/components/Vacancies.svelte @@ -205,10 +205,7 @@ viewlet, viewOptions, viewOptionsConfig: viewlet.viewOptions?.other, - query: { - ...resultQuery, - ...(viewOptions?.hideArchived !== false ? { archived: false } : {}) - }, + query: resultQuery, totalQuery: {}, tableId: 'vacanciesData' }} diff --git a/plugins/recruit-resources/src/index.ts b/plugins/recruit-resources/src/index.ts index 1b870990b4b..d6494cc8717 100644 --- a/plugins/recruit-resources/src/index.ts +++ b/plugins/recruit-resources/src/index.ts @@ -13,6 +13,7 @@ // limitations under the License. // +import contact from '@hcengineering/contact' import { toIdMap, type Client, @@ -24,14 +25,14 @@ import { type RelatedDocument } from '@hcengineering/core' import { OK, Severity, Status, type Resources } from '@hcengineering/platform' -import { createQuery, getClient, type ObjectSearchResult } from '@hcengineering/presentation' +import { getClient, type ObjectSearchResult } from '@hcengineering/presentation' import { type Applicant, type Candidate, type Vacancy } from '@hcengineering/recruit' -import contact from '@hcengineering/contact' import task from '@hcengineering/task' import { showPopup } from '@hcengineering/ui' import { type Filter } from '@hcengineering/view' import { FilterQuery, statusStore } from '@hcengineering/view-resources' import ApplicantFilter from './components/ApplicantFilter.svelte' +import ApplicantNamePresenter from './components/ApplicantNamePresenter.svelte' import ApplicationItem from './components/ApplicationItem.svelte' import ApplicationPresenter from './components/ApplicationPresenter.svelte' import Applications from './components/Applications.svelte' @@ -64,7 +65,6 @@ import Opinions from './components/review/Opinions.svelte' import OpinionsPresenter from './components/review/OpinionsPresenter.svelte' import ReviewPresenter from './components/review/ReviewPresenter.svelte' import Reviews from './components/review/Reviews.svelte' -import ApplicantNamePresenter from './components/ApplicantNamePresenter.svelte' import recruit from './plugin' import { getAppIdentifier, @@ -293,33 +293,6 @@ export function hideDoneState (value: any, query: DocumentQuery): DocumentQ return query } -const activeVacancyQuery = createQuery(true) - -let activeVacancies: Promise>> | Array> | undefined - -export async function hideArchivedVacancies (value: any, query: DocumentQuery): Promise> { - if (activeVacancies === undefined) { - activeVacancies = new Promise>>((resolve) => { - activeVacancyQuery.query( - recruit.class.Vacancy, - { archived: { $ne: true } }, - (res) => { - activeVacancies = res.map((it) => it._id) - resolve(activeVacancies) - }, - { projection: { _id: 1 } } - ) - }) - } - if (value as boolean) { - if (activeVacancies instanceof Promise) { - activeVacancies = await activeVacancies - } - return { ...query, space: { $in: activeVacancies } } - } - return query -} - export async function applicantHasEmail (doc: Doc | Doc[] | undefined): Promise { if (doc === undefined) return false const client = getClient() @@ -415,7 +388,6 @@ export default async (): Promise => ({ GetObjectLinkFragment: getSequenceLink, GetIdObjectLinkFragment: getObjectLink, HideDoneState: hideDoneState, - HideArchivedVacancies: hideArchivedVacancies, ApplicantHasEmail: applicantHasEmail, ParseLinkId: parseLinkId }, diff --git a/plugins/task-resources/src/components/TypesView.svelte b/plugins/task-resources/src/components/TypesView.svelte index b6c59a36626..5187f78ca45 100644 --- a/plugins/task-resources/src/components/TypesView.svelte +++ b/plugins/task-resources/src/components/TypesView.svelte @@ -13,13 +13,19 @@ // limitations under the License. -->
dispatch('changeContent')}> diff --git a/plugins/view-resources/src/components/filter/ValueFilter.svelte b/plugins/view-resources/src/components/filter/ValueFilter.svelte index 82f9dc8a424..0d77e78723c 100644 --- a/plugins/view-resources/src/components/filter/ValueFilter.svelte +++ b/plugins/view-resources/src/components/filter/ValueFilter.svelte @@ -82,31 +82,20 @@ [prefix + filter.key.key]: { $like: '%' + search + '%' } } : {} - const isDerivedFromSpace = hierarchy.isDerived(_class, core.class.Space) async function doQuery (limit: number | undefined, sortedValues: any[] | undefined): Promise { const p = client.findAll( _class, { ...resultQuery, - ...(space !== undefined - ? { space } - : isDerivedFromSpace - ? viewOptions === undefined || viewOptions?.hideArchived === true - ? { archived: false } - : {} - : { - '$lookup.space.archived': false - }), + ...(space !== undefined ? { space } : {}), ...(sortedValues !== undefined ? { [prefix + filter.key.key]: { $nin: sortedValues } } : {}) }, { sort: { modifiedOn: SortingOrder.Descending }, projection: { [prefix + filter.key.key]: 1 }, ...(limit !== undefined ? { limit } : {}), - lookup: { - space: core.class.Space - } + showArchived: viewOptions?.hideArchived === false } ) if (limit !== undefined) { diff --git a/plugins/view-resources/src/components/list/List.svelte b/plugins/view-resources/src/components/list/List.svelte index 87e3c05fd06..893917e1e05 100644 --- a/plugins/view-resources/src/components/list/List.svelte +++ b/plugins/view-resources/src/components/list/List.svelte @@ -26,11 +26,19 @@ import { IntlString, getResource } from '@hcengineering/platform' import { createQuery, getClient, reduceCalls } from '@hcengineering/presentation' import { AnyComponent, AnySvelteComponent } from '@hcengineering/ui' - import { BuildModelKey, ViewOptionModel, ViewOptions, ViewQueryOption, Viewlet } from '@hcengineering/view' + import { + BuildModelKey, + ViewOptionModel, + ViewOptions, + ViewOptionsOption, + ViewQueryOption, + Viewlet + } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' import { SelectionFocusProvider } from '../../selection' import { buildConfigLookup } from '../../utils' import ListCategories from './ListCategories.svelte' + import { getResultOptions, getResultQuery } from '../../viewOptions' export let _class: Ref> export let space: Ref | undefined = undefined @@ -68,12 +76,22 @@ const docsQuerySlow = createQuery() $: lookup = buildConfigLookup(client.getHierarchy(), _class, config, options?.lookup) - $: resultOptions = { ...options, lookup, ...(orderBy !== undefined ? { sort: { [orderBy[0]]: orderBy[1] } } : {}) } + $: configOptions = options + $: resultOptions = { + ...configOptions, + lookup, + ...(orderBy !== undefined ? { sort: { [orderBy[0]]: orderBy[1] } } : {}) + } + + const updateOptions = reduceCalls(async function (options: FindOptions | undefined, viewOptions: ViewOptions) { + configOptions = await getResultOptions(options, viewOptionsConfig, viewOptions) + }) + $: void updateOptions(options, viewOptions) let resultQuery: DocumentQuery = query const update = reduceCalls(async function (query: DocumentQuery, viewOptions: ViewOptions) { - const p = await getResultQuery(query, viewOptionsConfig, viewOptions) + const p = await getResultQuery(hierarchy, query, viewOptionsConfig, viewOptions) resultQuery = mergeQueries(p, query) }) $: void update(query, viewOptions) @@ -163,27 +181,6 @@ $: dispatch('content', docs) - async function getResultQuery ( - query: DocumentQuery, - viewOptions: ViewOptionModel[] | undefined, - viewOptionsStore: ViewOptions - ): Promise> { - if (viewOptions === undefined) return query - let result: DocumentQuery = hierarchy.clone(query) - for (const viewOption of viewOptions) { - if (viewOption.actionTarget !== 'query') continue - const queryOption = viewOption as ViewQueryOption - const f = await getResource(queryOption.action) - const resultP = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, result) - if (resultP instanceof Promise) { - result = await resultP - } else { - result = resultP - } - } - return result - } - function uncheckAll (): void { dispatch('check', { docs, value: false }) selectedObjectIds = [] diff --git a/plugins/view-resources/src/index.ts b/plugins/view-resources/src/index.ts index 6f105fba5c0..542fc70aef4 100644 --- a/plugins/view-resources/src/index.ts +++ b/plugins/view-resources/src/index.ts @@ -129,7 +129,7 @@ import { } from './filter' import { AggregationMiddleware, AnalyticsMiddleware } from './middleware' -import { showEmptyGroups } from './viewOptions' +import { hideArchived, showEmptyGroups } from './viewOptions' import { canArchiveSpace, canDeleteObject, @@ -321,6 +321,7 @@ export default async (): Promise => ({ FilterContainsResult: containsResult, FilterNestedMatchResult: nestedMatchResult, FilterNestedDontMatchResult: nestedDontMatchResult, + HideArchived: hideArchived, ShowEmptyGroups: showEmptyGroups, FilterDateOutdated: dateOutdated, FilterDateToday: dateToday, diff --git a/plugins/view-resources/src/viewOptions.ts b/plugins/view-resources/src/viewOptions.ts index 38eba416177..e56cd337f38 100644 --- a/plugins/view-resources/src/viewOptions.ts +++ b/plugins/view-resources/src/viewOptions.ts @@ -1,8 +1,19 @@ -import { type Class, type Doc, type DocumentQuery, type Ref, SortingOrder, type Space } from '@hcengineering/core' +import { + type Class, + type Doc, + type DocumentQuery, + type FindOptions, + type Hierarchy, + type Ref, + SortingOrder, + type Space +} from '@hcengineering/core' import { getResource } from '@hcengineering/platform' import { type LiveQuery, createQuery, getAttributePresenterClass, getClient } from '@hcengineering/presentation' import { locationToUrl, getCurrentResolvedLocation } from '@hcengineering/ui' import { + type ViewOptionsOption, + type ViewQueryOption, type DropdownViewOption, type Groupping, type ToggleViewOption, @@ -128,6 +139,10 @@ export function migrateViewOpttions (): void { } } +export function hideArchived (value: any, options: FindOptions | undefined): FindOptions { + return value === false ? { ...options, showArchived: true } : options ?? {} +} + export async function showEmptyGroups ( _class: Ref>, query: DocumentQuery | undefined, @@ -190,3 +205,45 @@ export const CategoryQuery = { } export const viewOptionStore = writable(new Map()) + +export async function getResultOptions ( + options: FindOptions | undefined, + viewOptions: ViewOptionModel[] | undefined, + viewOptionsStore: ViewOptions | undefined +): Promise | undefined> { + if (viewOptions === undefined || viewOptionsStore === undefined) { + return options + } + let result: FindOptions = options !== undefined ? { ...options } : {} + for (const viewOption of viewOptions) { + if (viewOption.actionTarget !== 'options') continue + const queryOption = viewOption as ViewOptionsOption + const f = await getResource(queryOption.action) + result = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, result) as FindOptions + } + return Object.keys(result).length > 0 ? result : undefined +} + +export async function getResultQuery ( + hierarchy: Hierarchy, + query: DocumentQuery, + viewOptions: ViewOptionModel[] | undefined, + viewOptionsStore: ViewOptions | undefined +): Promise> { + if (viewOptions === undefined || viewOptionsStore === undefined) { + return query + } + let result: DocumentQuery = hierarchy.clone(query) + for (const viewOption of viewOptions) { + if (viewOption.actionTarget !== 'query') continue + const queryOption = viewOption as ViewQueryOption + const f = await getResource(queryOption.action) + const resultP = f(viewOptionsStore[queryOption.key] ?? queryOption.defaultValue, result) + if (resultP instanceof Promise) { + result = await resultP + } else { + result = resultP + } + } + return result +} diff --git a/plugins/view/src/types.ts b/plugins/view/src/types.ts index 15586de1f6d..b5064ab2a65 100644 --- a/plugins/view/src/types.ts +++ b/plugins/view/src/types.ts @@ -697,9 +697,25 @@ export interface ViewOption { defaultValue: any label: IntlString hidden?: (viewOptions: ViewOptions) => boolean - actionTarget?: 'query' | 'category' | 'display' + actionTarget?: 'query' | 'category' | 'display' | 'options' action?: Resource<(value: any, ...params: any) => any> } + +/** + * @public + */ +export type ViewOptionsAction = Resource< +(value: any, query: FindOptions | undefined) => FindOptions +> + +/** + * @public + */ +export interface ViewOptionsOption extends ViewOption { + actionTarget: 'options' + action: ViewOptionsAction +} + /** * @public */ diff --git a/plugins/workbench-resources/src/components/Navigator.svelte b/plugins/workbench-resources/src/components/Navigator.svelte index 10b72261af5..78f2088a4b8 100644 --- a/plugins/workbench-resources/src/components/Navigator.svelte +++ b/plugins/workbench-resources/src/components/Navigator.svelte @@ -81,7 +81,7 @@ let requestIndex = 0 async function update (model: NavigatorModel, spaces: Space[], preferences: Map, SpacePreference>) { - shownSpaces = spaces.filter((sp) => !sp.archived && !preferences.has(sp._id)) + shownSpaces = spaces.filter((sp) => !preferences.has(sp._id)) starred = spaces.filter((sp) => preferences.has(sp._id)) if (model.specials !== undefined) { const [sp, resIndex] = await updateSpecials(model.specials, spaces, ++requestIndex) diff --git a/plugins/workbench-resources/src/components/SpecialView.svelte b/plugins/workbench-resources/src/components/SpecialView.svelte index 170c95e0157..56d8a6d585c 100644 --- a/plugins/workbench-resources/src/components/SpecialView.svelte +++ b/plugins/workbench-resources/src/components/SpecialView.svelte @@ -13,32 +13,31 @@ // limitations under the License. -->