Nested filter fixes (#2123)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-06-22 11:58:28 +06:00 committed by GitHub
parent 0cadc19331
commit 41ebded8c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 97 additions and 95 deletions

View File

@ -120,25 +120,6 @@ export function createModel (builder: Builder): void {
hr.action.EditDepartment
)
createAction(
builder,
{
action: view.actionImpl.ShowPopup,
actionProps: {
component: hr.component.DepartmentStaff,
element: 'float'
},
label: hr.string.ShowEmployees,
icon: contact.icon.Person,
keyBinding: ['m'],
input: 'any',
category: hr.category.HR,
target: hr.class.Department,
context: { mode: 'context', application: hr.app.HR, group: 'top' }
},
hr.action.ShowEmployees
)
createAction(
builder,
{

View File

@ -23,8 +23,7 @@ import { Action, ActionCategory } from '@anticrm/view'
export default mergeIds(hrId, hr, {
string: {
HRApplication: '' as IntlString,
Departments: '' as IntlString,
ShowEmployees: '' as IntlString
Departments: '' as IntlString
},
component: {
Structure: '' as AnyComponent,
@ -37,7 +36,6 @@ export default mergeIds(hrId, hr, {
},
action: {
EditDepartment: '' as Ref<Action>,
ShowEmployees: '' as Ref<Action>,
DeleteDepartment: '' as Ref<Action>
}
})

View File

@ -60,9 +60,6 @@ export default mergeIds(viewId, view, {
Open: '' as ViewAction
},
component: {
ObjectFilter: '' as AnyComponent,
ValueFilter: '' as AnyComponent,
TimestampFilter: '' as AnyComponent,
StringEditor: '' as AnyComponent,
StringEditorPopup: '' as AnyComponent,
StringPresenter: '' as AnyComponent,

View File

@ -28,13 +28,21 @@
export let label: IntlString | undefined = undefined
export let labelProps: Record<string, any> = {}
export let withHover: boolean = false
export let element: HTMLElement | undefined = undefined
let element: HTMLElement
let optionsMod: LabelAndProps
$: optionsMod = { component: options.component ?? Menu, props, element, kind: 'submenu' }
</script>
<div bind:this={element} use:tooltip={optionsMod} class="antiPopup-submenu" class:withHover tabindex={focusIndex}>
<div
bind:this={element}
on:keydown
on:click
use:tooltip={optionsMod}
class="antiPopup-submenu"
class:withHover
tabindex={focusIndex}
>
{#if component}
{#if typeof component === 'string'}
<Component is={component} {props} />

View File

@ -4,7 +4,7 @@
"ParentDepartmentLabel": "Parent department",
"Structure":"Structure",
"CreateDepartment": "Create department",
"CreateDepartmentLabel": "Create department",
"CreateDepartmentLabel": "Department",
"DepartmentPlaceholder": "Department",
"TeamLead": "Team lead",
"UnAssignLead": "Unassign team lead",
@ -15,7 +15,6 @@
"MoveStaff": "Employee transfer",
"MoveStaffDescr": "Do you want to transfer employee from {current} to {department}",
"Departments": "Departments",
"ShowEmployees": "Show employees",
"AddEmployee": "Add employee"
}
}

View File

@ -4,7 +4,7 @@
"ParentDepartmentLabel": "Родительский департамент",
"Structure":"Структура",
"CreateDepartment": "Создать департамент",
"CreateDepartmentLabel": "Создать департамент",
"CreateDepartmentLabel": "Департамент",
"DepartmentPlaceholder": "Департамент",
"TeamLead": "Менеджер",
"UnAssignLead": "Отменить назначение менеджера",
@ -15,7 +15,6 @@
"MoveStaff": "Перевод сотрудника",
"MoveStaffDescr": "Вы действительно хотите перевести сотрудника из {current} в {department}",
"Departments": "Департаменты",
"ShowEmployees": "Просмотреть сотрудников",
"AddEmployee": "Добавить сотрудника"
}
}

View File

@ -13,11 +13,12 @@
// limitations under the License.
-->
<script lang="ts">
import core, { AnyAttribute, ArrOf, AttachedDoc, Class, Collection, Doc, Ref, Type } from '@anticrm/core'
import core, { AnyAttribute, ArrOf, AttachedDoc, Class, Collection, Doc, Ref, RefTo, Type } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import { Icon, Label, showPopup } from '@anticrm/ui'
import { closePopup, closeTooltip, Icon, Label, showPopup, Submenu } from '@anticrm/ui'
import { Filter, KeyFilter } from '@anticrm/view'
import { createEventDispatcher } from 'svelte'
import { FilterQuery } from '../../filter'
import view from '../../plugin'
export let _class: Ref<Class<Doc>>
@ -106,7 +107,8 @@
const dispatch = createEventDispatcher()
function click (type: KeyFilter): void {
dispatch('close')
closePopup()
closeTooltip()
showPopup(
type.component,
@ -122,28 +124,78 @@
target
)
}
function hasNested (type: KeyFilter): boolean {
const targetClass = (hierarchy.getAttribute(_class, type.key).type as RefTo<Doc>).to
const clazz = hierarchy.getClass(targetClass)
return hierarchy.hasMixin(clazz, view.mixin.ClassFilters)
}
function setNestedFilter (type: KeyFilter, e: Filter | undefined) {
const filter: Filter = {
value: [],
key: type,
index,
mode: view.filter.FilterNestedMatch,
modes: [view.filter.FilterNestedMatch, view.filter.FilterNestedDontMatch],
onRemove: () => {
FilterQuery.remove(index)
}
}
if (e === undefined || filter === undefined) return
filter.nested = e
filter.value = e.value
onChange(filter)
dispatch('close')
}
function getNestedProps (type: KeyFilter): any {
const targetClass = (hierarchy.getAttribute(_class, type.key).type as RefTo<Doc>).to
return {
_class: targetClass,
index: index,
target,
onChange: (e: Filter | undefined) => {
setNestedFilter(type, e)
}
}
}
</script>
<div class="selectPopup">
<div class="scroll">
<div class="box">
{#each getTypes(_class) as type, i}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
class="menu-item withIcon"
on:keydown={(event) => keyDown(event, i)}
on:mouseover={(event) => {
event.currentTarget.focus()
}}
on:click={(event) => {
click(type)
}}
>
{#if type.icon}
<div class="icon"><Icon icon={type.icon} size={'small'} /></div>
{/if}
<div class="ml-3 pr-1"><Label label={type.label} /></div>
</button>
{#if filter === undefined && type.component === view.component.ObjectFilter && hasNested(type)}
<Submenu
on:keydown={(event) => keyDown(event, i)}
on:click={(event) => {
click(type)
}}
icon={type.icon}
label={type.label}
props={getNestedProps(type)}
options={{ component: view.component.FilterTypePopup }}
withHover
/>
{:else}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<button
class="menu-item withIcon"
on:keydown={(event) => keyDown(event, i)}
on:mouseover={(event) => {
event.currentTarget.focus()
}}
on:click={(event) => {
click(type)
}}
>
{#if type.icon}
<div class="icon mr-3"><Icon icon={type.icon} size={'small'} /></div>
{/if}
<div class="pr-1"><Label label={type.label} /></div>
</button>
{/if}
{/each}
</div>
</div>

View File

@ -16,16 +16,13 @@
import { Class, Doc, FindResult, getObjectValue, Ref, RefTo, SortingOrder } from '@anticrm/core'
import { translate } from '@anticrm/platform'
import presentation, { getClient } from '@anticrm/presentation'
import ui, { Button, CheckBox, eventToHTMLElement, Label, Loading, showPopup } from '@anticrm/ui'
import { Filter } from '@anticrm/view'
import { onMount } from 'svelte'
import { buildConfigLookup, getPresenter } from '../../utils'
import view from '../../plugin'
import { createEventDispatcher } from 'svelte'
import task from '@anticrm/task'
import type { State } from '@anticrm/task'
import FilterTypePopup from './FilterTypePopup.svelte'
import { FilterQuery } from '../../filter'
import task from '@anticrm/task'
import ui, { Button, CheckBox, Label, Loading } from '@anticrm/ui'
import { Filter } from '@anticrm/view'
import { createEventDispatcher, onMount } from 'svelte'
import view from '../../plugin'
import { buildConfigLookup, getPresenter } from '../../utils'
export let _class: Ref<Class<Doc>>
export let filter: Filter
@ -136,42 +133,9 @@
const dispatch = createEventDispatcher()
getValues(search)
$: byCriteria = hierarchy.hasMixin(clazz, view.mixin.ClassFilters)
function setNestedFilter (e: Filter | undefined) {
if (e === undefined) return
filter.nested = e
filter.mode = view.filter.FilterNestedMatch
filter.modes = [view.filter.FilterNestedMatch, view.filter.FilterNestedDontMatch]
filter.value = e.value
filter.onRemove = () => {
FilterQuery.remove(filter.index)
}
onChange(filter)
dispatch('close')
}
function nestedFilter (e: MouseEvent) {
const target = eventToHTMLElement(e)
showPopup(
FilterTypePopup,
{
_class: targetClass,
target,
index: filter.index,
filter: filter.nested,
onChange: setNestedFilter
},
target
)
}
</script>
<div class="selectPopup">
{#if byCriteria}
<Button shape={'round'} label={view.string.MatchCriteria} on:click={nestedFilter} />
{/if}
{#if clazz.sortingKey}
<div class="header">
<input

View File

@ -56,7 +56,6 @@ export const FilterQuery = {
getLiveQuery (index: number): LiveQuery {
const current = FilterQuery.queries.get(index)
if (current !== undefined) return current
console.error('create new query')
const query = createQuery(true)
this.queries.set(index, query)
return query
@ -89,7 +88,6 @@ export async function getRefs (filter: Filter, onUpdate: () => void): Promise<Ar
onUpdate()
}
)
console.error(refresh)
if (!refresh) {
resolve(FilterQuery.results.get(filter.index) ?? [])
}

View File

@ -33,6 +33,7 @@ import FilterBar from './components/filter/FilterBar.svelte'
import ObjectFilter from './components/filter/ObjectFilter.svelte'
import TimestampFilter from './components/filter/TimestampFilter.svelte'
import ValueFilter from './components/filter/ValueFilter.svelte'
import FilterTypePopup from './components/filter/FilterTypePopup.svelte'
import HTMLPresenter from './components/HTMLPresenter.svelte'
import IntlStringPresenter from './components/IntlStringPresenter.svelte'
import GithubPresenter from './components/linkPresenters/GithubPresenter.svelte'
@ -129,7 +130,8 @@ export default async (): Promise<Resources> => ({
ActionsPopup,
StringEditorPopup: EditBoxPopup,
BooleanTruePresenter,
EnumEditor
EnumEditor,
FilterTypePopup
},
popup: {
PositionElementAlignment

View File

@ -20,6 +20,10 @@ import view, { viewId } from '@anticrm/view'
export default mergeIds(viewId, view, {
component: {
ObjectFilter: '' as AnyComponent,
ValueFilter: '' as AnyComponent,
TimestampFilter: '' as AnyComponent,
FilterTypePopup: '' as AnyComponent,
ActionsPopup: '' as AnyComponent
},
string: {