@webitel/ui-sdk 24.12.85 → 24.12.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -8
- package/dist/img/sprite/add-filter.svg +8 -0
- package/dist/img/sprite/index.js +2 -0
- package/dist/ui-sdk.css +1 -1
- package/dist/ui-sdk.js +1416 -1415
- package/dist/ui-sdk.umd.cjs +15 -15
- package/package.json +1 -1
- package/src/assets/icons/sprite/add-filter.svg +8 -0
- package/src/assets/icons/sprite/index.js +2 -0
- package/src/components/index.js +71 -0
- package/src/components/wt-action-bar/wt-action-bar.vue +9 -4
- package/src/components/wt-icon-action/iconMappings.js +1 -0
- package/src/components/wt-loader/_internals/wt-loader--md.vue +3 -2
- package/src/components/wt-tooltip/_internals/useTooltipTriggerSubscriptions.js +0 -1
- package/src/components/wt-tooltip/wt-tooltip.vue +4 -1
- package/src/css/main.scss +0 -1
- package/src/css/pages/table-page.scss +0 -1
- package/src/css/styleguide/placeholder/_placeholder.scss +2 -2
- package/src/enums/IconAction/IconAction.enum.js +1 -0
- package/src/locale/en/en.js +19 -0
- package/src/locale/ru/ru.js +1 -0
- package/src/locale/ua/ua.js +1 -0
- package/src/modules/Filters/v2/filters/classes/Filter.ts +30 -0
- package/src/modules/Filters/v2/filters/classes/FilterStorage.ts +34 -0
- package/src/modules/Filters/v2/filters/classes/FilterStorageOptions.d.ts +6 -0
- package/src/modules/Filters/v2/filters/classes/FiltersManager.ts +189 -0
- package/src/modules/Filters/v2/filters/components/dynamic/config/dynamic-filter-config-form.vue +146 -0
- package/src/modules/Filters/v2/filters/components/dynamic/config/dynamic-filter-config-view.vue +29 -0
- package/src/modules/Filters/v2/filters/components/dynamic/dynamic-filter-add-action.vue +41 -0
- package/src/modules/Filters/v2/filters/components/dynamic/preview/dynamic-filter-preview-info.vue +48 -0
- package/src/modules/Filters/v2/filters/components/dynamic/preview/dynamic-filter-preview.vue +61 -0
- package/src/modules/Filters/v2/filters/components/static/search-filter.vue +14 -0
- package/src/modules/Filters/v2/filters/components/table-filters-panel.vue +87 -0
- package/src/modules/Filters/v2/filters/createTableFiltersStore.ts +81 -0
- package/src/modules/Filters/v2/filters/index.ts +27 -0
- package/src/modules/Filters/v2/filters/scripts/utils.ts +31 -0
- package/src/modules/Filters/v2/filters/types/Filter.d.ts +41 -0
- package/src/modules/Filters/v2/filters/types/FiltersManager.d.ts +76 -0
- package/src/modules/Filters/v2/headers/createTableHeadersStore.ts +89 -0
- package/src/modules/Filters/v2/index.ts +0 -0
- package/src/modules/Filters/v2/pagination/createTablePaginationStore.ts +54 -0
- package/src/modules/Filters/v2/persist/PersistedStorage.types.ts +51 -0
- package/src/modules/Filters/v2/persist/useLocalStoragePersistedStorage.ts +31 -0
- package/src/modules/Filters/v2/persist/usePersistedStorage.ts +150 -0
- package/src/modules/Filters/v2/persist/useRoutePersistedStorage.ts +41 -0
- package/src/modules/Filters/v2/table/createTableStore.store.ts +180 -0
- package/src/modules/Filters/v2/types/tableStore.types.ts +60 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { computed, ref } from 'vue';
|
|
2
|
+
import { defineStore } from 'pinia';
|
|
3
|
+
import { sortToQueryAdapter } from '../../../../scripts';
|
|
4
|
+
import { SortSymbols } from '../../../../scripts/sortQueryAdapters';
|
|
5
|
+
|
|
6
|
+
export const createTableHeadersStore = (
|
|
7
|
+
namespace: string,
|
|
8
|
+
{ headers: rawHeaders },
|
|
9
|
+
) => {
|
|
10
|
+
const id = `${namespace}/headers`;
|
|
11
|
+
|
|
12
|
+
return defineStore(id, () => {
|
|
13
|
+
const headers = ref(rawHeaders);
|
|
14
|
+
|
|
15
|
+
const shownHeaders = computed(() => {
|
|
16
|
+
return headers.value.filter((header) => header.show);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const fields = computed(() => {
|
|
20
|
+
return shownHeaders.value.map((header) => header.field);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const sort = computed(() => {
|
|
24
|
+
const encodeSortQuery = ({ column, order }) =>
|
|
25
|
+
`${sortToQueryAdapter(order)}${column.field}`;
|
|
26
|
+
|
|
27
|
+
const sortedCol = headers.value.find((header) => header.sort);
|
|
28
|
+
|
|
29
|
+
return sortedCol
|
|
30
|
+
? encodeSortQuery({ column: sortedCol, order: sortedCol.sort })
|
|
31
|
+
: null;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const updateShownHeaders = () => {};
|
|
35
|
+
|
|
36
|
+
const updateSort = (column) => {
|
|
37
|
+
const getNextSortOrder = (sort) => {
|
|
38
|
+
switch (sort) {
|
|
39
|
+
case SortSymbols.NONE:
|
|
40
|
+
return SortSymbols.ASC;
|
|
41
|
+
case SortSymbols.ASC:
|
|
42
|
+
return SortSymbols.DESC;
|
|
43
|
+
case SortSymbols.DESC:
|
|
44
|
+
return SortSymbols.NONE;
|
|
45
|
+
default:
|
|
46
|
+
return SortSymbols.ASC;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const changeHeadersSort = ({ headers, sortedHeader, order }) => {
|
|
51
|
+
return headers.map((header) => {
|
|
52
|
+
if (header.sort === undefined) return header;
|
|
53
|
+
|
|
54
|
+
// reset all headers by default
|
|
55
|
+
let newSort = null;
|
|
56
|
+
|
|
57
|
+
if (header.field === sortedHeader.field) {
|
|
58
|
+
newSort = order;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
...header,
|
|
63
|
+
sort: newSort,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const order = getNextSortOrder(column.sort);
|
|
69
|
+
|
|
70
|
+
const newHeaders = changeHeadersSort({
|
|
71
|
+
headers: headers.value,
|
|
72
|
+
sortedHeader: column,
|
|
73
|
+
order,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
headers.value = newHeaders;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
headers,
|
|
81
|
+
shownHeaders,
|
|
82
|
+
fields,
|
|
83
|
+
sort,
|
|
84
|
+
|
|
85
|
+
updateShownHeaders,
|
|
86
|
+
updateSort,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { usePersistedStorage } from '../persist/usePersistedStorage.ts';
|
|
5
|
+
|
|
6
|
+
export const createTablePaginationStore = (namespace: string) => {
|
|
7
|
+
const id = `${namespace}/pagination`;
|
|
8
|
+
|
|
9
|
+
return defineStore(id, () => {
|
|
10
|
+
const page = ref(1);
|
|
11
|
+
const size = ref(10);
|
|
12
|
+
const next = ref(false);
|
|
13
|
+
|
|
14
|
+
const updatePage = (newPage: number) => {
|
|
15
|
+
page.value = newPage;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const updateSize = (newSize: number) => {
|
|
19
|
+
size.value = newSize;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const $reset = () => {
|
|
23
|
+
page.value = 1;
|
|
24
|
+
size.value = 10;
|
|
25
|
+
next.value = false;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const setupPersistence = async () => {
|
|
29
|
+
const { restore: restorePage } = usePersistedStorage({
|
|
30
|
+
name: 'page',
|
|
31
|
+
value: page,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const { restore: restoreSize } = usePersistedStorage({
|
|
35
|
+
name: 'size',
|
|
36
|
+
value: size,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return Promise.allSettled([restorePage(), restoreSize()]);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
page,
|
|
44
|
+
size,
|
|
45
|
+
next,
|
|
46
|
+
|
|
47
|
+
updatePage,
|
|
48
|
+
updateSize,
|
|
49
|
+
|
|
50
|
+
setupPersistence,
|
|
51
|
+
$reset,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Ref, WatchOptions } from 'vue';
|
|
2
|
+
|
|
3
|
+
export enum PersistedStorageType {
|
|
4
|
+
LocalStorage = 'localStorage',
|
|
5
|
+
Route = 'route',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// in route query, or in localStorage
|
|
9
|
+
export type PersistStorableValue = string;
|
|
10
|
+
|
|
11
|
+
export type PersistableValue =
|
|
12
|
+
| PersistStorableValue
|
|
13
|
+
| { toString: () => PersistStorableValue };
|
|
14
|
+
|
|
15
|
+
export interface StorageLike {
|
|
16
|
+
getItem(key: string): Promise<PersistableValue | null>;
|
|
17
|
+
|
|
18
|
+
setItem(key: string, value: PersistableValue): Promise<void>;
|
|
19
|
+
|
|
20
|
+
removeItem(key: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface PersistedPropertyConfig {
|
|
24
|
+
name: string;
|
|
25
|
+
value: Ref<PersistableValue>;
|
|
26
|
+
storages?: PersistedStorageType | PersistedStorageType[];
|
|
27
|
+
storagePath?: string;
|
|
28
|
+
startWatchManually?: boolean;
|
|
29
|
+
watchConfig?: WatchOptions;
|
|
30
|
+
onStore?: (
|
|
31
|
+
save: ({
|
|
32
|
+
name,
|
|
33
|
+
value,
|
|
34
|
+
}: {
|
|
35
|
+
name: string;
|
|
36
|
+
value: PersistableValue;
|
|
37
|
+
}) => Promise<void>,
|
|
38
|
+
{ value, name },
|
|
39
|
+
) => Promise<void>;
|
|
40
|
+
onRestore?: (
|
|
41
|
+
restore: (name: string) => Promise<PersistableValue>,
|
|
42
|
+
name: string,
|
|
43
|
+
) => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface PersistedStorageController {
|
|
47
|
+
watch: () => void;
|
|
48
|
+
unwatch: () => void;
|
|
49
|
+
restore: () => Promise<void>;
|
|
50
|
+
reset: () => Promise<void>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { StorageLike } from './PersistedStorage.types.ts';
|
|
2
|
+
|
|
3
|
+
const separator = ';';
|
|
4
|
+
|
|
5
|
+
const makePath = (storagePath: string, key: string) => `${storagePath}/${key}`;
|
|
6
|
+
|
|
7
|
+
export const useLocalStoragePersistedStorage = ({ storagePath = '' }: { storagePath: string }): StorageLike => {
|
|
8
|
+
const getItem = async (key: string) => {
|
|
9
|
+
const value = localStorage.getItem(makePath(storagePath, key));
|
|
10
|
+
try {
|
|
11
|
+
return value.split(separator);
|
|
12
|
+
} catch {
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const setItem = async (key: string, inputValue: string | string[]) => {
|
|
18
|
+
const value = Array.isArray(inputValue) ? inputValue.join(separator) : inputValue;
|
|
19
|
+
localStorage.setItem(makePath(storagePath, key), value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const removeItem = async (key: string) => {
|
|
23
|
+
localStorage.removeItem(makePath(storagePath, key));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
getItem,
|
|
28
|
+
setItem,
|
|
29
|
+
removeItem,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PersistableValue,
|
|
5
|
+
PersistedPropertyConfig,
|
|
6
|
+
PersistedStorageController,
|
|
7
|
+
PersistedStorageType,
|
|
8
|
+
} from './PersistedStorage.types.ts';
|
|
9
|
+
import { useLocalStoragePersistedStorage } from './useLocalStoragePersistedStorage.ts';
|
|
10
|
+
import { useRoutePersistedStorage } from './useRoutePersistedStorage.ts';
|
|
11
|
+
|
|
12
|
+
export const usePersistedStorage = ({
|
|
13
|
+
name,
|
|
14
|
+
value,
|
|
15
|
+
storages: configStorages = [PersistedStorageType.Route],
|
|
16
|
+
storagePath,
|
|
17
|
+
startWatchManually = false,
|
|
18
|
+
onStore,
|
|
19
|
+
onRestore,
|
|
20
|
+
}: PersistedPropertyConfig): PersistedStorageController => {
|
|
21
|
+
let unwatch = null;
|
|
22
|
+
|
|
23
|
+
const setItemFns = [];
|
|
24
|
+
const getItemFns: Array<(name: string) => Promise<PersistableValue>> = [];
|
|
25
|
+
const removeItemFns = [];
|
|
26
|
+
|
|
27
|
+
const composedValueGetter = async (name: string): Promise<PersistableValue[]> => {
|
|
28
|
+
const settledResults = await Promise.allSettled(
|
|
29
|
+
getItemFns.map((getter) => getter(name))
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return settledResults.reduce((acc, result) => {
|
|
33
|
+
if (result.status === 'fulfilled') {
|
|
34
|
+
return [...acc, result.value];
|
|
35
|
+
}
|
|
36
|
+
return acc;
|
|
37
|
+
}, []);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const storages = Array.isArray(configStorages)
|
|
41
|
+
? configStorages
|
|
42
|
+
: [configStorages];
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
order matters, as the first storage in the list has the highest priority
|
|
46
|
+
*/
|
|
47
|
+
if (storages.includes(PersistedStorageType.Route)) {
|
|
48
|
+
const { setItem, getItem, removeItem } = useRoutePersistedStorage();
|
|
49
|
+
setItemFns.push(setItem);
|
|
50
|
+
getItemFns.push(getItem);
|
|
51
|
+
removeItemFns.push(removeItem);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (storages.includes(PersistedStorageType.LocalStorage)) {
|
|
55
|
+
const { setItem, getItem, removeItem } = useLocalStoragePersistedStorage({
|
|
56
|
+
storagePath,
|
|
57
|
+
});
|
|
58
|
+
setItemFns.push(setItem);
|
|
59
|
+
getItemFns.push(getItem);
|
|
60
|
+
removeItemFns.push(removeItem);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const startWatch = () => {
|
|
64
|
+
unwatch = watch(value, async () => {
|
|
65
|
+
/*
|
|
66
|
+
if onStore callback is provided,
|
|
67
|
+
call custom logic for storing value
|
|
68
|
+
*/
|
|
69
|
+
if (onStore) {
|
|
70
|
+
/*
|
|
71
|
+
wrap all setItemFns in one callback
|
|
72
|
+
so that onStore is called only once on each value change
|
|
73
|
+
*/
|
|
74
|
+
const save = async ({ name, value: storedValue }) => {
|
|
75
|
+
// await Promise.allSettled(
|
|
76
|
+
// setItemFns.map((setItem) => {
|
|
77
|
+
// return setItem({ name, value: storedValue });
|
|
78
|
+
// }),
|
|
79
|
+
// );
|
|
80
|
+
setItemFns.forEach((setter) => {
|
|
81
|
+
setter(name, storedValue);
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
await onStore(save, { name, value });
|
|
85
|
+
} else {
|
|
86
|
+
/*
|
|
87
|
+
else, perform default storing logic
|
|
88
|
+
*/
|
|
89
|
+
const storedValue = value.value;
|
|
90
|
+
setItemFns.forEach((setter) => {
|
|
91
|
+
setter(name, storedValue);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}, { deep: true });
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const restore = async () => {
|
|
98
|
+
/*
|
|
99
|
+
if onRestore callback is provided,
|
|
100
|
+
call custom logic for restoring value
|
|
101
|
+
*/
|
|
102
|
+
if (onRestore) {
|
|
103
|
+
/*
|
|
104
|
+
wrap all getItemFns in one callback
|
|
105
|
+
so that onRestore is called only once on each value change
|
|
106
|
+
*/
|
|
107
|
+
const restore = async (name: string) => {
|
|
108
|
+
const restoredValues = await composedValueGetter(name);
|
|
109
|
+
/*
|
|
110
|
+
not sure if value to restore should be picked automatically
|
|
111
|
+
before running onRestore
|
|
112
|
+
*/
|
|
113
|
+
return restoredValues.find((value) => {
|
|
114
|
+
return value !== null;
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
await onRestore(restore, name);
|
|
118
|
+
} else {
|
|
119
|
+
/*
|
|
120
|
+
else, perform default restoring logic
|
|
121
|
+
*/
|
|
122
|
+
const restoredValues = await composedValueGetter(name);
|
|
123
|
+
const restoredValue = restoredValues.find((value) => value !== null);
|
|
124
|
+
|
|
125
|
+
if (restoredValue !== undefined) {
|
|
126
|
+
value.value = restoredValue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/*
|
|
130
|
+
start watching after restoring value to prevent restored value
|
|
131
|
+
from storing again
|
|
132
|
+
*/
|
|
133
|
+
if (!startWatchManually) {
|
|
134
|
+
startWatch();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const reset = async () => {
|
|
139
|
+
await Promise.all(removeItemFns.map((removeItem) => removeItem(name)));
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const endWatch = () => unwatch && unwatch();
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
watch: startWatch,
|
|
146
|
+
unwatch: endWatch,
|
|
147
|
+
restore,
|
|
148
|
+
reset,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
2
|
+
|
|
3
|
+
import { StorageLike } from './PersistedStorage.types.ts';
|
|
4
|
+
|
|
5
|
+
export const useRoutePersistedStorage = (): StorageLike => {
|
|
6
|
+
const router = useRouter();
|
|
7
|
+
const route = useRoute();
|
|
8
|
+
|
|
9
|
+
const getItem = async (key: string) => {
|
|
10
|
+
return route.query[key];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const setItem = async (key: string, value: string | string[]) => {
|
|
14
|
+
await router.replace({
|
|
15
|
+
name: route.name,
|
|
16
|
+
params: route.params,
|
|
17
|
+
hash: route.hash,
|
|
18
|
+
query: {
|
|
19
|
+
...route.query,
|
|
20
|
+
[key]: value,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const removeItem = async (key: string) => {
|
|
26
|
+
const query = { ...route.query };
|
|
27
|
+
delete query[key];
|
|
28
|
+
await router.replace({
|
|
29
|
+
name: route.name,
|
|
30
|
+
params: route.params,
|
|
31
|
+
hash: route.hash,
|
|
32
|
+
query,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
getItem,
|
|
38
|
+
setItem,
|
|
39
|
+
removeItem,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import set from 'lodash/fp/set';
|
|
2
|
+
import { defineStore, storeToRefs } from 'pinia';
|
|
3
|
+
import { type Ref, ref, watch } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { createTableFiltersStore } from '../filters/createTableFiltersStore.ts';
|
|
6
|
+
import { createTableHeadersStore } from '../headers/createTableHeadersStore.ts';
|
|
7
|
+
import { createTablePaginationStore } from '../pagination/createTablePaginationStore.ts';
|
|
8
|
+
import {
|
|
9
|
+
PatchItemPropertyParams,
|
|
10
|
+
TableStore,
|
|
11
|
+
useTableStoreParams,
|
|
12
|
+
} from '../types/tableStore.types.ts';
|
|
13
|
+
|
|
14
|
+
export const createTableStore = <Entity extends { id: string; etag?: string }>(
|
|
15
|
+
namespace: string,
|
|
16
|
+
{ parentId, apiModule, headers }: useTableStoreParams<Entity>,
|
|
17
|
+
) => {
|
|
18
|
+
const usePaginationStore = createTablePaginationStore(namespace);
|
|
19
|
+
const useHeadersStore = createTableHeadersStore(namespace, { headers });
|
|
20
|
+
const useFiltersStore = createTableFiltersStore(namespace);
|
|
21
|
+
|
|
22
|
+
return defineStore(namespace, (): TableStore<Entity> => {
|
|
23
|
+
const paginationStore = usePaginationStore();
|
|
24
|
+
const { page, size, next } = storeToRefs(paginationStore);
|
|
25
|
+
const {
|
|
26
|
+
updatePage,
|
|
27
|
+
updateSize,
|
|
28
|
+
// $reset: $resetPaginationStore,
|
|
29
|
+
$patch: $patchPaginationStore,
|
|
30
|
+
setupPersistence: setupPaginationPersistence,
|
|
31
|
+
} = paginationStore;
|
|
32
|
+
|
|
33
|
+
const headersStore = useHeadersStore();
|
|
34
|
+
const { headers, shownHeaders, fields, sort } = storeToRefs(headersStore);
|
|
35
|
+
const { updateSort, updateShownHeaders } = headersStore;
|
|
36
|
+
|
|
37
|
+
const filtersStore = useFiltersStore();
|
|
38
|
+
const { filtersManager, isRestoring: isFiltersRestoring } =
|
|
39
|
+
storeToRefs(filtersStore);
|
|
40
|
+
const {
|
|
41
|
+
hasFilter,
|
|
42
|
+
addFilter,
|
|
43
|
+
updateFilter,
|
|
44
|
+
deleteFilter,
|
|
45
|
+
setupPersistence: setupFiltersPersistence,
|
|
46
|
+
} = filtersStore;
|
|
47
|
+
|
|
48
|
+
const dataList: Ref<Entity[]> = ref([]);
|
|
49
|
+
const selected: Ref<Entity[]> = ref([]);
|
|
50
|
+
const error = ref(null);
|
|
51
|
+
const isLoading = ref(false);
|
|
52
|
+
|
|
53
|
+
const loadDataList = async () => {
|
|
54
|
+
isLoading.value = true;
|
|
55
|
+
$patchPaginationStore({ next: false });
|
|
56
|
+
|
|
57
|
+
const params = {
|
|
58
|
+
...filtersManager.value.getAllValues(),
|
|
59
|
+
page: page.value,
|
|
60
|
+
size: size.value,
|
|
61
|
+
sort: sort.value,
|
|
62
|
+
fields: fields.value,
|
|
63
|
+
parentId,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { items, next } = await apiModule.getList(params);
|
|
68
|
+
|
|
69
|
+
dataList.value = items;
|
|
70
|
+
$patchPaginationStore({ next });
|
|
71
|
+
} catch (err) {
|
|
72
|
+
error.value = err;
|
|
73
|
+
throw err;
|
|
74
|
+
} finally {
|
|
75
|
+
isLoading.value = false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const patchItemProperty = async ({
|
|
80
|
+
index,
|
|
81
|
+
path,
|
|
82
|
+
value,
|
|
83
|
+
}: PatchItemPropertyParams) => {
|
|
84
|
+
const item = dataList.value[index];
|
|
85
|
+
const changes = {};
|
|
86
|
+
set(path, value, changes);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await apiModule.patch({
|
|
90
|
+
changes,
|
|
91
|
+
parentId,
|
|
92
|
+
id: item.id,
|
|
93
|
+
etag: item.etag,
|
|
94
|
+
});
|
|
95
|
+
set(path, value, item);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
await loadDataList();
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const deleteEls = async (_els: Entity[]) => {
|
|
103
|
+
const els = Array.isArray(_els) ? _els : [_els];
|
|
104
|
+
const deleteEl = (el: Entity) => {
|
|
105
|
+
return apiModule.delete({ id: el.id });
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
await Promise.all(els.map(deleteEl));
|
|
110
|
+
} finally {
|
|
111
|
+
await loadDataList();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const initialize = async () => {
|
|
116
|
+
await Promise.allSettled([
|
|
117
|
+
setupPaginationPersistence(),
|
|
118
|
+
setupFiltersPersistence(),
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
let loadingAfterFiltersChange = false;
|
|
122
|
+
|
|
123
|
+
watch(
|
|
124
|
+
[() => filtersManager.value.getAllValues(), sort, size],
|
|
125
|
+
async () => {
|
|
126
|
+
loadingAfterFiltersChange = true;
|
|
127
|
+
updatePage(1);
|
|
128
|
+
await loadDataList();
|
|
129
|
+
loadingAfterFiltersChange = false;
|
|
130
|
+
},
|
|
131
|
+
/* filtersManager requires deep watching for its values */
|
|
132
|
+
{ deep: true },
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
watch([page], () => {
|
|
136
|
+
if (!loadingAfterFiltersChange) {
|
|
137
|
+
return loadDataList();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return loadDataList();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
dataList,
|
|
146
|
+
selected,
|
|
147
|
+
error,
|
|
148
|
+
isLoading,
|
|
149
|
+
|
|
150
|
+
page,
|
|
151
|
+
size,
|
|
152
|
+
next,
|
|
153
|
+
|
|
154
|
+
headers,
|
|
155
|
+
shownHeaders,
|
|
156
|
+
fields,
|
|
157
|
+
sort,
|
|
158
|
+
|
|
159
|
+
filtersManager,
|
|
160
|
+
isFiltersRestoring,
|
|
161
|
+
|
|
162
|
+
initialize,
|
|
163
|
+
|
|
164
|
+
loadDataList,
|
|
165
|
+
patchItemProperty,
|
|
166
|
+
deleteEls,
|
|
167
|
+
|
|
168
|
+
updatePage,
|
|
169
|
+
updateSize,
|
|
170
|
+
|
|
171
|
+
updateSort,
|
|
172
|
+
updateShownHeaders,
|
|
173
|
+
|
|
174
|
+
hasFilter,
|
|
175
|
+
addFilter,
|
|
176
|
+
updateFilter,
|
|
177
|
+
deleteFilter,
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
import { ApiModule } from '../../../../api/types/ApiModule.type.ts';
|
|
4
|
+
import { IFiltersManager } from '../filters';
|
|
5
|
+
|
|
6
|
+
export interface useTableStoreParams<Entity> {
|
|
7
|
+
parentId?: string;
|
|
8
|
+
apiModule: ApiModule<Entity>;
|
|
9
|
+
headers: [];
|
|
10
|
+
// etagMode: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface PatchItemPropertyParams {
|
|
14
|
+
index: number;
|
|
15
|
+
path: string;
|
|
16
|
+
value: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TableStore<Entity> {
|
|
20
|
+
// tableStore
|
|
21
|
+
dataList: Ref<Entity[]>;
|
|
22
|
+
selected: Ref<Entity[]>;
|
|
23
|
+
error: Ref<Error | null>;
|
|
24
|
+
isLoading: Ref<boolean>;
|
|
25
|
+
|
|
26
|
+
// paginationStore
|
|
27
|
+
page: Ref<number>;
|
|
28
|
+
size: Ref<number>;
|
|
29
|
+
next: Ref<boolean>;
|
|
30
|
+
|
|
31
|
+
// headersStore
|
|
32
|
+
headers: Ref<[]>;
|
|
33
|
+
shownHeaders: Ref<[]>;
|
|
34
|
+
fields: Ref<[]>;
|
|
35
|
+
sort: Ref<string>;
|
|
36
|
+
|
|
37
|
+
// filtersStore
|
|
38
|
+
filtersManager: Ref<IFiltersManager>;
|
|
39
|
+
isFiltersRestoring: Ref<boolean>;
|
|
40
|
+
|
|
41
|
+
// tableStore
|
|
42
|
+
initialize: () => Promise<void>;
|
|
43
|
+
loadDataList: (query?: object) => Promise<void>;
|
|
44
|
+
patchItemProperty: (payload: PatchItemPropertyParams) => Promise<void>;
|
|
45
|
+
deleteEls: (deleted: Entity[]) => Promise<void>;
|
|
46
|
+
|
|
47
|
+
// paginationStore
|
|
48
|
+
updatePage: (page: number) => void;
|
|
49
|
+
updateSize: (size: number) => void;
|
|
50
|
+
|
|
51
|
+
// headersStore
|
|
52
|
+
updateSort: (column: object) => void;
|
|
53
|
+
updateShownHeaders: () => void;
|
|
54
|
+
|
|
55
|
+
// filtersStore
|
|
56
|
+
hasFilter: IFiltersManager['hasFilter'];
|
|
57
|
+
addFilter: IFiltersManager['addFilter'];
|
|
58
|
+
updateFilter: IFiltersManager['updateFilter'];
|
|
59
|
+
deleteFilter: IFiltersManager['deleteFilter'];
|
|
60
|
+
}
|