@webitel/ui-datalist 26.8.7 → 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 (137) hide show
  1. package/package.json +1 -1
  2. package/src/modules/filter-presets/components/apply-preset/apply-preset-action.vue +16 -4
  3. package/src/modules/filter-presets/components/save-preset/save-preset-action.vue +18 -4
  4. package/src/modules/filters/components/column/column-filter-preview.vue +70 -0
  5. package/src/modules/filters/components/column/column-filter.vue +76 -0
  6. package/src/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-value-input.vue +2 -0
  7. package/src/modules/filters/components/config/dynamic-view/dynamic-filter-config-form.vue +43 -5
  8. package/src/modules/filters/components/config/static-view/static-filter-field.vue +6 -21
  9. package/src/modules/filters/components/filters-actions-menu.vue +177 -0
  10. package/src/modules/filters/components/preview/dynamic-filter-preview.vue +5 -60
  11. package/src/modules/filters/components/table-filters-panel.vue +6 -28
  12. package/src/modules/filters/components/types/Filter.types.ts +5 -0
  13. package/src/modules/filters/composables/useColumnFilter.ts +116 -0
  14. package/src/modules/filters/composables/useFilterValueChange.ts +58 -0
  15. package/src/modules/filters/composables/useFilterValuePreview.ts +87 -0
  16. package/src/modules/filters/composables/useSelectedFilters.ts +64 -0
  17. package/src/modules/filters/index.ts +4 -0
  18. package/src/modules/filters/modules/filterConfig/components/_custom/type-extension-filter-value-field.vue +9 -5
  19. package/src/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-filter-value-field.vue +7 -4
  20. package/src/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-options/date-time-options-filter-value-field.vue +7 -4
  21. package/src/modules/filters/modules/filterConfig/components/_shared/durations/duration-filter-value-field.vue +7 -4
  22. package/src/modules/filters/modules/filterConfig/components/_shared/string-filter/string-filter-value-field.vue +6 -3
  23. package/src/modules/filters/modules/filterConfig/components/agent/agent-filter-value-field.vue +6 -3
  24. package/src/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue +6 -3
  25. package/src/modules/filters/modules/filterConfig/components/call-direction/call-direction-filter-value-field.vue +6 -3
  26. package/src/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue +4 -4
  27. package/src/modules/filters/modules/filterConfig/components/case-author/case-author-filter-value-field.vue +6 -3
  28. package/src/modules/filters/modules/filterConfig/components/case-close-reason-groups/case-close-reason-groups-filter-value-field.vue +7 -4
  29. package/src/modules/filters/modules/filterConfig/components/case-impacted/case-impacted-filter-value-field.vue +6 -3
  30. package/src/modules/filters/modules/filterConfig/components/case-priority/case-priority-filter-value-field.vue +6 -3
  31. package/src/modules/filters/modules/filterConfig/components/case-reporter/case-reporter-filter-value-field.vue +6 -3
  32. package/src/modules/filters/modules/filterConfig/components/case-service/case-service-filter-value-field.vue +1 -32
  33. package/src/modules/filters/modules/filterConfig/components/case-sla/case-sla-filter-value-field.vue +6 -3
  34. package/src/modules/filters/modules/filterConfig/components/case-sla-condition/case-sla-condition-filter-value-field.vue +7 -4
  35. package/src/modules/filters/modules/filterConfig/components/case-source/case-source-filter-value-field.vue +6 -3
  36. package/src/modules/filters/modules/filterConfig/components/case-status/case-status-filter-value-field.vue +7 -4
  37. package/src/modules/filters/modules/filterConfig/components/contact/contact-filter-value-field.vue +6 -3
  38. package/src/modules/filters/modules/filterConfig/components/contact-owner/contact-owner-filter-value-field.vue +3 -3
  39. package/src/modules/filters/modules/filterConfig/components/gateway/gateway-filter-value-field.vue +6 -3
  40. package/src/modules/filters/modules/filterConfig/components/grantee/grantee-filter-value-field.vue +6 -3
  41. package/src/modules/filters/modules/filterConfig/components/hangup-cause/hangup-cause-filter-value-field.vue +6 -3
  42. package/src/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue +6 -3
  43. package/src/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue +6 -3
  44. package/src/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue +7 -4
  45. package/src/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue +4 -4
  46. package/src/modules/filters/modules/filterConfig/components/tag/tag-filter-value-field.vue +6 -3
  47. package/src/modules/filters/modules/filterConfig/components/user/user-filter-value-field.vue +6 -3
  48. package/src/modules/filters/modules/filterConfig/components/variable/variable-filter-value-field.vue +6 -3
  49. package/src/modules/table/createTableStore.store.ts +24 -3
  50. package/src/modules/types/tableStore.types.ts +21 -2
  51. package/types/.tsbuildinfo +1 -1
  52. package/types/modules/filter-presets/components/apply-preset/apply-preset-action.vue.d.ts +15 -1
  53. package/types/modules/filter-presets/components/save-preset/save-preset-action.vue.d.ts +17 -1
  54. package/types/modules/filter-presets/stores/createFilterPresetsStore.d.ts +2 -35
  55. package/types/modules/filters/components/column/column-filter-preview.vue.d.ts +21 -0
  56. package/types/modules/filters/components/column/column-filter.vue.d.ts +36 -0
  57. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-label.vue.d.ts +2 -2
  58. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form-value-input.vue.d.ts +3 -2
  59. package/types/modules/filters/components/config/dynamic-view/dynamic-filter-config-form.vue.d.ts +13 -1
  60. package/types/modules/filters/components/config/static-view/static-filter-field.vue.d.ts +2 -2
  61. package/types/modules/filters/components/filters-actions-menu.vue.d.ts +29 -0
  62. package/types/modules/filters/components/table-filters-panel.vue.d.ts +6 -6
  63. package/types/modules/filters/components/types/Filter.types.d.ts +4 -0
  64. package/types/modules/filters/composables/useColumnFilter.d.ts +27 -0
  65. package/types/modules/filters/composables/useFilterValueChange.d.ts +23 -0
  66. package/types/modules/filters/composables/useFilterValuePreview.d.ts +21 -0
  67. package/types/modules/filters/composables/useSelectedFilters.d.ts +22 -0
  68. package/types/modules/filters/index.d.ts +3 -1
  69. package/types/modules/filters/modules/filterConfig/components/_custom/type-extension-filter-value-field.vue.d.ts +3 -2
  70. package/types/modules/filters/modules/filterConfig/components/_shared/date-time-filter/date-time-filter-value-field.vue.d.ts +8 -4
  71. 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
  72. package/types/modules/filters/modules/filterConfig/components/_shared/durations/duration-filter-value-field.vue.d.ts +8 -4
  73. package/types/modules/filters/modules/filterConfig/components/_shared/string-filter/string-filter-value-field.vue.d.ts +8 -4
  74. package/types/modules/filters/modules/filterConfig/components/agent/agent-filter-value-field.vue.d.ts +8 -4
  75. package/types/modules/filters/modules/filterConfig/components/agent-status/agent-status-filter-value-field.vue.d.ts +2 -2
  76. package/types/modules/filters/modules/filterConfig/components/amd-result/amd-result-filter-value-field.vue.d.ts +8 -4
  77. package/types/modules/filters/modules/filterConfig/components/auditor/auditor-filter-value-field.vue.d.ts +2 -2
  78. package/types/modules/filters/modules/filterConfig/components/auditor/index.d.ts +2 -2
  79. package/types/modules/filters/modules/filterConfig/components/bucket/bucket-filter-value-field.vue.d.ts +2 -2
  80. package/types/modules/filters/modules/filterConfig/components/bucket/index.d.ts +2 -2
  81. package/types/modules/filters/modules/filterConfig/components/call-direction/call-direction-filter-value-field.vue.d.ts +8 -4
  82. package/types/modules/filters/modules/filterConfig/components/call-reporting-result/call-reporting-result-filter-value-field.vue.d.ts +2 -2
  83. package/types/modules/filters/modules/filterConfig/components/case-assignee/case-assignee-filter-value-field.vue.d.ts +3 -2
  84. package/types/modules/filters/modules/filterConfig/components/case-assignee/filterConfig.d.ts +4 -2
  85. package/types/modules/filters/modules/filterConfig/components/case-author/case-author-filter-value-field.vue.d.ts +8 -4
  86. package/types/modules/filters/modules/filterConfig/components/case-close-reason-groups/case-close-reason-groups-filter-value-field.vue.d.ts +8 -4
  87. package/types/modules/filters/modules/filterConfig/components/case-impacted/case-impacted-filter-value-field.vue.d.ts +8 -4
  88. package/types/modules/filters/modules/filterConfig/components/case-priority/case-priority-filter-value-field.vue.d.ts +8 -4
  89. package/types/modules/filters/modules/filterConfig/components/case-reporter/case-reporter-filter-value-field.vue.d.ts +8 -4
  90. package/types/modules/filters/modules/filterConfig/components/case-sla/case-sla-filter-value-field.vue.d.ts +8 -4
  91. package/types/modules/filters/modules/filterConfig/components/case-sla-condition/case-sla-condition-filter-value-field.vue.d.ts +8 -4
  92. package/types/modules/filters/modules/filterConfig/components/case-source/case-source-filter-value-field.vue.d.ts +8 -4
  93. package/types/modules/filters/modules/filterConfig/components/case-status/case-status-filter-value-field.vue.d.ts +8 -4
  94. package/types/modules/filters/modules/filterConfig/components/contact/contact-filter-value-field.vue.d.ts +8 -4
  95. package/types/modules/filters/modules/filterConfig/components/contact-group/contact-group-filter-value-field.vue.d.ts +2 -2
  96. package/types/modules/filters/modules/filterConfig/components/contact-group/index.d.ts +2 -2
  97. package/types/modules/filters/modules/filterConfig/components/contact-label/contact-label-filter-value-field.vue.d.ts +2 -2
  98. package/types/modules/filters/modules/filterConfig/components/contact-label/index.d.ts +2 -2
  99. package/types/modules/filters/modules/filterConfig/components/contact-owner/contact-owner-filter-value-field.vue.d.ts +3 -2
  100. package/types/modules/filters/modules/filterConfig/components/contact-owner/index.d.ts +4 -2
  101. package/types/modules/filters/modules/filterConfig/components/gateway/gateway-filter-value-field.vue.d.ts +8 -4
  102. package/types/modules/filters/modules/filterConfig/components/grantee/grantee-filter-value-field.vue.d.ts +8 -4
  103. package/types/modules/filters/modules/filterConfig/components/hangup-cause/hangup-cause-filter-value-field.vue.d.ts +8 -4
  104. package/types/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue.d.ts +8 -4
  105. package/types/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue.d.ts +2 -2
  106. package/types/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue.d.ts +2 -2
  107. package/types/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue.d.ts +2 -2
  108. package/types/modules/filters/modules/filterConfig/components/has-user/has-user-filter-value-field.vue.d.ts +2 -2
  109. package/types/modules/filters/modules/filterConfig/components/index.d.ts +24 -22
  110. package/types/modules/filters/modules/filterConfig/components/queue/index.d.ts +2 -2
  111. package/types/modules/filters/modules/filterConfig/components/queue/queue-filter-value-field.vue.d.ts +2 -2
  112. package/types/modules/filters/modules/filterConfig/components/queue-period/queue-period-filter-value-field.vue.d.ts +2 -2
  113. package/types/modules/filters/modules/filterConfig/components/queue-type/queue-type-filter-value-field.vue.d.ts +2 -2
  114. package/types/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue.d.ts +8 -4
  115. package/types/modules/filters/modules/filterConfig/components/rating/rating-from-to-filter-value-field.vue.d.ts +8 -4
  116. package/types/modules/filters/modules/filterConfig/components/region/index.d.ts +2 -2
  117. package/types/modules/filters/modules/filterConfig/components/region/region-filter-value-field.vue.d.ts +2 -2
  118. package/types/modules/filters/modules/filterConfig/components/score/score-from-to-filter-value-field.vue.d.ts +3 -2
  119. package/types/modules/filters/modules/filterConfig/components/skill/index.d.ts +2 -2
  120. package/types/modules/filters/modules/filterConfig/components/skill/skill-filter-value-field.vue.d.ts +2 -2
  121. package/types/modules/filters/modules/filterConfig/components/stop-cause/stop-cause-filter-value-field.vue.d.ts +2 -2
  122. package/types/modules/filters/modules/filterConfig/components/supervisor/index.d.ts +2 -2
  123. package/types/modules/filters/modules/filterConfig/components/supervisor/supervisor-filter-value-field.vue.d.ts +2 -2
  124. package/types/modules/filters/modules/filterConfig/components/tag/tag-filter-value-field.vue.d.ts +8 -4
  125. package/types/modules/filters/modules/filterConfig/components/tags/index.d.ts +2 -2
  126. package/types/modules/filters/modules/filterConfig/components/tags/tags-filter-value-field.vue.d.ts +2 -2
  127. package/types/modules/filters/modules/filterConfig/components/talk-duration/talk-duration-filter-value-field.vue.d.ts +2 -2
  128. package/types/modules/filters/modules/filterConfig/components/team/index.d.ts +2 -2
  129. package/types/modules/filters/modules/filterConfig/components/team/team-filter-value-field.vue.d.ts +2 -2
  130. package/types/modules/filters/modules/filterConfig/components/total-duration/total-duration-filter-value-field.vue.d.ts +2 -2
  131. package/types/modules/filters/modules/filterConfig/components/user/user-filter-value-field.vue.d.ts +8 -4
  132. package/types/modules/filters/modules/filterConfig/components/utilization-progress/utilization-progress-filter-value-field.vue.d.ts +2 -2
  133. package/types/modules/filters/modules/filterConfig/components/variable/variable-filter-value-field.vue.d.ts +8 -4
  134. package/types/modules/headers/createTableHeadersStore.d.ts +42 -18
  135. package/types/modules/permissions-page/stores/createPermissionsStore.d.ts +4 -70
  136. package/types/modules/table/createTableStore.store.d.ts +76 -141
  137. package/types/modules/types/tableStore.types.d.ts +20 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-datalist",
3
- "version": "26.8.7",
3
+ "version": "26.8.8",
4
4
  "description": "Toolkit for building data lists in webitel ui system",
5
5
  "scripts": {
6
6
  "build:types": "vue-tsc -b tsconfig.build.json",
@@ -1,9 +1,14 @@
1
1
  <template>
2
2
  <div class="apply-preset-action">
3
- <wt-icon-action
4
- :action="IconAction.APPLY_PRESET"
5
- @click="showPresetsList = true"
6
- />
3
+ <slot
4
+ name="activator"
5
+ :open="() => (showPresetsList = true)"
6
+ >
7
+ <wt-icon-action
8
+ :action="IconAction.APPLY_PRESET"
9
+ @click="showPresetsList = true"
10
+ />
11
+ </slot>
7
12
  <wt-popup
8
13
  :shown="showPresetsList"
9
14
  size="md"
@@ -128,6 +133,13 @@ const { t } = useI18n();
128
133
 
129
134
  const showPresetsList = ref(false);
130
135
 
136
+ /** lets a parent (e.g. filters actions menu) open the popup without the icon */
137
+ defineExpose({
138
+ open: () => {
139
+ showPresetsList.value = true;
140
+ },
141
+ });
142
+
131
143
  const { dataList, error, isLoading, filtersManager, presetId } = storeToRefs(
132
144
  props.presetsStore,
133
145
  );
@@ -1,10 +1,16 @@
1
1
  <template>
2
2
  <div class="save-preset-action">
3
- <wt-icon-action
4
- :action="IconAction.SAVE_PRESET"
3
+ <slot
4
+ name="activator"
5
+ :open="() => (showSaveForm = true)"
5
6
  :disabled="disableAction"
6
- @click="showSaveForm = true"
7
- />
7
+ >
8
+ <wt-icon-action
9
+ :action="IconAction.SAVE_PRESET"
10
+ :disabled="disableAction"
11
+ @click="showSaveForm = true"
12
+ />
13
+ </slot>
8
14
 
9
15
  <save-preset-popup
10
16
  v-if="
@@ -100,6 +106,14 @@ const disableAction = computed(() => {
100
106
  * */
101
107
  const showSaveForm = ref(false);
102
108
 
109
+ /** lets a parent (e.g. filters actions menu) open the popup without the icon */
110
+ defineExpose({
111
+ open: () => {
112
+ showSaveForm.value = true;
113
+ },
114
+ disabled: disableAction,
115
+ });
116
+
103
117
  /**
104
118
  * if preset with the same name already exists, this will be suggested to set to that preset
105
119
  */
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <dynamic-filter-preview-info
3
+ v-if="filter"
4
+ class="column-filter-preview"
5
+ >
6
+ <template #header>
7
+ {{ filterConfig.label }}
8
+ </template>
9
+
10
+ <template #default>
11
+ <wt-loader
12
+ v-if="!isRenderPreview"
13
+ :size="ComponentSize.SM"
14
+ />
15
+ <component
16
+ v-else
17
+ :is="filterConfig.valuePreviewComponent"
18
+ :filter="filter"
19
+ :filter-config="filterConfig"
20
+ :value="localValue"
21
+ />
22
+ </template>
23
+ </dynamic-filter-preview-info>
24
+ </template>
25
+
26
+ <script lang="ts" setup>
27
+ import type { DataField } from '@webitel/api-services/gen/models';
28
+ import { WtLoader } from '@webitel/ui-sdk/components';
29
+ import { ComponentSize } from '@webitel/ui-sdk/enums';
30
+
31
+ import type { DatalistTableHeader } from '../../../types/tableStore.types';
32
+ import type { IFiltersManager } from '../../classes/FiltersManager';
33
+ import { useColumnFilter } from '../../composables/useColumnFilter';
34
+ import { useFilterValuePreview } from '../../composables/useFilterValuePreview';
35
+ import type { FilterConfigDefinition } from '../../modules/filterConfig/types/FilterConfigDefinition';
36
+ import DynamicFilterPreviewInfo from '../preview/dynamic-filter-preview-info.vue';
37
+
38
+ /**
39
+ * Hover preview of an applied column filter (`column-filter` slot, `formView: false`):
40
+ * the same "label + values" card the panel chip shows on hover.
41
+ *
42
+ * [WTEL-7727](https://webitel.atlassian.net/browse/WTEL-7727)
43
+ */
44
+ const props = defineProps<{
45
+ header: DatalistTableHeader;
46
+ filtersManager: IFiltersManager;
47
+ /** the page's filter definitions; a configured one is reused for the matching header */
48
+ filterOptions?: FilterConfigDefinition[];
49
+ /** custom (type extension) fields the table can filter by; matched to the header by field id */
50
+ filterableExtensionFields?: DataField[];
51
+ }>();
52
+
53
+ const { filterConfig, filter } = useColumnFilter({
54
+ header: () => props.header,
55
+ filtersManager: () => props.filtersManager,
56
+ filterOptions: () => props.filterOptions ?? [],
57
+ filterableExtensionFields: () => props.filterableExtensionFields ?? [],
58
+ });
59
+
60
+ const { localValue, isRenderPreview } = useFilterValuePreview({
61
+ filter,
62
+ filterConfig,
63
+ });
64
+ </script>
65
+
66
+ <style lang="scss" scoped>
67
+ .wt-loader {
68
+ margin: auto;
69
+ }
70
+ </style>
@@ -0,0 +1,76 @@
1
+ <template>
2
+ <column-filter-preview
3
+ v-if="!formView"
4
+ :header="header"
5
+ :filters-manager="filtersManager"
6
+ :filter-options="filterOptions"
7
+ :filterable-extension-fields="filterableExtensionFields"
8
+ />
9
+ <dynamic-filter-config-form
10
+ v-else
11
+ class="column-filter"
12
+ :filter="filter"
13
+ :filter-config="filterConfig"
14
+ column-mode
15
+ @cancel="close"
16
+ @submit="onSubmit"
17
+ />
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import type { DataField } from '@webitel/api-services/gen/models';
22
+
23
+ import type { DatalistTableHeader } from '../../../types/tableStore.types';
24
+ import type { FilterInitParams } from '../../classes/Filter';
25
+ import type { IFiltersManager } from '../../classes/FiltersManager';
26
+ import { useColumnFilter } from '../../composables/useColumnFilter';
27
+ import { useFilterValueChange } from '../../composables/useFilterValueChange';
28
+ import type { FilterConfigDefinition } from '../../modules/filterConfig/types/FilterConfigDefinition';
29
+ import DynamicFilterConfigForm from '../config/dynamic-view/dynamic-filter-config-form.vue';
30
+ import type { ColumnFilterEmits } from '../types/Filter.types';
31
+ import ColumnFilterPreview from './column-filter-preview.vue';
32
+
33
+ /**
34
+ * Column header filter for the `wt-table` `column-filter` slot, bound with `v-bind="scope"`:
35
+ * `formView: true` renders the value form in the filter popover, `false` the hover card.
36
+ * Resolves the filter from `header.filter`, reads the applied value from the filters manager and,
37
+ * like the panel, only emits — the app binds `add/update/delete:filter` to its table store:
38
+ * Apply → `add:filter` / `update:filter`; Clear then Apply → `delete:filter`; then the popover is closed via `hide`.
39
+ * Values stay local to the form until Apply, so the table doesn't reload on every click.
40
+ *
41
+ * [WTEL-7727](https://webitel.atlassian.net/browse/WTEL-7727)
42
+ */
43
+ const props = defineProps<{
44
+ header: DatalistTableHeader;
45
+ filtersManager: IFiltersManager;
46
+ filterOptions?: FilterConfigDefinition[];
47
+ filterableExtensionFields?: DataField[];
48
+ formView?: boolean;
49
+ hide?: () => void;
50
+ }>();
51
+
52
+ const emit = defineEmits<ColumnFilterEmits>();
53
+
54
+ const { filterConfig, filter } = useColumnFilter({
55
+ header: () => props.header,
56
+ filtersManager: () => props.filtersManager,
57
+ filterOptions: () => props.filterOptions ?? [],
58
+ filterableExtensionFields: () => props.filterableExtensionFields ?? [],
59
+ });
60
+
61
+ const { onValueChange } = useFilterValueChange({
62
+ filterConfig,
63
+ filter,
64
+ emit,
65
+ });
66
+
67
+ const close = () => {
68
+ props.hide?.();
69
+ emit('close');
70
+ };
71
+
72
+ const onSubmit = ({ value }: FilterInitParams) => {
73
+ onValueChange(value);
74
+ close();
75
+ };
76
+ </script>
@@ -4,6 +4,7 @@
4
4
  v-model:model-value="filterValue"
5
5
  :label="label"
6
6
  :filter-config="props.filterConfig"
7
+ :disable-validation="disableValidation"
7
8
  @update:invalid="emit('update:invalid', $event)"
8
9
  />
9
10
  </template>
@@ -16,6 +17,7 @@ const filterValue = defineModel<unknown>();
16
17
  const props = defineProps<{
17
18
  filterConfig: AnyFilterConfig;
18
19
  label?: string;
20
+ disableValidation?: boolean;
19
21
  }>();
20
22
 
21
23
  const emit = defineEmits<{
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <form class="dynamic-filter-config-form" @submit.prevent>
3
3
  <wt-single-select
4
+ v-if="!columnMode"
4
5
  :show-clear="false"
5
6
  :disabled="editMode"
6
7
  :label="t('webitelUI.filters.filterName')"
@@ -20,6 +21,7 @@
20
21
  filterName,
21
22
  filterValue,
22
23
  inputLabel: valueInputLabelText,
24
+ disableValidation: columnMode,
23
25
  onValueChange,
24
26
  onValueInvalidChange,
25
27
  }"
@@ -30,12 +32,14 @@
30
32
  :model-value="filterValue"
31
33
  :filter-config="selectedFilterConfig"
32
34
  :label="valueInputLabelText"
35
+ :disable-validation="columnMode"
33
36
  @update:model-value="onValueChange"
34
37
  @update:invalid="onValueInvalidChange"
35
38
  />
36
39
  </slot>
37
40
 
38
41
  <dynamic-filter-config-form-label
42
+ v-if="!columnMode"
39
43
  :value="filterLabel"
40
44
  @update:model-value="onLabelValueUpdate"
41
45
  @update:invalid="(v) => (invalid = v)"
@@ -43,19 +47,19 @@
43
47
 
44
48
  <footer class="dynamic-filter-config-form-footer">
45
49
  <wt-button
46
- :disabled="invalid || v$.$invalid"
50
+ :disabled="isSubmitDisabled"
47
51
  wide
48
52
  @click="submit"
49
53
  >
50
- {{ t('reusable.save') }}
54
+ {{ t('vocabulary.apply') }}
51
55
  </wt-button>
52
56
 
53
57
  <wt-button
54
58
  color="secondary"
55
59
  wide
56
- @click="emit('cancel')"
60
+ @click="columnMode ? handleClear() : emit('cancel')"
57
61
  >
58
- {{ t('reusable.cancel') }}
62
+ {{ columnMode ? t('reusable.clear') : t('reusable.cancel') }}
59
63
  </wt-button>
60
64
  </footer>
61
65
  </form>
@@ -65,6 +69,7 @@
65
69
  import { useVuelidate } from '@vuelidate/core';
66
70
  import { required } from '@vuelidate/validators';
67
71
  import { WtButton, WtSingleSelect } from '@webitel/ui-sdk/components';
72
+ import { isEmpty } from '@webitel/ui-sdk/scripts';
68
73
  import deepcopy from 'deep-copy';
69
74
  import { computed, ref, watch } from 'vue';
70
75
  import { useI18n } from 'vue-i18n';
@@ -90,6 +95,17 @@ const props = defineProps<{
90
95
  * Edited filter instance
91
96
  */
92
97
  filter?: IFilter;
98
+ /**
99
+ * @description
100
+ * Column filter mode: the filter is fixed by `filterConfig`, so only the value input is shown
101
+ * (no filter name select, no label); the secondary button is "Clear" (empties the value) instead
102
+ * of "Cancel", and Apply goes through with an empty value — deleting the filter.
103
+ * A `notDeletable` filter config keeps Apply disabled on an empty value instead,
104
+ * the same way its panel chip has no "x".
105
+ *
106
+ * [WTEL-7727](https://webitel.atlassian.net/browse/WTEL-7727)
107
+ */
108
+ columnMode?: boolean;
93
109
  }>();
94
110
 
95
111
  const emit = defineEmits<{
@@ -101,7 +117,7 @@ const emit = defineEmits<{
101
117
 
102
118
  const { t } = useI18n();
103
119
 
104
- const filterName = ref();
120
+ const filterName = ref<string | undefined>(props.filterConfig?.name);
105
121
  const filterLabel = ref('');
106
122
  const filterValue = ref();
107
123
 
@@ -124,6 +140,16 @@ v$.value.$touch();
124
140
 
125
141
  const invalid = ref(false);
126
142
 
143
+ const isSubmitDisabled = computed(() => {
144
+ if (props.columnMode && isEmpty(filterValue.value)) {
145
+ return !editMode || !filterName.value || !!props.filterConfig?.notDeletable;
146
+ }
147
+
148
+ if (v$.value.$invalid) return true;
149
+
150
+ return invalid.value;
151
+ });
152
+
127
153
  const filterConfigOptions = computed(() => {
128
154
  if (props.filterConfig) {
129
155
  return [
@@ -148,6 +174,16 @@ const onValueChange = (v: unknown) => {
148
174
  filterValue.value = v;
149
175
  };
150
176
 
177
+ const clearValue = () => {
178
+ filterValue.value = null;
179
+ invalid.value = false;
180
+ };
181
+
182
+ const handleClear = () => {
183
+ clearValue();
184
+ if (!isSubmitDisabled.value) submit();
185
+ };
186
+
151
187
  const onValueInvalidChange = (v: boolean) => {
152
188
  invalid.value = v;
153
189
  };
@@ -167,6 +203,8 @@ const onFilterNameUpdate = (val: string) => {
167
203
  };
168
204
 
169
205
  const submit = () => {
206
+ if (!filterName.value) return;
207
+
170
208
  emit('submit', {
171
209
  name: filterName.value,
172
210
  label: filterLabel.value,
@@ -13,10 +13,9 @@
13
13
  </template>
14
14
 
15
15
  <script lang="ts" setup>
16
- import { isEmpty } from '@webitel/ui-sdk/scripts';
17
16
  import { computed } from 'vue';
18
17
 
19
- import type { FilterValue } from '../../../classes/Filter';
18
+ import { useFilterValueChange } from '../../../composables/useFilterValueChange';
20
19
  import { StaticFilterEmits, StaticFilterProps } from '../../types/Filter.types';
21
20
 
22
21
  /* Author @Lera24
@@ -30,25 +29,11 @@ const emit = defineEmits<StaticFilterEmits>();
30
29
 
31
30
  const filterValue = computed(() => props.filter?.value);
32
31
 
33
- const onValueChange = (value: FilterValue) => {
34
- if (isEmpty(value) && typeof value !== 'boolean') {
35
- if (!props.filter) return;
36
- return emit('delete:filter', props.filter);
37
- }
38
-
39
- if (isEmpty(filterValue.value)) {
40
- return emit('add:filter', {
41
- name: props.filterConfig.name,
42
- value,
43
- });
44
- }
45
-
46
- emit('update:filter', {
47
- name: props.filterConfig.name,
48
- value,
49
- label: props.filter?.label,
50
- });
51
- };
32
+ const { onValueChange } = useFilterValueChange({
33
+ filterConfig: () => props.filterConfig,
34
+ filter: () => props.filter,
35
+ emit,
36
+ });
52
37
  </script>
53
38
 
54
39
  <style lang="scss" scoped>
@@ -0,0 +1,177 @@
1
+ <template>
2
+ <div class="filters-actions-menu">
3
+ <wt-context-menu
4
+ :disabled="isMenuDisabled"
5
+ :options="options"
6
+ @click="onOptionClick"
7
+ >
8
+ <template #activator="{ toggle, show }">
9
+ <span
10
+ class="filters-actions-menu__activator"
11
+ @pointerenter="show($event)"
12
+ >
13
+ <wt-badge :hidden="!hasAnyFilters">
14
+ <wt-icon-action
15
+ :action="IconAction.FILTERS"
16
+ :disabled="isMenuDisabled"
17
+ @click="toggle($event)"
18
+ />
19
+ </wt-badge>
20
+ </span>
21
+ </template>
22
+ </wt-context-menu>
23
+
24
+ <template v-if="enablePresets && presetStore">
25
+ <apply-preset-action
26
+ ref="applyPreset"
27
+ :filter-configs="filterConfigs"
28
+ :has-any-filters="hasAnyFilters"
29
+ :namespace="presetNamespace ?? ''"
30
+ :presets-store="presetStore"
31
+ @apply="emit('preset:apply', $event)"
32
+ @restore="emit('preset:restore', $event)"
33
+ >
34
+ <template #activator />
35
+ </apply-preset-action>
36
+
37
+ <save-preset-action
38
+ ref="savePreset"
39
+ :filter-configs="filterConfigs"
40
+ :filters-included="filtersIncluded"
41
+ :filters-manager="filtersManager"
42
+ :namespace="presetNamespace ?? ''"
43
+ >
44
+ <template #activator />
45
+ </save-preset-action>
46
+ </template>
47
+ </div>
48
+ </template>
49
+
50
+ <script lang="ts" setup>
51
+ import type { DataField } from '@webitel/api-services/gen/models';
52
+ import {
53
+ WtBadge,
54
+ WtContextMenu,
55
+ WtIconAction,
56
+ } from '@webitel/ui-sdk/components';
57
+ import { IconAction } from '@webitel/ui-sdk/enums';
58
+ import type { StoreGeneric } from 'pinia';
59
+ import { computed, useTemplateRef } from 'vue';
60
+ import { useI18n } from 'vue-i18n';
61
+
62
+ import { ApplyPresetAction, SavePresetAction } from '../../filter-presets';
63
+ import type { IFiltersManager } from '../classes/FiltersManager';
64
+ import { useFilterConfigsToolkit } from '../composables/useFilterConfigsToolkit';
65
+ import { useSelectedFilters } from '../composables/useSelectedFilters';
66
+ import type { FilterConfigDefinition } from '../modules/filterConfig/types/FilterConfigDefinition';
67
+
68
+ /**
69
+ * Filter actions for pages without a filters panel (column filters only, WTEL-7727):
70
+ * the "filters" icon with a badge when filters are applied, and a context menu
71
+ * with reset + presets (when `presetNamespace` is given) — the same actions the panel has.
72
+ * Only emits, like the panel; the page binds them to its table store.
73
+ */
74
+ const props = defineProps<{
75
+ filtersManager: IFiltersManager;
76
+ filterOptions: FilterConfigDefinition[];
77
+ filterableExtensionFields?: DataField[];
78
+ /** enables preset actions */
79
+ presetNamespace?: string;
80
+ usePresetsStore?: () => StoreGeneric;
81
+ }>();
82
+
83
+ const emit = defineEmits<{
84
+ 'filter:reset-all': [];
85
+ 'preset:apply': [
86
+ string,
87
+ ];
88
+ 'preset:restore': [
89
+ string,
90
+ ];
91
+ }>();
92
+
93
+ const { t } = useI18n();
94
+
95
+ const applyPreset =
96
+ useTemplateRef<InstanceType<typeof ApplyPresetAction>>('applyPreset');
97
+ const savePreset =
98
+ useTemplateRef<InstanceType<typeof SavePresetAction>>('savePreset');
99
+
100
+ const { filterConfigs, filtersIncluded } = useFilterConfigsToolkit({
101
+ filterOptions: props.filterOptions,
102
+ filtersManager: props.filtersManager,
103
+ filterableExtensionFields: props.filterableExtensionFields,
104
+ });
105
+
106
+ const { listSelectedFilters, hasAnyFilters } = useSelectedFilters({
107
+ filtersManager: () => props.filtersManager,
108
+ filterOptions: () => props.filterOptions,
109
+ filterableExtensionFields: () => props.filterableExtensionFields,
110
+ filterConfigs,
111
+ });
112
+
113
+ const enablePresets = computed(() => !!props.presetNamespace);
114
+ const presetStore = props.usePresetsStore ? props.usePresetsStore() : null;
115
+
116
+ const MenuAction = {
117
+ RESET: 'reset',
118
+ APPLY_PRESET: 'apply-preset',
119
+ SAVE_PRESET: 'save-preset',
120
+ } as const;
121
+
122
+ const hasFiltersToReset = computed(() => !!listSelectedFilters.value.size);
123
+
124
+ // reset is the only action without presets: then there is nothing to open the menu for
125
+ const isMenuDisabled = computed(
126
+ () => !enablePresets.value && !hasFiltersToReset.value,
127
+ );
128
+
129
+ const options = computed(() => [
130
+ {
131
+ action: MenuAction.RESET,
132
+ text: t(`webitelUI.iconAction.hints.${IconAction.CLEAR}`),
133
+ disabled: !hasFiltersToReset.value,
134
+ },
135
+ ...(enablePresets.value
136
+ ? [
137
+ {
138
+ action: MenuAction.APPLY_PRESET,
139
+ text: t(`webitelUI.iconAction.hints.${IconAction.APPLY_PRESET}`),
140
+ disabled: false,
141
+ },
142
+ {
143
+ action: MenuAction.SAVE_PRESET,
144
+ text: t(`webitelUI.iconAction.hints.${IconAction.SAVE_PRESET}`),
145
+ disabled: !!savePreset.value?.disabled,
146
+ },
147
+ ]
148
+ : []),
149
+ ]);
150
+
151
+ const onOptionClick = ({
152
+ option,
153
+ }: {
154
+ option: (typeof options.value)[number];
155
+ }) => {
156
+ if (option.disabled) return;
157
+
158
+ switch (option.action) {
159
+ case MenuAction.RESET:
160
+ emit('filter:reset-all');
161
+ presetStore?.resetPreset();
162
+ break;
163
+ case MenuAction.APPLY_PRESET:
164
+ applyPreset.value?.open();
165
+ break;
166
+ case MenuAction.SAVE_PRESET:
167
+ savePreset.value?.open();
168
+ break;
169
+ }
170
+ };
171
+ </script>
172
+
173
+ <style lang="scss" scoped>
174
+ .filters-actions-menu__activator {
175
+ display: inline-flex;
176
+ }
177
+ </style>
@@ -65,11 +65,8 @@
65
65
 
66
66
  <script lang="ts" setup>
67
67
  import { WtChip, WtLoader, WtPopover } from '@webitel/ui-sdk/components';
68
- import { computed, ref, watch } from 'vue';
69
-
70
68
  import { FilterInitParams } from '../../classes/Filter';
71
- import type { FilterConfigSearchMethodParams } from '../../modules/filterConfig/classes/FilterConfig';
72
- import { FilterOptionToPreviewApiSearchMethodMap } from '../../modules/filterConfig/components';
69
+ import { useFilterValuePreview } from '../../composables/useFilterValuePreview';
73
70
  import DynamicFilterConfigForm from '../config/dynamic-view/dynamic-filter-config-form.vue';
74
71
  import DynamicFilterConfigView from '../config/dynamic-view/dynamic-filter-config-view.vue';
75
72
  import { DynamicFilterEmits, DynamicFilterProps } from '../types/Filter.types';
@@ -79,7 +76,10 @@ const props = defineProps<DynamicFilterProps>();
79
76
 
80
77
  const emit = defineEmits<DynamicFilterEmits>();
81
78
 
82
- const localValue = ref();
79
+ const { localValue, isRenderPreview, fillLocalValue } = useFilterValuePreview({
80
+ filter: () => props.filter,
81
+ filterConfig: () => props.filterConfig,
82
+ });
83
83
 
84
84
  const showChipPopover = (
85
85
  event: Event,
@@ -92,61 +92,6 @@ const showChipPopover = (
92
92
  showPopoverCb(event);
93
93
  };
94
94
 
95
- /**
96
- * @author @dlohvinov
97
- *
98
- * @description
99
- * loading filters preview data -> main preview component
100
- * instead of tooltip-components to avoid api requests spam
101
- */
102
- const fillLocalValue = async (filter = props.filter) => {
103
- const filterName = props.filter.name;
104
- const filterValue = filter.value;
105
-
106
- const { filterConfig } = props;
107
- const valueSearchMethod =
108
- 'searchRecords' in filterConfig
109
- ? (...params: FilterConfigSearchMethodParams) => {
110
- /* arrow fn here preserves filterConfig class "this" */
111
- return filterConfig.searchRecords(...params);
112
- }
113
- : FilterOptionToPreviewApiSearchMethodMap[filterName];
114
-
115
- if (valueSearchMethod) {
116
- const { items } = await valueSearchMethod(
117
- {
118
- id: filterValue,
119
- // -1 returns all records
120
- size: -1,
121
- },
122
- {
123
- filterValue,
124
- filterName,
125
- filterConfig: props.filterConfig,
126
- },
127
- );
128
- localValue.value = items;
129
- } else {
130
- localValue.value = filterValue;
131
- }
132
- };
133
-
134
- watch(
135
- () => props.filter.value,
136
- () => {
137
- fillLocalValue(props.filter);
138
- },
139
- {
140
- immediate: true,
141
- },
142
- );
143
-
144
- // [https://webitel.atlassian.net/browse/WTEL-6732]
145
- // if type filter is boolean and value = false, need display preview
146
- const isRenderPreview = computed(
147
- () => localValue.value === false || localValue.value,
148
- );
149
-
150
95
  const submit = (
151
96
  filter: FilterInitParams,
152
97
  {