@webitel/ui-datalist 1.0.34 → 1.0.36

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.
Files changed (31) hide show
  1. package/package.json +12 -2
  2. package/src/modules/_shared/createDatalistStore.ts +73 -0
  3. package/src/modules/filters/components/search-bar/dynamic-filter-search.vue +15 -11
  4. package/src/modules/filters/createTableFiltersStore.ts +82 -72
  5. package/src/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue +3 -2
  6. package/src/modules/filters/modules/filterConfig/components/case-assignee/filterConfig.ts +1 -0
  7. package/src/modules/filters/modules/filterConfig/components/case-source/config.js +2 -2
  8. package/src/modules/form/index.ts +1 -0
  9. package/src/modules/form/stores/createFormStore.ts +107 -0
  10. package/src/modules/headers/createTableHeadersStore.ts +119 -108
  11. package/src/modules/pagination/createTablePaginationStore.ts +58 -49
  12. package/src/modules/scripts/utils.ts +25 -0
  13. package/src/modules/table/createTableStore.store.ts +202 -177
  14. package/src/modules/types/StoreProvider.ts +7 -0
  15. package/src/modules/types/createDatalistStore.types.ts +38 -0
  16. package/src/modules/types/tableStore.types.ts +6 -3
  17. package/types/modules/_shared/createDatalistStore.d.ts +9 -0
  18. package/types/modules/filter-presets/stores/createFilterPresetsStore.d.ts +90 -1
  19. package/types/modules/filters/components/search-bar/dynamic-filter-search.vue.d.ts +7 -2
  20. package/types/modules/filters/createTableFiltersStore.d.ts +51 -86
  21. package/types/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue.d.ts +2 -2
  22. package/types/modules/filters/modules/filterConfig/components/case-assignee/filterConfig.d.ts +2 -2
  23. package/types/modules/form/index.d.ts +1 -0
  24. package/types/modules/form/stores/createFormStore.d.ts +126 -0
  25. package/types/modules/headers/createTableHeadersStore.d.ts +13 -14
  26. package/types/modules/pagination/createTablePaginationStore.d.ts +5 -11
  27. package/types/modules/scripts/utils.d.ts +6 -0
  28. package/types/modules/table/createTableStore.store.d.ts +185 -2
  29. package/types/modules/types/StoreProvider.d.ts +5 -0
  30. package/types/modules/types/createDatalistStore.types.d.ts +28 -0
  31. package/types/modules/types/tableStore.types.d.ts +6 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-datalist",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
4
4
  "description": "Toolkit for building data lists in webitel ui system",
5
5
  "scripts": {
6
6
  "build:types": "vue-tsc -p ./tsconfig.build.json",
@@ -29,6 +29,10 @@
29
29
  "./presets": {
30
30
  "import": "./src/modules/filter-presets/index.ts",
31
31
  "types": "./types/filter-presets/index.d.ts"
32
+ },
33
+ "./form": {
34
+ "import": "./src/modules/form/index.ts",
35
+ "types": "./types/form/index.d.ts"
32
36
  }
33
37
  },
34
38
  "files": [
@@ -44,13 +48,16 @@
44
48
  "vue": "^3.5"
45
49
  },
46
50
  "dependencies": {
51
+ "@regle/schemas": "^1.2.3",
47
52
  "@vuelidate/core": "^2.0.3",
48
53
  "@vuelidate/validators": "^2.0.4",
49
54
  "@webitel/styleguide": "^24.12.26",
50
- "@webitel/ui-sdk": "^25.4.76"
55
+ "@webitel/ui-sdk": "^25.4.76",
56
+ "zod": "^4.0.0-beta.20250505T195954"
51
57
  },
52
58
  "devDependencies": {
53
59
  "@eslint/js": "^9.22.0",
60
+ "@standard-schema/spec": "^1.0.0",
54
61
  "@tsconfig/node22": "^22.0.0",
55
62
  "@types/node": "^22.13.10",
56
63
  "@vitejs/plugin-vue": "^5.2.3",
@@ -74,6 +81,9 @@
74
81
  "vite-plugin-checker": "^0.9.0",
75
82
  "vue-tsc": "^2.2.8"
76
83
  },
84
+ "overrides": {
85
+ "zod": "^4.0.0-beta.20250505T195954"
86
+ },
77
87
  "engines": {
78
88
  "npm": "10",
79
89
  "node": "v22"
@@ -0,0 +1,73 @@
1
+ import {
2
+ defineStore as definePiniaStore,
3
+ StoreGeneric,
4
+ storeToRefs as piniaStoreToRefs,
5
+ } from 'pinia';
6
+ import { ToRefs, toRefs as composableStoreToRefs } from 'vue';
7
+
8
+ import { applyStorePatch } from '../scripts/utils';
9
+ import {
10
+ CreateDatalistStoreParams,
11
+ Identifiable,
12
+ Patch,
13
+ PatchableStore,
14
+ PatchableStoreFactory,
15
+ StoreInstance,
16
+ } from '../types/createDatalistStore.types';
17
+ import {
18
+ DatalistStoreProvider,
19
+ DatalistStoreProviderType,
20
+ } from '../types/StoreProvider';
21
+
22
+ const defaultStoreType = DatalistStoreProvider.Pinia;
23
+
24
+ /**
25
+ * makeThisToRefs converts a store object into a set of reactive references (toRefs),
26
+ * using Pinia's storeToRefs if it's a Pinia store, or Vue's toRefs for composable stores.
27
+ * */
28
+ export const makeThisToRefs = <StoreBody extends object>(
29
+ store: StoreBody,
30
+ storeType: DatalistStoreProviderType,
31
+ ): ToRefs<StoreBody> => {
32
+ const thisStoreType = storeType || defaultStoreType;
33
+
34
+ if (thisStoreType === DatalistStoreProvider.Pinia) {
35
+ return piniaStoreToRefs(store as StoreGeneric) as ToRefs<StoreBody>;
36
+ }
37
+
38
+ return composableStoreToRefs(store) as ToRefs<StoreBody>;
39
+ };
40
+
41
+ export const createDatalistStore = <
42
+ StoreBody extends StoreInstance,
43
+ G extends Identifiable,
44
+ >({
45
+ config,
46
+ namespace,
47
+ storeBody,
48
+ }: CreateDatalistStoreParams<
49
+ StoreBody,
50
+ G
51
+ >): PatchableStoreFactory<StoreBody> => {
52
+ const thisStoreType = config.storeType || defaultStoreType;
53
+
54
+ if (thisStoreType === DatalistStoreProvider.Composable) {
55
+ const storeFactory = storeBody({
56
+ ...config,
57
+ storeType: thisStoreType,
58
+ }) as PatchableStore<StoreBody>;
59
+ storeFactory.$patch = (val: Patch) => applyStorePatch(storeFactory, val);
60
+ return () => storeFactory;
61
+ }
62
+
63
+ if (thisStoreType === DatalistStoreProvider.Pinia) {
64
+ return definePiniaStore(namespace, () =>
65
+ storeBody({
66
+ ...config,
67
+ storeType: thisStoreType,
68
+ }),
69
+ );
70
+ }
71
+
72
+ throw new Error(`Unsupported store type: ${thisStoreType}`);
73
+ };
@@ -12,25 +12,26 @@
12
12
 
13
13
  <script lang="ts" setup>
14
14
  import { WtSearchBar } from '@webitel/ui-sdk/components';
15
- import {computed, type Ref, ref,watch} from 'vue';
15
+ import { computed, type Ref, ref, watch } from 'vue';
16
16
  import { useI18n } from 'vue-i18n';
17
17
 
18
- import {FilterInitParams, FilterName} from "../../classes/Filter";
19
- import {IFiltersManager} from "../../classes/FiltersManager";
18
+ import { FilterInitParams, FilterName } from '../../classes/Filter';
19
+ import { IFiltersManager } from '../../classes/FiltersManager';
20
20
  import type { DynamicFilterSearchSearchModeOption } from './types/DynamicFilterSearch';
21
21
 
22
- /**
23
- * @description
24
- * default search name is used when there are no search modes
25
- */
26
- const defaultSearchName = 'search';
27
-
28
22
  const props = defineProps<{
29
23
  filtersManager: IFiltersManager;
30
24
  searchModeOptions?: DynamicFilterSearchSearchModeOption[];
31
25
  isFiltersRestoring?: boolean;
26
+ /**
27
+ * @description
28
+ * default search name is used when there are no search modes
29
+ */
30
+ singleSearchName?: string;
32
31
  }>();
33
32
 
33
+ const defaultSearchName = props.singleSearchName || 'search';
34
+
34
35
  const emit = defineEmits<{
35
36
  'filter:add': [FilterInitParams];
36
37
  'filter:update': [FilterInitParams];
@@ -85,7 +86,9 @@ const handleSearch = (value = localSearchValue.value) => {
85
86
  }
86
87
  };
87
88
 
88
- const updateSearchMode = (nextSearchMode: DynamicFilterSearchSearchModeOption) => {
89
+ const updateSearchMode = (
90
+ nextSearchMode: DynamicFilterSearchSearchModeOption,
91
+ ) => {
89
92
  if (hasFilter(currentSearchName.value)) {
90
93
  deleteFilter({
91
94
  name: currentSearchName.value,
@@ -99,7 +102,8 @@ const updateSearchMode = (nextSearchMode: DynamicFilterSearchSearchModeOption) =
99
102
  * @description
100
103
  * Restoring search value after filters were restored
101
104
  */
102
- watch(() => props.isFiltersRestoring,
105
+ watch(
106
+ () => props.isFiltersRestoring,
103
107
  (next) => {
104
108
  if (next) return;
105
109
 
@@ -1,83 +1,93 @@
1
- import { defineStore } from 'pinia';
2
1
  import { computed, reactive, ref } from 'vue';
3
2
 
4
- import { PersistedStorageType } from '../persist/PersistedStorage.types.ts';
5
- import { usePersistedStorage } from '../persist/usePersistedStorage.ts';
3
+ import { createDatalistStore } from '../_shared/createDatalistStore';
4
+ import { PersistedStorageType } from '../persist/PersistedStorage.types';
5
+ import { usePersistedStorage } from '../persist/usePersistedStorage';
6
+ import { useTableStoreConfig } from '../types/tableStore.types';
6
7
  import {
7
8
  createFiltersManager,
8
9
  FiltersManagerConfig,
9
- } from './classes/FiltersManager.ts';
10
+ } from './classes/FiltersManager';
11
+
12
+ export const tableFiltersStoreBody = (config?: {
13
+ filtersManagerConfig: FiltersManagerConfig;
14
+ }) => {
15
+ const filtersManager = reactive(
16
+ createFiltersManager(config?.filtersManagerConfig),
17
+ );
18
+
19
+ /* for watchers in filter components */
20
+ const isRestoring = ref(false);
21
+
22
+ /*
23
+ wrapping filtersManager methods to extend their functionality
24
+ if it will be needed in future
25
+ */
26
+ const hasFilter = filtersManager.hasFilter.bind(filtersManager);
27
+ const addFilter = filtersManager.addFilter.bind(filtersManager);
28
+ const updateFilter = filtersManager.updateFilter.bind(filtersManager);
29
+ const deleteFilter = filtersManager.deleteFilter.bind(filtersManager);
30
+
31
+ const filtersList = computed(() => filtersManager.getFiltersList());
32
+
33
+ const setupPersistence = () => {
34
+ const { restore: restoreFilters } = usePersistedStorage({
35
+ name: 'filters',
36
+
37
+ value: computed(
38
+ () => filtersManager,
39
+ ) /* computed is used to provide value as ref(), not reactive() – as per usePersistedStorage interface */,
40
+
41
+ storages: [PersistedStorageType.Route],
42
+
43
+ /* use custom .toString() logic, provided by FiltersManager */
44
+ onStore: async (save, { name }) => {
45
+ const snapshotStr = filtersManager.toString();
46
+ return save({ name, value: snapshotStr });
47
+ },
48
+
49
+ /* use custom .fromString() logic, provided by FiltersManager */
50
+ onRestore: async (restore, name) => {
51
+ isRestoring.value = true;
52
+ const snapshotStr = await restore(name);
53
+ /*
54
+ snapshot as string because we know that filtersManager.toString() returns string,
55
+ not string[]
56
+ */
57
+ if (snapshotStr) filtersManager.fromString(snapshotStr as string);
58
+
59
+ isRestoring.value = false;
60
+ },
61
+ });
62
+
63
+ return restoreFilters();
64
+ };
65
+
66
+ return {
67
+ filtersManager,
68
+ isRestoring,
69
+
70
+ filtersList,
71
+
72
+ hasFilter,
73
+ addFilter,
74
+ updateFilter,
75
+ deleteFilter,
76
+
77
+ setupPersistence,
78
+ };
79
+ };
10
80
 
11
- export const createTableFiltersStore = (
81
+ export const createTableFiltersStore = <Entity>(
12
82
  namespace: string,
13
- config?: { filtersManagerConfig: FiltersManagerConfig },
83
+ config: useTableStoreConfig<Entity> & {
84
+ filtersManagerConfig?: FiltersManagerConfig;
85
+ },
14
86
  ) => {
15
87
  const id = `${namespace}/filters`;
16
-
17
- return defineStore(id, () => {
18
- const filtersManager = reactive(
19
- createFiltersManager(config?.filtersManagerConfig),
20
- );
21
-
22
- /* for watchers in filter components */
23
- const isRestoring = ref(false);
24
-
25
- /*
26
- wrapping filtersManager methods to extend their functionality
27
- if it will be needed in future
28
- */
29
- const hasFilter = filtersManager.hasFilter.bind(filtersManager);
30
- const addFilter = filtersManager.addFilter.bind(filtersManager);
31
- const updateFilter = filtersManager.updateFilter.bind(filtersManager);
32
- const deleteFilter = filtersManager.deleteFilter.bind(filtersManager);
33
-
34
- const filtersList = computed(() => filtersManager.getFiltersList());
35
-
36
- const setupPersistence = () => {
37
- const { restore: restoreFilters } = usePersistedStorage({
38
- name: 'filters',
39
-
40
- value: computed(
41
- () => filtersManager,
42
- ) /* computed is used to provide value as ref(), not reactive() – as per usePersistedStorage interface */,
43
-
44
- storages: [PersistedStorageType.Route],
45
-
46
- /* use custom .toString() logic, provided by FiltersManager */
47
- onStore: async (save, { name }) => {
48
- const snapshotStr = filtersManager.toString();
49
- return save({ name, value: snapshotStr });
50
- },
51
-
52
- /* use custom .fromString() logic, provided by FiltersManager */
53
- onRestore: async (restore, name) => {
54
- isRestoring.value = true;
55
- const snapshotStr = await restore(name);
56
- /*
57
- snapshot as string because we know that filtersManager.toString() returns string,
58
- not string[]
59
- */
60
- if (snapshotStr) filtersManager.fromString(snapshotStr as string);
61
-
62
- isRestoring.value = false;
63
- },
64
- });
65
-
66
- return restoreFilters();
67
- };
68
-
69
- return {
70
- filtersManager,
71
- isRestoring,
72
-
73
- filtersList,
74
-
75
- hasFilter,
76
- addFilter,
77
- updateFilter,
78
- deleteFilter,
79
-
80
- setupPersistence,
81
- };
88
+ return createDatalistStore({
89
+ storeBody: tableFiltersStoreBody,
90
+ config,
91
+ namespace: id,
82
92
  });
83
93
  };
@@ -25,7 +25,8 @@ import { WtCheckbox, WtSelect } from '@webitel/ui-sdk/components';
25
25
  import { computed, onMounted, watch } from 'vue';
26
26
  import { useI18n } from 'vue-i18n';
27
27
 
28
- import {WtSysTypeFilterConfig} from "../../classes/FilterConfig";
28
+ import { CaseAssigneeFilterConfig } from "./index";
29
+
29
30
 
30
31
  type ModelValue = {
31
32
  list: string[];
@@ -35,7 +36,7 @@ type ModelValue = {
35
36
  const model = defineModel<ModelValue>();
36
37
 
37
38
  const props = defineProps<{
38
- filterConfig: WtSysTypeFilterConfig;
39
+ filterConfig: CaseAssigneeFilterConfig;
39
40
  }>();
40
41
 
41
42
  const emit = defineEmits<{
@@ -14,6 +14,7 @@ class CaseAssigneeFilterConfig extends WtSysTypeFilterConfig {
14
14
  params: object,
15
15
  { filterValue } = {},
16
16
  ): Promise<{ items: unknown[]; next?: boolean }> {
17
+ if (filterValue?.unassigned && !filterValue.list.length) return { items: [] };
17
18
  const id =
18
19
  params.id?.list /* general logic from dynamic-filter-preview.vue*/ ||
19
20
  params.id /* wt-select options loadings */ ||
@@ -1,3 +1,3 @@
1
- import CaseSourcesAPI from '@webitel/ui-sdk/api/clients/caseSources/caseSources';
1
+ import { caseSources } from '@webitel/ui-sdk/api/clients/index';
2
2
 
3
- export const searchMethod = CaseSourcesAPI.getLookup;
3
+ export const searchMethod = caseSources.getLookup;
@@ -0,0 +1 @@
1
+ export * from './stores/createFormStore';
@@ -0,0 +1,107 @@
1
+ import { ref } from 'vue';
2
+ import { useRegleSchema, RegleSchemaBehaviourOptions } from '@regle/schemas';
3
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
4
+ import { ApiModule } from '@webitel/ui-sdk/api/types/ApiModule.type';
5
+ import { defineStore } from 'pinia';
6
+
7
+ export const createFormStore = <Entity = object>({
8
+ namespace,
9
+ apiModule,
10
+ standardValidationSchema,
11
+ validationSchemaOptions,
12
+ }: {
13
+ namespace: string;
14
+ apiModule: ApiModule<Entity>;
15
+ standardValidationSchema?: StandardSchemaV1 | null;
16
+ validationSchemaOptions?: RegleSchemaBehaviourOptions;
17
+ }) => {
18
+ return defineStore(namespace, () => {
19
+ // form data vars
20
+ const parentId = ref<string | number | null>();
21
+ const itemId = ref<string | number | null>();
22
+ const itemInstance = ref<Entity>({} as Entity); // mb rename to formData? – in case of multiple stores for 1 main item instance
23
+
24
+ // form state vars
25
+ const validationSchema = ref();
26
+
27
+ // processing progress vars
28
+ const isLoading = ref(false);
29
+ const isSaving = ref(false);
30
+ const error = ref(null); // if needed
31
+
32
+ if (standardValidationSchema) {
33
+ validationSchema.value = useRegleSchema(
34
+ itemInstance,
35
+ standardValidationSchema,
36
+ validationSchemaOptions,
37
+ );
38
+ }
39
+
40
+ const loadItem = async () => {
41
+ isLoading.value = true;
42
+ try {
43
+ const loadedItemInstance = await apiModule.get({
44
+ id: itemId.value,
45
+ itemId: itemId.value, // compat, use "id" instead
46
+ parentId: parentId.value,
47
+ });
48
+
49
+ itemInstance.value = loadedItemInstance;
50
+ } catch (err) {
51
+ error.value = err;
52
+ } finally {
53
+ isLoading.value = false;
54
+ }
55
+ };
56
+
57
+ const saveItem = async () => {};
58
+
59
+ const initializeItemInstance = async () => {
60
+ if (itemId.value) {
61
+ await loadItem();
62
+ } else {
63
+ // todo: fill with defaults from zod schema
64
+ itemInstance.value = {} as Entity;
65
+ }
66
+ };
67
+
68
+ const initialize = ({
69
+ itemInstance: initialItemInstance,
70
+ itemId: initialItemId,
71
+ parentId: initialParentId,
72
+ }: {
73
+ itemInstance?: Entity;
74
+ itemId?: string | number;
75
+ parentId?: string | number;
76
+ }) => {
77
+ if (initialParentId) {
78
+ parentId.value = initialParentId;
79
+ }
80
+
81
+ if (initialItemId) {
82
+ itemId.value = initialItemId;
83
+ }
84
+
85
+ if (initialItemInstance) {
86
+ itemInstance.value = initialItemInstance;
87
+ } else {
88
+ } // todo: ??
89
+
90
+ return initializeItemInstance();
91
+ };
92
+
93
+ return {
94
+ parentId,
95
+ itemId,
96
+ itemInstance,
97
+
98
+ validationSchema,
99
+
100
+ isLoading,
101
+ isSaving,
102
+ error,
103
+
104
+ initialize,
105
+ };
106
+ });
107
+ };