@webitel/ui-sdk 24.12.85 → 24.12.86

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 (47) hide show
  1. package/CHANGELOG.md +23 -8
  2. package/dist/img/sprite/add-filter.svg +8 -0
  3. package/dist/img/sprite/index.js +2 -0
  4. package/dist/ui-sdk.css +1 -1
  5. package/dist/ui-sdk.js +1416 -1415
  6. package/dist/ui-sdk.umd.cjs +15 -15
  7. package/package.json +1 -1
  8. package/src/assets/icons/sprite/add-filter.svg +8 -0
  9. package/src/assets/icons/sprite/index.js +2 -0
  10. package/src/components/index.js +71 -0
  11. package/src/components/wt-action-bar/wt-action-bar.vue +9 -4
  12. package/src/components/wt-icon-action/iconMappings.js +1 -0
  13. package/src/components/wt-loader/_internals/wt-loader--md.vue +3 -2
  14. package/src/components/wt-tooltip/_internals/useTooltipTriggerSubscriptions.js +0 -1
  15. package/src/components/wt-tooltip/wt-tooltip.vue +4 -1
  16. package/src/css/main.scss +0 -1
  17. package/src/css/pages/table-page.scss +0 -1
  18. package/src/css/styleguide/placeholder/_placeholder.scss +2 -2
  19. package/src/enums/IconAction/IconAction.enum.js +1 -0
  20. package/src/locale/en/en.js +19 -0
  21. package/src/locale/ru/ru.js +1 -0
  22. package/src/locale/ua/ua.js +1 -0
  23. package/src/modules/Filters/v2/filters/classes/Filter.ts +30 -0
  24. package/src/modules/Filters/v2/filters/classes/FilterStorage.ts +34 -0
  25. package/src/modules/Filters/v2/filters/classes/FilterStorageOptions.d.ts +6 -0
  26. package/src/modules/Filters/v2/filters/classes/FiltersManager.ts +189 -0
  27. package/src/modules/Filters/v2/filters/components/dynamic/config/dynamic-filter-config-form.vue +146 -0
  28. package/src/modules/Filters/v2/filters/components/dynamic/config/dynamic-filter-config-view.vue +29 -0
  29. package/src/modules/Filters/v2/filters/components/dynamic/dynamic-filter-add-action.vue +41 -0
  30. package/src/modules/Filters/v2/filters/components/dynamic/preview/dynamic-filter-preview-info.vue +48 -0
  31. package/src/modules/Filters/v2/filters/components/dynamic/preview/dynamic-filter-preview.vue +61 -0
  32. package/src/modules/Filters/v2/filters/components/static/search-filter.vue +14 -0
  33. package/src/modules/Filters/v2/filters/components/table-filters-panel.vue +87 -0
  34. package/src/modules/Filters/v2/filters/createTableFiltersStore.ts +81 -0
  35. package/src/modules/Filters/v2/filters/index.ts +27 -0
  36. package/src/modules/Filters/v2/filters/scripts/utils.ts +31 -0
  37. package/src/modules/Filters/v2/filters/types/Filter.d.ts +41 -0
  38. package/src/modules/Filters/v2/filters/types/FiltersManager.d.ts +76 -0
  39. package/src/modules/Filters/v2/headers/createTableHeadersStore.ts +89 -0
  40. package/src/modules/Filters/v2/index.ts +0 -0
  41. package/src/modules/Filters/v2/pagination/createTablePaginationStore.ts +54 -0
  42. package/src/modules/Filters/v2/persist/PersistedStorage.types.ts +51 -0
  43. package/src/modules/Filters/v2/persist/useLocalStoragePersistedStorage.ts +31 -0
  44. package/src/modules/Filters/v2/persist/usePersistedStorage.ts +150 -0
  45. package/src/modules/Filters/v2/persist/useRoutePersistedStorage.ts +41 -0
  46. package/src/modules/Filters/v2/table/createTableStore.store.ts +180 -0
  47. package/src/modules/Filters/v2/types/tableStore.types.ts +60 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "24.12.85",
3
+ "version": "24.12.86",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -0,0 +1,8 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="Name=add-filter, Filled=false, Colored=false, Version=current, Badged=False">
3
+ <g id="Union">
4
+ <path d="M13 8C13 7.44772 12.5523 7 12 7C11.4477 7 11 7.44772 11 8V11L8 11C7.44771 11 7 11.4477 7 12C7 12.5523 7.44771 13 8 13L11 13V16C11 16.5523 11.4477 17 12 17C12.5523 17 13 16.5523 13 16V13H16C16.5523 13 17 12.5523 17 12C17 11.4477 16.5523 11 16 11H13V8Z" fill="#454E68"/>
5
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM20 12C20 16.4183 16.4183 20 12 20C7.58172 20 4 16.4183 4 12C4 7.58172 7.58172 4 12 4C16.4183 4 20 7.58172 20 12Z" fill="#454E68"/>
6
+ </g>
7
+ </g>
8
+ </svg>
@@ -14,6 +14,7 @@ import assignee from './assignee.svg';
14
14
  import attach from './attach.svg';
15
15
  import attention from './attention.svg';
16
16
  import azure from './azure.svg';
17
+ import addFilter from './add-filter.svg';
17
18
  import back from './back.svg';
18
19
  import bell from './bell.svg';
19
20
  import bellBadged from './bell-badged.svg';
@@ -213,6 +214,7 @@ export default objCamelToKebab({
213
214
  attach,
214
215
  attention,
215
216
  azure,
217
+ addFilter,
216
218
  back,
217
219
  bell,
218
220
  bellBadged,
@@ -138,4 +138,75 @@ const Components = {
138
138
  WtSelectionPopup,
139
139
  };
140
140
 
141
+ export {
142
+ WtActionBar,
143
+ WtAppHeader,
144
+ WtAppNavigator,
145
+ WtAvatar,
146
+ WtBadge,
147
+ WtButton,
148
+ WtButtonSelect,
149
+ WtCheckbox,
150
+ WtChip,
151
+ WtConfirmDialog,
152
+ WtContextMenu,
153
+ WtCopyAction,
154
+ WtDatepicker,
155
+ WtDivider,
156
+ WtDualPanel,
157
+ WtDummy,
158
+ WtEmpty,
159
+ WtErrorPage,
160
+ WtExpansionPanel,
161
+ WtFiltersPanelWrapper,
162
+ WtHeaderActions,
163
+ WtHeadline,
164
+ WtHeadlineNav,
165
+ WtHint,
166
+ WtIcon,
167
+ WtIconAction,
168
+ WtIconBtn,
169
+ WtImage,
170
+ WtIndicator,
171
+ WtInput,
172
+ WtInputInfo,
173
+ WtIntersectionObserver,
174
+ WtItemLink,
175
+ WtLabel,
176
+ WtLoadBar,
177
+ WtLoader,
178
+ WtLogo,
179
+ WtNavigationBar,
180
+ WtNavigationMenu,
181
+ WtNotification,
182
+ WtNotificationsBar,
183
+ WtPageHeader,
184
+ WtPageWrapper,
185
+ WtPagination,
186
+ WtPlayer,
187
+ WtPopup,
188
+ WtProgressBar,
189
+ WtRadio,
190
+ WtRoundedAction,
191
+ WtSearchBar,
192
+ WtSelect,
193
+ WtSelectionPopup,
194
+ WtSlider,
195
+ WtStartPage,
196
+ WtStatusSelect,
197
+ WtStepper,
198
+ WtSwitcher,
199
+ WtTable,
200
+ WtTableActions,
201
+ WtTableColumnSelect,
202
+ WtTabs,
203
+ WtTagsInput,
204
+ WtTextarea,
205
+ WtTimeInput,
206
+ WtTimepicker,
207
+ WtTooltip,
208
+ WtTree,
209
+ WtTreeTable,
210
+ };
211
+
141
212
  export default Components;
@@ -14,17 +14,17 @@
14
14
  <slot v-bind="{ size }" />
15
15
 
16
16
  <!-- @slot May be useful to set complex component which draws the same `wt-icon-action`
17
- @scope `{ action<IconAction>, size<ComponentSize> }`
17
+ @scope `{ action<IconAction>, size<ComponentSize>, onClick: () => emit('click:[action]') }`
18
18
  -->
19
19
  <slot
20
20
  v-for="action in shownActions"
21
21
  :name="action"
22
- v-bind="{ action, size }"
22
+ v-bind="{ action, size, onClick: () => handleActionClick(action) }"
23
23
  >
24
24
  <wt-icon-action
25
25
  :action="action"
26
26
  :disabled="props[`disabled:${action}`]"
27
- @click="emit(`click:${action}`)"
27
+ @click="handleActionClick(action)"
28
28
  />
29
29
  </slot>
30
30
  </div>
@@ -32,11 +32,12 @@
32
32
 
33
33
  <script setup>
34
34
  import { computed } from 'vue';
35
+
35
36
  import IconAction from '../../enums/IconAction/IconAction.enum.js';
36
37
  import WtIconAction from '../wt-icon-action/wt-icon-action.vue';
37
38
  import {
38
- tableActionsOrder,
39
39
  sectionActionsOrder,
40
+ tableActionsOrder,
40
41
  } from './WtActionBarActionsOrder.js';
41
42
 
42
43
  const props = defineProps({
@@ -110,6 +111,10 @@ const shownActions = computed(() => {
110
111
 
111
112
  return actionsOrder;
112
113
  });
114
+
115
+ const handleActionClick = (action) => {
116
+ emit(`click:${action}`);
117
+ };
113
118
  </script>
114
119
 
115
120
  <style lang="scss" scoped>
@@ -11,4 +11,5 @@ export const WtIconActionIconMappings = Object.freeze({
11
11
  [IconAction.COLLAPSE]: 'collapse',
12
12
  [IconAction.FILTERS]: 'filter',
13
13
  [IconAction.COLUMNS]: 'column-select',
14
+ [IconAction.CLOSE]: 'close--filled',
14
15
  });
@@ -21,7 +21,7 @@ export default {};
21
21
 
22
22
  <style lang="scss" scoped>
23
23
  // https://codepen.io/aaroniker/pen/omvYNZ
24
- @use "sass:math";
24
+ @use 'sass:math';
25
25
 
26
26
  .wt-loader--md {
27
27
  position: relative;
@@ -55,7 +55,8 @@ export default {};
55
55
  stroke-width: 10px;
56
56
  stroke-linejoin: round;
57
57
  stroke-linecap: round;
58
- stroke-dasharray: math.div(256, 4) * 3 math.div(256, 4) math.div(256, 4) * 3 math.div(256, 4);
58
+ stroke-dasharray: math.div(256, 4) * 3 math.div(256, 4) math.div(256, 4) *
59
+ 3 math.div(256, 4);
59
60
  stroke-dashoffset: 0;
60
61
  }
61
62
  }
@@ -18,7 +18,6 @@ const HIDE_EVENT_MAP = {
18
18
  pointer: 'pointerup',
19
19
  };
20
20
 
21
- // eslint-disable-next-line import/prefer-default-export
22
21
  export const useTooltipTriggerSubscriptions = ({
23
22
  target,
24
23
  triggers,
@@ -9,7 +9,10 @@
9
9
  ref="activator"
10
10
  class="wt-tooltip__activator"
11
11
  >
12
- <slot name="activator" />
12
+ <slot
13
+ name="activator"
14
+ v-bind="{ visible: isVisible }"
15
+ />
13
16
  </div>
14
17
  <wt-tooltip-floating
15
18
  v-if="isVisible"
package/src/css/main.scss CHANGED
@@ -3,7 +3,6 @@
3
3
  @use 'pages/card-page';
4
4
  @use 'pages/table-page';
5
5
 
6
-
7
6
  @include wt-placeholder;
8
7
 
9
8
  :root {
@@ -1,7 +1,6 @@
1
1
  @use '../styleguide/styleguide' as *;
2
2
 
3
3
  .table-page {
4
-
5
4
  &.wt-page-wrapper {
6
5
  width: 100%;
7
6
  height: 100%;
@@ -1,7 +1,7 @@
1
1
  // https://stackoverflow.com/a/17181946/17782185
2
2
  // https://stackoverflow.com/a/49192800/17782185
3
- @use "sass:selector";
4
- ///піу
3
+ @use 'sass:selector';
4
+
5
5
  //@mixin optional-at-root($sel) {
6
6
  // @at-root #{if(not &, $sel, selector-append(&, $sel))} {
7
7
  // @content;
@@ -12,6 +12,7 @@ const IconAction = Object.freeze({
12
12
  EDIT: 'edit',
13
13
  COLLAPSE: 'collapse',
14
14
  EXPAND: 'expand',
15
+ CLOSE: 'close',
15
16
  });
16
17
 
17
18
  export default IconAction;
@@ -115,6 +115,7 @@ export default {
115
115
  messaging: 'Messaging',
116
116
  emptyResultSearch: 'Your search yielded no results',
117
117
  contact: 'Contact | Contacts',
118
+ column: 'Column | Columns',
118
119
  },
119
120
  // date-related texts
120
121
  date: {
@@ -373,6 +374,7 @@ export default {
373
374
  [IconAction.REFRESH]: ({ linked }) => linked('reusable.refresh'),
374
375
  [IconAction.EXPAND]: ({ linked }) => linked('reusable.expand'),
375
376
  [IconAction.COLLAPSE]: ({ linked }) => linked('reusable.collapse'),
377
+ [IconAction.CLOSE]: ({ linked }) => linked('reusable.close'),
376
378
  },
377
379
  },
378
380
  errorPages: {
@@ -436,6 +438,23 @@ export default {
436
438
  label: 'Something went wrong, please try again',
437
439
  exportToJson: 'Export to JSON',
438
440
  },
441
+ filters: {
442
+ addFilter: ({ linked }) => {
443
+ return `${linked('reusable.add')} ${linked(
444
+ 'reusable.filter',
445
+ ).toLowerCase()}`;
446
+ },
447
+ filterName: ({ linked }) => {
448
+ // because filter select has a 'column' label now
449
+ return linked('vocabulary.column');
450
+ },
451
+ filterValue: ({ linked }) => {
452
+ return linked('vocabulary.values');
453
+ },
454
+ filterLabel: ({ linked }) => {
455
+ return linked('vocabulary.labels');
456
+ },
457
+ },
439
458
  },
440
459
  errorNotifications: {
441
460
  chatHistoryApi: 'There was an error loading the chat history',
@@ -371,6 +371,7 @@ export default {
371
371
  [IconAction.REFRESH]: ({ linked }) => linked('reusable.refresh'),
372
372
  [IconAction.EXPAND]: ({ linked }) => linked('reusable.expand'),
373
373
  [IconAction.COLLAPSE]: ({ linked }) => linked('reusable.collapse'),
374
+ [IconAction.CLOSE]: ({ linked }) => linked('reusable.close'),
374
375
  },
375
376
  },
376
377
  errorPages: {
@@ -371,6 +371,7 @@ export default {
371
371
  [IconAction.REFRESH]: ({ linked }) => linked('reusable.refresh'),
372
372
  [IconAction.EXPAND]: ({ linked }) => linked('reusable.expand'),
373
373
  [IconAction.COLLAPSE]: ({ linked }) => linked('reusable.collapse'),
374
+ [IconAction.CLOSE]: ({ linked }) => linked('reusable.close'),
374
375
  },
375
376
  },
376
377
  errorPages: {
@@ -0,0 +1,30 @@
1
+ import type {
2
+ FilterConfig,
3
+ FilterInitParams,
4
+ FilterLabel,
5
+ FilterName,
6
+ FilterValue,
7
+ IFilter,
8
+ } from '../types/Filter';
9
+
10
+ export class Filter implements IFilter {
11
+ readonly name: FilterName;
12
+ label: FilterLabel;
13
+ value: FilterValue;
14
+
15
+ constructor(
16
+ { name, value, label }: FilterInitParams,
17
+ public payload: object | undefined,
18
+ public config: FilterConfig,
19
+ ) {
20
+ this.name = name;
21
+ this.value = value;
22
+ this.label = label;
23
+ }
24
+
25
+ set({ value, label }: { value?: FilterValue; label?: FilterLabel }): IFilter {
26
+ this.value = value;
27
+ this.label = label;
28
+ return this;
29
+ }
30
+ }
@@ -0,0 +1,34 @@
1
+ import { FilterValue } from '../types/Filter';
2
+ import type { FilterStorageOptions } from './FilterStorageOptions';
3
+
4
+ export class BrowserFilterStorage implements FilterStorageOptions {
5
+ constructor(private prefix: string) {}
6
+
7
+ get(name: string): FilterValue {
8
+ const value = localStorage.getItem(`filters:${this.prefix}:${name}`);
9
+ return value ? JSON.parse(value) : undefined;
10
+ }
11
+
12
+ set(name: string, value: FilterValue): void {
13
+ localStorage.setItem(
14
+ `filters:${this.prefix}:${name}`,
15
+ JSON.stringify(value),
16
+ );
17
+ }
18
+ }
19
+
20
+ export class QueryFilterStorage implements FilterStorageOptions {
21
+ constructor(private prefix: string) {}
22
+
23
+ get(name: string): FilterValue {
24
+ const url = new URL(window.location.href);
25
+ const value = url.searchParams.get(`${this.prefix}:${name}`);
26
+ return value ? JSON.parse(value) : undefined;
27
+ }
28
+
29
+ set(name: string, value: FilterValue): void {
30
+ const url = new URL(window.location.href);
31
+ url.searchParams.set(`${this.prefix}:${name}`, JSON.stringify(value));
32
+ window.history.pushState({}, '', url.toString());
33
+ }
34
+ }
@@ -0,0 +1,6 @@
1
+ import { FilterValue } from '../types/Filter';
2
+
3
+ export interface FilterStorageOptions {
4
+ get: (name: string) => FilterValue;
5
+ set: (name: string, value: FilterValue) => void;
6
+ }
@@ -0,0 +1,189 @@
1
+ import { isEmpty } from '../../../../../scripts';
2
+ import {
3
+ filterLabelToSnapshotKey,
4
+ filterNameFromSnapshotKey,
5
+ filterValuePropFromSnapshotKey,
6
+ filterValueToSnapshotKey,
7
+ } from '../scripts/utils.ts';
8
+ import type {
9
+ FilterConfig,
10
+ FilterData,
11
+ FilterInitParams,
12
+ FilterLabel,
13
+ FilterName,
14
+ FilterValue,
15
+ IFilter,
16
+ } from '../types/Filter';
17
+ import { FiltersManagerConfig, IFiltersManager } from '../types/FiltersManager';
18
+ import { Filter } from './Filter.ts';
19
+
20
+ class FiltersManager implements IFiltersManager {
21
+ filters = new Map<FilterName, IFilter>();
22
+
23
+ constructor(private config?: FiltersManagerConfig) {}
24
+
25
+ hasFilter(name: FilterName): boolean {
26
+ return this.filters.has(name);
27
+ }
28
+
29
+ getFilter(name: FilterName): IFilter {
30
+ return this.filters.get(name);
31
+ }
32
+
33
+ addFilter(
34
+ filterInitParams: FilterInitParams,
35
+ payload?: object,
36
+ config?: FilterConfig,
37
+ ): IFilter {
38
+ const filter = new Filter(filterInitParams, payload, config || this.config);
39
+ this.filters.set(filterInitParams.name, filter);
40
+ return filter;
41
+ }
42
+
43
+ updateFilter({
44
+ name,
45
+ value,
46
+ label,
47
+ }: {
48
+ name: FilterName;
49
+ value?: FilterValue;
50
+ label?: FilterLabel;
51
+ }): IFilter {
52
+ const filter = this.filters.get(name);
53
+ filter.set({ value, label });
54
+ return filter;
55
+ }
56
+
57
+ deleteFilter(name: FilterName): IFilter {
58
+ const filter = this.filters.get(name);
59
+ this.filters.delete(name);
60
+ return filter;
61
+ }
62
+
63
+ getAllValues(): { [name: FilterName]: FilterValue } {
64
+ const filters = [...this.filters.values()].reduce((acc, filter) => {
65
+ acc[filter.name] = filter.value;
66
+ return acc;
67
+ }, {});
68
+
69
+ return filters;
70
+ }
71
+
72
+ toString(): string {
73
+ const filtersData = [...this.filters.values()].reduce(
74
+ (acc, { name, label, value }) => {
75
+ if (isEmpty(value)) return acc;
76
+
77
+ acc[filterValueToSnapshotKey(name)] = value;
78
+
79
+ if (label) {
80
+ acc[filterLabelToSnapshotKey(name)] = label;
81
+ }
82
+
83
+ return acc;
84
+ },
85
+ {},
86
+ );
87
+
88
+ return JSON.stringify(filtersData);
89
+ }
90
+
91
+ fromString(snapshotStr: string): void {
92
+ const snapshot = JSON.parse(snapshotStr);
93
+
94
+ /*
95
+ first, make transition object from snapshot,
96
+ because filter should bw always added with value
97
+ */
98
+ const filtersData: { FilterName: FilterData } = Object.entries(
99
+ snapshot,
100
+ ).reduce(
101
+ (filtersAcc, [snapshotKey, snapshotValue]) => {
102
+ const name = filterNameFromSnapshotKey(snapshotKey);
103
+ const valueProp = filterValuePropFromSnapshotKey(snapshotKey);
104
+
105
+ if (filtersAcc[name]) {
106
+ filtersAcc[name][valueProp] = snapshotValue;
107
+ } else {
108
+ filtersAcc[name] = {
109
+ [valueProp]: snapshotValue,
110
+ };
111
+ }
112
+
113
+ return filtersAcc;
114
+ },
115
+ {} as { FilterName: FilterData },
116
+ );
117
+
118
+ Object.entries(filtersData).forEach(([name, filterData]) => {
119
+ this.addFilter({ ...filterData, name });
120
+ });
121
+ }
122
+
123
+ getAllKeys(): FilterName[] {
124
+ return [...this.filters.keys()];
125
+ }
126
+
127
+ getFiltersList({
128
+ include,
129
+ exclude,
130
+ }: {
131
+ include: FilterName[];
132
+ exclude: FilterName[];
133
+ }): IFilter[] {
134
+ const useInclude = !isEmpty(include);
135
+ const useExclude = !isEmpty(exclude) && !useInclude;
136
+
137
+ if (!useInclude && !useExclude) {
138
+ return [...this.filters.values()];
139
+ }
140
+
141
+ return [...this.filters.values()].filter(({ name }) => {
142
+ if (useInclude) {
143
+ return include.includes(name);
144
+ } else if (useExclude) {
145
+ return !exclude.includes(name);
146
+ }
147
+
148
+ return true;
149
+ });
150
+ }
151
+
152
+ reset({
153
+ include,
154
+ exclude,
155
+ }: {
156
+ include: FilterName[];
157
+ exclude: FilterName[];
158
+ }): void {
159
+ const useInclude = !isEmpty(include);
160
+ const useExclude = !isEmpty(exclude) && !useInclude;
161
+
162
+ if (!useInclude && !useExclude) {
163
+ this.filters.clear();
164
+ return;
165
+ }
166
+
167
+ if (useInclude) {
168
+ include.forEach((name) => {
169
+ this.filters.delete(name);
170
+ });
171
+ return;
172
+ }
173
+
174
+ if (useExclude) {
175
+ this.filters.forEach((_, filterName) => {
176
+ if (exclude.includes(filterName)) {
177
+ this.filters.delete(filterName);
178
+ }
179
+ });
180
+ return;
181
+ }
182
+ }
183
+ }
184
+
185
+ export const createFiltersManager = (
186
+ config?: FiltersManagerConfig,
187
+ ): IFiltersManager => {
188
+ return new FiltersManager(config);
189
+ };