diff --git a/src/lib/components/filters/content.svelte b/src/lib/components/filters/content.svelte index cb56ca1e5..6bd854c4c 100644 --- a/src/lib/components/filters/content.svelte +++ b/src/lib/components/filters/content.svelte @@ -8,94 +8,21 @@ FormList, InputSelectCheckbox } from '$lib/elements/forms'; - import { Query } from '@appwrite.io/console'; import { createEventDispatcher, onMount } from 'svelte'; - import { tags, type Operator, queries, type TagValue } from './store'; + import { tags, queries, type TagValue, operators, addFilter } from './store'; import type { Column } from '$lib/helpers/types'; import type { Writable } from 'svelte/store'; import { tooltip } from '$lib/actions/tooltip'; + // We cast to any to not cause type errors in the input components + /* eslint @typescript-eslint/no-explicit-any: 'off' */ + export let value: any = null; export let columns: Writable; export let columnId: string | null = null; - - const dispatch = createEventDispatcher<{ - clear: void; - apply: { applied: number }; - }>(); + export let arrayValues: string[] = []; + export let operatorKey: string | null = null; $: column = $columns.find((c) => c.id === columnId) as Column; - let arrayValues: string[] = []; - - dispatch('apply', { applied: $tags.length }); - - const operators: Record = { - 'starts with': { - toQuery: Query.startsWith, - toTag: (attribute, input) => `**${attribute}** starts with **${input}**`, - types: ['string'] - }, - 'ends with': { - toQuery: Query.endsWith, - toTag: (attribute, input) => `**${attribute}** ends with **${input}**`, - types: ['string'] - }, - 'greater than': { - toQuery: (attr, input) => Query.greaterThan(attr, Number(input)), - toTag: (attribute, input) => `**${attribute}** greater than **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'greater than or equal': { - toQuery: (attr, input) => Query.greaterThanEqual(attr, Number(input)), - toTag: (attribute, input) => `**${attribute}** greater than or equal to **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'less than': { - toQuery: Query.lessThan, - toTag: (attribute, input) => `**${attribute}** less than **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - 'less than or equal': { - toQuery: Query.lessThanEqual, - toTag: (attribute, input) => `**${attribute}** less than or equal to **${input}**`, - types: ['integer', 'double', 'datetime'] - }, - equal: { - toQuery: Query.equal, - toTag: (attribute, input) => `**${attribute}** equal to **${input}**`, - types: ['string', 'integer', 'double', 'boolean'] - }, - 'not equal': { - toQuery: Query.notEqual, - toTag: (attribute, input) => `**${attribute}** not equal to **${input}**`, - types: ['string', 'integer', 'double', 'boolean'] - }, - 'is not null': { - toQuery: Query.isNotNull, - toTag: (attribute) => `**${attribute}** is not null`, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], - hideInput: true - }, - 'is null': { - toQuery: Query.isNull, - toTag: (attribute) => `**${attribute}** is null`, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], - hideInput: true - }, - contains: { - toQuery: Query.contains, - toTag: (attribute, input) => { - if (Array.isArray(input) && input.length > 2) { - return { - value: input, - tag: `**${attribute}** contains **${formatArray(input)}** ` - }; - } else { - return `**${attribute}** contains **${input}**`; - } - }, - types: ['string', 'integer', 'double', 'boolean', 'datetime', 'enum'] - } - }; $: operatorsForColumn = Object.entries(operators) .filter(([, v]) => v.types.includes(column?.type)) @@ -104,48 +31,30 @@ value: k })); - let operatorKey: string | null = null; $: operator = operatorKey ? operators[operatorKey] : null; $: { columnId; operatorKey = null; } - // We cast to any to not cause type errors in the input components - /* eslint @typescript-eslint/no-explicit-any: 'off' */ - let value: any = null; + $: isDisabled = !operator; onMount(() => { value = column?.array ? [] : null; }); - // This Map is keyed by tags, and has a query as the value - function addFilter() { - if (!column || !operator) return; - if (column.array) { - queries.addFilter({ column, operator, value: arrayValues }); - columnId = null; - arrayValues = []; - } else { - queries.addFilter({ column, operator, value: value ?? '' }); - columnId = null; - value = null; - } + function addFilterAndReset() { + addFilter($columns, columnId, operatorKey, value, arrayValues); + columnId = null; + operatorKey = null; + value = null; + arrayValues = []; } function tagFormat(node: HTMLElement) { node.innerHTML = node.innerHTML.replace(/\*\*(.*?)\*\*/g, '$1'); } - function formatArray(array: string[]) { - if (!array?.length) return; - if (array.length > 2) { - return `${array[0]} or ${array.length - 1} others`; - } else { - return array.join(' or '); - } - } - function isTypeTagValue(obj: any): obj is TagValue { if (typeof obj === 'string') return false; return ( @@ -157,11 +66,15 @@ ); } - $: isDisabled = !operator; + const dispatch = createEventDispatcher<{ + clear: void; + apply: { applied: number }; + }>(); + dispatch('apply', { applied: $tags.length });
-
+
    {/if} {/if} - diff --git a/src/lib/components/filters/filters.svelte b/src/lib/components/filters/filters.svelte index 6c60050da..45e121eb7 100644 --- a/src/lib/components/filters/filters.svelte +++ b/src/lib/components/filters/filters.svelte @@ -5,7 +5,7 @@ import type { Column } from '$lib/helpers/types'; import type { Writable } from 'svelte/store'; import Content from './content.svelte'; - import { queries, queriesAreDirty, queryParamToMap, tags } from './store'; + import { addFilter, queries, queriesAreDirty, queryParamToMap, tags } from './store'; export let query = '[]'; export let columns: Writable; @@ -15,7 +15,12 @@ const parsedQueries = queryParamToMap(query); queries.set(parsedQueries); + /* eslint @typescript-eslint/no-explicit-any: 'off' */ + let value: any = null; let selectedColumn: string | null = null; + let operatorKey: string | null = null; + let arrayValues: string[] = []; + // We need to separate them so we don't trigger Drop's handlers let showFiltersDesktop = false; let showFiltersMobile = false; @@ -33,9 +38,22 @@ queries.clearAll(); } + function apply() { + if (selectedColumn && operatorKey && value) { + addFilter($columns, selectedColumn, operatorKey, value, arrayValues); + selectedColumn = null; + value = null; + operatorKey = null; + arrayValues = []; + } + queries.apply(); + } + $: if (!showFiltersDesktop && !showFiltersMobile) { selectedColumn = null; } + + $: isButtonDisabled = $queriesAreDirty ? false : !selectedColumn || !operatorKey || !value;
    @@ -54,13 +72,16 @@

    Apply filter rules to refine the table view

    (applied = e.detail.applied)} on:clear={() => (applied = 0)} />
    - +
    @@ -85,12 +106,16 @@ size="big"> (applied = e.detail.applied)} on:clear={() => (applied = 0)} /> - + +
diff --git a/src/lib/components/filters/store.ts b/src/lib/components/filters/store.ts index 64fe6e2ad..f919a9402 100644 --- a/src/lib/components/filters/store.ts +++ b/src/lib/components/filters/store.ts @@ -4,6 +4,7 @@ import { derived, get, writable } from 'svelte/store'; import { page } from '$app/stores'; import deepEqual from 'deep-equal'; import type { Column, ColumnType } from '$lib/helpers/types'; +import { Query } from '@appwrite.io/console'; export type TagValue = { tag: string; @@ -84,3 +85,100 @@ export const hasPageQueries = derived(page, ($page) => { }); export const tags = derived(queries, ($queries) => Array.from($queries.keys())); + +/* eslint @typescript-eslint/no-explicit-any: 'off' */ +export function addFilter( + columns: Column[], + columnId: string, + operatorKey: string, + value: any, // We cast to any to not cause type errors in the input components + arrayValues: string[] = [] +) { + const operator = operatorKey ? operators[operatorKey] : null; + const column = columns.find((c) => c.id === columnId) as Column; + + if (!column || !operator) return; + if (column.array) { + queries.addFilter({ column, operator, value: arrayValues }); + } else { + queries.addFilter({ column, operator, value: value ?? '' }); + } +} + +export const operators: Record = { + 'starts with': { + toQuery: Query.startsWith, + toTag: (attribute, input) => `**${attribute}** starts with **${input}**`, + types: ['string'] + }, + 'ends with': { + toQuery: Query.endsWith, + toTag: (attribute, input) => `**${attribute}** ends with **${input}**`, + types: ['string'] + }, + 'greater than': { + toQuery: (attr, input) => Query.greaterThan(attr, Number(input)), + toTag: (attribute, input) => `**${attribute}** greater than **${input}**`, + types: ['integer', 'double', 'datetime'] + }, + 'greater than or equal': { + toQuery: (attr, input) => Query.greaterThanEqual(attr, Number(input)), + toTag: (attribute, input) => `**${attribute}** greater than or equal to **${input}**`, + types: ['integer', 'double', 'datetime'] + }, + 'less than': { + toQuery: Query.lessThan, + toTag: (attribute, input) => `**${attribute}** less than **${input}**`, + types: ['integer', 'double', 'datetime'] + }, + 'less than or equal': { + toQuery: Query.lessThanEqual, + toTag: (attribute, input) => `**${attribute}** less than or equal to **${input}**`, + types: ['integer', 'double', 'datetime'] + }, + equal: { + toQuery: Query.equal, + toTag: (attribute, input) => `**${attribute}** equal to **${input}**`, + types: ['string', 'integer', 'double', 'boolean'] + }, + 'not equal': { + toQuery: Query.notEqual, + toTag: (attribute, input) => `**${attribute}** not equal to **${input}**`, + types: ['string', 'integer', 'double', 'boolean'] + }, + 'is not null': { + toQuery: Query.isNotNull, + toTag: (attribute) => `**${attribute}** is not null`, + types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], + hideInput: true + }, + 'is null': { + toQuery: Query.isNull, + toTag: (attribute) => `**${attribute}** is null`, + types: ['string', 'integer', 'double', 'boolean', 'datetime', 'relationship'], + hideInput: true + }, + contains: { + toQuery: Query.contains, + toTag: (attribute, input) => { + if (Array.isArray(input) && input.length > 2) { + return { + value: input, + tag: `**${attribute}** contains **${formatArray(input)}** ` + }; + } else { + return `**${attribute}** contains **${input}**`; + } + }, + types: ['string', 'integer', 'double', 'boolean', 'datetime', 'enum'] + } +}; + +function formatArray(array: string[]) { + if (!array?.length) return; + if (array.length > 2) { + return `${array[0]} or ${array.length - 1} others`; + } else { + return array.join(' or '); + } +}