@webitel/ui-sdk 24.12.138 → 24.12.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "24.12.138",
3
+ "version": "24.12.140",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -12,6 +12,7 @@
12
12
  :item-data="itemData"
13
13
  :data="item"
14
14
  :children-prop="childrenProp"
15
+ :multiple="multiple"
15
16
  @update:model-value="emit('update:modelValue', $event)"
16
17
  />
17
18
  </div>
@@ -75,6 +76,7 @@ const props = withDefaults(
75
76
  * You can pass the name of the property that will be used for getting children elements
76
77
  */
77
78
  childrenProp?: string;
79
+ multiple?: boolean;
78
80
  }>(),
79
81
  {
80
82
  childrenProp: 'children',
@@ -20,11 +20,9 @@
20
20
  <div
21
21
  :class="{ active: isSelected }"
22
22
  class="wt-tree-line__label-wrapper"
23
+ @click="selectElement"
23
24
  >
24
- <p
25
- class="wt-tree-line__label"
26
- @click="selectElement"
27
- >
25
+ <p class="wt-tree-line__label">
28
26
  {{ label }}
29
27
  </p>
30
28
  <wt-icon
@@ -47,6 +45,7 @@
47
45
  :next-element="!!data[childrenProp][index + 1]"
48
46
  :nested-icons="displayIcons"
49
47
  :last-child="index === data[childrenProp].length - 1"
48
+ :multiple="multiple"
50
49
  @open-parent="onOpenParent"
51
50
  @update:model-value="emit('update:modelValue', $event)"
52
51
  />
@@ -72,6 +71,7 @@ const props = withDefaults(
72
71
  lastChild?: boolean;
73
72
  nestedIcons?: WtTreeNestedIcons[];
74
73
  nextElement?: boolean;
74
+ multiple?: boolean;
75
75
  /**
76
76
  * 'It's a key in data object, which contains field what display searched elements. By this field, table will be opened to elements with this field value. '
77
77
  */
@@ -82,6 +82,7 @@ const props = withDefaults(
82
82
  childrenProp: 'children',
83
83
  lastChild: false,
84
84
  nextElement: false,
85
+ multiple: false,
85
86
  searchedProp: 'searched',
86
87
  },
87
88
  );
@@ -110,7 +111,20 @@ const displayIcons = computed(() => {
110
111
  return icons;
111
112
  });
112
113
 
114
+ const isMultipleItemsSelected = () => {
115
+ if (props.itemData) {
116
+ return props.modelValue.includes(props.data[props.itemData]);
117
+ }
118
+
119
+ const match = props.modelValue.find((item) => deepEqual(item, props.data));
120
+ return !!match;
121
+ };
122
+
113
123
  const isSelected = computed(() => {
124
+ if (props.multiple) {
125
+ return isMultipleItemsSelected();
126
+ }
127
+
114
128
  if (props.itemData) {
115
129
  return props.data[props.itemData] === props.modelValue;
116
130
  }
@@ -118,7 +132,36 @@ const isSelected = computed(() => {
118
132
  return deepEqual(props.modelValue, props.data);
119
133
  });
120
134
 
135
+ const setMultipleModelValue = () => {
136
+ const value = props.itemData ? props.data[props.itemData] : props.data;
137
+ let existingIndex;
138
+
139
+ if (props.itemData) {
140
+ existingIndex = props.modelValue.indexOf(props.data[props.itemData]);
141
+ } else {
142
+ existingIndex = props.modelValue.findIndex((item) =>
143
+ deepEqual(item, props.data),
144
+ );
145
+ }
146
+
147
+ if (existingIndex === -1) {
148
+ const newArray = [...props.modelValue];
149
+ newArray.push(value);
150
+ emit('update:modelValue', newArray);
151
+ return;
152
+ }
153
+
154
+ const newArray = [...props.modelValue];
155
+ newArray.splice(existingIndex, 1);
156
+ emit('update:modelValue', newArray);
157
+ };
158
+
121
159
  const selectElement = () => {
160
+ if (props.multiple && !props.data.service) {
161
+ setMultipleModelValue();
162
+ return;
163
+ }
164
+
122
165
  if (props.data[props.childrenProp]?.length) {
123
166
  return;
124
167
  }
@@ -153,9 +153,9 @@ class FiltersManager implements IFiltersManager {
153
153
  include,
154
154
  exclude,
155
155
  }: {
156
- include: FilterName[];
157
- exclude: FilterName[];
158
- }): void {
156
+ include?: FilterName[];
157
+ exclude?: FilterName[];
158
+ } = {}): void {
159
159
  const useInclude = !isEmpty(include);
160
160
  const useExclude = !isEmpty(exclude) && !useInclude;
161
161
 
@@ -173,7 +173,7 @@ class FiltersManager implements IFiltersManager {
173
173
 
174
174
  if (useExclude) {
175
175
  this.filters.forEach((_, filterName) => {
176
- if (exclude.includes(filterName)) {
176
+ if (!exclude.includes(filterName)) {
177
177
  this.filters.delete(filterName);
178
178
  }
179
179
  });
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <div class="dynamic-filter-config-view">
3
- <wt-tooltip :triggers="['click']">
3
+ <wt-tooltip
4
+ :triggers="['click']"
5
+ :disabled="props.disabled"
6
+ >
4
7
  <template #activator="slotScope">
5
8
  <slot
6
9
  name="activator"
@@ -24,6 +27,12 @@
24
27
  */
25
28
 
26
29
  import WtTooltip from '../../../../../../components/wt-tooltip/wt-tooltip.vue';
30
+
31
+ interface Props {
32
+ disabled?: boolean;
33
+ }
34
+
35
+ const props = defineProps<Props>();
27
36
  </script>
28
37
 
29
38
  <style lang="scss" scoped></style>
@@ -1,13 +1,14 @@
1
1
  <template>
2
- <dynamic-filter-config-view>
2
+ <dynamic-filter-config-view
3
+ :disabled="dummy"
4
+ >
3
5
  <template #activator="{ visible: configFormVisible }">
4
6
  <wt-tooltip :disabled="configFormVisible">
5
7
  <template #activator>
6
8
  <wt-chip color="primary">
7
- {{
8
- props.filter.label || t(`webitelUI.filters.${props.filter.name}`)
9
- }}
9
+ {{ filter.label || t(`webitelUI.filters.${filter.name}`) }}
10
10
  <wt-icon-btn
11
+ v-if="!dummy"
11
12
  icon="close--filled"
12
13
  size="sm"
13
14
  @mousedown.stop="deleteFilter"
@@ -44,12 +45,13 @@ import { useI18n } from 'vue-i18n';
44
45
  import WtChip from '../../../../../../components/wt-chip/wt-chip.vue';
45
46
  import WtIconBtn from '../../../../../../components/wt-icon-btn/wt-icon-btn.vue';
46
47
  import WtTooltip from '../../../../../../components/wt-tooltip/wt-tooltip.vue';
47
- import type { IFilter } from '../../types/Filter';
48
+ import type {IFilter} from '../../types/Filter';
48
49
  import DynamicFilterConfigView from '../config/dynamic-filter-config-view.vue';
49
50
  import DynamicFilterPreviewInfo from './dynamic-filter-preview-info.vue';
50
51
 
51
52
  interface Props {
52
53
  filter: IFilter;
54
+ dummy?: boolean;
53
55
  }
54
56
 
55
57
  const { t } = useI18n();
@@ -36,8 +36,8 @@ import HasTranscriptionFilter from './has-transcription/has-transcription-filter
36
36
  import HasTranscriptionFilterPreview from './has-transcription/has-transcription-filter-value-preview.vue';
37
37
  import ImpactedFilter from './impacted/impacted-filter-value-field.vue';
38
38
  import ImpactedFilterPreview from './impacted/impacted-filter-value-preview.vue';
39
- import PriorityCaseFilter from './priority-case/priority-case-filter-value-field.vue';
40
- import PriorityCaseFilterPreview from './priority-case/priority-case-filter-value-preview.vue';
39
+ import CasePriorityFilter from './priority-case/priority-case-filter-value-field.vue';
40
+ import CasePriorityFilterPreview from './priority-case/priority-case-filter-value-preview.vue';
41
41
  import QueueFilter from './queue/queue-filter-value-field.vue';
42
42
  import QueueFilterPreview from './queue/queue-filter-value-preview.vue';
43
43
  import RatedFilter from './rated/rated-filter-value-field.vue';
@@ -54,16 +54,16 @@ import ResolutionTimeFilter from './resolution-time/resolution-time-filter-value
54
54
  import ResolutionTimeFilterPreview from './resolution-time/resolution-time-filter-value-preview.vue';
55
55
  import ScoreFilter from './score/score-from-to-filter-value-field.vue';
56
56
  import ScoreFilterPreview from './score/score-from-to-filter-value-preview.vue';
57
- // import ServiceCaseFilter from './service-case/service-case-filter-value-field.vue';
58
- // import ServiceCaseFilterPreview from './service-case/service-case-filter-value-preview.vue';
57
+ import CaseServiceFilter from './service-case/service-case-filter-value-field.vue';
58
+ import CaseServiceFilterPreview from './service-case/service-case-filter-value-preview.vue';
59
59
  import SlaFilter from './sla/sla-filter-value-field.vue';
60
60
  import SlaFilterPreview from './sla/sla-filter-value-preview.vue';
61
61
  import SlaConditionFilter from './sla-condition/sla-condition-filter-value-field.vue';
62
62
  import SlaConditionFilterPreview from './sla-condition/sla-condition-filter-value-preview.vue';
63
- import SourceCaseFilter from './source-case/source-case-filter-value-field.vue';
64
- import SourceCaseFilterPreview from './source-case/source-case-filter-value-preview.vue';
65
- import StatusCaseFilter from './status-case/status-case-filter-value-field.vue';
66
- import StatusCaseFilterPreview from './status-case/status-case-filter-value-preview.vue';
63
+ import CaseSourceFilter from './source-case/source-case-filter-value-field.vue';
64
+ import CaseSourceFilterPreview from './source-case/source-case-filter-value-preview.vue';
65
+ import CaseStatusFilter from './status-case/status-case-filter-value-field.vue';
66
+ import CaseStatusFilterPreview from './status-case/status-case-filter-value-preview.vue';
67
67
  import TagFilter from './tag/tag-filter-value-field.vue';
68
68
  import TagFilterPreview from './tag/tag-filter-value-preview.vue';
69
69
  import TalkDurationFilter from './talk-duration/talk-duration-filter-value-field.vue';
@@ -90,6 +90,14 @@ export {
90
90
  AssigneeFilterPreview,
91
91
  AuthorFilter,
92
92
  AuthorFilterPreview,
93
+ CasePriorityFilter,
94
+ CasePriorityFilterPreview,
95
+ CaseServiceFilter,
96
+ CaseServiceFilterPreview,
97
+ CaseSourceFilter,
98
+ CaseSourceFilterPreview,
99
+ CaseStatusFilter,
100
+ CaseStatusFilterPreview,
93
101
  CauseFilter,
94
102
  CauseFilterPreview,
95
103
  CloseReasonGroupsCaseFilter,
@@ -116,8 +124,6 @@ export {
116
124
  HasTranscriptionFilterPreview,
117
125
  ImpactedFilter,
118
126
  ImpactedFilterPreview,
119
- PriorityCaseFilter,
120
- PriorityCaseFilterPreview,
121
127
  QueueFilter,
122
128
  QueueFilterPreview,
123
129
  RatedByFilter,
@@ -136,14 +142,8 @@ export {
136
142
  ScoreFilterPreview,
137
143
  SlaConditionFilter,
138
144
  SlaConditionFilterPreview,
139
- // ServiceCaseFilter,
140
- // ServiceCaseFilterPreview,
141
145
  SlaFilter,
142
146
  SlaFilterPreview,
143
- SourceCaseFilter,
144
- SourceCaseFilterPreview,
145
- StatusCaseFilter,
146
- StatusCaseFilterPreview,
147
147
  TagFilter,
148
148
  TagFilterPreview,
149
149
  TalkDurationFilter,
@@ -1,6 +1,6 @@
1
1
  import ServiceCatalogsAPI from '../../../../../../../api/clients/caseServiceCatalogs/service-catalogs.js';
2
2
  import ServicesAPI from '../../../../../../../api/clients/caseServices/services.js';
3
3
 
4
- export const servicesSearchMethod = ServicesAPI.getLookup;
5
- export const serviceCatalogsSearchMethod = ServiceCatalogsAPI.getLookup;
4
+ export const searchMethod = ServiceCatalogsAPI.getList;
5
+ export const servicesSearchMethod = ServicesAPI.getList;
6
6
  export const localePath = '';
@@ -1,84 +1,31 @@
1
1
  <template>
2
- <div>
3
- <wt-select
4
- :clearable="false"
5
- :label="t('cases.reason')"
6
- :search-method="serviceCatalogsSearchMethod"
7
- :v="v$.model?.selection"
8
- :value="model?.selection"
9
- track-by="id"
10
- use-value-from-options-by-prop="id"
11
- @input="changeSelection($event)"
12
- />
13
-
14
- <wt-select
15
- v-if="model?.selection"
16
- :clearable="false"
17
- :disabled="!model?.selection"
18
- :label="t('webitelUI.filters.filterValue')"
19
- :options="conditionList"
20
- :v="v$.model?.conditions"
21
- :value="model?.conditions"
22
- multiple
23
- track-by="id"
24
- use-value-from-options-by-prop="id"
25
- @input="model.conditions = $event"
26
- />
27
- </div>
2
+ <wt-tree
3
+ :model-value="model"
4
+ :data="catalogData"
5
+ item-data="id"
6
+ item-label="name"
7
+ children-prop="service"
8
+ class="service-case-filter-value-field"
9
+ multiple
10
+ @update:model-value="model = $event"
11
+ />
28
12
  </template>
29
13
 
30
14
  <script lang="ts" setup>
31
15
  import { useVuelidate } from '@vuelidate/core';
32
16
  import { required } from '@vuelidate/validators';
17
+ import deepCopy from 'deep-copy';
33
18
  import { computed, onMounted, ref, watch } from 'vue';
34
- import { useI18n } from 'vue-i18n';
35
19
 
36
- import WtSelect from '../../../../../../../components/wt-select/wt-select.vue';
37
- import { serviceCatalogsSearchMethod, servicesSearchMethod } from './config.js';
20
+ import WtTree from '../../../../../../../components/wt-tree/wt-tree.vue';
21
+ import { searchMethod } from './config.js';
38
22
 
39
- type ModelValue = {
40
- selection: string;
41
- conditions: string;
42
- };
43
- const model = defineModel<ModelValue>();
44
- const { t } = useI18n();
45
-
46
- const initModel = () => {
47
- if (!model.value) {
48
- model.value = {
49
- selection: '',
50
- conditions: '',
51
- };
52
- } else {
53
- onSelectionUpdate(model.value.selection);
54
- }
55
- };
56
- onMounted(() => initModel());
57
-
58
- const conditionList = ref([]);
59
-
60
- const onSelectionUpdate = async (val: string) => {
61
- model.value.selection = val;
62
-
63
- if (val) {
64
- const { items } = await getConditionList();
65
- if (items.length) {
66
- conditionList.value = items;
67
- }
68
- }
69
- };
23
+ type ModelValue = string[];
24
+ const model = defineModel<ModelValue>({
25
+ default: [],
26
+ });
70
27
 
71
- const changeSelection = (value) => {
72
- onSelectionUpdate(value);
73
- model.value.conditions = '';
74
- };
75
-
76
- const getConditionList = async (params) => {
77
- return await servicesSearchMethod({
78
- parentId: model.value.selection,
79
- ...params,
80
- });
81
- };
28
+ const catalogData = ref([]);
82
29
 
83
30
  const v$ = useVuelidate(
84
31
  computed(() => ({
@@ -91,7 +38,7 @@ const v$ = useVuelidate(
91
38
  },
92
39
  },
93
40
  })),
94
- { model, conditionList },
41
+ { model },
95
42
  { $autoDirty: true },
96
43
  );
97
44
 
@@ -108,6 +55,59 @@ watch(
108
55
  },
109
56
  { immediate: true },
110
57
  );
58
+
59
+ const loadCatalogs = async () => {
60
+ const { items } = await searchMethod({
61
+ size: -1, // To get all catalogs with services we need to pass size -1
62
+ fields: ['id', 'name', 'closeReasonGroup', 'status', 'service'],
63
+ hasSubservices: true,
64
+ });
65
+
66
+ catalogData.value = deepCopy(items);
67
+ };
68
+
69
+ if (!model.value) {
70
+ model.value = [];
71
+ }
72
+
73
+ onMounted(loadCatalogs);
111
74
  </script>
112
75
 
113
- <style lang="scss" scoped></style>
76
+ <style lang="scss">
77
+ $form-width: 800px;
78
+
79
+ .service-case-filter-value-field {
80
+ background: transparent;
81
+ max-height: 350px;
82
+ height: 100%;
83
+ overflow-y: auto;
84
+ grid-area: value;
85
+ }
86
+
87
+ .dynamic-filter-config-form {
88
+ &:has(.service-case-filter-value-field) {
89
+ width: $form-width;
90
+ height: 500px;
91
+ display: grid;
92
+ grid-template-columns: repeat(2, 1fr);
93
+ grid-template-rows: 64px 1fr auto;
94
+ grid-template-areas:
95
+ 'column label'
96
+ 'value value'
97
+ 'footer footer';
98
+
99
+ .wt-select {
100
+ grid-area: column;
101
+ height: fit-content;
102
+ }
103
+
104
+ .wt-input {
105
+ grid-area: label;
106
+ }
107
+
108
+ .dynamic-filter-config-form-footer {
109
+ grid-area: footer;
110
+ }
111
+ }
112
+ }
113
+ </style>
@@ -1,15 +1,34 @@
1
1
  <template>
2
- <div class=""></div>
2
+ <ul v-if="localValue">
3
+ <li
4
+ v-for="({ name }, index) of localValue"
5
+ :key="index"
6
+ >
7
+ {{ name }}
8
+ </li>
9
+ </ul>
3
10
  </template>
4
11
 
5
- <script setup lang="ts">
6
- interface Props {}
12
+ <script lang="ts" setup>
13
+ import { ref } from 'vue';
7
14
 
8
- const props = defineProps<Props>();
15
+ import { servicesSearchMethod } from './config.js';
9
16
 
10
- interface Emits {}
17
+ const props = defineProps<{
18
+ value: number[];
19
+ }>();
11
20
 
12
- const emit = defineEmits<Emits>();
21
+ const localValue = ref([]);
22
+
23
+ const getLocalValue = async () => {
24
+ const { items } = await servicesSearchMethod({
25
+ id: props.value,
26
+ fields: ['id', 'name'],
27
+ });
28
+ localValue.value = items;
29
+ };
30
+
31
+ getLocalValue();
13
32
  </script>
14
33
 
15
34
  <style lang="scss" scoped></style>