@webitel/ui-datalist 1.1.55 → 1.1.57

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 (61) hide show
  1. package/package.json +1 -1
  2. package/src/modules/_shared/createDatalistStore.ts +1 -1
  3. package/src/modules/card/stores/createCardStore.ts +7 -2
  4. package/src/modules/filter-presets/api/PresetQuery.ts +12 -2
  5. package/src/modules/filter-presets/stores/createFilterPresetsStore.ts +1 -1
  6. package/src/modules/filters/classes/Filter.ts +1 -1
  7. package/src/modules/filters/classes/FiltersManager.ts +29 -18
  8. package/src/modules/filters/classes/__tests__/FiltersManager.spec.ts +1 -1
  9. package/src/modules/filters/modules/filterConfig/classes/FilterConfig.ts +6 -4
  10. package/src/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-filter-value-field.vue +7 -13
  11. package/src/modules/filters/modules/filterConfig/components/_shared/durations/duration-filter-value-field.vue +6 -8
  12. package/src/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue +33 -4
  13. package/src/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-preview.vue +15 -2
  14. package/src/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue +7 -12
  15. package/src/modules/filters/modules/filterConfig/components/case-close-reason-groups/case-close-reason-groups-filter-value-field.vue +7 -12
  16. package/src/modules/filters/modules/filterConfig/components/case-sla-condition/case-sla-condition-filter-value-field.vue +7 -11
  17. package/src/modules/filters/modules/filterConfig/components/case-status/case-status-filter-value-field.vue +7 -12
  18. package/src/modules/filters/modules/filterConfig/components/contact-group/contact-group-filter-value-field.vue +6 -12
  19. package/src/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue +1 -1
  20. package/src/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue +1 -1
  21. package/src/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue +1 -1
  22. package/src/modules/filters/modules/filterConfig/components/has-user/has-user-filter-value-field.vue +1 -1
  23. package/src/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue +9 -8
  24. package/src/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue +6 -7
  25. package/src/modules/filters/modules/filterConfig/composables/booleanFilterToolkit.ts +2 -2
  26. package/src/modules/filters/modules/filterConfig/composables/useQueueTypeOptions.ts +2 -1
  27. package/src/modules/filters/modules/filterConfig/enums/options/AMDResultOptions.ts +8 -0
  28. package/src/modules/filters/scripts/utils.ts +6 -2
  29. package/src/modules/headers/createTableHeadersStore.ts +6 -4
  30. package/src/modules/pagination/createTablePaginationStore.ts +2 -2
  31. package/src/modules/permissions-page/scripts/PermissionsApiModule.ts +3 -4
  32. package/src/modules/permissions-page/stores/createPermissionsStore.ts +3 -3
  33. package/src/modules/persist/PersistedStorage.types.ts +5 -2
  34. package/src/modules/persist/useLocalStoragePersistedStorage.ts +3 -6
  35. package/src/modules/persist/usePersistedStorage.ts +18 -12
  36. package/src/modules/table/createTableStore.store.ts +6 -6
  37. package/src/modules/types/tableStore.types.ts +9 -1
  38. package/types/.tsbuildinfo +1 -1
  39. package/types/modules/_shared/createDatalistStore.d.ts +1 -1
  40. package/types/modules/card/stores/createCardStore.d.ts +14 -10
  41. package/types/modules/filter-presets/stores/createFilterPresetsStore.d.ts +8 -8
  42. package/types/modules/filters/classes/Filter.d.ts +2 -2
  43. package/types/modules/filters/classes/FiltersManager.d.ts +3 -2
  44. package/types/modules/filters/createTableFiltersStore.d.ts +4 -4
  45. package/types/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue.d.ts +3 -3
  46. package/types/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-preview.vue.d.ts +1 -1
  47. package/types/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue.d.ts +1 -1
  48. package/types/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue.d.ts +1 -1
  49. package/types/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue.d.ts +1 -1
  50. package/types/modules/filters/modules/filterConfig/components/has-user/has-user-filter-value-field.vue.d.ts +1 -1
  51. package/types/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue.d.ts +2 -2
  52. package/types/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue.d.ts +2 -2
  53. package/types/modules/filters/modules/filterConfig/composables/booleanFilterToolkit.d.ts +3 -3
  54. package/types/modules/filters/scripts/utils.d.ts +2 -2
  55. package/types/modules/headers/createTableHeadersStore.d.ts +6 -4
  56. package/types/modules/permissions-page/scripts/PermissionsApiModule.d.ts +2 -2
  57. package/types/modules/permissions-page/stores/createPermissionsStore.d.ts +14 -14
  58. package/types/modules/persist/PersistedStorage.types.d.ts +2 -2
  59. package/types/modules/persist/useLocalStoragePersistedStorage.d.ts +1 -1
  60. package/types/modules/table/createTableStore.store.d.ts +14 -14
  61. package/types/modules/types/tableStore.types.d.ts +7 -1
@@ -29,16 +29,15 @@ import { computed, watch } from 'vue';
29
29
  import { useI18n } from 'vue-i18n';
30
30
 
31
31
  type ModelValue = {
32
- from: number;
33
- to: number;
32
+ from: number | null;
33
+ to: number | null;
34
34
  };
35
- const model = defineModel<ModelValue>();
36
- if (!model.value) {
37
- model.value = {
35
+ const model = defineModel<ModelValue>({
36
+ default: (): ModelValue => ({
38
37
  from: null,
39
38
  to: null,
40
- };
41
- }
39
+ }),
40
+ });
42
41
 
43
42
  const emit = defineEmits<{
44
43
  'update:invalid': [
@@ -56,7 +55,9 @@ const v$ = useVuelidate<{
56
55
  from: {
57
56
  required: requiredIf(() => !model.value.to),
58
57
  maxValue: maxValue(
59
- model?.value?.to && model.value.from > model.value.to
58
+ model.value.to &&
59
+ model.value.from !== null &&
60
+ model.value.from > model.value.to
60
61
  ? model.value.to
61
62
  : Infinity,
62
63
  ),
@@ -35,16 +35,15 @@ import { computed, watch } from 'vue';
35
35
  import { useI18n } from 'vue-i18n';
36
36
 
37
37
  type ModelValue = {
38
- from: number;
39
- to: number;
38
+ from: number | null;
39
+ to: number | null;
40
40
  };
41
- const model = defineModel<ModelValue>();
42
- if (!model.value) {
43
- model.value = {
41
+ const model = defineModel<ModelValue>({
42
+ default: (): ModelValue => ({
44
43
  from: null,
45
44
  to: null,
46
- };
47
- }
45
+ }),
46
+ });
48
47
 
49
48
  const props = withDefaults(
50
49
  defineProps<{
@@ -23,12 +23,12 @@ export const usePrettifyBooleanValuePreview = (
23
23
  export const useBooleanFilterValueValidation = <
24
24
  T extends BooleanFilterModelValue,
25
25
  >(
26
- model: ModelRef<T>,
26
+ model: ModelRef<T | null | undefined>,
27
27
  ) => {
28
28
  const v$ = useVuelidate(
29
29
  computed(() => ({
30
30
  model: {
31
- required: (v: T) => !(!v && v !== false),
31
+ required: (v: T | null | undefined) => !(!v && v !== false),
32
32
  },
33
33
  })),
34
34
  {
@@ -13,7 +13,8 @@ export function useQueueTypeOptions() {
13
13
  // staging only https://webitel.atlassian.net/browse/WS-2
14
14
  .filter(
15
15
  ([, value]) =>
16
- import.meta.env.VITE_STAGING_ENV || value !== QueueType.IM_CHAT_QUEUE,
16
+ import.meta.env.VITE_STAGING_ENV === 'true' ||
17
+ value !== QueueType.IM_CHAT_QUEUE,
17
18
  )
18
19
  .map(([, value]) => ({
19
20
  value,
@@ -39,4 +39,12 @@ export const AmdResultOptions: Array<FilterInitParams> = [
39
39
  name: 'TIMEOUT',
40
40
  value: 'TIMEOUT',
41
41
  },
42
+ {
43
+ name: 'UNDEFINED',
44
+ value: 'UNDEFINED',
45
+ },
46
+ {
47
+ name: 'NO ANSWER',
48
+ value: 'NO ANSWER',
49
+ },
42
50
  ] as const;
@@ -18,14 +18,18 @@ const isLabelSnapshotKey = (snapshotKey: string): boolean =>
18
18
  const isValueSnapshotKey = (snapshotKey: string): boolean =>
19
19
  snapshotKey.includes('_val');
20
20
 
21
- export const filterNameFromSnapshotKey = (snapshotKey: string): FilterName => {
21
+ export const filterNameFromSnapshotKey = (
22
+ snapshotKey: string,
23
+ ): FilterName | undefined => {
22
24
  if (isLabelSnapshotKey(snapshotKey))
23
25
  return filterLabelFromSnapshotKey(snapshotKey);
24
26
  if (isValueSnapshotKey(snapshotKey))
25
27
  return filterValueFromSnapshotKey(snapshotKey);
26
28
  };
27
29
 
28
- export const filterValuePropFromSnapshotKey = (snapshotKey: string): string => {
30
+ export const filterValuePropFromSnapshotKey = (
31
+ snapshotKey: string,
32
+ ): string | undefined => {
29
33
  if (isLabelSnapshotKey(snapshotKey)) return 'label';
30
34
  if (isValueSnapshotKey(snapshotKey)) return 'value';
31
35
  };
@@ -11,6 +11,8 @@ import type {
11
11
  useTableStoreConfig,
12
12
  } from '../types/tableStore.types';
13
13
 
14
+ type SortSymbol = (typeof SortSymbols)[keyof typeof SortSymbols];
15
+
14
16
  interface TableHeadersStoreBodyParams {
15
17
  rawHeaders: DatalistTableHeader[];
16
18
  id: string;
@@ -74,7 +76,7 @@ export const tableHeadersStoreBody = ({
74
76
  }
75
77
  });
76
78
 
77
- const newOrder = [];
79
+ const newOrder: number[] = [];
78
80
  for (const field of orderedFields) {
79
81
  const indices = arrayFieldOrder.get(field);
80
82
  const next = indices?.shift();
@@ -153,9 +155,9 @@ export const tableHeadersStoreBody = ({
153
155
  column,
154
156
  options:
155
157
  | {
156
- order?: SortSymbols;
158
+ order?: SortSymbol;
157
159
  }
158
- | SortSymbols = {},
160
+ | SortSymbol = {},
159
161
  ) => {
160
162
  const getNextSortOrder = (sort) => {
161
163
  switch (sort) {
@@ -188,7 +190,7 @@ export const tableHeadersStoreBody = ({
188
190
  });
189
191
  };
190
192
 
191
- let order: SortSymbols;
193
+ let order: SortSymbol;
192
194
 
193
195
  if (typeof options === 'string') {
194
196
  order = options;
@@ -30,7 +30,7 @@ export const tablePaginationStoreBody = () => {
30
30
  value: page,
31
31
  onRestore: async (restore, name) => {
32
32
  const value = await restore(name);
33
- const numValue = +value;
33
+ const numValue = Number(value);
34
34
  if (numValue) page.value = numValue;
35
35
  },
36
36
  });
@@ -40,7 +40,7 @@ export const tablePaginationStoreBody = () => {
40
40
  value: size,
41
41
  onRestore: async (restore, name) => {
42
42
  const value = await restore(name);
43
- const numValue = +value;
43
+ const numValue = Number(value);
44
44
  if (numValue) size.value = numValue;
45
45
  },
46
46
  });
@@ -1,5 +1,4 @@
1
- import type { ApiModule } from '@webitel/ui-sdk/src/api/types/ApiModule';
2
-
1
+ import type { TableApiModule } from '../../types/tableStore.types';
3
2
  import type {
4
3
  PermissionEntity,
5
4
  RawPermissionsApiModule,
@@ -13,9 +12,9 @@ import type {
13
12
  */
14
13
  export const PermissionsApiModule = (
15
14
  rawApiModule: RawPermissionsApiModule,
16
- ): ApiModule<PermissionEntity> => {
15
+ ): TableApiModule<PermissionEntity> => {
17
16
  return {
18
17
  getList: rawApiModule.getPermissionsList,
19
18
  patch: rawApiModule.patchPermissions,
20
- } as unknown as ApiModule<PermissionEntity>;
19
+ } as unknown as TableApiModule<PermissionEntity>;
21
20
  };
@@ -73,7 +73,7 @@ export const permissionsStoreBody = (
73
73
  const parentId = ref<Id>();
74
74
 
75
75
  const initialize: typeof tableStoreInitialize = (options) => {
76
- parentId.value = options.parentId;
76
+ parentId.value = options?.parentId;
77
77
  return tableStoreInitialize(options);
78
78
  };
79
79
 
@@ -81,7 +81,7 @@ export const permissionsStoreBody = (
81
81
  try {
82
82
  await (
83
83
  config.apiModule.patch as unknown as (payload: {
84
- id: Id;
84
+ id: Id | undefined;
85
85
  changes: PermissionsChange[];
86
86
  }) => Promise<unknown>
87
87
  )({
@@ -119,7 +119,7 @@ export const permissionsStoreBody = (
119
119
  error.value = null;
120
120
  isLoading.value = false;
121
121
  resetInfiniteScrollTableParamsToDefaults();
122
- parentId.value = null;
122
+ parentId.value = undefined;
123
123
  };
124
124
 
125
125
  return {
@@ -24,7 +24,9 @@ export interface StorageLike {
24
24
 
25
25
  export interface PersistedPropertyConfig {
26
26
  name: string;
27
- value: Ref<PersistableValue>;
27
+ // note: createTableHeadersStore passes a computed here, which the default
28
+ // restore path cannot write to
29
+ value: Ref<PersistableValue | null>;
28
30
  storages?: PersistedStorageType | PersistedStorageType[];
29
31
  storagePath?: string;
30
32
  startWatchManually?: boolean;
@@ -40,7 +42,8 @@ export interface PersistedPropertyConfig {
40
42
  { value, name },
41
43
  ) => Promise<void>;
42
44
  onRestore?: (
43
- restore: (name: string) => Promise<PersistableValue>,
45
+ // resolves `undefined` when no storage held a value for `name`
46
+ restore: (name: string) => Promise<PersistableValue | undefined>,
44
47
  name: string,
45
48
  ) => Promise<void>;
46
49
  }
@@ -7,15 +7,12 @@ const makePath = (storagePath: string, key: string) => `${storagePath}/${key}`;
7
7
  export const useLocalStoragePersistedStorage = ({
8
8
  storagePath = '',
9
9
  }: {
10
- storagePath: string;
10
+ storagePath?: string;
11
11
  }): StorageLike => {
12
12
  const getItem = async (key: string) => {
13
13
  const value = localStorage.getItem(makePath(storagePath, key));
14
- try {
15
- return value.split(separator).join();
16
- } catch {
17
- return value;
18
- }
14
+ if (value === null) return null;
15
+ return value.split(separator).join();
19
16
  };
20
17
 
21
18
  const setItem = async (key: string, inputValue: string | string[]) => {
@@ -1,10 +1,11 @@
1
- import { watch } from 'vue';
1
+ import { type WatchHandle, watch } from 'vue';
2
2
 
3
3
  import {
4
4
  type PersistableValue,
5
5
  type PersistedPropertyConfig,
6
6
  type PersistedStorageController,
7
7
  PersistedStorageType,
8
+ type StorageLike,
8
9
  } from './PersistedStorage.types';
9
10
  import { useLocalStoragePersistedStorage } from './useLocalStoragePersistedStorage';
10
11
  import { useRoutePersistedStorage } from './useRoutePersistedStorage';
@@ -20,25 +21,30 @@ export const usePersistedStorage = ({
20
21
  onStore,
21
22
  onRestore,
22
23
  }: PersistedPropertyConfig): PersistedStorageController => {
23
- let unwatch = null;
24
+ let unwatch: WatchHandle | null = null;
24
25
 
25
- const setItemFns = [];
26
- const getItemFns: Array<(name: string) => Promise<PersistableValue>> = [];
27
- const removeItemFns = [];
26
+ const setItemFns: StorageLike['setItem'][] = [];
27
+ const getItemFns: StorageLike['getItem'][] = [];
28
+ const removeItemFns: StorageLike['removeItem'][] = [];
28
29
 
30
+ // `null` entries are kept: callers below pick the first non-null value, so the
31
+ // per-storage misses have to stay in the list to preserve priority order.
29
32
  const composedValueGetter = async (
30
33
  name: string,
31
- ): Promise<PersistableValue[]> => {
34
+ ): Promise<Array<PersistableValue | null>> => {
32
35
  const settledResults = await Promise.allSettled(
33
36
  getItemFns.map((getter) => getter(name)),
34
37
  );
35
38
 
36
- return settledResults.reduce((acc, result) => {
37
- if (result.status === 'fulfilled') {
38
- acc.push(result.value);
39
- }
40
- return acc;
41
- }, [] as PersistableValue[]);
39
+ return settledResults.reduce(
40
+ (acc, result) => {
41
+ if (result.status === 'fulfilled') {
42
+ acc.push(result.value);
43
+ }
44
+ return acc;
45
+ },
46
+ [] as Array<PersistableValue | null>,
47
+ );
42
48
  };
43
49
 
44
50
  const storages = Array.isArray(configStorages)
@@ -93,7 +93,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
93
93
 
94
94
  const dataList: Ref<Entity[]> = ref([]);
95
95
  const selected: Ref<Entity[]> = ref([]);
96
- const error = ref(null);
96
+ const error = ref<unknown>(null);
97
97
  const isLoading = ref(false);
98
98
 
99
99
  const updateSelected = (value: Entity[]) => {
@@ -125,7 +125,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
125
125
  try {
126
126
  const { items, next } = await apiModule.getList(params);
127
127
 
128
- dataList.value = items;
128
+ dataList.value = items ?? [];
129
129
 
130
130
  /**
131
131
  * @author: @Oleksandr Palonnyi
@@ -134,7 +134,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
134
134
  *
135
135
  * link to refactor task - https://webitel.atlassian.net/browse/WTEL-8599
136
136
  * */
137
- updateSelected(filterSelected(items));
137
+ updateSelected(filterSelected(items ?? []));
138
138
 
139
139
  $patchPaginationStore({
140
140
  next,
@@ -169,7 +169,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
169
169
  try {
170
170
  const { items, next } = await apiModule.getList(params);
171
171
 
172
- dataList.value.push(...items);
172
+ dataList.value.push(...(items ?? []));
173
173
  $patchPaginationStore({
174
174
  next,
175
175
  });
@@ -191,7 +191,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
191
191
  set(changes, path, value);
192
192
 
193
193
  try {
194
- await apiModule.patch({
194
+ await apiModule.patch?.({
195
195
  changes,
196
196
  parentId: parentId.value,
197
197
  id: item.id,
@@ -211,7 +211,7 @@ export const tableStoreBody = <Entity extends Identifiable>(
211
211
  _els,
212
212
  ];
213
213
  const deleteEl = (el: Entity) => {
214
- return apiModule.delete({
214
+ return apiModule.delete?.({
215
215
  id: el.id,
216
216
  etag: el.etag,
217
217
  parentId: parentId.value,
@@ -17,8 +17,16 @@ export type DatalistTableHeader = WtTableHeader & {
17
17
 
18
18
  export type TrackSelectedRowBy<T> = (row: T) => T;
19
19
 
20
+ /**
21
+ * Every method on {@link ApiModule} is optional, but a table store cannot load
22
+ * anything without `getList`, so it is required here. `patch`/`delete` stay
23
+ * optional and are called defensively.
24
+ */
25
+ export type TableApiModule<Entity> = ApiModule<Entity> &
26
+ Required<Pick<ApiModule<Entity>, 'getList'>>;
27
+
20
28
  export interface useTableStoreConfig<Entity> {
21
- apiModule: ApiModule<Entity>;
29
+ apiModule: TableApiModule<Entity>;
22
30
  headers: DatalistTableHeader[];
23
31
  disablePersistence?: boolean | [];
24
32
  storeType?: DatalistStoreProviderType;