@webitel/ui-sdk 24.10.46 → 24.10.47

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.10.46",
3
+ "version": "24.10.47",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "vite",
@@ -120,7 +120,7 @@
120
120
  "vue-multiselect": "^3.0.0-beta.3",
121
121
  "vue-observe-visibility": "^2.0.0-alpha.1",
122
122
  "vue-router": "^4.1.6",
123
- "webitel-sdk": "^24.8.1",
123
+ "webitel-sdk": "^24.8.2",
124
124
  "xlsx": "^0.18.5"
125
125
  },
126
126
  "devDependencies": {
@@ -143,7 +143,7 @@
143
143
  "vite-plugin-static-copy": "^0.17.1",
144
144
  "vite-plugin-svg-sprite": "^0.5.1",
145
145
  "vite-plugin-vue-docgen": "^0.3.4",
146
- "vitepress": "=1.0.0-rc.26",
146
+ "vitepress": "1.4.1",
147
147
  "vitest": "^1.4.0",
148
148
  "vue": "^3.4.15",
149
149
  "vuex": "^4.1.0"
@@ -0,0 +1,32 @@
1
+ import { AgentChatsServiceApi } from 'webitel-sdk';
2
+ import {
3
+ getDefaultInstance,
4
+ getDefaultOpenAPIConfig,
5
+ } from '../../defaults/index.js';
6
+ import applyTransform, {
7
+ notify,
8
+ snakeToCamel,
9
+ } from '../../transformers/index.js';
10
+
11
+ const instance = getDefaultInstance();
12
+ const configuration = getDefaultOpenAPIConfig();
13
+
14
+ const chatsService = new AgentChatsServiceApi(configuration, '', instance);
15
+
16
+ const getList = async (params) => {
17
+ try {
18
+ const response = await chatsService.getAgentChats();
19
+ const { items } = applyTransform(response.data, [
20
+ snakeToCamel(),
21
+ ]);
22
+ return items;
23
+ } catch (err) {
24
+ throw applyTransform(err, [notify]);
25
+ }
26
+ };
27
+
28
+ const ClosedChatsAPI = {
29
+ getList,
30
+ };
31
+
32
+ export default ClosedChatsAPI;
@@ -4,6 +4,7 @@ import calendars from './calendars/calendars.js';
4
4
  import chatGateways from './chatGateways/chatGateways.js';
5
5
  import communications from './communications/communications.js';
6
6
  import configurations from './configurations/configurations.js';
7
+ import closedChats from './chats/closedChats.js'
7
8
  import flows from './flows/flow.js';
8
9
  import gateways from './gateways/gateways.js';
9
10
  import lists from './lists/blacklists.js';
@@ -19,6 +20,7 @@ export {
19
20
  calendars,
20
21
  chatGateways,
21
22
  communications,
23
+ closedChats,
22
24
  flows,
23
25
  gateways,
24
26
  lists,
@@ -12,19 +12,23 @@ import WtCopyAction from './wt-copy-action/wt-copy-action.vue';
12
12
  import WtDatepicker from './wt-datepicker/wt-datepicker.vue';
13
13
  import WtDivider from './wt-divider/wt-divider.vue';
14
14
  import WtDummy from './wt-dummy/wt-dummy.vue';
15
+ import WtEmpty from './wt-empty/wt-empty.vue';
15
16
  import WtErrorPage from './wt-error-page/wt-error-page.vue';
16
17
  import WtExpansionPanel from './wt-expansion-panel/wt-expansion-panel.vue';
17
- import WtFiltersPanelWrapper from './wt-filters-panel-wrapper/wt-filters-panel-wrapper.vue';
18
+ import WtFiltersPanelWrapper
19
+ from './wt-filters-panel-wrapper/wt-filters-panel-wrapper.vue';
18
20
  import WtHeadlineNav from './wt-headline-nav/wt-headline-nav.vue';
19
21
  import WtHeadline from './wt-headline/wt-headline.vue';
20
22
  import WtHint from './wt-hint/wt-hint.vue';
21
23
  import WtIconAction from './wt-icon-action/wt-icon-action.vue';
22
24
  import WtIconBtn from './wt-icon-btn/wt-icon-btn.vue';
23
25
  import WtIcon from './wt-icon/wt-icon.vue';
26
+ import WtImage from './wt-image/wt-image.vue';
24
27
  import WtIndicator from './wt-indicator/wt-indicator.vue';
25
28
  import WtInputInfo from './wt-input-info/wt-input-info.vue';
26
29
  import WtInput from './wt-input/wt-input.vue';
27
- import WtIntersectionObserver from './wt-intersection-observer/wt-intersection-observer.vue';
30
+ import WtIntersectionObserver
31
+ from './wt-intersection-observer/wt-intersection-observer.vue';
28
32
  import WtItemLink from './wt-item-link/wt-item-link.vue';
29
33
  import WtLabel from './wt-label/wt-label.vue';
30
34
  import WtLoadBar from './wt-load-bar/wt-load-bar.vue';
@@ -32,7 +36,8 @@ import WtLoader from './wt-loader/wt-loader.vue';
32
36
  import WtLogo from './wt-logo/wt-logo.vue';
33
37
  import WtNavigationBar from './wt-navigation-bar/wt-navigation-bar.vue';
34
38
  import WtNotification from './wt-notification/wt-notification.vue';
35
- import WtNotificationsBar from './wt-notifications-bar/wt-notifications-bar.vue';
39
+ import WtNotificationsBar
40
+ from './wt-notifications-bar/wt-notifications-bar.vue';
36
41
  import WtPageHeader from './wt-page-header/wt-page-header.vue';
37
42
  import WtPageWrapper from './wt-page-wrapper/wt-page-wrapper.vue';
38
43
  import WtPagination from './wt-pagination/wt-pagination.vue';
@@ -48,7 +53,8 @@ import WtStatusSelect from './wt-status-select/wt-status-select.vue';
48
53
  import WtStepper from './wt-stepper/wt-stepper.vue';
49
54
  import WtSwitcher from './wt-switcher/wt-switcher.vue';
50
55
  import WtTableActions from './wt-table-actions/wt-table-actions.vue';
51
- import WtTableColumnSelect from './wt-table-column-select/wt-table-column-select.vue';
56
+ import WtTableColumnSelect
57
+ from './wt-table-column-select/wt-table-column-select.vue';
52
58
  import WtTable from './wt-table/wt-table.vue';
53
59
  import WtTabs from './wt-tabs/wt-tabs.vue';
54
60
  import WtTagsInput from './wt-tags-input/wt-tags-input.vue';
@@ -58,6 +64,8 @@ import WtTimepicker from './wt-timepicker/wt-timepicker.vue';
58
64
  import WtTooltip from './wt-tooltip/wt-tooltip.vue';
59
65
 
60
66
  const Components = {
67
+ WtImage,
68
+ WtEmpty,
61
69
  WtLogo,
62
70
  WtAvatar,
63
71
  WtBadge,
@@ -0,0 +1,9 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import WtActionBar from '../wt-action-bar.vue';
3
+
4
+ describe('WtActionBar', () => {
5
+ it('renders a component', () => {
6
+ const wrapper = mount(WtActionBar);
7
+ expect(wrapper.exists()).toBe(true);
8
+ });
9
+ });
@@ -0,0 +1,78 @@
1
+ <template>
2
+ <div class="wt-action-bar">
3
+ <!-- @slot -->
4
+ <slot name="search-bar" />
5
+
6
+ <!-- @slot
7
+ @scope="{ `action`: IconAction enum string }"
8
+ -->
9
+ <slot
10
+ v-for="action in shownActions"
11
+ v-bind="{ action }"
12
+ >
13
+ <wt-icon-action
14
+ :action="action"
15
+ @click="emit(`click:${action}`)"
16
+ />
17
+ </slot>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup>
22
+ import { computed } from 'vue';
23
+ import IconAction from '../../enums/IconAction/IconAction.enum.js';
24
+ import WtIconAction from '../wt-icon-action/wt-icon-action.vue';
25
+
26
+ const props = defineProps({
27
+ // options: [`table`, `card`]
28
+ mode: {
29
+ type: String,
30
+ default: 'table',
31
+ validator: (v) => ['table', 'card'].includes(v),
32
+ },
33
+ /**
34
+ * see IconAction enum
35
+ */
36
+ actions: {
37
+ type: Array,
38
+ default: () => [],
39
+ validator: (v) => v.every((action) => Object.values(IconAction).includes(action)),
40
+ },
41
+ size: {
42
+ type: String,
43
+ default: 'md',
44
+ validator: (v) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(v),
45
+ },
46
+ });
47
+
48
+ const emit = defineEmits(Object.values(IconAction).map((action) => `click:${action}`));
49
+
50
+ const tableActionsOrder = [
51
+ IconAction.ADD,
52
+ IconAction.COLUMNS,
53
+ IconAction.COPY,
54
+ IconAction.DOWNLOAD,
55
+ IconAction.UPLOAD,
56
+ IconAction.FILTERS,
57
+ IconAction.DELETE,
58
+ IconAction.REFRESH,
59
+ ];
60
+
61
+ // TODO
62
+ const cardActionsOrder = tableActionsOrder;
63
+
64
+ const shownActions = computed(() => {
65
+ const actionsOrder = props.mode === 'card' ? cardActionsOrder : tableActionsOrder;
66
+
67
+ return actionsOrder.filter((action) => props.actions.includes(action));
68
+ });
69
+ </script>
70
+
71
+ <style lang="scss" scoped>
72
+ .wt-action-bar {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ gap: var(--spacing-xs);
77
+ }
78
+ </style>
@@ -25,10 +25,7 @@ export default {
25
25
  },
26
26
  tooltips: {
27
27
  type: Object,
28
- default: () => ({
29
- copy: '',
30
- copied: '',
31
- }),
28
+ default: () => ({}),
32
29
  },
33
30
  },
34
31
  data: () => ({
@@ -44,16 +41,12 @@ export default {
44
41
  },
45
42
  methods: {
46
43
  async copy() {
47
- try {
48
- await copy(this.value);
49
- this.copied = this.value;
50
- if (copiedIdTimeout) window.clearTimeout(copiedIdTimeout);
51
- copiedIdTimeout = setTimeout(() => {
52
- this.copied = null;
53
- }, 1500);
54
- } catch (err) {
55
- throw err;
56
- }
44
+ await copy(this.value);
45
+ this.copied = this.value;
46
+ if (copiedIdTimeout) window.clearTimeout(copiedIdTimeout);
47
+ copiedIdTimeout = setTimeout(() => {
48
+ this.copied = null;
49
+ }, 1500);
57
50
  },
58
51
  },
59
52
  };
@@ -0,0 +1,9 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import WtEmpty from '../wt-empty.vue';
3
+
4
+ describe('WtEmpty', () => {
5
+ it('renders a component', () => {
6
+ const wrapper = shallowMount(WtEmpty);
7
+ expect(wrapper.exists()).toBe(true);
8
+ });
9
+ });
@@ -0,0 +1,140 @@
1
+ <template>
2
+ <section
3
+ :class="[`wt-empty--${size}`]"
4
+ class="wt-empty"
5
+ >
6
+ <div
7
+ v-if="image || slots.media"
8
+ class="wt-empty__media"
9
+ >
10
+ <slot name="media">
11
+ <wt-image
12
+ :src="image"
13
+ alt="empty-state"
14
+ />
15
+ </slot>
16
+ </div>
17
+
18
+ <h2
19
+ v-if="headline || slots.headline"
20
+ class="wt-empty__headline"
21
+ >
22
+ <slot name="headline">
23
+ {{ headline }}
24
+ </slot>
25
+ </h2>
26
+
27
+ <h3
28
+ v-if="title || slots.title"
29
+ class="wt-empty__title"
30
+ >
31
+ <slot name="title">
32
+ {{ title }}
33
+ </slot>
34
+ </h3>
35
+
36
+ <slot></slot>
37
+
38
+ <p
39
+ v-if="text || slots.text"
40
+ class="wt-empty__text"
41
+ >
42
+ <slot name="text">
43
+ {{ text }}
44
+ </slot>
45
+ </p>
46
+
47
+ <div
48
+ v-if="actionText || slots.actions"
49
+ class="wt-empty__actions"
50
+ >
51
+ <slot
52
+ name="actions"
53
+ v-bind="{ onClick }"
54
+ >
55
+ <wt-button
56
+ :color="actionColor"
57
+ @click="onClick"
58
+ >
59
+ {{ actionText }}
60
+ </wt-button>
61
+ </slot>
62
+ </div>
63
+ </section>
64
+ </template>
65
+
66
+ <script setup>
67
+ // based on https://vuetifyjs.com/en/components/empty-states/
68
+
69
+ import { useSlots } from 'vue';
70
+ import WtImage from '../wt-image/wt-image.vue';
71
+
72
+ const props = defineProps({
73
+ image: {
74
+ type: [Object, null],
75
+ },
76
+ size: {
77
+ type: String,
78
+ default: 'md',
79
+ validator: (v) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(v),
80
+ },
81
+ headline: {
82
+ type: [String, null],
83
+ default: '',
84
+ },
85
+ title: {
86
+ type: [String, null],
87
+ default: '',
88
+ },
89
+ text: {
90
+ type: [String, null],
91
+ default: '',
92
+ },
93
+ actionText: {
94
+ type: [String, null],
95
+ default: '',
96
+ },
97
+ actionColor: {
98
+ type: [String, null],
99
+ default: 'primary',
100
+ },
101
+ });
102
+
103
+ const emit = defineEmits([
104
+ 'click:action',
105
+ ]);
106
+
107
+ const slots = useSlots();
108
+
109
+ const onClick = (params) => {
110
+ return emit('click:action', params);
111
+ };
112
+ </script>
113
+
114
+ <style lang="scss" scoped>
115
+ @import '../../../src/css/main.scss';
116
+
117
+ .wt-empty {
118
+ display: flex;
119
+ align-items: center;
120
+ flex-direction: column;
121
+ justify-content: center;
122
+ text-align: center;
123
+ gap: var(--spacing-sm);
124
+
125
+ &__media {
126
+ }
127
+
128
+ &__headline {
129
+ }
130
+
131
+ &__title {
132
+ }
133
+
134
+ &__text {
135
+ }
136
+
137
+ &__actions {
138
+ }
139
+ }
140
+ </style>
@@ -8,6 +8,7 @@
8
8
 
9
9
  <script setup>
10
10
  import { computed } from 'vue';
11
+ import IconAction from '../../enums/IconAction/IconAction.enum.js';
11
12
  import WtAddIconAction from './_internals/wt-add-icon-action.vue';
12
13
  import WtDeleteIconAction from './_internals/wt-delete-icon-action.vue';
13
14
  import WtDownloadIconAction from './_internals/wt-download-icon-action.vue';
@@ -16,10 +17,20 @@ import WtHistoryIconAction from './_internals/wt-history-icon-action.vue';
16
17
  import WtRefreshIconAction from './_internals/wt-refresh-icon-action.vue';
17
18
 
18
19
  const props = defineProps({
20
+ /**
21
+ * available actions: IconAction.DELETE, IconAction.EDIT, IconAction.ADD, IconAction.HISTORY, IconAction.DOWNLOAD, IconAction.REFRESH
22
+ */
19
23
  action: {
20
24
  type: String,
21
25
  required: true,
22
- options: ['delete', 'edit', 'add', 'history', 'download', 'refresh'],
26
+ validator: (v) => Object.values([
27
+ IconAction.DELETE,
28
+ IconAction.EDIT,
29
+ IconAction.ADD,
30
+ IconAction.HISTORY,
31
+ IconAction.DOWNLOAD,
32
+ IconAction.REFRESH,
33
+ ]).includes(v),
23
34
  },
24
35
  disabled: {
25
36
  type: Boolean,
@@ -31,19 +42,20 @@ const emit = defineEmits(['click']);
31
42
 
32
43
  const actionComponent = computed(() => {
33
44
  switch (props.action) {
34
- case 'edit':
45
+ case IconAction.EDIT:
35
46
  return WtEditIconAction;
36
- case 'delete':
47
+ case IconAction.DELETE:
37
48
  return WtDeleteIconAction;
38
- case 'add':
49
+ case IconAction.ADD:
39
50
  return WtAddIconAction;
40
- case 'history':
51
+ case IconAction.HISTORY:
41
52
  return WtHistoryIconAction;
42
- case 'download':
53
+ case IconAction.DOWNLOAD:
43
54
  return WtDownloadIconAction;
44
- case 'refresh':
55
+ case IconAction.REFRESH:
45
56
  return WtRefreshIconAction;
46
57
  default:
58
+ console.error(`Unknown action for wt-icon-action component: ${props.action}`);
47
59
  return WtEditIconAction;
48
60
  }
49
61
  });
@@ -0,0 +1,9 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import WtImage from '../wt-image.vue';
3
+
4
+ describe('WtImage', () => {
5
+ it('renders a component', () => {
6
+ const wrapper = shallowMount(WtImage);
7
+ expect(wrapper.exists()).toBe(true);
8
+ });
9
+ });
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <div
3
+ :style="{
4
+ width,
5
+ height,
6
+ minWidth,
7
+ minHeight,
8
+ maxWidth,
9
+ maxHeight,
10
+ }"
11
+ class="wt-image"
12
+ >
13
+ <!-- @slot Replaces `<img>` tag
14
+ @scope `{ alt, src }`
15
+ -->
16
+ <slot v-bind="{ alt, src }">
17
+ <img
18
+ :alt="alt"
19
+ :src="src"
20
+ class="wt-image__img"
21
+ >
22
+ </slot>
23
+ </div>
24
+ </template>
25
+
26
+ <script setup>
27
+ import { computed } from 'vue';
28
+
29
+ const sizeToUnits = {
30
+ '3xs': '32px',
31
+ '2xs': '64px',
32
+ 'xs': '92px',
33
+ 'sm': '128px',
34
+ 'md': '192px',
35
+ 'lg': '256px',
36
+ 'xl': '380px',
37
+ '2xl': '512px',
38
+ '3xl': '600px',
39
+ };
40
+
41
+ const props = defineProps({
42
+ src: {
43
+ type: [Object, String],
44
+ required: true,
45
+ },
46
+ // все в одну лінію, бо повалиться дока
47
+ /**
48
+ * `'3xs': '32px', '2xs': '64px', 'xs': '92px', 'sm': '128px', 'md': '192px', 'lg': '256px', 'xl': '380px', '2xl': '512px', '3xl': '600px',`
49
+ */
50
+ size: {
51
+ type: String,
52
+ // default: 'md',
53
+ // required: true,
54
+ validator: (v) => ['3xs', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'].includes(v),
55
+ },
56
+ alt: {
57
+ type: String,
58
+ default: 'wt-image',
59
+ },
60
+ width: {
61
+ type: [String, Number],
62
+ },
63
+ height: {
64
+ type: [String, Number],
65
+ },
66
+ minWidth: {
67
+ type: [String, Number],
68
+ },
69
+ minHeight: {
70
+ type: [String, Number],
71
+ },
72
+ maxWidth: {
73
+ type: [String, Number],
74
+ },
75
+ maxHeight: {
76
+ type: [String, Number],
77
+ },
78
+ // aspectRatio: {
79
+ // type: [String, Number, null],
80
+ // default: 1,
81
+ // },
82
+ });
83
+
84
+ const emit = defineEmits([]);
85
+
86
+ const width = computed(() => {
87
+ const width = props.size ? sizeToUnits[props.size] : props.width;
88
+
89
+ // if converted to Number without an error, it has no units in it
90
+ if (+width) {
91
+ return `${width}px`;
92
+ }
93
+
94
+ return width;
95
+ });
96
+
97
+ const height = computed(() => {
98
+ // if (props.aspectRatio) return null;
99
+
100
+ const height = props.size ? sizeToUnits[props.size] : props.height;
101
+
102
+ // if converted to Number without an error, it has no units in it
103
+ if (+height) {
104
+ return `${height}px`;
105
+ }
106
+
107
+ return height;
108
+ });
109
+ </script>
110
+
111
+ <style lang="scss" scoped>
112
+ @import '../../../src/css/main.scss';
113
+
114
+ .wt-image {
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+
119
+ &__img {
120
+ max-width: 100%;
121
+ max-height: 100%;
122
+ }
123
+ }
124
+ </style>
@@ -26,7 +26,7 @@
26
26
  @click="sort(col)"
27
27
  >
28
28
  <div class="wt-table__th__text">
29
- {{ col.text }}
29
+ {{ col.text || col.value }}
30
30
  </div>
31
31
  <wt-icon
32
32
  v-if="sortable"
@@ -0,0 +1,15 @@
1
+ const IconAction = Object.freeze({
2
+ REFRESH: 'refresh',
3
+ ADD: 'add',
4
+ DELETE: 'delete',
5
+ FILTERS: 'filters',
6
+ UPLOAD: 'upload',
7
+ DOWNLOAD: 'download',
8
+ EXPORT: 'export',
9
+ COPY: 'copy',
10
+ COLUMNS: 'columns',
11
+ HISTORY: 'history',
12
+ EDIT: 'edit',
13
+ });
14
+
15
+ export default IconAction;
@@ -121,10 +121,16 @@ import RolePopup from '../_internals/components/permissions-tab-role-popup.vue';
121
121
  import { AccessMode } from '../_internals/enums/AccessMode.enum.js';
122
122
 
123
123
  const props = defineProps({
124
+ /**
125
+ * Namespace of the parent card store
126
+ */
124
127
  namespace: {
125
128
  type: String,
126
129
  required: true,
127
130
  },
131
+ /**
132
+ * Access to the component actions, related to permissions
133
+ */
128
134
  access: {
129
135
  type: Object,
130
136
  default: () => ({
@@ -0,0 +1,20 @@
1
+ import { computed } from 'vue';
2
+ import { useI18n } from 'vue-i18n';
3
+
4
+ export const useTableEmpty = (emptyState) => {
5
+ const { t } = useI18n();
6
+
7
+ const media = computed(() => {});
8
+ const headline = computed(() => {});
9
+ const title = computed(() => {});
10
+ const text = computed(() => {});
11
+ const actionText = computed(() => {});
12
+
13
+ return {
14
+ media,
15
+ headline,
16
+ title,
17
+ text,
18
+ actionText,
19
+ };
20
+ };