@webitel/ui-sdk 25.6.11 → 25.6.13

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": "25.6.11",
3
+ "version": "25.6.13",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "dev": "npm run docs:dev",
@@ -146,6 +146,7 @@ import plyrRestart from './plyr-restart.svg';
146
146
  import plyrRewind from './plyr-rewind.svg';
147
147
  import plyrSettings from './plyr-settings.svg';
148
148
  import plyrVolume from './plyr-volume.svg';
149
+ import portal from './portal.svg';
149
150
  import previewTagApplication from './preview-tag-application.svg';
150
151
  import previewTagAudio from './preview-tag-audio.svg';
151
152
  import previewTagImage from './preview-tag-image.svg';
@@ -390,6 +391,8 @@ export default objCamelToKebab({
390
391
 
391
392
  webitelLogo,
392
393
 
394
+ portal,
395
+
393
396
  previewTagAudio,
394
397
  previewTagVideo,
395
398
  previewTagApplication,
@@ -0,0 +1,3 @@
1
+ <svg id="portal" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM9 19.416C9.92666 19.7912 10.9388 20 12 20C12.4458 20 12.8827 19.9617 13.3086 19.8916L9 16.3008V19.416ZM15.5596 19.1641C16.6047 18.6438 17.5195 17.9024 18.2432 17H12.9629L15.5596 19.1641ZM4.83496 15.5596C5.35516 16.6047 6.09769 17.5185 7 18.2422V12.9619L4.83496 15.5596ZM12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9ZM16.3018 15H19.416C19.7912 14.0733 20 13.0612 20 12C20 11.5539 19.9618 11.1166 19.8916 10.6904L16.3018 15ZM4.58398 9C4.20875 9.92666 4 10.9388 4 12C4 12.4457 4.03734 12.8827 4.10742 13.3086L7.69824 9H4.58398ZM17 11.0371L19.1641 8.43945C18.6438 7.39467 17.9022 6.48031 17 5.75684V11.0371ZM12 4C11.554 4 11.1166 4.03724 10.6904 4.10742L15 7.69824V4.58301C14.0734 4.20786 13.0611 4 12 4ZM8.43945 4.83496C7.3945 5.35523 6.4804 6.0977 5.75684 7H11.0371L8.43945 4.83496Z" />
3
+ </svg>
@@ -50,35 +50,32 @@
50
50
  </div>
51
51
  <component
52
52
  :is="QuestionTypeComponent"
53
- :question="question"
53
+ v-model:question="questionModel"
54
54
  mode="write"
55
- @change:question="emit('change:question', $event)"
56
55
  />
57
56
  </section>
58
57
  </article>
59
58
  </template>
60
59
 
61
- <script setup>
62
- import cloneDeep from 'lodash/cloneDeep.js';
63
- import set from 'lodash/set.js';
60
+ <script lang="ts" setup>
61
+ import cloneDeep from 'lodash/cloneDeep';
64
62
  import { computed } from 'vue';
65
- import { EngineAuditQuestionType } from 'webitel-sdk';
63
+ import { EngineAuditQuestionType, EngineQuestion } from 'webitel-sdk';
66
64
 
67
65
  import WtIconBtn from '../../../components/wt-icon-btn/wt-icon-btn.vue';
68
66
  import WtInput from '../../../components/wt-input/wt-input.vue';
69
67
  import WtSelect from '../../../components/wt-select/wt-select.vue';
70
68
  import WtSwitcher from '../../../components/wt-switcher/wt-switcher.vue';
71
69
  import WtTooltip from '../../../components/wt-tooltip/wt-tooltip.vue';
70
+ import {updateObject} from '../../../scripts';
72
71
  import { generateQuestionOptionsSchema } from '../schemas/AuditFormQuestionOptionsSchema.js';
73
72
  import { generateQuestionScoreSchema } from '../schemas/AuditFormQuestionScoreSchema.js';
74
73
  import AuditFormQuestionOptions from './form-questions/options/audit-form-question-options.vue';
75
74
  import AuditFormQuestionScore from './form-questions/score/audit-form-question-score.vue';
76
75
 
77
- const props = defineProps({
78
- question: {
79
- type: Object,
80
- required: true,
81
- },
76
+ const questionModel = defineModel<EngineQuestion>('question');
77
+
78
+ defineProps({
82
79
  first: {
83
80
  type: Boolean,
84
81
  default: false,
@@ -88,7 +85,7 @@ const props = defineProps({
88
85
  },
89
86
  });
90
87
 
91
- const emit = defineEmits(['change:question', 'copy', 'delete']);
88
+ const emit = defineEmits(['copy', 'delete']);
92
89
 
93
90
  const QuestionType = [
94
91
  {
@@ -102,30 +99,29 @@ const QuestionType = [
102
99
  ];
103
100
 
104
101
  const prettifiedQuestionType = computed(() =>
105
- QuestionType.find(({ value }) => value === props.question.type),
102
+ QuestionType.find(({ value }) => value === questionModel.value.type),
106
103
  );
107
104
 
108
105
  const QuestionTypeComponent = computed(() => {
109
- if (props.question.type === EngineAuditQuestionType.Option)
106
+ if (questionModel.value.type === EngineAuditQuestionType.Option)
110
107
  return AuditFormQuestionOptions;
111
- if (props.question.type === EngineAuditQuestionType.Score)
108
+ if (questionModel.value.type === EngineAuditQuestionType.Score)
112
109
  return AuditFormQuestionScore;
113
110
  return null;
114
111
  });
115
112
 
116
113
  function updateQuestion({ path, value }) {
117
- const question = set(cloneDeep(props.question), path, value);
118
- emit('change:question', question);
114
+ questionModel.value = updateObject({ obj: questionModel.value, path, value });
119
115
  }
120
116
 
121
117
  function handleQuestionTypeChange(type) {
122
- const question = cloneDeep(props.question);
118
+ const question = cloneDeep(questionModel.value);
123
119
  if (type === EngineAuditQuestionType.Option) {
124
120
  Object.assign(question, generateQuestionOptionsSchema());
125
121
  } else if (type === EngineAuditQuestionType.Score) {
126
122
  Object.assign(question, generateQuestionScoreSchema());
127
123
  }
128
- emit('change:question', question);
124
+ questionModel.value = question;
129
125
  }
130
126
  </script>
131
127
 
@@ -1,6 +1,8 @@
1
1
  <template>
2
2
  <component
3
3
  :is="component"
4
+ v-model:question="questionModel"
5
+ v-model:answer="answerModel"
4
6
  v-clickaway="saveQuestion"
5
7
  :class="[
6
8
  `audit-form-question--mode-${mode}`,
@@ -13,26 +15,19 @@
13
15
  ]"
14
16
  :disable-dragging="mode === 'fill'"
15
17
  :first="first"
16
- :question="question"
17
18
  :readonly="readonly"
18
- :result="answer /* compat, should be ':answer' */"
19
- :answer="answer"
20
19
  :v="v$"
21
20
  class="audit-form-question"
22
21
  @activate="activateQuestion"
23
22
  @copy="emit('copy')"
24
23
  @delete="emit('delete')"
25
- @change:question="emit('update:question', $event) /* compat, should be removed */"
26
- @update:question="emit('update:question', $event)"
27
- @change:result="emit('update:answer', $event) /* compat, should be ':answer' */"
28
- @update:answer="emit('update:answer', $event)"
29
24
  />
30
25
  </template>
31
26
 
32
27
  <script lang="ts" setup>
33
28
  import { useVuelidate } from '@vuelidate/core';
34
29
  import { required } from '@vuelidate/validators';
35
- import { computed, inject,onMounted, ref, toRefs } from 'vue';
30
+ import { computed, inject,onMounted, ref } from 'vue';
36
31
  import { EngineQuestion, EngineQuestionAnswer } from "webitel-sdk";
37
32
 
38
33
  import vClickaway from '../../../directives/clickaway/clickaway.js';
@@ -43,9 +38,10 @@ import QuestionWrite from './audit-form-question-write-wrapper.vue';
43
38
  const mode = inject('mode');
44
39
  const readonly = inject('readonly');
45
40
 
46
- const props = withDefaults(defineProps<{
47
- question: EngineQuestion;
48
- answer: EngineQuestionAnswer | null;
41
+ const questionModel = defineModel<EngineQuestion>('question');
42
+ const answerModel = defineModel<EngineQuestionAnswer | null>('answer');
43
+
44
+ withDefaults(defineProps<{
49
45
  first?: boolean;
50
46
  }>(), {
51
47
  first: false,
@@ -54,8 +50,6 @@ const props = withDefaults(defineProps<{
54
50
  const emit = defineEmits<{
55
51
  'copy': [];
56
52
  'delete': [];
57
- 'update:question': [unknown]; // todo
58
- 'update:answer': [unknown]; // todo
59
53
  }>();
60
54
 
61
55
  const QuestionState = {
@@ -65,9 +59,6 @@ const QuestionState = {
65
59
 
66
60
  const state = ref(QuestionState.SAVED);
67
61
 
68
- // is needed for useVuelidate, because props.question/props.result isn't reactive
69
- const { question, answer } = toRefs(props);
70
-
71
62
  const v$ = useVuelidate(
72
63
  computed(() =>
73
64
  mode === 'create'
@@ -80,7 +71,7 @@ const v$ = useVuelidate(
80
71
  answer: {
81
72
  required: (value) => {
82
73
  // if not required, no need to validate
83
- if (!props.question.required) return true;
74
+ if (!questionModel.value.required) return true;
84
75
 
85
76
  if (value && value?.score != null) {
86
77
  return true;
@@ -89,7 +80,7 @@ const v$ = useVuelidate(
89
80
  },
90
81
  },
91
82
  ),
92
- { question, answer },
83
+ { question: questionModel, answer: answerModel },
93
84
  { $autoDirty: true },
94
85
  );
95
86
 
@@ -102,7 +93,7 @@ const component = computed(() => {
102
93
  return QuestionRead;
103
94
  });
104
95
 
105
- const isAnswer = computed(() => !isEmpty(props.answer));
96
+ const isAnswer = computed(() => !isEmpty(answerModel.value));
106
97
 
107
98
  function saveQuestion() {
108
99
  state.value = QuestionState.SAVED;
@@ -49,7 +49,7 @@ import OptionsWriteRow from './audit-form-question-options-write-row.vue';
49
49
  const questionModel = defineModel<EngineQuestion>('question');
50
50
  const answerModel = defineModel<EngineQuestionAnswer | null>('answer');
51
51
 
52
- const props = defineProps<{
52
+ defineProps<{
53
53
  /**
54
54
  * question mode, NOT audit form mode
55
55
  */
@@ -44,20 +44,17 @@
44
44
  <script lang="ts" setup>
45
45
  import { useVuelidate } from '@vuelidate/core';
46
46
  import { integer, maxValue, minValue, required } from '@vuelidate/validators';
47
- import { computed, onMounted, toRefs } from 'vue';
48
- import { EngineQuestionAnswer } from 'webitel-sdk';
47
+ import { computed, onMounted } from 'vue';
48
+ import {EngineQuestion, EngineQuestionAnswer} from 'webitel-sdk';
49
49
 
50
50
  import WtInput from '../../../../../components/wt-input/wt-input.vue';
51
51
  import WtRadio from '../../../../../components/wt-radio/wt-radio.vue';
52
52
  import updateObject from '../../../../../scripts/updateObject.js';
53
53
 
54
54
  const answerModel = defineModel<EngineQuestionAnswer | null>('answer');
55
+ const questionModel = defineModel<EngineQuestion>('question');
55
56
 
56
- const props = defineProps({
57
- question: {
58
- type: Object,
59
- required: true,
60
- },
57
+ defineProps({
61
58
  mode: {
62
59
  // options: ['read', 'write']
63
60
  type: String,
@@ -65,11 +62,6 @@ const props = defineProps({
65
62
  },
66
63
  });
67
64
 
68
- const emit = defineEmits(['change:question']);
69
-
70
- // is needed for useVuelidate, because props.question/props.result isn't reactive
71
- const { question } = toRefs(props);
72
-
73
65
  const v$ = useVuelidate(
74
66
  computed(() => ({
75
67
  question: {
@@ -80,25 +72,25 @@ const v$ = useVuelidate(
80
72
  integer,
81
73
  },
82
74
  max: {
83
- minValue: minValue(props.question.min ? props.question.min : 1),
75
+ minValue: minValue(questionModel.value.min ? questionModel.value.min : 1),
84
76
  maxValue: maxValue(10),
85
77
  required,
86
78
  integer,
87
79
  },
88
80
  },
89
81
  })),
90
- { question },
82
+ { question: questionModel },
91
83
  { $autoDirty: true },
92
84
  );
93
85
 
94
86
  const scoreRange = computed(() => {
95
- if (props.question.min > props.question.max) return [];
87
+ if (questionModel.value.min > questionModel.value.max) return [];
96
88
  const result = [];
97
- let i = +props.question.min;
89
+ let i = +questionModel.value.min;
98
90
  do {
99
91
  result.push(i);
100
92
  i += 1;
101
- } while (i <= props.question.max);
93
+ } while (i <= questionModel.value.max);
102
94
  return result;
103
95
  });
104
96
 
@@ -110,7 +102,7 @@ function updateAnswer(score) {
110
102
  }
111
103
 
112
104
  function updateQuestion({ path, value }) {
113
- emit('change:question', updateObject({ obj: props.question, path, value }));
105
+ questionModel.value = updateObject({ obj: questionModel.value, path, value });
114
106
  }
115
107
 
116
108
  // init validation
@@ -1,15 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
-
3
- import AuditFormQuestionReadWrapper from '../audit-form-question-read-wrapper.vue';
4
-
5
- describe('AuditFormQuestionReadWrapper', () => {
6
- it('renders a component', () => {
7
- const wrapper = shallowMount(AuditFormQuestionReadWrapper, {
8
- props: {
9
- question: {},
10
- result: {},
11
- },
12
- });
13
- expect(wrapper.isVisible()).toBe(true);
14
- });
15
- });
@@ -1,68 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
- import { EngineAuditQuestionType } from 'webitel-sdk';
3
-
4
- import { generateQuestionOptionsSchema } from '../../schemas/AuditFormQuestionOptionsSchema.js';
5
- import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema.js';
6
- import { generateQuestionScoreSchema } from '../../schemas/AuditFormQuestionScoreSchema.js';
7
- import AuditFormQuestionWriteWrapper from '../audit-form-question-write-wrapper.vue';
8
-
9
- const v = { question: {} };
10
-
11
- describe('AuditFormQuestionWriteWrapper', () => {
12
- it('renders a component', () => {
13
- const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
14
- props: {
15
- question: {},
16
- v,
17
- },
18
- });
19
- expect(wrapper.isVisible()).toBe(true);
20
- });
21
- it('correctly changes question', () => {
22
- const question = generateQuestionSchema();
23
- const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
24
- props: {
25
- question,
26
- v,
27
- },
28
- });
29
- wrapper
30
- .findComponent({ name: 'wt-switcher' })
31
- .vm.$emit('change', !question.required);
32
- expect(wrapper.emitted()['change:question'][0][0].required).toBe(
33
- !question.required,
34
- );
35
- });
36
- it('correctly changes question type to Score', () => {
37
- const question = {};
38
- const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
39
- props: {
40
- question,
41
- v,
42
- },
43
- });
44
- wrapper
45
- .find('.audit-form-question-write-content-question')
46
- .findComponent({ name: 'wt-select' })
47
- .vm.$emit('input', { value: EngineAuditQuestionType.Score });
48
- expect(wrapper.emitted()['change:question'][0][0]).toEqual(
49
- generateQuestionScoreSchema(),
50
- );
51
- });
52
- it('correctly changes question type to Options', () => {
53
- const question = {};
54
- const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
55
- props: {
56
- question,
57
- v,
58
- },
59
- });
60
- wrapper
61
- .find('.audit-form-question-write-content-question')
62
- .findComponent({ name: 'wt-select' })
63
- .vm.$emit('input', { value: EngineAuditQuestionType.Option });
64
- expect(wrapper.emitted()['change:question'][0][0]).toEqual(
65
- generateQuestionOptionsSchema(),
66
- );
67
- });
68
- });
@@ -1,15 +0,0 @@
1
- import { shallowMount } from '@vue/test-utils';
2
-
3
- import AuditFormQuestion from '../audit-form-question.vue';
4
-
5
- describe('AuditFormQuestion', () => {
6
- it('renders a component', () => {
7
- const wrapper = shallowMount(AuditFormQuestion, {
8
- props: {
9
- question: {},
10
- result: {},
11
- },
12
- });
13
- expect(wrapper.isVisible()).toBe(true);
14
- });
15
- });
@@ -1,83 +0,0 @@
1
- import { mount } from '@vue/test-utils';
2
- import { ref } from 'vue';
3
-
4
- import { useDestroyableSortable } from '../../../../composables/useDestroyableSortable/useDestroyableSortable.js';
5
- import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema.js';
6
- import AuditForm from '../audit-form.vue';
7
-
8
- vi.mock(
9
- '../../../../composables/useDestroyableSortable/useDestroyableSortable.js',
10
- );
11
-
12
- useDestroyableSortable.mockImplementation(() => ({
13
- reloadSortable: ref(false),
14
- }));
15
-
16
- describe('AuditForm', () => {
17
- it('renders a component', async () => {
18
- const wrapper = mount(AuditForm, {
19
- props: {
20
- mode: '',
21
- questions: [],
22
- },
23
- });
24
- expect(wrapper.isVisible()).toBe(true);
25
- });
26
- it('add question button triggers update question event', async () => {
27
- const wrapper = mount(AuditForm, {
28
- props: {
29
- mode: 'create',
30
- questions: [],
31
- },
32
- });
33
- await wrapper.findComponent('.audit-form__add-button').vm.$emit('click');
34
- await wrapper.vm.$nextTick();
35
- await wrapper.vm.$nextTick();
36
- await wrapper.vm.$nextTick();
37
- console.info(wrapper.html());
38
- expect(wrapper.emitted()['update:questions'][0][0]).toEqual([
39
- generateQuestionSchema({ required: true }),
40
- ]);
41
- });
42
- it('delete event from child question emits update without passed question', async () => {
43
- const wrapper = mount(AuditForm, {
44
- props: {
45
- mode: 'create',
46
- questions: [generateQuestionSchema()],
47
- },
48
- });
49
- await wrapper
50
- .findComponent({ name: 'audit-form-question' })
51
- .vm.$emit('delete', { key: 0 });
52
- expect(wrapper.emitted()['update:questions'][0][0]).toEqual([]);
53
- });
54
- it('copy event from child question emits update with duplicated questions', async () => {
55
- const question = generateQuestionSchema();
56
- const wrapper = mount(AuditForm, {
57
- props: {
58
- mode: 'create',
59
- questions: [question],
60
- },
61
- });
62
- await wrapper
63
- .findComponent({ name: 'audit-form-question' })
64
- .vm.$emit('copy', { question, key: 0 });
65
- expect(wrapper.emitted()['update:questions'][0][0]).toEqual([
66
- question,
67
- question,
68
- ]);
69
- });
70
- it('initializes result depending on passed questions', () => {
71
- const wrapper = mount(AuditForm, {
72
- props: {
73
- mode: 'fill',
74
- questions: [
75
- generateQuestionSchema(),
76
- generateQuestionSchema(),
77
- generateQuestionSchema(),
78
- ],
79
- },
80
- });
81
- expect(wrapper.emitted()['update:result'][0][0]).toEqual([{}, {}, {}]);
82
- });
83
- });