@webitel/ui-datalist 26.8.6 → 26.8.8

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 (148) hide show
  1. package/Readme.md +1 -0
  2. package/package.json +3 -2
  3. package/src/modules/filter-presets/components/apply-preset/apply-preset-action.vue +16 -4
  4. package/src/modules/filter-presets/components/save-preset/save-preset-action.vue +18 -4
  5. package/src/modules/filters/__tests__/createTableFiltersStore.spec.ts +38 -2
  6. package/src/modules/filters/components/column/column-filter-preview.vue +70 -0
  7. package/src/modules/filters/components/column/column-filter.vue +76 -0
  8. package/src/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-value-input.vue +2 -0
  9. package/src/modules/filters/components/config/dynamic-view/dynamic-filter-config-form.vue +43 -5
  10. package/src/modules/filters/components/config/static-view/static-filter-field.vue +6 -21
  11. package/src/modules/filters/components/filters-actions-menu.vue +177 -0
  12. package/src/modules/filters/components/preview/dynamic-filter-preview.vue +5 -60
  13. package/src/modules/filters/components/table-filters-panel.vue +6 -28
  14. package/src/modules/filters/components/types/Filter.types.ts +5 -0
  15. package/src/modules/filters/composables/useColumnFilter.ts +116 -0
  16. package/src/modules/filters/composables/useFilterValueChange.ts +58 -0
  17. package/src/modules/filters/composables/useFilterValuePreview.ts +87 -0
  18. package/src/modules/filters/composables/useSelectedFilters.ts +64 -0
  19. package/src/modules/filters/createTableFiltersStore.ts +13 -5
  20. package/src/modules/filters/index.ts +4 -0
  21. package/src/modules/filters/modules/filterConfig/components/_custom/filterConfig.ts +1 -1
  22. package/src/modules/filters/modules/filterConfig/components/_custom/type-extension-filter-value-field.vue +9 -5
  23. package/src/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-filter-value-field.vue +7 -4
  24. package/src/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-options/date-time-options-filter-value-field.vue +7 -4
  25. package/src/modules/filters/modules/filterConfig/components/_shared/durations/duration-filter-value-field.vue +7 -4
  26. package/src/modules/filters/modules/filterConfig/components/_shared/string-filter/string-filter-value-field.vue +6 -3
  27. package/src/modules/filters/modules/filterConfig/components/agent/agent-filter-value-field.vue +6 -3
  28. package/src/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue +6 -3
  29. package/src/modules/filters/modules/filterConfig/components/call-direction/call-direction-filter-value-field.vue +6 -3
  30. package/src/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue +4 -4
  31. package/src/modules/filters/modules/filterConfig/components/case-author/case-author-filter-value-field.vue +6 -3
  32. package/src/modules/filters/modules/filterConfig/components/case-close-reason-groups/case-close-reason-groups-filter-value-field.vue +7 -4
  33. package/src/modules/filters/modules/filterConfig/components/case-impacted/case-impacted-filter-value-field.vue +6 -3
  34. package/src/modules/filters/modules/filterConfig/components/case-priority/case-priority-filter-value-field.vue +6 -3
  35. package/src/modules/filters/modules/filterConfig/components/case-reporter/case-reporter-filter-value-field.vue +6 -3
  36. package/src/modules/filters/modules/filterConfig/components/case-service/case-service-filter-value-field.vue +1 -32
  37. package/src/modules/filters/modules/filterConfig/components/case-sla/case-sla-filter-value-field.vue +6 -3
  38. package/src/modules/filters/modules/filterConfig/components/case-sla-condition/case-sla-condition-filter-value-field.vue +7 -4
  39. package/src/modules/filters/modules/filterConfig/components/case-source/case-source-filter-value-field.vue +6 -3
  40. package/src/modules/filters/modules/filterConfig/components/case-status/case-status-filter-value-field.vue +7 -4
  41. package/src/modules/filters/modules/filterConfig/components/contact/contact-filter-value-field.vue +6 -3
  42. package/src/modules/filters/modules/filterConfig/components/contact-owner/contact-owner-filter-value-field.vue +3 -3
  43. package/src/modules/filters/modules/filterConfig/components/gateway/gateway-filter-value-field.vue +6 -3
  44. package/src/modules/filters/modules/filterConfig/components/grantee/grantee-filter-value-field.vue +6 -3
  45. package/src/modules/filters/modules/filterConfig/components/hangup-cause/hangup-cause-filter-value-field.vue +6 -3
  46. package/src/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue +6 -3
  47. package/src/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue +6 -3
  48. package/src/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue +7 -4
  49. package/src/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue +4 -4
  50. package/src/modules/filters/modules/filterConfig/components/tag/tag-filter-value-field.vue +6 -3
  51. package/src/modules/filters/modules/filterConfig/components/user/user-filter-value-field.vue +6 -3
  52. package/src/modules/filters/modules/filterConfig/components/variable/variable-filter-value-field.vue +6 -3
  53. package/src/modules/headers/__tests__/createTableHeadersStore.spec.ts +34 -2
  54. package/src/modules/headers/createTableHeadersStore.ts +19 -5
  55. package/src/modules/pagination/__tests__/createTablePaginationStore.spec.ts +27 -3
  56. package/src/modules/pagination/createTablePaginationStore.ts +23 -4
  57. package/src/modules/table/__tests__/createTableStore.spec.ts +26 -0
  58. package/src/modules/table/createTableStore.store.ts +34 -15
  59. package/src/modules/types/tableStore.types.ts +21 -2
  60. package/types/.tsbuildinfo +1 -1
  61. package/types/modules/filter-presets/components/apply-preset/apply-preset-action.vue.d.ts +15 -1
  62. package/types/modules/filter-presets/components/save-preset/save-preset-action.vue.d.ts +17 -1
  63. package/types/modules/filter-presets/stores/createFilterPresetsStore.d.ts +2 -35
  64. package/types/modules/filters/components/column/column-filter-preview.vue.d.ts +21 -0
  65. package/types/modules/filters/components/column/column-filter.vue.d.ts +36 -0
  66. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-label.vue.d.ts +2 -2
  67. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-value-input.vue.d.ts +3 -2
  68. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form.vue.d.ts +13 -1
  69. package/types/modules/filters/components/config/static-view/static-filter-field.vue.d.ts +2 -2
  70. package/types/modules/filters/components/filters-actions-menu.vue.d.ts +29 -0
  71. package/types/modules/filters/components/table-filters-panel.vue.d.ts +6 -6
  72. package/types/modules/filters/components/types/Filter.types.d.ts +4 -0
  73. package/types/modules/filters/composables/useColumnFilter.d.ts +27 -0
  74. package/types/modules/filters/composables/useFilterValueChange.d.ts +23 -0
  75. package/types/modules/filters/composables/useFilterValuePreview.d.ts +21 -0
  76. package/types/modules/filters/composables/useSelectedFilters.d.ts +22 -0
  77. package/types/modules/filters/createTableFiltersStore.d.ts +6 -2
  78. package/types/modules/filters/index.d.ts +3 -1
  79. package/types/modules/filters/modules/filterConfig/components/_custom/type-extension-filter-value-field.vue.d.ts +3 -2
  80. package/types/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-filter-value-field.vue.d.ts +8 -4
  81. package/types/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-options/date-time-options-filter-value-field.vue.d.ts +8 -4
  82. package/types/modules/filters/modules/filterConfig/components/_shared/durations/duration-filter-value-field.vue.d.ts +8 -4
  83. package/types/modules/filters/modules/filterConfig/components/_shared/string-filter/string-filter-value-field.vue.d.ts +8 -4
  84. package/types/modules/filters/modules/filterConfig/components/agent/agent-filter-value-field.vue.d.ts +8 -4
  85. package/types/modules/filters/modules/filterConfig/components/agent-status/agent-status-filter-value-field.vue.d.ts +2 -2
  86. package/types/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue.d.ts +8 -4
  87. package/types/modules/filters/modules/filterConfig/components/auditor/auditor-filter-value-field.vue.d.ts +2 -2
  88. package/types/modules/filters/modules/filterConfig/components/auditor/index.d.ts +2 -2
  89. package/types/modules/filters/modules/filterConfig/components/bucket/bucket-filter-value-field.vue.d.ts +2 -2
  90. package/types/modules/filters/modules/filterConfig/components/bucket/index.d.ts +2 -2
  91. package/types/modules/filters/modules/filterConfig/components/call-direction/call-direction-filter-value-field.vue.d.ts +8 -4
  92. package/types/modules/filters/modules/filterConfig/components/call-reporting-result/call-reporting-result-filter-value-field.vue.d.ts +2 -2
  93. package/types/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue.d.ts +3 -2
  94. package/types/modules/filters/modules/filterConfig/components/case-assignee/filterConfig.d.ts +4 -2
  95. package/types/modules/filters/modules/filterConfig/components/case-author/case-author-filter-value-field.vue.d.ts +8 -4
  96. package/types/modules/filters/modules/filterConfig/components/case-close-reason-groups/case-close-reason-groups-filter-value-field.vue.d.ts +8 -4
  97. package/types/modules/filters/modules/filterConfig/components/case-impacted/case-impacted-filter-value-field.vue.d.ts +8 -4
  98. package/types/modules/filters/modules/filterConfig/components/case-priority/case-priority-filter-value-field.vue.d.ts +8 -4
  99. package/types/modules/filters/modules/filterConfig/components/case-reporter/case-reporter-filter-value-field.vue.d.ts +8 -4
  100. package/types/modules/filters/modules/filterConfig/components/case-sla/case-sla-filter-value-field.vue.d.ts +8 -4
  101. package/types/modules/filters/modules/filterConfig/components/case-sla-condition/case-sla-condition-filter-value-field.vue.d.ts +8 -4
  102. package/types/modules/filters/modules/filterConfig/components/case-source/case-source-filter-value-field.vue.d.ts +8 -4
  103. package/types/modules/filters/modules/filterConfig/components/case-status/case-status-filter-value-field.vue.d.ts +8 -4
  104. package/types/modules/filters/modules/filterConfig/components/contact/contact-filter-value-field.vue.d.ts +8 -4
  105. package/types/modules/filters/modules/filterConfig/components/contact-group/contact-group-filter-value-field.vue.d.ts +2 -2
  106. package/types/modules/filters/modules/filterConfig/components/contact-group/index.d.ts +2 -2
  107. package/types/modules/filters/modules/filterConfig/components/contact-label/contact-label-filter-value-field.vue.d.ts +2 -2
  108. package/types/modules/filters/modules/filterConfig/components/contact-label/index.d.ts +2 -2
  109. package/types/modules/filters/modules/filterConfig/components/contact-owner/contact-owner-filter-value-field.vue.d.ts +3 -2
  110. package/types/modules/filters/modules/filterConfig/components/contact-owner/index.d.ts +4 -2
  111. package/types/modules/filters/modules/filterConfig/components/gateway/gateway-filter-value-field.vue.d.ts +8 -4
  112. package/types/modules/filters/modules/filterConfig/components/grantee/grantee-filter-value-field.vue.d.ts +8 -4
  113. package/types/modules/filters/modules/filterConfig/components/hangup-cause/hangup-cause-filter-value-field.vue.d.ts +8 -4
  114. package/types/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue.d.ts +8 -4
  115. package/types/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue.d.ts +2 -2
  116. package/types/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue.d.ts +2 -2
  117. package/types/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue.d.ts +2 -2
  118. package/types/modules/filters/modules/filterConfig/components/has-user/has-user-filter-value-field.vue.d.ts +2 -2
  119. package/types/modules/filters/modules/filterConfig/components/index.d.ts +24 -22
  120. package/types/modules/filters/modules/filterConfig/components/queue/index.d.ts +2 -2
  121. package/types/modules/filters/modules/filterConfig/components/queue/queue-filter-value-field.vue.d.ts +2 -2
  122. package/types/modules/filters/modules/filterConfig/components/queue-period/queue-period-filter-value-field.vue.d.ts +2 -2
  123. package/types/modules/filters/modules/filterConfig/components/queue-type/queue-type-filter-value-field.vue.d.ts +2 -2
  124. package/types/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue.d.ts +8 -4
  125. package/types/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue.d.ts +8 -4
  126. package/types/modules/filters/modules/filterConfig/components/region/index.d.ts +2 -2
  127. package/types/modules/filters/modules/filterConfig/components/region/region-filter-value-field.vue.d.ts +2 -2
  128. package/types/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue.d.ts +3 -2
  129. package/types/modules/filters/modules/filterConfig/components/skill/index.d.ts +2 -2
  130. package/types/modules/filters/modules/filterConfig/components/skill/skill-filter-value-field.vue.d.ts +2 -2
  131. package/types/modules/filters/modules/filterConfig/components/stop-cause/stop-cause-filter-value-field.vue.d.ts +2 -2
  132. package/types/modules/filters/modules/filterConfig/components/supervisor/index.d.ts +2 -2
  133. package/types/modules/filters/modules/filterConfig/components/supervisor/supervisor-filter-value-field.vue.d.ts +2 -2
  134. package/types/modules/filters/modules/filterConfig/components/tag/tag-filter-value-field.vue.d.ts +8 -4
  135. package/types/modules/filters/modules/filterConfig/components/tags/index.d.ts +2 -2
  136. package/types/modules/filters/modules/filterConfig/components/tags/tags-filter-value-field.vue.d.ts +2 -2
  137. package/types/modules/filters/modules/filterConfig/components/talk-duration/talk-duration-filter-value-field.vue.d.ts +2 -2
  138. package/types/modules/filters/modules/filterConfig/components/team/index.d.ts +2 -2
  139. package/types/modules/filters/modules/filterConfig/components/team/team-filter-value-field.vue.d.ts +2 -2
  140. package/types/modules/filters/modules/filterConfig/components/total-duration/total-duration-filter-value-field.vue.d.ts +2 -2
  141. package/types/modules/filters/modules/filterConfig/components/user/user-filter-value-field.vue.d.ts +8 -4
  142. package/types/modules/filters/modules/filterConfig/components/utilization-progress/utilization-progress-filter-value-field.vue.d.ts +2 -2
  143. package/types/modules/filters/modules/filterConfig/components/variable/variable-filter-value-field.vue.d.ts +8 -4
  144. package/types/modules/headers/createTableHeadersStore.d.ts +48 -20
  145. package/types/modules/pagination/createTablePaginationStore.d.ts +7 -3
  146. package/types/modules/permissions-page/stores/createPermissionsStore.d.ts +4 -70
  147. package/types/modules/table/createTableStore.store.d.ts +76 -141
  148. package/types/modules/types/tableStore.types.d.ts +20 -2
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <has-option-filter-value-field
3
3
  :model-value="model"
4
- :v="v$.model"
4
+ :v="!disableValidation && v$.model"
5
5
  @update:model-value="model = $event"
6
6
  />
7
7
  </template>
@@ -13,6 +13,10 @@ import { computed, watch } from 'vue';
13
13
 
14
14
  import HasOptionFilterValueField from '../_shared/has-options/has-option-filter-value-field.vue';
15
15
 
16
+ const props = defineProps<{
17
+ disableValidation?: boolean;
18
+ }>();
19
+
16
20
  const model = defineModel<boolean | null>();
17
21
 
18
22
  const v$ = useVuelidate(
@@ -29,8 +33,7 @@ const v$ = useVuelidate(
29
33
  },
30
34
  );
31
35
 
32
- v$.value.$touch();
33
-
36
+ if (!props?.disableValidation) v$.value.$touch();
34
37
  const emit = defineEmits<{
35
38
  'update:invalid': [
36
39
  boolean,
@@ -3,7 +3,7 @@
3
3
  :label="t('webitelUI.filters.filterValue')"
4
4
  :search-method="searchMethod"
5
5
  :model-value="model"
6
- :v="v$.model"
6
+ :v="!disableValidation && v$.model"
7
7
  option-value="id"
8
8
  @update:model-value="handleInput"
9
9
  />
@@ -20,6 +20,10 @@ import { searchMethod } from './config.js';
20
20
 
21
21
  type ModelValue = number[];
22
22
 
23
+ const props = defineProps<{
24
+ disableValidation?: boolean;
25
+ }>();
26
+
23
27
  const model = defineModel<ModelValue>();
24
28
 
25
29
  const emit = defineEmits<{
@@ -42,8 +46,7 @@ const v$ = useVuelidate(
42
46
  $autoDirty: true,
43
47
  },
44
48
  );
45
- v$.value.$touch();
46
-
49
+ if (!props?.disableValidation) v$.value.$touch();
47
50
  watch(
48
51
  () => v$.value.$invalid,
49
52
  (invalid) => {
@@ -3,7 +3,7 @@
3
3
  <wt-input-number
4
4
  :label="`${t('reusable.from')}:`"
5
5
  :placeholder="t('webitelUI.filters.filterValue')"
6
- :v="vFrom"
6
+ :v="!disableValidation && vFrom"
7
7
  :model-value="value.from"
8
8
  class="rating-from-to-filter-value-field__input"
9
9
  @update:model-value="handleInput('from', $event)"
@@ -12,7 +12,7 @@
12
12
  <wt-input-number
13
13
  :label="`${t('reusable.to')}:`"
14
14
  :placeholder="t('webitelUI.filters.filterValue')"
15
- :v="vTo"
15
+ :v="!disableValidation && vTo"
16
16
  :model-value="value.to"
17
17
  class="rating-from-to-filter-value-field__input"
18
18
  @update:model-value="handleInput('to', $event)"
@@ -26,6 +26,10 @@ import { maxValue, requiredIf } from '@vuelidate/validators';
26
26
  import { computed, watch } from 'vue';
27
27
  import { useI18n } from 'vue-i18n';
28
28
 
29
+ const props = defineProps<{
30
+ disableValidation?: boolean;
31
+ }>();
32
+
29
33
  type ModelValue = {
30
34
  from: number | null;
31
35
  to: number | null;
@@ -80,8 +84,7 @@ const v$ = useVuelidate<{
80
84
  $autoDirty: true,
81
85
  },
82
86
  );
83
- v$.value.$touch();
84
-
87
+ if (!props?.disableValidation) v$.value.$touch();
85
88
  const vFrom = computed(() => {
86
89
  const modelValidation = v$.value.model;
87
90
  if (!modelValidation) return undefined;
@@ -4,7 +4,7 @@
4
4
  :model-value="value.from"
5
5
  :max="props.numberMax"
6
6
  :min="0"
7
- :v="vFrom"
7
+ :v="!disableValidation && vFrom"
8
8
  :label="`${t('reusable.from')}:`"
9
9
  :placeholder="t('webitelUI.filters.filterValue')"
10
10
  class="score-from-to-filter-value-field__input"
@@ -16,7 +16,7 @@
16
16
  :model-value="value.to"
17
17
  :max="props.numberMax"
18
18
  :min="0"
19
- :v="vTo"
19
+ :v="!disableValidation && vTo"
20
20
  :label="`${t('reusable.to')}:`"
21
21
  :placeholder="t('webitelUI.filters.filterValue')"
22
22
  class="score-from-to-filter-value-field__input"
@@ -54,6 +54,7 @@ const value = computed<ModelValue>(
54
54
  const props = withDefaults(
55
55
  defineProps<{
56
56
  numberMax?: number;
57
+ disableValidation?: boolean;
57
58
  }>(),
58
59
  {
59
60
  numberMax: 100,
@@ -88,8 +89,7 @@ const v$ = useVuelidate<{
88
89
  $autoDirty: true,
89
90
  },
90
91
  );
91
- v$.value.$touch();
92
-
92
+ if (!props?.disableValidation) v$.value.$touch();
93
93
  const vFrom = computed(() => {
94
94
  const modelValidation = v$.value.model;
95
95
  if (!modelValidation) return undefined;
@@ -3,7 +3,7 @@
3
3
  :label="t('webitelUI.filters.filterValue')"
4
4
  :options="CallHistoryTagFilterOptions"
5
5
  v-model:model-value="model"
6
- :v="v$.model"
6
+ :v="!disableValidation && v$.model"
7
7
  data-key="value"
8
8
  option-value="value"
9
9
  />
@@ -18,6 +18,10 @@ import { useI18n } from 'vue-i18n';
18
18
 
19
19
  import { CallHistoryTagFilterOptions } from '../../enums/options/CallHistoryTagFilterOptions';
20
20
 
21
+ const props = defineProps<{
22
+ disableValidation?: boolean;
23
+ }>();
24
+
21
25
  const model = defineModel<string>();
22
26
  const { t } = useI18n();
23
27
 
@@ -35,8 +39,7 @@ const v$ = useVuelidate(
35
39
  },
36
40
  );
37
41
 
38
- v$.value.$touch();
39
-
42
+ if (!props?.disableValidation) v$.value.$touch();
40
43
  const emit = defineEmits<{
41
44
  'update:invalid': [
42
45
  boolean,
@@ -3,7 +3,7 @@
3
3
  :label="t('webitelUI.filters.filterValue')"
4
4
  :search-method="searchMethod"
5
5
  :model-value="model"
6
- :v="v$.model"
6
+ :v="!disableValidation && v$.model"
7
7
  option-value="id"
8
8
  @update:model-value="handleInput"
9
9
  />
@@ -20,6 +20,10 @@ import { searchMethod } from './config.js';
20
20
 
21
21
  type ModelValue = number[];
22
22
 
23
+ const props = defineProps<{
24
+ disableValidation?: boolean;
25
+ }>();
26
+
23
27
  const model = defineModel<ModelValue>();
24
28
 
25
29
  const emit = defineEmits<{
@@ -42,8 +46,7 @@ const v$ = useVuelidate(
42
46
  $autoDirty: true,
43
47
  },
44
48
  );
45
- v$.value.$touch();
46
-
49
+ if (!props?.disableValidation) v$.value.$touch();
47
50
  watch(
48
51
  () => v$.value.$invalid,
49
52
  (invalid) => {
@@ -2,7 +2,7 @@
2
2
  <wt-input-text
3
3
  v-model:model-value="model"
4
4
  :label="t('webitelUI.filters.filterValue')"
5
- :v="v$.model"
5
+ :v="!disableValidation && v$.model"
6
6
  />
7
7
  </template>
8
8
 
@@ -14,6 +14,10 @@ import { useI18n } from 'vue-i18n';
14
14
 
15
15
  type ModelValue = string;
16
16
 
17
+ const props = defineProps<{
18
+ disableValidation?: boolean;
19
+ }>();
20
+
17
21
  const model = defineModel<ModelValue>();
18
22
  if (!model.value) {
19
23
  model.value = '';
@@ -35,8 +39,7 @@ const v$ = useVuelidate(
35
39
  },
36
40
  );
37
41
 
38
- v$.value.$touch();
39
-
42
+ if (!props?.disableValidation) v$.value.$touch();
40
43
  const emit = defineEmits<{
41
44
  'update:invalid': [
42
45
  boolean,
@@ -58,6 +58,7 @@ describe('tableHeadersStoreBody', () => {
58
58
 
59
59
  beforeEach(async () => {
60
60
  localStorage.clear();
61
+ sessionStorage.clear();
61
62
 
62
63
  router = createRouter({
63
64
  history: createMemoryHistory(),
@@ -73,9 +74,9 @@ describe('tableHeadersStoreBody', () => {
73
74
  runWithRouter = (fn) => app.runWithContext(fn);
74
75
  });
75
76
 
76
- const setUpStore = async () => {
77
+ const setUpStore = async (options?: { isNested?: boolean }) => {
77
78
  const store = createStore();
78
- await runWithRouter(() => store.setupPersistence());
79
+ await runWithRouter(() => store.setupPersistence(options));
79
80
  return store;
80
81
  };
81
82
 
@@ -226,6 +227,37 @@ describe('tableHeadersStoreBody', () => {
226
227
  ]);
227
228
  expect(store.headers.value.some(({ field }) => !field)).toBe(false);
228
229
  });
230
+
231
+ describe('a nested list', () => {
232
+ it('keeps a changed sort out of the route query, in a namespaced sessionStorage key instead', async () => {
233
+ const store = await setUpStore({
234
+ isNested: true,
235
+ });
236
+
237
+ store.updateSort(store.headers.value[0], 'asc');
238
+ await flushWrites();
239
+
240
+ expect(router.currentRoute.value.query.sort).toBeUndefined();
241
+ expect(sessionStorage.getItem(`${id}/sort`)).toBe('+name');
242
+ });
243
+
244
+ it('keeps a changed field set out of the route query, in localStorage instead', async () => {
245
+ const store = await setUpStore({
246
+ isNested: true,
247
+ });
248
+
249
+ store.updateShownHeaders(
250
+ store.headers.value.map((header) => ({
251
+ ...header,
252
+ show: header.field === 'name',
253
+ })),
254
+ );
255
+ await flushWrites();
256
+
257
+ expect(router.currentRoute.value.query[fieldsQueryKey]).toBeUndefined();
258
+ expect(localStorage.getItem(fieldsQueryKey)).toBe('name');
259
+ });
260
+ });
229
261
  });
230
262
 
231
263
  describe('access', () => {
@@ -249,15 +249,23 @@ export const tableHeadersStoreBody = ({
249
249
 
250
250
  let persistedStorageControllers: PersistedStorageController[] = [];
251
251
 
252
- const setupPersistence = async () => {
252
+ const setupPersistence = async ({
253
+ isNested = false,
254
+ }: {
255
+ isNested?: boolean;
256
+ } = {}) => {
253
257
  const fieldsStorage = usePersistedStorage({
254
258
  name: 'fields',
255
259
  value: fields,
256
260
  /* order is the restore priority: a shared link wins over local columns */
257
- storages: [
258
- PersistedStorageType.Route,
259
- PersistedStorageType.LocalStorage,
260
- ],
261
+ storages: isNested
262
+ ? [
263
+ PersistedStorageType.LocalStorage,
264
+ ]
265
+ : [
266
+ PersistedStorageType.Route,
267
+ PersistedStorageType.LocalStorage,
268
+ ],
261
269
  storagePath: id,
262
270
  onStore: (save, { name }) => {
263
271
  const value = fields.value.join(',');
@@ -277,6 +285,12 @@ export const tableHeadersStoreBody = ({
277
285
  const sortStorage = usePersistedStorage({
278
286
  name: 'sort',
279
287
  value: sort,
288
+ ...(isNested && {
289
+ storages: [
290
+ PersistedStorageType.SessionStorage,
291
+ ],
292
+ storagePath: id,
293
+ }),
280
294
  });
281
295
 
282
296
  const columnWidthsStorage = usePersistedStorage({
@@ -19,6 +19,8 @@ describe('tablePaginationStoreBody', () => {
19
19
  let runWithRouter: <T>(fn: () => T) => T;
20
20
 
21
21
  beforeEach(async () => {
22
+ sessionStorage.clear();
23
+
22
24
  router = createRouter({
23
25
  history: createMemoryHistory(),
24
26
  routes,
@@ -33,9 +35,14 @@ describe('tablePaginationStoreBody', () => {
33
35
  runWithRouter = (fn) => app.runWithContext(fn);
34
36
  });
35
37
 
36
- const setUpStore = async () => {
37
- const store = tablePaginationStoreBody();
38
- await runWithRouter(() => store.setupPersistence());
38
+ const setUpStore = async (
39
+ options?: {
40
+ isNested?: boolean;
41
+ },
42
+ namespace?: string,
43
+ ) => {
44
+ const store = tablePaginationStoreBody(namespace);
45
+ await runWithRouter(() => store.setupPersistence(options));
39
46
  return store;
40
47
  };
41
48
 
@@ -131,4 +138,21 @@ describe('tablePaginationStoreBody', () => {
131
138
  expect(router.currentRoute.value.query.page).toBe('5');
132
139
  });
133
140
  });
141
+
142
+ describe('a nested list', () => {
143
+ it('keeps a changed page out of the route query, in a namespaced sessionStorage key instead', async () => {
144
+ const store = await setUpStore(
145
+ {
146
+ isNested: true,
147
+ },
148
+ 'cases',
149
+ );
150
+
151
+ store.updatePage(3);
152
+ await new Promise((resolve) => setTimeout(resolve));
153
+
154
+ expect(router.currentRoute.value.query.page).toBeUndefined();
155
+ expect(sessionStorage.getItem('cases/page')).toBe('3');
156
+ });
157
+ });
134
158
  });
@@ -1,12 +1,15 @@
1
1
  import { ref } from 'vue';
2
2
 
3
3
  import { createDatalistStore } from '../_shared/createDatalistStore';
4
- import type { PersistedStorageController } from '../persist/PersistedStorage.types';
4
+ import {
5
+ type PersistedStorageController,
6
+ PersistedStorageType,
7
+ } from '../persist/PersistedStorage.types';
5
8
  import { usePersistedStorage } from '../persist/usePersistedStorage';
6
9
  import type { Identifiable } from '../types/createDatalistStore.types';
7
10
  import type { useTableStoreConfig } from '../types/tableStore.types';
8
11
 
9
- export const tablePaginationStoreBody = () => {
12
+ export const tablePaginationStoreBody = (namespace?: string) => {
10
13
  const page = ref(1);
11
14
  const size = ref(10);
12
15
  const next = ref(false);
@@ -27,10 +30,20 @@ export const tablePaginationStoreBody = () => {
27
30
 
28
31
  let persistedStorageControllers: PersistedStorageController[] = [];
29
32
 
30
- const setupPersistence = () => {
33
+ const setupPersistence = ({
34
+ isNested = false,
35
+ }: {
36
+ isNested?: boolean;
37
+ } = {}) => {
31
38
  const pageStorage = usePersistedStorage({
32
39
  name: 'page',
33
40
  value: page,
41
+ ...(isNested && {
42
+ storages: [
43
+ PersistedStorageType.SessionStorage,
44
+ ],
45
+ storagePath: namespace,
46
+ }),
34
47
  onStore: (save, { name }) => {
35
48
  return save({
36
49
  name,
@@ -47,6 +60,12 @@ export const tablePaginationStoreBody = () => {
47
60
  const sizeStorage = usePersistedStorage({
48
61
  name: 'size',
49
62
  value: size,
63
+ ...(isNested && {
64
+ storages: [
65
+ PersistedStorageType.SessionStorage,
66
+ ],
67
+ storagePath: namespace,
68
+ }),
50
69
  onStore: (save, { name }) => {
51
70
  return save({
52
71
  name,
@@ -98,7 +117,7 @@ export const createTablePaginationStore = <Entity extends Identifiable>(
98
117
  ) => {
99
118
  const id = `${namespace}/pagination`;
100
119
  return createDatalistStore({
101
- storeBody: tablePaginationStoreBody,
120
+ storeBody: () => tablePaginationStoreBody(namespace),
102
121
  namespace: id,
103
122
  config,
104
123
  });
@@ -259,4 +259,30 @@ describe('tableStoreBody', () => {
259
259
  );
260
260
  });
261
261
  });
262
+
263
+ describe('filters persistence of a nested list', () => {
264
+ it('keeps an added filter out of the route query, in sessionStorage instead', async () => {
265
+ const useStore = createTableStore('cases-nested-filters/datalist', {
266
+ apiModule: {
267
+ getList,
268
+ },
269
+ headers,
270
+ });
271
+
272
+ mountTab(useStore);
273
+ await flush();
274
+
275
+ const store = useStore();
276
+ store.addFilter({
277
+ name: 'search',
278
+ value: 'lorem',
279
+ });
280
+ await flush();
281
+
282
+ expect(router.currentRoute.value.query).toEqual({});
283
+ expect(
284
+ sessionStorage.getItem('cases-nested-filters/datalist/filters'),
285
+ ).toContain('lorem');
286
+ });
287
+ });
262
288
  });
@@ -1,21 +1,28 @@
1
1
  import deepEqual from 'deep-equal';
2
- import set from 'lodash/set';
3
- import { nextTick, type Ref, ref, toRaw, watch } from 'vue';
2
+ import { set } from 'lodash-es';
3
+ import { computed, nextTick, type Ref, ref, toRaw, watch } from 'vue';
4
4
 
5
5
  import {
6
6
  createDatalistStore,
7
7
  makeThisToRefs,
8
8
  } from '../_shared/createDatalistStore';
9
+ import type { FilterName } from '../filters';
9
10
  import { createTableFiltersStore } from '../filters/createTableFiltersStore';
10
11
  import { createTableHeadersStore } from '../headers/createTableHeadersStore';
11
12
  import { createTablePaginationStore } from '../pagination/createTablePaginationStore';
12
13
  import type { Identifiable } from '../types/createDatalistStore.types';
13
14
  import type {
15
+ DatalistTableHeader,
14
16
  LoadDataListOptions,
15
17
  PatchItemPropertyParams,
16
18
  useTableStoreConfig,
17
19
  } from '../types/tableStore.types';
18
20
 
21
+ const getFilterName = (
22
+ filter: DatalistTableHeader['filter'],
23
+ ): FilterName | undefined =>
24
+ typeof filter === 'object' ? filter?.name : filter;
25
+
19
26
  export const tableStoreBody = <Entity extends Identifiable>(
20
27
  namespace: string,
21
28
  config: useTableStoreConfig<Entity>,
@@ -58,8 +65,8 @@ export const tableStoreBody = <Entity extends Identifiable>(
58
65
 
59
66
  const headersStore = useHeadersStore();
60
67
  const {
61
- headers,
62
- shownHeaders,
68
+ headers: rawHeaders,
69
+ shownHeaders: rawShownHeaders,
63
70
  fields,
64
71
  sort,
65
72
  columnWidths,
@@ -90,6 +97,20 @@ export const tableStoreBody = <Entity extends Identifiable>(
90
97
  updateSearchMode,
91
98
  } = filtersStore;
92
99
 
100
+ const withFilteredFlag = (list: DatalistTableHeader[]) =>
101
+ list.map((header) => {
102
+ const name = getFilterName(header.filter);
103
+ return name
104
+ ? {
105
+ ...header,
106
+ filtered: filtersManager.value.hasFilter(name),
107
+ }
108
+ : header;
109
+ });
110
+
111
+ const headers = computed(() => withFilteredFlag(rawHeaders.value));
112
+ const shownHeaders = computed(() => withFilteredFlag(rawShownHeaders.value));
113
+
93
114
  /**
94
115
  * @internal
95
116
  * @description
@@ -317,9 +338,15 @@ export const tableStoreBody = <Entity extends Identifiable>(
317
338
 
318
339
  if (!disablePersistence) {
319
340
  await Promise.allSettled([
320
- setupPaginationPersistence(),
321
- setupFiltersPersistence(),
322
- setupHeadersPersistence(),
341
+ setupPaginationPersistence({
342
+ isNested: isNested.value,
343
+ }),
344
+ setupFiltersPersistence({
345
+ isNested: isNested.value,
346
+ }),
347
+ setupHeadersPersistence({
348
+ isNested: isNested.value,
349
+ }),
323
350
  ]);
324
351
  }
325
352
 
@@ -367,14 +394,6 @@ export const tableStoreBody = <Entity extends Identifiable>(
367
394
 
368
395
  await setupStore();
369
396
 
370
- /*
371
- on the first setup the restore path is authoritative.
372
-
373
- a store initialized with a parentId is a list nested in a card page, not a
374
- registry: it shares the query param names with the registry stores, and
375
- the url it would publish into is the card one – so it keeps writing on
376
- change only, and syncs merely on demand
377
- */
378
397
  if (isStoreAlreadySetUp && !disablePersistence && !storeParentId) {
379
398
  await syncPersistence();
380
399
  }
@@ -2,15 +2,26 @@ import type { ApiModule } from '@webitel/ui-sdk/api/types/ApiModule';
2
2
  import type { WtTableHeader } from '@webitel/ui-sdk/components/wt-table/types/WtTable';
3
3
  import type { Ref } from 'vue';
4
4
 
5
- import type { IFiltersManager } from '../filters';
5
+ import type { FilterName, IFiltersManager } from '../filters';
6
6
  import type { DatalistStoreProviderType } from './StoreProvider';
7
7
 
8
+ /**
9
+ * Minimal shape of an already-resolved header filter. Deliberately not the full
10
+ * `AnyFilterConfig` (with its `Component` props): `createTableHeadersStore` keeps headers in a
11
+ * plain `ref<DatalistTableHeader[]>`, and `Component` props there send Vue's `UnwrapRef` into
12
+ * excessive type-instantiation depth (TS2589). `useColumnFilter`'s `isResolvedFilterConfig`
13
+ * narrows a value of this shape back to `AnyFilterConfig` for actual use.
14
+ */
15
+ export type ResolvedHeaderFilter = {
16
+ name: FilterName;
17
+ };
18
+
8
19
  /**
9
20
  * Table header shape used inside the datalist stores. In addition to the
10
21
  * base {@link WtTableHeader} shape, datalist stores key columns by `field`
11
22
  * and may flag dynamically-appended headers for lazy initialization.
12
23
  */
13
- export type DatalistTableHeader = WtTableHeader & {
24
+ export type DatalistTableHeader = Omit<WtTableHeader, 'filter'> & {
14
25
  field: string;
15
26
  shouldBeInitialized?: boolean;
16
27
  /**
@@ -20,6 +31,14 @@ export type DatalistTableHeader = WtTableHeader & {
20
31
  * restorable from persisted state. Omitted means allowed.
21
32
  */
22
33
  access?: () => boolean | Ref<boolean>;
34
+ /**
35
+ * Name of the filter shown in the column header popover (`column-filter` slot),
36
+ * or an already-resolved config for it (build one with `createFilterConfig`). Passing a
37
+ * config here lets `headers.ts` map the header to its filter once, instead of
38
+ * `useColumnFilter` searching `filterOptions`/`filterableExtensionFields` for it on every
39
+ * column.
40
+ */
41
+ filter?: WtTableHeader['filter'] | ResolvedHeaderFilter;
23
42
  };
24
43
 
25
44
  export type TrackSelectedRowBy<T> = (row: T) => T;