Save last filter (#2003)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov
2022-06-03 23:12:18 +07:00
committed by GitHub
parent e85fcdbc30
commit 49572cc712
22 changed files with 302 additions and 184 deletions
+1
View File
@@ -10,6 +10,7 @@ Platform:
- Fix skills/labels selection and show real usage counter
- Fix skills/labels activity
- Project selector in issue list
- Save last filter for page
HR:
+1
View File
@@ -33,6 +33,7 @@
"@anticrm/tags-resources": "~0.6.0",
"@anticrm/ui": "~0.6.0",
"@anticrm/model-core": "~0.6.0",
"@anticrm/view": "~0.6.0",
"@anticrm/model-view": "~0.6.0"
}
}
+20
View File
@@ -104,4 +104,24 @@ export function createModel (builder: Builder): void {
builder.mixin(tags.class.TagReference, core.class.Class, view.mixin.AttributeFilter, {
component: tags.component.TagsFilter
})
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsEither,
result: tags.function.FilterTagsInResult
},
tags.ids.FilterTagsIn
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsNot,
result: tags.function.FilterTagsNinResult
},
tags.ids.FilterTagsNin
)
}
+2
View File
@@ -18,6 +18,8 @@ import { TagCategory, tagsId } from '@anticrm/tags'
import tags from '@anticrm/tags-resources/src/plugin'
import type { AnyComponent } from '@anticrm/ui'
import { ViewAction } from '@anticrm/model-view'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import view from '@anticrm/view'
export default mergeIds(tagsId, tags, {
// Without it, CLI version is failed with some svelte dependency exception.
+68
View File
@@ -29,6 +29,7 @@ import type {
ClassFilters,
CollectionEditor,
CollectionPresenter,
FilterMode,
HTMLPresenter,
IgnoreActions,
KeyBinding,
@@ -82,6 +83,12 @@ export function classPresenter (
}
}
@Model(view.class.FilterMode, core.class.Doc, DOMAIN_MODEL)
export class TFilterMode extends TDoc implements FilterMode {
label!: IntlString
result!: Resource<(values: any[], onUpdate: () => void) => Promise<any>>
}
@Mixin(view.mixin.ClassFilters, core.class.Class)
export class TClassFilters extends TClass implements ClassFilters {
filters!: (string | KeyFilter)[]
@@ -245,6 +252,7 @@ export const actionTemplates = template({
export function createModel (builder: Builder): void {
builder.createModel(
TFilterMode,
TClassFilters,
TAttributeFilter,
TAttributeEditor,
@@ -510,6 +518,66 @@ export function createModel (builder: Builder): void {
component: view.component.TimestampFilter
})
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsEither,
result: view.function.FilterValueInResult
},
view.ids.FilterValueIn
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsNot,
result: view.function.FilterValueNinResult
},
view.ids.FilterValueNin
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsEither,
result: view.function.FilterObjectInResult
},
view.ids.FilterObjectIn
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.FilterIsNot,
result: view.function.FilterObjectNinResult
},
view.ids.FilterObjectNin
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.Before,
result: view.function.FilterBeforeResult
},
view.ids.FilterBefore
)
builder.createDoc(
view.class.FilterMode,
core.space.Model,
{
label: view.string.After,
result: view.function.FilterAfterResult
},
view.ids.FilterAfter
)
classPresenter(builder, core.class.EnumOf, view.component.StringPresenter, view.component.EnumEditor)
}
+22 -2
View File
@@ -13,8 +13,8 @@
// limitations under the License.
//
import { Ref } from '@anticrm/core'
import { IntlString, mergeIds } from '@anticrm/platform'
import { ObjQueryType, Ref } from '@anticrm/core'
import { IntlString, mergeIds, Resource } from '@anticrm/platform'
import type { AnyComponent } from '@anticrm/ui'
import { Action, ViewAction, viewId } from '@anticrm/view'
import view from '@anticrm/view-resources/src/plugin'
@@ -104,5 +104,25 @@ export default mergeIds(viewId, view, {
Navigation: '' as IntlString,
Editor: '' as IntlString,
MarkdownFormatting: '' as IntlString
},
function: {
FilterObjectInResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterObjectNinResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterValueInResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterValueNinResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterBeforeResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterAfterResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>
}
})
@@ -12,92 +12,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script context="module" lang="ts">
const liveQueries: Map<number, LiveQuery> = new Map<number, LiveQuery>()
const results: Map<number, Ref<Doc>[]> = new Map<number, Ref<Doc>[]>()
</script>
<script lang="ts">
import { Class, Doc, FindResult, Ref } from '@anticrm/core'
import { translate } from '@anticrm/platform'
import presentation, { createQuery, getClient, LiveQuery } from '@anticrm/presentation'
import presentation, { getClient } from '@anticrm/presentation'
import { Button, CheckBox, getPlatformColor, Loading } from '@anticrm/ui'
import { Filter } from '@anticrm/view'
import view from '@anticrm/view-resources/src/plugin'
import { createEventDispatcher, onMount } from 'svelte'
import tags from '../plugin'
import { TagCategory, TagElement } from '@anticrm/tags'
import { TagFilterQuery } from '../utils'
export let _class: Ref<Class<Doc>>
export let filter: Filter
export let onChange: (e: Filter) => void
filter.onRemove = () => {
const lq = liveQueries.get(filter.index)
lq?.unsubscribe()
liveQueries.delete(filter.index)
results.delete(filter.index)
TagFilterQuery.remove(filter.index)
}
const lq = getLiveQuery(filter.index)
const client = getClient()
let selected: Ref<TagElement>[] = filter.value
function getLiveQuery (index: number): LiveQuery {
let lq = liveQueries.get(index)
if (lq === undefined) {
lq = createQuery(true)
liveQueries.set(index, lq)
}
return lq
}
async function getRefs (res: Ref<TagElement>[], onUpdate: () => void): Promise<Ref<Doc>[]> {
const promise = new Promise<Ref<Doc>[]>((resolve, reject) => {
const refresh = lq.query(
tags.class.TagReference,
{
tag: { $in: res }
},
(refs) => {
const result = Array.from(new Set(refs.map((p) => p.attachedTo)))
results.set(filter.index, result)
resolve(result)
onUpdate()
}
)
if (!refresh) {
resolve(results.get(filter.index) ?? [])
}
})
return promise
}
filter.modes = [
{
label: view.string.FilterIs,
isAvailable: (res: any[]) => res.length <= 1,
result: async (res: any[], onUpdate: () => void) => {
const result = await getRefs(res, onUpdate)
return { $in: result }
}
},
{
label: view.string.FilterIsEither,
isAvailable: (res: any[]) => res.length > 1,
result: async (res: any[], onUpdate: () => void) => {
const result = await getRefs(res, onUpdate)
return { $in: result }
}
},
{
label: view.string.FilterIsNot,
isAvailable: () => true,
result: async (res: any[], onUpdate: () => void) => {
const result = await getRefs(res, onUpdate)
return { $nin: result }
}
}
]
filter.modes = [tags.ids.FilterTagsIn, tags.ids.FilterTagsNin]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
let categories: TagCategory[] = []
let objects: TagElement[] = []
@@ -123,12 +60,6 @@
objectsPromise = undefined
}
function checkMode () {
if (filter.mode?.isAvailable(filter.value)) return
const newMode = filter.modes.find((p: any) => p.isAvailable(filter.value))
filter.mode = newMode !== undefined ? newMode : filter.mode
}
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
@@ -239,7 +170,6 @@
label={view.string.Apply}
on:click={async () => {
filter.value = selected
checkMode()
onChange(filter)
dispatch('close')
}}
+16
View File
@@ -29,6 +29,18 @@ import TagElementCountPresenter from './components/TagElementCountPresenter.svel
import TagsFilter from './components/TagsFilter.svelte'
import TagsAttributeEditor from './components/TagsAttributeEditor.svelte'
import TagsEditorPopup from './components/TagsEditorPopup.svelte'
import { ObjQueryType } from '@anticrm/core'
import { TagFilterQuery } from './utils'
export async function tagsInResult (res: any[], onUpdate: () => void, index: number): Promise<ObjQueryType<any>> {
const result = await TagFilterQuery.getRefs(res, onUpdate, index)
return { $in: result }
}
export async function tagsNinResult (res: any[], onUpdate: () => void, index: number): Promise<ObjQueryType<any>> {
const result = await TagFilterQuery.getRefs(res, onUpdate, index)
return { $nin: result }
}
export default async (): Promise<Resources> => ({
component: {
@@ -51,5 +63,9 @@ export default async (): Promise<Resources> => ({
Open: (value: TagElement, evt: MouseEvent) => {
showPopup(EditTagElement, { value, keyTitle: '' }, eventToHTMLElement(evt))
}
},
function: {
FilterTagsInResult: tagsInResult,
FilterTagsNinResult: tagsNinResult
}
})
+10 -1
View File
@@ -11,7 +11,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { IntlString, mergeIds } from '@anticrm/platform'
import { ObjQueryType } from '@anticrm/core'
import { IntlString, mergeIds, Resource } from '@anticrm/platform'
import tags, { tagsId } from '@anticrm/tags'
import { AnyComponent } from '@anticrm/ui'
@@ -45,5 +46,13 @@ export default mergeIds(tagsId, tags, {
SelectAll: '' as IntlString,
SelectNone: '' as IntlString,
ApplyTags: '' as IntlString
},
function: {
FilterTagsInResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>,
FilterTagsNinResult: '' as Resource<
(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>
>
}
})
+47
View File
@@ -1,8 +1,55 @@
// Copyright © 2022 Hardcore Engineering Inc.
import { Doc, FindResult, Ref } from '@anticrm/core'
import { createQuery, LiveQuery } from '@anticrm/presentation'
import { TagElement, TagReference } from '@anticrm/tags'
import tags from './plugin'
export function getTagStyle (color: string, selected = false): string {
return `
background: ${color + (selected ? 'ff' : '33')};
border: 1px solid ${color + (selected ? 'ff' : '66')};
`
}
export const TagFilterQuery = {
queries: new Map<number, LiveQuery>(),
results: new Map<number, Array<Ref<Doc>>>(),
getLiveQuery (index: number): LiveQuery {
const current = TagFilterQuery.queries.get(index)
if (current !== undefined) return current
const query = createQuery(true)
this.queries.set(index, query)
return query
},
async getRefs (res: Array<Ref<TagElement>>, onUpdate: () => void, index: number): Promise<Array<Ref<Doc>>> {
const lq = this.getLiveQuery(index)
const promise = new Promise<Array<Ref<Doc>>>((resolve, reject) => {
const refresh = lq.query(
tags.class.TagReference,
{
tag: { $in: res }
},
(refs: FindResult<TagReference>) => {
const result = Array.from(new Set(refs.map((p) => p.attachedTo)))
TagFilterQuery.results.set(index, result)
resolve(result)
onUpdate()
}
)
if (!refresh) {
resolve(TagFilterQuery.results.get(index) ?? [])
}
})
return await promise
},
remove (index: number): void {
const lq = this.queries.get(index)
lq?.unsubscribe()
this.queries.delete(index)
this.results.delete(index)
}
}
+1
View File
@@ -29,6 +29,7 @@
"dependencies": {
"@anticrm/platform": "~0.6.6",
"@anticrm/core": "~0.6.16",
"@anticrm/view": "~0.6.0",
"@anticrm/ui": "~0.6.0",
"svelte": "^3.47"
}
+5
View File
@@ -18,6 +18,7 @@ import type { Asset, Plugin } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import { AnyComponent } from '@anticrm/ui'
import { writable } from 'svelte/store'
import { FilterMode } from '@anticrm/view'
/**
* @public
@@ -87,6 +88,10 @@ const tagsPlugin = plugin(tagsId, {
},
category: {
NoCategory: '' as Ref<TagCategory>
},
ids: {
FilterTagsIn: '' as Ref<FilterMode>,
FilterTagsNin: '' as Ref<FilterMode>
}
})
+1 -2
View File
@@ -36,9 +36,8 @@
"CustomizeView": "Customize view",
"Filter": "Filter",
"ClearFilters": "Clear filters",
"FilterIs": "is",
"FilterIsNot": "is not",
"FilterIsEither": "is either of",
"FilterIsEither": "{value, plural, =1 {is} other {is either of}}",
"FilterStatesCount": "{value, plural, =1 {1 state} other {# states}}",
"Before": "Before",
"After": "After",
+1 -2
View File
@@ -34,9 +34,8 @@
"CustomizeView": "Настроить отображение",
"Filter": "Фильтр",
"ClearFilters": "Очистить",
"FilterIs": "равен",
"FilterIsNot": "не равен",
"FilterIsEither": "один из",
"FilterIsEither": "{value, plural, =1 {равен} other {один из}}",
"FilterStatesCount": "{value, plural, =1 {1 состоянию} other {# состояний}}",
"Before": "До",
"After": "После",
@@ -14,8 +14,9 @@
-->
<script lang="ts">
import { Class, Doc, DocumentQuery, Ref } from '@anticrm/core'
import { getResource } from '@anticrm/platform'
import { getClient } from '@anticrm/presentation'
import { Button, eventToHTMLElement, IconAdd, showPopup } from '@anticrm/ui'
import { Button, eventToHTMLElement, getCurrentLocation, IconAdd, locationToUrl, showPopup } from '@anticrm/ui'
import { Filter } from '@anticrm/view'
import { createEventDispatcher } from 'svelte'
import view from '../../plugin'
@@ -59,12 +60,7 @@
)
}
$: clear(_class)
function clear (_class: Ref<Class<Doc>>) {
filters.map((p) => p.onRemove?.())
filters = []
}
$: load(_class)
function remove (i: number) {
filters[i]?.onRemove?.()
@@ -72,13 +68,44 @@
filters = filters
}
$: saveFilters(filters)
function saveFilters (filters: Filter[]) {
const loc = getCurrentLocation()
const key = 'filter' + locationToUrl(loc)
if (filters.length > 0) {
localStorage.setItem(key, JSON.stringify(filters))
} else {
localStorage.removeItem(key)
}
}
function load (_class: Ref<Class<Doc>>) {
const loc = getCurrentLocation()
const key = 'filter' + locationToUrl(loc)
const saved = localStorage.getItem(key)
filters.map((p) => p.onRemove?.())
if (saved !== null) {
filters = JSON.parse(saved)
} else {
filters = []
}
}
async function makeQuery (query: DocumentQuery<Doc>, filters: Filter[]): Promise<void> {
const newQuery = hierarchy.clone(query)
for (let i = 0; i < filters.length; i++) {
const filter = filters[i]
const newValue = await filter.mode.result(filter.value, () => {
makeQuery(query, filters)
})
const mode = await client.findOne(view.class.FilterMode, { _id: filter.mode })
if (mode === undefined) continue
const result = await getResource(mode.result)
const newValue = await result(
filter.value,
() => {
makeQuery(query, filters)
},
filter.index
)
if (newQuery[filter.key.key] === undefined) {
newQuery[filter.key.key] = newValue
} else {
@@ -139,6 +166,7 @@
{filter}
on:change={() => {
makeQuery(query, filters)
saveFilters(filters)
}}
on:remove={() => {
remove(i)
@@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { translate } from '@anticrm/platform'
import { IntlString, translate } from '@anticrm/platform'
import { Class, Doc, Ref, RefTo } from '@anticrm/core'
import { eventToHTMLElement, IconClose, showPopup, Icon, Label } from '@anticrm/ui'
import { Filter } from '@anticrm/view'
@@ -27,6 +27,7 @@
export let _class: Ref<Class<Doc>>
export let filter: Filter
let label: IntlString | undefined
let current = 0
const client = getClient()
const hierarchy = client.getHierarchy()
@@ -47,13 +48,15 @@
}
$: if (filter) getLabel()
function toggle () {
const modes = filter.modes.filter((p) => p.isAvailable(filter.value))
async function toggle () {
current++
filter.mode = modes[current % modes.length]
filter.mode = filter.modes[current % filter.modes.length]
label = (await client.findOne(view.class.FilterMode, { _id: filter.mode }))?.label
dispatch('change')
}
client.findOne(view.class.FilterMode, { _id: filter.mode }).then((p) => (label = p?.label))
function onChange (e: Filter | undefined) {
filter = filter
dispatch('change')
@@ -74,7 +77,9 @@
<span><Label label={filter.key.label} /></span>
</button>
<button class="filter-button" on:click={toggle}>
<span><Label label={filter.mode.label} /></span>
{#if label}
<span><Label {label} params={{ value: filter.value.length }} /></span>
{/if}
</button>
<button
class="filter-button"
@@ -35,29 +35,8 @@
const key = { key: tkey }
const lookup = buildConfigLookup(hierarchy, _class, [tkey])
const promise = getPresenter(client, _class, key, key, lookup)
filter.modes = [
{
label: view.string.FilterIs,
isAvailable: (res: any[]) => res.length <= 1,
result: async (res: any[]) => {
return { $in: res }
}
},
{
label: view.string.FilterIsEither,
isAvailable: (res: any[]) => res.length > 1,
result: async (res: any[]) => {
return { $in: res }
}
},
{
label: view.string.FilterIsNot,
isAvailable: () => true,
result: async (res: any[]) => {
return { $nin: res }
}
}
]
filter.modes = [view.ids.FilterObjectIn, view.ids.FilterObjectNin]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
let values: (Doc | undefined | null)[] = []
let objectsPromise: Promise<FindResult<Doc>> | undefined
@@ -120,12 +99,6 @@
return values.includes(value?._id ?? value)
}
function checkMode () {
if (filter.mode?.isAvailable(filter.value)) return
const newMode = filter.modes.find((p) => p.isAvailable(filter.value))
filter.mode = newMode !== undefined ? newMode : filter.mode
}
function toggle (value: Doc | undefined | null): void {
if (isSelected(value, filter.value)) {
if (isState) {
@@ -146,7 +119,6 @@
filter.value = [...filter.value, undefined]
}
}
checkMode()
}
let search: string = ''
@@ -25,22 +25,7 @@
const dispatch = createEventDispatcher()
filter.modes = [
{
label: view.string.Before,
isAvailable: (res: any[]) => true,
result: async (res: any[]) => {
return { $lt: res[0] }
}
},
{
label: view.string.After,
isAvailable: () => true,
result: async (res: any[]) => {
return { $gt: res[0] }
}
}
]
filter.modes = [view.ids.FilterBefore, view.ids.FilterAfter]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
function click (value: number): void {
@@ -27,29 +27,8 @@
export let filter: Filter
export let onChange: (e: Filter) => void
filter.modes = [
{
label: view.string.FilterIs,
isAvailable: (res: any[]) => res.length <= 1,
result: async (res: [any, any[]][]) => {
return { $in: res.map((p) => p[1]).flat() }
}
},
{
label: view.string.FilterIsEither,
isAvailable: (res: any[]) => res.length > 1,
result: async (res: [any, any[]][]) => {
return { $in: res.map((p) => p[1]).flat() }
}
},
{
label: view.string.FilterIsNot,
isAvailable: () => true,
result: async (res: [any, any[]][]) => {
return { $nin: res.map((p) => p[1]).flat() }
}
}
]
filter.modes = [view.ids.FilterValueIn, view.ids.FilterValueNin]
filter.mode = filter.mode === undefined ? filter.modes[0] : filter.mode
const client = getClient()
const key = { key: filter.key.key }
@@ -109,12 +88,6 @@
return values.has(value)
}
function checkMode () {
if (filter.mode?.isAvailable(filter.value)) return
const newMode = filter.modes.find((p) => p.isAvailable(filter.value))
filter.mode = newMode !== undefined ? newMode : filter.mode
}
function toggle (value: any): void {
if (isSelected(value, selectedValues)) {
selectedValues.delete(value)
@@ -197,7 +170,6 @@
filter.value = Array.from(selectedValues.values()).map((p) => {
return [p, Array.from(realValues.get(p) ?? [])]
})
checkMode()
onChange(filter)
dispatch('close')
}}
+33
View File
@@ -13,6 +13,7 @@
// limitations under the License.
//
import { ObjQueryType } from '@anticrm/core'
import { Resources } from '@anticrm/platform'
import { getEventPopupPositionElement, PopupAlignment } from '@anticrm/ui'
import { actionImpl } from './actionImpl'
@@ -80,6 +81,30 @@ export {
ClassAttributeBar
}
export async function objectInResult (res: any[]): Promise<ObjQueryType<any>> {
return { $in: res }
}
export async function objectNinResult (res: any[]): Promise<ObjQueryType<any>> {
return { $nin: res }
}
export async function valueInResult (res: any[]): Promise<ObjQueryType<any>> {
return { $in: res.map((p) => p[1]).flat() }
}
export async function valueNinResult (res: any[]): Promise<ObjQueryType<any>> {
return { $nin: res.map((p) => p[1]).flat() }
}
export async function beforeResult (res: any[]): Promise<ObjQueryType<any>> {
return { $lt: res[0] }
}
export async function afterResult (res: any[]): Promise<ObjQueryType<any>> {
return { $gt: res[0] }
}
export default async (): Promise<Resources> => ({
actionImpl: actionImpl,
component: {
@@ -112,5 +137,13 @@ export default async (): Promise<Resources> => ({
},
popup: {
PositionElementAlignment
},
function: {
FilterObjectInResult: objectInResult,
FilterObjectNinResult: objectNinResult,
FilterValueInResult: valueInResult,
FilterValueNinResult: valueNinResult,
FilterBeforeResult: beforeResult,
FilterAfterResult: afterResult
}
})
-1
View File
@@ -39,7 +39,6 @@ export default mergeIds(viewId, view, {
RestoreDefaults: '' as IntlString,
Filter: '' as IntlString,
ClearFilters: '' as IntlString,
FilterIs: '' as IntlString,
FilterIsNot: '' as IntlString,
FilterIsEither: '' as IntlString,
FilterStatesCount: '' as IntlString,
+16 -10
View File
@@ -30,10 +30,8 @@ import type {
Type,
UXObject
} from '@anticrm/core'
import type { Asset, IntlString, Plugin, Resource, Status } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
import { PopupAlignment, PopupPosAlignment } from '@anticrm/ui/src/types'
import { Asset, IntlString, Plugin, plugin, Resource, Status } from '@anticrm/platform'
import type { AnyComponent, AnySvelteComponent, PopupAlignment, PopupPosAlignment } from '@anticrm/ui'
import type { Preference } from '@anticrm/preference'
/**
@@ -49,10 +47,9 @@ export interface KeyFilter {
/**
* @public
*/
export interface FilterMode {
export interface FilterMode extends Doc {
label: IntlString
isAvailable: (values: any[]) => boolean
result: (values: any[], onUpdate: () => void) => Promise<ObjQueryType<any>>
result: Resource<(values: any[], onUpdate: () => void, index: number) => Promise<ObjQueryType<any>>>
}
/**
@@ -60,8 +57,8 @@ export interface FilterMode {
*/
export interface Filter {
key: KeyFilter
mode: FilterMode
modes: FilterMode[]
mode: Ref<FilterMode>
modes: Ref<FilterMode>[]
value: any[]
index: number
onRemove?: () => void
@@ -387,7 +384,8 @@ const view = plugin(viewId, {
Viewlet: '' as Ref<Class<Viewlet>>,
Action: '' as Ref<Class<Action>>,
ActionCategory: '' as Ref<Class<ActionCategory>>,
LinkPresenter: '' as Ref<Class<LinkPresenter>>
LinkPresenter: '' as Ref<Class<LinkPresenter>>,
FilterMode: '' as Ref<Class<FilterMode>>
},
viewlet: {
Table: '' as Ref<ViewletDescriptor>
@@ -422,6 +420,14 @@ const view = plugin(viewId, {
Editor: '' as Ref<ActionCategory>,
MarkdownFormatting: '' as Ref<ActionCategory>
},
ids: {
FilterObjectIn: '' as Ref<FilterMode>,
FilterObjectNin: '' as Ref<FilterMode>,
FilterValueIn: '' as Ref<FilterMode>,
FilterValueNin: '' as Ref<FilterMode>,
FilterBefore: '' as Ref<FilterMode>,
FilterAfter: '' as Ref<FilterMode>
},
popup: {
PositionElementAlignment: '' as Resource<(e?: Event) => PopupAlignment | undefined>
},