Fix status filter (#3937)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2023-11-03 21:31:19 +06:00 committed by GitHub
parent 9f82ec3b7f
commit 66915d29e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 62 additions and 80 deletions

View File

@ -707,7 +707,7 @@ export function createModel (builder: Builder): void {
label: recruit.string.HideArchivedVacancies label: recruit.string.HideArchivedVacancies
} }
const applicantViewOptions = (colors: boolean, hides: boolean): ViewOptionsModel => { const applicantViewOptions = (colors: boolean): ViewOptionsModel => {
const model: ViewOptionsModel = { const model: ViewOptionsModel = {
groupBy: ['status', 'assignee', 'space', 'createdBy', 'modifiedBy'], groupBy: ['status', 'assignee', 'space', 'createdBy', 'modifiedBy'],
orderBy: [ orderBy: [
@ -725,15 +725,14 @@ export function createModel (builder: Builder): void {
actionTarget: 'category', actionTarget: 'category',
action: view.function.ShowEmptyGroups, action: view.function.ShowEmptyGroups,
label: view.string.ShowEmptyGroups label: view.string.ShowEmptyGroups
} },
applicationDoneOption,
vacancyHideOption
] ]
} }
if (colors) { if (colors) {
model.other.push(showColorsViewOption) model.other.push(showColorsViewOption)
} }
if (hides) {
model.other.push(...[applicationDoneOption, vacancyHideOption])
}
return model return model
} }
@ -811,7 +810,7 @@ export function createModel (builder: Builder): void {
strict: true, strict: true,
hiddenKeys: ['name', 'attachedTo'] hiddenKeys: ['name', 'attachedTo']
}, },
viewOptions: applicantViewOptions(true, true) viewOptions: applicantViewOptions(true)
}, },
recruit.viewlet.ListApplicant recruit.viewlet.ListApplicant
) )
@ -978,12 +977,8 @@ export function createModel (builder: Builder): void {
attachTo: recruit.class.Applicant, attachTo: recruit.class.Applicant,
descriptor: task.viewlet.Kanban, descriptor: task.viewlet.Kanban,
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
baseQuery: {
isDone: { $ne: true },
'$lookup.space.archived': false
},
viewOptions: { viewOptions: {
...applicantViewOptions(false, false), ...applicantViewOptions(false),
groupDepth: 1 groupDepth: 1
}, },
options: { options: {

View File

@ -412,6 +412,10 @@ export function createModel (builder: Builder): void {
func: task.function.StatusSort func: task.function.StatusSort
}) })
builder.mixin(core.class.Status, core.class.Class, view.mixin.AttributeFilter, {
component: task.component.StatusFilter
})
builder.mixin(core.class.Status, core.class.Class, view.mixin.AllValuesFunc, { builder.mixin(core.class.Status, core.class.Class, view.mixin.AllValuesFunc, {
func: task.function.GetAllStates func: task.function.GetAllStates
}) })

View File

@ -753,10 +753,6 @@ export function createModel (builder: Builder): void {
component: view.component.ObjectFilter component: view.component.ObjectFilter
}) })
builder.mixin(core.class.Status, core.class.Class, view.mixin.AttributeFilter, {
component: view.component.StatusFilter
})
builder.mixin(core.class.TypeTimestamp, core.class.Class, view.mixin.AttributeFilter, { builder.mixin(core.class.TypeTimestamp, core.class.Class, view.mixin.AttributeFilter, {
component: view.component.DateFilter, component: view.component.DateFilter,
group: 'bottom' group: 'bottom'

View File

@ -16,7 +16,7 @@
import core, { Doc, FindResult, IdMap, Ref, RefTo, Space, Status, toIdMap } from '@hcengineering/core' import core, { Doc, FindResult, IdMap, Ref, RefTo, Space, Status, toIdMap } from '@hcengineering/core'
import { translate } from '@hcengineering/platform' import { translate } from '@hcengineering/platform'
import presentation, { createQuery, getClient } from '@hcengineering/presentation' import presentation, { createQuery, getClient } from '@hcengineering/presentation'
import task, { Project, ProjectType, getStates } from '@hcengineering/task' import task, { Project, ProjectType } from '@hcengineering/task'
import ui, { import ui, {
EditWithIcon, EditWithIcon,
Icon, Icon,
@ -30,10 +30,16 @@
themeStore themeStore
} from '@hcengineering/ui' } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view' import { Filter } from '@hcengineering/view'
import {
FILTER_DEBOUNCE_MS,
FilterRemovedNotification,
sortFilterValues,
statusStore
} from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin'
import { buildConfigLookup, getPresenter } from '@hcengineering/view-resources/src/utils'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues, statusStore } from '../..' import { selectedTypeStore, typeStore } from '..'
import view from '../../plugin'
import { buildConfigLookup, getPresenter } from '../../utils'
export let filter: Filter export let filter: Filter
export let space: Ref<Space> | undefined = undefined export let space: Ref<Space> | undefined = undefined
@ -65,7 +71,12 @@
let filterUpdateTimeout: any | undefined let filterUpdateTimeout: any | undefined
async function getValues (search: string, typeStore: IdMap<ProjectType>, statusStore: IdMap<Status>): Promise<void> { async function getValues (
search: string,
selectedType: Ref<ProjectType> | undefined,
typeStore: IdMap<ProjectType>,
statusStore: IdMap<Status>
): Promise<void> {
if (objectsPromise) { if (objectsPromise) {
await objectsPromise await objectsPromise
} }
@ -74,16 +85,14 @@
for (const object of filter.value) { for (const object of filter.value) {
targets.add(object) targets.add(object)
} }
if (space !== undefined) { const type = selectedType ? typeStore.get(selectedType) : undefined
const _space = await client.findOne(task.class.Project, { _id: space as Ref<Project> }) if (type !== undefined) {
if (_space) { values = type?.statuses?.map((p) => statusStore.get(p._id))
values = getStates(_space, typeStore, statusStore) for (const value of values) {
for (const value of values) { targets.add(value?._id)
targets.add(value?._id) }
} if (search !== '') {
if (search !== '') { values = values.filter((p) => p?.name.includes(search))
values = values.filter((p) => p?.name.includes(search))
}
} }
} else { } else {
const statuses: Status[] = [] const statuses: Status[] = []
@ -162,13 +171,7 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const typesQuery = createQuery() $: if (targetClass) getValues(search, $selectedTypeStore, $typeStore, $statusStore.byId)
let types: IdMap<ProjectType> = new Map()
typesQuery.query(task.class.ProjectType, {}, (res) => {
types = toIdMap(res)
})
$: if (targetClass) getValues(search, types, $statusStore.byId)
</script> </script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}> <div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>

View File

@ -33,6 +33,8 @@
import { ViewOptions, Viewlet, ViewletDescriptor, ViewletPreference } from '@hcengineering/view' import { ViewOptions, Viewlet, ViewletDescriptor, ViewletPreference } from '@hcengineering/view'
import { FilterBar, FilterButton, ViewletSelector, ViewletSettingButton } from '@hcengineering/view-resources' import { FilterBar, FilterButton, ViewletSelector, ViewletSettingButton } from '@hcengineering/view-resources'
import task from '../plugin' import task from '../plugin'
import { onDestroy } from 'svelte'
import { selectedTypeStore } from '..'
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let space: Ref<Space> | undefined = undefined export let space: Ref<Space> | undefined = undefined
@ -82,6 +84,7 @@
let modeSelectorProps: IModeSelector | undefined = undefined let modeSelectorProps: IModeSelector | undefined = undefined
$: if (mode === undefined && config.length > 0) { $: if (mode === undefined && config.length > 0) {
;[[mode]] = config ;[[mode]] = config
selectedTypeStore.set(mode as Ref<ProjectType>)
} }
$: if (mode !== undefined) { $: if (mode !== undefined) {
modeSelectorProps = { modeSelectorProps = {
@ -89,9 +92,14 @@
config, config,
onChange: (_mode: string) => { onChange: (_mode: string) => {
mode = _mode mode = _mode
selectedTypeStore.set(mode as Ref<ProjectType>)
} }
} }
} }
onDestroy(() => {
selectedTypeStore.set(undefined)
})
</script> </script>
<div class="ac-header full divide caption-height"> <div class="ac-header full divide caption-height">

View File

@ -16,21 +16,24 @@
import { Attribute, Class, Doc, DocumentQuery, IdMap, Ref, Status, TxOperations, toIdMap } from '@hcengineering/core' import { Attribute, Class, Doc, DocumentQuery, IdMap, Ref, Status, TxOperations, toIdMap } from '@hcengineering/core'
import { IntlString, Resources } from '@hcengineering/platform' import { IntlString, Resources } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import task, { Project, ProjectType, Task, calcRank } from '@hcengineering/task' import task, { Project, ProjectType, Task, calcRank } from '@hcengineering/task'
import { getCurrentLocation, navigate, showPopup } from '@hcengineering/ui' import { getCurrentLocation, navigate, showPopup } from '@hcengineering/ui'
import { ViewletDescriptor } from '@hcengineering/view' import { ViewletDescriptor } from '@hcengineering/view'
import { CategoryQuery, statusStore } from '@hcengineering/view-resources' import { statusStore } from '@hcengineering/view-resources'
import { get, writable } from 'svelte/store' import { get, writable } from 'svelte/store'
import AssignedTasks from './components/AssignedTasks.svelte' import AssignedTasks from './components/AssignedTasks.svelte'
import CreateStatePopup from './components/CreateStatePopup.svelte' import CreateStatePopup from './components/CreateStatePopup.svelte'
import Dashboard from './components/Dashboard.svelte' import Dashboard from './components/Dashboard.svelte'
import DueDateEditor from './components/DueDateEditor.svelte' import DueDateEditor from './components/DueDateEditor.svelte'
import KanbanTemplatePresenter from './components/KanbanTemplatePresenter.svelte' import KanbanTemplatePresenter from './components/KanbanTemplatePresenter.svelte'
import StatusFilter from './components/StatusFilter.svelte'
import StatusSelector from './components/StatusSelector.svelte' import StatusSelector from './components/StatusSelector.svelte'
import StatusTableView from './components/StatusTableView.svelte' import StatusTableView from './components/StatusTableView.svelte'
import TaskHeader from './components/TaskHeader.svelte' import TaskHeader from './components/TaskHeader.svelte'
import TaskPresenter from './components/TaskPresenter.svelte' import TaskPresenter from './components/TaskPresenter.svelte'
import TemplatesIcon from './components/TemplatesIcon.svelte' import TemplatesIcon from './components/TemplatesIcon.svelte'
import TypesView from './components/TypesView.svelte'
import KanbanView from './components/kanban/KanbanView.svelte' import KanbanView from './components/kanban/KanbanView.svelte'
import ProjectEditor from './components/kanban/ProjectEditor.svelte' import ProjectEditor from './components/kanban/ProjectEditor.svelte'
import ProjectTypeSelector from './components/kanban/ProjectTypeSelector.svelte' import ProjectTypeSelector from './components/kanban/ProjectTypeSelector.svelte'
@ -41,8 +44,6 @@ import TodoItemPresenter from './components/todos/TodoItemPresenter.svelte'
import TodoItemsPopup from './components/todos/TodoItemsPopup.svelte' import TodoItemsPopup from './components/todos/TodoItemsPopup.svelte'
import TodoStatePresenter from './components/todos/TodoStatePresenter.svelte' import TodoStatePresenter from './components/todos/TodoStatePresenter.svelte'
import Todos from './components/todos/Todos.svelte' import Todos from './components/todos/Todos.svelte'
import TypesView from './components/TypesView.svelte'
import { createQuery, getClient } from '@hcengineering/presentation'
export { default as AssigneePresenter } from './components/AssigneePresenter.svelte' export { default as AssigneePresenter } from './components/AssigneePresenter.svelte'
export { StateRefPresenter } export { StateRefPresenter }
@ -106,7 +107,8 @@ export default async (): Promise<Resources> => ({
CreateStatePopup, CreateStatePopup,
StatusSelector, StatusSelector,
TemplatesIcon, TemplatesIcon,
TypesView TypesView,
StatusFilter
}, },
actionImpl: { actionImpl: {
EditStatuses: editStatuses, EditStatuses: editStatuses,
@ -124,29 +126,14 @@ async function getAllStates (
queryId: Ref<Doc>, queryId: Ref<Doc>,
attr: Attribute<Status> attr: Attribute<Status>
): Promise<any[]> { ): Promise<any[]> {
const _space = query?.space const typeId = get(selectedTypeStore)
if (_space !== undefined) { const type = typeId !== undefined ? get(typeStore).get(typeId) : undefined
const promise = new Promise<Array<Ref<Doc>>>((resolve, reject) => { if (type !== undefined) {
let refresh: boolean = false const statusMap = get(statusStore).byId
const lq = CategoryQuery.getLiveQuery(queryId) const statuses = (type.statuses?.map((p) => statusMap.get(p._id)) as Status[]) ?? []
refresh = lq.query(task.class.Project, { _id: _space as Ref<Project> }, (res) => { return statuses
const typeId = res[0]?.type .filter((p) => p?.category !== task.statusCategory.Lost && p?.category !== task.statusCategory.Won)
const type = get(typeStore).get(typeId) .map((p) => p?._id)
const statusMap = get(statusStore).byId
const statuses = (type?.statuses?.map((p) => statusMap.get(p._id)) as Status[]) ?? []
const result = statuses
.filter((p) => p?.category !== task.statusCategory.Lost && p?.category !== task.statusCategory.Won)
.map((p) => p?._id)
CategoryQuery.results.set(queryId, result)
resolve(result)
onUpdate()
})
if (!refresh) {
resolve(CategoryQuery.results.get(queryId) ?? [])
}
})
return await promise
} }
return get(statusStore) return get(statusStore)
.array.filter( .array.filter(
@ -162,19 +149,8 @@ async function statusSort (
space: Ref<Project> | undefined, space: Ref<Project> | undefined,
viewletDescriptorId?: Ref<ViewletDescriptor> viewletDescriptorId?: Ref<ViewletDescriptor>
): Promise<Array<Ref<Status>>> { ): Promise<Array<Ref<Status>>> {
let type: ProjectType | undefined const typeId = get(selectedTypeStore)
if (space !== undefined) { const type = typeId !== undefined ? get(typeStore).get(typeId) : undefined
const _space = await client.findOne(
task.class.Project,
{ _id: space },
{
lookup: {
type: task.class.ProjectType
}
}
)
type = _space?.$lookup?.type
}
const statuses = get(statusStore).byId const statuses = get(statusStore).byId
if (type !== undefined) { if (type !== undefined) {
@ -238,3 +214,5 @@ function fillStores (): void {
} }
fillStores() fillStores()
export const selectedTypeStore = writable<Ref<ProjectType> | undefined>(undefined)

View File

@ -79,6 +79,7 @@ export default mergeIds(taskId, task, {
AssigneeRequired: '' as IntlString AssigneeRequired: '' as IntlString
}, },
component: { component: {
StatusFilter: '' as AnyComponent,
TodoStatePresenter: '' as AnyComponent, TodoStatePresenter: '' as AnyComponent,
AssignedTasks: '' as AnyComponent, AssignedTasks: '' as AnyComponent,
DueDateEditor: '' as AnyComponent DueDateEditor: '' as AnyComponent

View File

@ -40,7 +40,6 @@ import FilterTypePopup from './components/filter/FilterTypePopup.svelte'
import ObjectFilter from './components/filter/ObjectFilter.svelte' import ObjectFilter from './components/filter/ObjectFilter.svelte'
import StringFilter from './components/filter/StringFilter.svelte' import StringFilter from './components/filter/StringFilter.svelte'
import StringFilterPresenter from './components/filter/StringFilterPresenter.svelte' import StringFilterPresenter from './components/filter/StringFilterPresenter.svelte'
import StatusFilter from './components/filter/StatusFilter.svelte'
import TimestampFilter from './components/filter/TimestampFilter.svelte' import TimestampFilter from './components/filter/TimestampFilter.svelte'
import ValueFilter from './components/filter/ValueFilter.svelte' import ValueFilter from './components/filter/ValueFilter.svelte'
import HTMLEditor from './components/HTMLEditor.svelte' import HTMLEditor from './components/HTMLEditor.svelte'
@ -206,7 +205,6 @@ export default async (): Promise<Resources> => ({
DateFilter, DateFilter,
ValueFilter, ValueFilter,
StringFilter, StringFilter,
StatusFilter,
TimestampFilter, TimestampFilter,
TableBrowser, TableBrowser,
SpacePresenter, SpacePresenter,

View File

@ -25,7 +25,6 @@ export default mergeIds(viewId, view, {
DateFilter: '' as AnyComponent, DateFilter: '' as AnyComponent,
ValueFilter: '' as AnyComponent, ValueFilter: '' as AnyComponent,
ArrayFilter: '' as AnyComponent, ArrayFilter: '' as AnyComponent,
StatusFilter: '' as AnyComponent,
StringFilter: '' as AnyComponent, StringFilter: '' as AnyComponent,
TimestampFilter: '' as AnyComponent, TimestampFilter: '' as AnyComponent,
FilterTypePopup: '' as AnyComponent, FilterTypePopup: '' as AnyComponent,