test: add some tests for page filter (#2593)
This commit is contained in:
@@ -5,7 +5,7 @@ import type {
|
|||||||
View,
|
View,
|
||||||
} from '@affine/component/page-list';
|
} from '@affine/component/page-list';
|
||||||
import {
|
import {
|
||||||
filterByView,
|
filterByFilterList,
|
||||||
PageList,
|
PageList,
|
||||||
PageListTrashView,
|
PageListTrashView,
|
||||||
} from '@affine/component/page-list';
|
} from '@affine/component/page-list';
|
||||||
@@ -92,10 +92,10 @@ export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({
|
|||||||
if (!view) {
|
if (!view) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return filterByView(view, {
|
return filterByFilterList(view.filterList, {
|
||||||
Favorite: !!pageMeta.favorite,
|
Favorite: !!pageMeta.favorite,
|
||||||
Created: pageMeta.createDate,
|
Created: pageMeta.createDate,
|
||||||
Updated: pageMeta.updatedDate,
|
Updated: pageMeta.updatedDate ?? pageMeta.createDate,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
[pageMetas, listType, view]
|
[pageMetas, listType, view]
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/**
|
||||||
|
* @vitest-environment happy-dom
|
||||||
|
*/
|
||||||
|
import 'fake-indexeddb/auto';
|
||||||
|
|
||||||
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import { Condition } from '../filter/condition';
|
||||||
|
import { tBoolean, tDate } from '../filter/logical/custom-type';
|
||||||
|
import type {
|
||||||
|
Filter,
|
||||||
|
FilterMatcherDataType,
|
||||||
|
LiteralValue,
|
||||||
|
Ref,
|
||||||
|
VariableMap,
|
||||||
|
} from '../filter/vars';
|
||||||
|
import { filterMatcher, toLiteral } from '../filter/vars';
|
||||||
|
import { filterByFilterList } from '../use-all-page-setting';
|
||||||
|
|
||||||
|
const ref = (name: keyof VariableMap): Ref => {
|
||||||
|
return {
|
||||||
|
type: 'ref',
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const mockVariableMap = (vars: Partial<VariableMap>): VariableMap => {
|
||||||
|
return {
|
||||||
|
Created: 0,
|
||||||
|
Updated: 0,
|
||||||
|
Favorite: false,
|
||||||
|
...vars,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const filter = (
|
||||||
|
matcherData: FilterMatcherDataType,
|
||||||
|
left: Ref,
|
||||||
|
args: LiteralValue[]
|
||||||
|
): Filter => {
|
||||||
|
return {
|
||||||
|
type: 'filter',
|
||||||
|
left,
|
||||||
|
funcName: matcherData.name,
|
||||||
|
args: args.map(toLiteral),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
describe('match filter', () => {
|
||||||
|
test('boolean variable will match `is` filter', () => {
|
||||||
|
const is = filterMatcher
|
||||||
|
.allMatchedData(tBoolean.create())
|
||||||
|
.find(v => v.name === 'is');
|
||||||
|
expect(is?.name).toBe('is');
|
||||||
|
});
|
||||||
|
test('Date variable will match `before` filter', () => {
|
||||||
|
const before = filterMatcher
|
||||||
|
.allMatchedData(tDate.create())
|
||||||
|
.find(v => v.name === 'before');
|
||||||
|
expect(before?.name).toBe('before');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('eval filter', () => {
|
||||||
|
test('before', async () => {
|
||||||
|
const before = filterMatcher.findData(v => v.name === 'before');
|
||||||
|
assertExists(before);
|
||||||
|
const filter1 = filter(before, ref('Created'), [
|
||||||
|
new Date(2023, 5, 28).getTime(),
|
||||||
|
]);
|
||||||
|
const filter2 = filter(before, ref('Created'), [
|
||||||
|
new Date(2023, 5, 30).getTime(),
|
||||||
|
]);
|
||||||
|
const filter3 = filter(before, ref('Created'), [
|
||||||
|
new Date(2023, 5, 29).getTime(),
|
||||||
|
]);
|
||||||
|
const varMap = mockVariableMap({
|
||||||
|
Created: new Date(2023, 5, 29).getTime(),
|
||||||
|
});
|
||||||
|
expect(filterByFilterList([filter1], varMap)).toBe(false);
|
||||||
|
expect(filterByFilterList([filter2], varMap)).toBe(true);
|
||||||
|
expect(filterByFilterList([filter3], varMap)).toBe(false);
|
||||||
|
});
|
||||||
|
test('after', async () => {
|
||||||
|
const after = filterMatcher.findData(v => v.name === 'after');
|
||||||
|
assertExists(after);
|
||||||
|
const filter1 = filter(after, ref('Created'), [
|
||||||
|
new Date(2023, 5, 28).getTime(),
|
||||||
|
]);
|
||||||
|
const filter2 = filter(after, ref('Created'), [
|
||||||
|
new Date(2023, 5, 30).getTime(),
|
||||||
|
]);
|
||||||
|
const filter3 = filter(after, ref('Created'), [
|
||||||
|
new Date(2023, 5, 29).getTime(),
|
||||||
|
]);
|
||||||
|
const varMap = mockVariableMap({
|
||||||
|
Created: new Date(2023, 5, 29).getTime(),
|
||||||
|
});
|
||||||
|
expect(filterByFilterList([filter1], varMap)).toBe(true);
|
||||||
|
expect(filterByFilterList([filter2], varMap)).toBe(false);
|
||||||
|
expect(filterByFilterList([filter3], varMap)).toBe(false);
|
||||||
|
});
|
||||||
|
test('is', async () => {
|
||||||
|
const is = filterMatcher.findData(v => v.name === 'is');
|
||||||
|
assertExists(is);
|
||||||
|
const filter1 = filter(is, ref('Favorite'), [false]);
|
||||||
|
const filter2 = filter(is, ref('Favorite'), [true]);
|
||||||
|
const varMap = mockVariableMap({
|
||||||
|
Favorite: true,
|
||||||
|
});
|
||||||
|
expect(filterByFilterList([filter1], varMap)).toBe(false);
|
||||||
|
expect(filterByFilterList([filter2], varMap)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('render filter', () => {
|
||||||
|
test('boolean condition value change', async () => {
|
||||||
|
const is = filterMatcher.match(tBoolean.create());
|
||||||
|
assertExists(is);
|
||||||
|
const Wrapper = () => {
|
||||||
|
const [value, onChange] = useState(filter(is, ref('Favorite'), [true]));
|
||||||
|
return <Condition value={value} onChange={onChange} />;
|
||||||
|
};
|
||||||
|
const result = render(<Wrapper />);
|
||||||
|
const dom = await result.findByText('true');
|
||||||
|
dom.click();
|
||||||
|
await result.findByText('false');
|
||||||
|
result.unmount();
|
||||||
|
});
|
||||||
|
test('date condition function change', async () => {
|
||||||
|
const dateFunction = filterMatcher.match(tDate.create());
|
||||||
|
assertExists(dateFunction);
|
||||||
|
const Wrapper = () => {
|
||||||
|
const [value, onChange] = useState(
|
||||||
|
filter(dateFunction, ref('Created'), [new Date(2023, 5, 29).getTime()])
|
||||||
|
);
|
||||||
|
return <Condition value={value} onChange={onChange} />;
|
||||||
|
};
|
||||||
|
const result = render(<Wrapper />);
|
||||||
|
const dom = await result.findByTestId('filter-name');
|
||||||
|
dom.click();
|
||||||
|
await result.findByTestId('filter-name');
|
||||||
|
result.unmount();
|
||||||
|
});
|
||||||
|
test('date condition variable change', async () => {
|
||||||
|
const dateFunction = filterMatcher.match(tDate.create());
|
||||||
|
assertExists(dateFunction);
|
||||||
|
const Wrapper = () => {
|
||||||
|
const [value, onChange] = useState(
|
||||||
|
filter(dateFunction, ref('Created'), [new Date(2023, 5, 29).getTime()])
|
||||||
|
);
|
||||||
|
return <Condition value={value} onChange={onChange} />;
|
||||||
|
};
|
||||||
|
const result = render(<Wrapper />);
|
||||||
|
const dom = await result.findByTestId('variable-name');
|
||||||
|
dom.click();
|
||||||
|
await result.findByTestId('variable-name');
|
||||||
|
result.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -7,6 +7,7 @@ import { renderHook } from '@testing-library/react';
|
|||||||
import { RESET } from 'jotai/utils';
|
import { RESET } from 'jotai/utils';
|
||||||
import { expect, test } from 'vitest';
|
import { expect, test } from 'vitest';
|
||||||
|
|
||||||
|
import { createDefaultFilter, vars } from '../filter/vars';
|
||||||
import { useAllPageSetting } from '../use-all-page-setting';
|
import { useAllPageSetting } from '../use-all-page-setting';
|
||||||
|
|
||||||
test('useAllPageSetting', async () => {
|
test('useAllPageSetting', async () => {
|
||||||
@@ -15,32 +16,12 @@ test('useAllPageSetting', async () => {
|
|||||||
expect(settingHook.result.current.savedViews).toEqual([]);
|
expect(settingHook.result.current.savedViews).toEqual([]);
|
||||||
settingHook.result.current.setCurrentView(view => ({
|
settingHook.result.current.setCurrentView(view => ({
|
||||||
...view,
|
...view,
|
||||||
filterList: [
|
filterList: [createDefaultFilter(vars[0])],
|
||||||
{
|
|
||||||
type: 'filter',
|
|
||||||
left: {
|
|
||||||
type: 'ref',
|
|
||||||
name: 'Created',
|
|
||||||
},
|
|
||||||
funcName: 'Create',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}));
|
}));
|
||||||
settingHook.rerender();
|
settingHook.rerender();
|
||||||
const nextView = settingHook.result.current.currentView;
|
const nextView = settingHook.result.current.currentView;
|
||||||
expect(nextView).not.toBe(prevView);
|
expect(nextView).not.toBe(prevView);
|
||||||
expect(nextView.filterList).toEqual([
|
expect(nextView.filterList).toEqual([createDefaultFilter(vars[0])]);
|
||||||
{
|
|
||||||
type: 'filter',
|
|
||||||
left: {
|
|
||||||
type: 'ref',
|
|
||||||
name: 'Created',
|
|
||||||
},
|
|
||||||
funcName: 'Create',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
settingHook.result.current.setCurrentView(RESET);
|
settingHook.result.current.setCurrentView(RESET);
|
||||||
await settingHook.result.current.createView({
|
await settingHook.result.current.createView({
|
||||||
...settingHook.result.current.currentView,
|
...settingHook.result.current.currentView,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Menu, MenuItem } from '../../../ui/menu';
|
|||||||
import { literalMatcher } from './literal-matcher';
|
import { literalMatcher } from './literal-matcher';
|
||||||
import type { TFunction, TType } from './logical/typesystem';
|
import type { TFunction, TType } from './logical/typesystem';
|
||||||
import type { Filter, Literal } from './vars';
|
import type { Filter, Literal } from './vars';
|
||||||
import { ChangeFilterMenu, filterMatcher, vars } from './vars';
|
import { filterMatcher, VariableSelect, vars } from './vars';
|
||||||
|
|
||||||
export const Condition = ({
|
export const Condition = ({
|
||||||
value,
|
value,
|
||||||
@@ -31,15 +31,20 @@ export const Condition = ({
|
|||||||
>
|
>
|
||||||
<Menu
|
<Menu
|
||||||
trigger="click"
|
trigger="click"
|
||||||
content={<ChangeFilterMenu selected={[]} onSelect={onChange} />}
|
content={<VariableSelect selected={[]} onSelect={onChange} />}
|
||||||
>
|
>
|
||||||
<div>{ast.left.name}</div>
|
<div data-testid="variable-name">{ast.left.name}</div>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu
|
<Menu
|
||||||
trigger="click"
|
trigger="click"
|
||||||
content={<FunctionSelect value={value} onChange={onChange} />}
|
content={<FunctionSelect value={value} onChange={onChange} />}
|
||||||
>
|
>
|
||||||
<div style={{ marginLeft: 4, color: 'gray' }}>{ast.funcName}</div>
|
<div
|
||||||
|
style={{ marginLeft: 4, color: 'gray' }}
|
||||||
|
data-testid="filter-name"
|
||||||
|
>
|
||||||
|
{ast.funcName}
|
||||||
|
</div>
|
||||||
</Menu>
|
</Menu>
|
||||||
{args}
|
{args}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ literalMatcher.register(tDate.create(), {
|
|||||||
onChange={e => {
|
onChange={e => {
|
||||||
onChange({
|
onChange({
|
||||||
type: 'literal',
|
type: 'literal',
|
||||||
value: dayjs(e.target.value, 'YYYY-MM-DD'),
|
value: dayjs(e.target.value, 'YYYY-MM-DD').millisecond(),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -34,14 +34,7 @@ export class Matcher<Data, Type extends TType = TType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allMatchedData(type: TType): Data[] {
|
allMatchedData(type: TType): Data[] {
|
||||||
const match = this._match ?? typesystem.isSubtype.bind(typesystem);
|
return this.allMatched(type).map(v => v.data);
|
||||||
const result: Data[] = [];
|
|
||||||
for (const t of this.list) {
|
|
||||||
if (match(t.type, type)) {
|
|
||||||
result.push(t.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findData(f: (data: Data) => boolean): Data | undefined {
|
findData(f: (data: Data) => boolean): Data | undefined {
|
||||||
|
|||||||
@@ -267,7 +267,6 @@ export class Typesystem {
|
|||||||
template: TFunction
|
template: TFunction
|
||||||
): TFunction {
|
): TFunction {
|
||||||
const ctx = { ...context };
|
const ctx = { ...context };
|
||||||
console.log(template);
|
|
||||||
template.args.forEach((arg, i) => {
|
template.args.forEach((arg, i) => {
|
||||||
const realArg = realArgs[i];
|
const realArg = realArgs[i];
|
||||||
if (realArg) {
|
if (realArg) {
|
||||||
|
|||||||
@@ -18,10 +18,19 @@ export type Filter = {
|
|||||||
funcName: string;
|
funcName: string;
|
||||||
args: Literal[];
|
args: Literal[];
|
||||||
};
|
};
|
||||||
|
export type LiteralValue =
|
||||||
|
| number
|
||||||
|
| string
|
||||||
|
| boolean
|
||||||
|
| { [K: string]: LiteralValue }
|
||||||
|
| Array<LiteralValue>;
|
||||||
|
export const toLiteral = (value: LiteralValue): Literal => ({
|
||||||
|
type: 'literal',
|
||||||
|
value,
|
||||||
|
});
|
||||||
export type Literal = {
|
export type Literal = {
|
||||||
type: 'literal';
|
type: 'literal';
|
||||||
value: unknown;
|
value: LiteralValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FilterVariable = {
|
export type FilterVariable = {
|
||||||
@@ -45,7 +54,9 @@ export const variableDefineMap = {
|
|||||||
// type: tBoolean.create(),
|
// type: tBoolean.create(),
|
||||||
// },
|
// },
|
||||||
} as const;
|
} as const;
|
||||||
export type VariableMap = { [K in keyof typeof variableDefineMap]: unknown };
|
export type VariableMap = {
|
||||||
|
[K in keyof typeof variableDefineMap]: LiteralValue;
|
||||||
|
};
|
||||||
export const vars: FilterVariable[] = Object.entries(variableDefineMap).map(
|
export const vars: FilterVariable[] = Object.entries(variableDefineMap).map(
|
||||||
([key, value]) => ({
|
([key, value]) => ({
|
||||||
name: key as keyof VariableMap,
|
name: key as keyof VariableMap,
|
||||||
@@ -53,7 +64,7 @@ export const vars: FilterVariable[] = Object.entries(variableDefineMap).map(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const createDefaultFilter = (variable: FilterVariable): Filter => {
|
export const createDefaultFilter = (variable: FilterVariable): Filter => {
|
||||||
const data = filterMatcher.match(variable.type);
|
const data = filterMatcher.match(variable.type);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
throw new Error('No matching function found');
|
throw new Error('No matching function found');
|
||||||
@@ -74,7 +85,7 @@ export const CreateFilterMenu = ({
|
|||||||
onChange: (value: Filter[]) => void;
|
onChange: (value: Filter[]) => void;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ChangeFilterMenu
|
<VariableSelect
|
||||||
selected={value}
|
selected={value}
|
||||||
onSelect={filter => {
|
onSelect={filter => {
|
||||||
onChange([...value, filter]);
|
onChange([...value, filter]);
|
||||||
@@ -83,7 +94,7 @@ export const CreateFilterMenu = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ChangeFilterMenu = ({
|
export const VariableSelect = ({
|
||||||
onSelect,
|
onSelect,
|
||||||
}: {
|
}: {
|
||||||
selected: Filter[];
|
selected: Filter[];
|
||||||
@@ -107,22 +118,22 @@ export const ChangeFilterMenu = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterMatcher = new Matcher<
|
export type FilterMatcherDataType = {
|
||||||
{
|
name: string;
|
||||||
name: string;
|
defaultArgs: () => LiteralValue[];
|
||||||
defaultArgs: () => unknown[];
|
render?: (props: { ast: Filter }) => ReactNode;
|
||||||
render?: (props: { ast: Filter }) => ReactNode;
|
impl: (...args: LiteralValue[]) => boolean;
|
||||||
impl: (...args: unknown[]) => boolean;
|
};
|
||||||
},
|
export const filterMatcher = new Matcher<FilterMatcherDataType, TFunction>(
|
||||||
TFunction
|
(type, target) => {
|
||||||
>((type, target) => {
|
const staticType = typesystem.subst(
|
||||||
const staticType = typesystem.subst(
|
Object.fromEntries(type.typeVars?.map(v => [v.name, v.bound]) ?? []),
|
||||||
Object.fromEntries(type.typeVars?.map(v => [v.name, v.bound]) ?? []),
|
type
|
||||||
type
|
);
|
||||||
);
|
const firstArg = staticType.args[0];
|
||||||
const firstArg = staticType.args[0];
|
return firstArg && typesystem.isSubtype(firstArg, target);
|
||||||
return firstArg && typesystem.isSubtype(firstArg, target);
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
filterMatcher.register(
|
filterMatcher.register(
|
||||||
tFunction({
|
tFunction({
|
||||||
@@ -143,13 +154,13 @@ filterMatcher.register(
|
|||||||
{
|
{
|
||||||
name: 'after',
|
name: 'after',
|
||||||
defaultArgs: () => {
|
defaultArgs: () => {
|
||||||
return [dayjs().subtract(1, 'day').endOf('day')];
|
return [dayjs().subtract(1, 'day').endOf('day').millisecond()];
|
||||||
},
|
},
|
||||||
impl: (date, target) => {
|
impl: (date, target) => {
|
||||||
if (typeof date !== 'number' || !dayjs.isDayjs(target)) {
|
if (typeof date !== 'number' || typeof target !== 'number') {
|
||||||
throw new Error('argument type error');
|
throw new Error('argument type error');
|
||||||
}
|
}
|
||||||
return dayjs(date).isAfter(target.endOf('day'));
|
return dayjs(date).isAfter(dayjs(target).endOf('day'));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -158,12 +169,12 @@ filterMatcher.register(
|
|||||||
tFunction({ args: [tDate.create(), tDate.create()], rt: tBoolean.create() }),
|
tFunction({ args: [tDate.create(), tDate.create()], rt: tBoolean.create() }),
|
||||||
{
|
{
|
||||||
name: 'before',
|
name: 'before',
|
||||||
defaultArgs: () => [dayjs().endOf('day')],
|
defaultArgs: () => [dayjs().endOf('day').millisecond()],
|
||||||
impl: (date, target) => {
|
impl: (date, target) => {
|
||||||
if (typeof date !== 'number' || !dayjs.isDayjs(target)) {
|
if (typeof date !== 'number' || typeof target !== 'number') {
|
||||||
throw new Error('argument type error');
|
throw new Error('argument type error');
|
||||||
}
|
}
|
||||||
return dayjs(date).isBefore(target.startOf('day'));
|
return dayjs(date).isBefore(dayjs(target).startOf('day'));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import dayjs from 'dayjs';
|
|
||||||
import type { DBSchema } from 'idb';
|
import type { DBSchema } from 'idb';
|
||||||
import { openDB } from 'idb';
|
import { openDB } from 'idb';
|
||||||
import type { IDBPDatabase } from 'idb/build/entry';
|
import type { IDBPDatabase } from 'idb/build/entry';
|
||||||
@@ -10,7 +9,6 @@ import { NIL } from 'uuid';
|
|||||||
|
|
||||||
import { evalFilterList } from './filter';
|
import { evalFilterList } from './filter';
|
||||||
import type { Filter, VariableMap } from './filter/vars';
|
import type { Filter, VariableMap } from './filter/vars';
|
||||||
import type { Literal } from './filter/vars';
|
|
||||||
|
|
||||||
export type View = {
|
export type View = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -18,13 +16,7 @@ export type View = {
|
|||||||
filterList: Filter[];
|
filterList: Filter[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type PersistenceView = Omit<View, 'filterList'> & {
|
type PersistenceView = View;
|
||||||
filterList: (Omit<Filter, 'args'> & {
|
|
||||||
args: (Omit<Literal, 'value'> & {
|
|
||||||
value: string;
|
|
||||||
})[];
|
|
||||||
})[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface PageViewDBV1 extends DBSchema {
|
export interface PageViewDBV1 extends DBSchema {
|
||||||
view: {
|
view: {
|
||||||
@@ -58,17 +50,7 @@ export const useAllPageSetting = () => {
|
|||||||
fetcher: async () => {
|
fetcher: async () => {
|
||||||
const db = await pageViewDBPromise;
|
const db = await pageViewDBPromise;
|
||||||
const t = db.transaction('view').objectStore('view');
|
const t = db.transaction('view').objectStore('view');
|
||||||
const all = await t.getAll();
|
return await t.getAll();
|
||||||
return all.map(view => ({
|
|
||||||
...view,
|
|
||||||
filterList: view.filterList.map(filter => ({
|
|
||||||
...filter,
|
|
||||||
args: filter.args.map(arg => ({
|
|
||||||
...arg,
|
|
||||||
value: dayjs(arg.value),
|
|
||||||
})),
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
suspense: true,
|
suspense: true,
|
||||||
fallbackData: [],
|
fallbackData: [],
|
||||||
@@ -85,22 +67,7 @@ export const useAllPageSetting = () => {
|
|||||||
}
|
}
|
||||||
const db = await pageViewDBPromise;
|
const db = await pageViewDBPromise;
|
||||||
const t = db.transaction('view', 'readwrite').objectStore('view');
|
const t = db.transaction('view', 'readwrite').objectStore('view');
|
||||||
const persistenceView: PersistenceView = {
|
await t.put(view);
|
||||||
...view,
|
|
||||||
filterList: view.filterList.map(filter => {
|
|
||||||
return {
|
|
||||||
...filter,
|
|
||||||
args: filter.args.map(arg => {
|
|
||||||
return {
|
|
||||||
type: arg.type,
|
|
||||||
// @ts-expect-error
|
|
||||||
value: arg.value.toString(),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
await t.put(persistenceView);
|
|
||||||
await mutate();
|
await mutate();
|
||||||
},
|
},
|
||||||
[mutate]
|
[mutate]
|
||||||
@@ -115,5 +82,5 @@ export const useAllPageSetting = () => {
|
|||||||
setCurrentView,
|
setCurrentView,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export const filterByView = (view: View, varMap: VariableMap) =>
|
export const filterByFilterList = (filterList: Filter[], varMap: VariableMap) =>
|
||||||
evalFilterList(view.filterList, varMap);
|
evalFilterList(filterList, varMap);
|
||||||
|
|||||||
Reference in New Issue
Block a user