@webitel/ui-datalist 26.8.12 → 26.8.14

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 (28) hide show
  1. package/package.json +1 -1
  2. package/src/modules/filters/components/config/static-view/__tests__/static-filter-field.spec.ts +10 -0
  3. package/src/modules/filters/components/config/static-view/static-filter-field.vue +0 -2
  4. package/src/modules/filters/components/search-bar/__tests__/dynamic-filter-search.spec.ts +97 -0
  5. package/src/modules/filters/components/search-bar/dynamic-filter-search.vue +7 -5
  6. package/src/modules/filters/modules/filterConfig/components/_shared/has-options/__tests__/has-option-filter-value-field.spec.ts +40 -0
  7. package/src/modules/filters/modules/filterConfig/components/_shared/has-options/has-option-filter-value-field.vue +11 -4
  8. package/src/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue +3 -0
  9. package/src/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue +9 -2
  10. package/src/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue +9 -2
  11. package/src/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue +9 -2
  12. package/src/modules/filters/modules/filterConfig/components/rated-by/__tests__/rated-by-filter-value-field.spec.ts +35 -0
  13. package/src/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue +10 -1
  14. package/types/.tsbuildinfo +1 -1
  15. package/types/modules/filters/modules/filterConfig/components/_shared/has-options/has-option-filter-value-field.vue.d.ts +3 -0
  16. package/types/modules/filters/modules/filterConfig/components/has-attachment/has-attachment-filter-value-field.vue.d.ts +2 -0
  17. package/types/modules/filters/modules/filterConfig/components/has-file/has-file-filter-value-field.vue.d.ts +8 -2
  18. package/types/modules/filters/modules/filterConfig/components/has-rating/has-rating-filter-value-field.vue.d.ts +8 -2
  19. package/types/modules/filters/modules/filterConfig/components/has-transcription/has-transcription-filter-value-field.vue.d.ts +8 -2
  20. package/types/modules/filters/modules/filterConfig/components/rated-by/rated-by-filter-value-field.vue.d.ts +2 -0
  21. package/src/modules/filters/modules/filterConfig/components/created-at-from/created-at-from-filter-value-field.vue +0 -23
  22. package/src/modules/filters/modules/filterConfig/components/created-at-from/created-at-from-filter-value-preview.vue +0 -17
  23. package/src/modules/filters/modules/filterConfig/components/created-at-to/created-at-to-filter-value-field.vue +0 -23
  24. package/src/modules/filters/modules/filterConfig/components/created-at-to/created-at-to-filter-value-preview.vue +0 -17
  25. package/types/modules/filters/modules/filterConfig/components/created-at-from/created-at-from-filter-value-field.vue.d.ts +0 -10
  26. package/types/modules/filters/modules/filterConfig/components/created-at-from/created-at-from-filter-value-preview.vue.d.ts +0 -6
  27. package/types/modules/filters/modules/filterConfig/components/created-at-to/created-at-to-filter-value-field.vue.d.ts +0 -10
  28. package/types/modules/filters/modules/filterConfig/components/created-at-to/created-at-to-filter-value-preview.vue.d.ts +0 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-datalist",
3
- "version": "26.8.12",
3
+ "version": "26.8.14",
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",
@@ -14,6 +14,7 @@ import StaticFilterField from '../static-filter-field.vue';
14
14
  const StubInput = {
15
15
  props: [
16
16
  'modelValue',
17
+ 'hideLabel',
17
18
  ],
18
19
  emits: [
19
20
  'update:modelValue',
@@ -124,4 +125,13 @@ describe('StaticFilterField', () => {
124
125
 
125
126
  expect(wrapper.emitted('delete:filter')).toBeUndefined();
126
127
  });
128
+
129
+ /* static mode used to force hideLabel on every value field, which left
130
+ select-based filters (has-option-filter-value-field) with no visible
131
+ label at all — the value field itself now decides whether to show one */
132
+ it('does not force hideLabel on its value field', () => {
133
+ const wrapper = mountField(deletableConfig, filtersManager);
134
+
135
+ expect(wrapper.findComponent(StubInput).props('hideLabel')).toBeUndefined();
136
+ });
127
137
  });
@@ -10,10 +10,8 @@
10
10
  :disable-default-value="true"
11
11
  :disable-validation="true /*for static filters validation is not needed (different presentation with dynamic filters)*/"
12
12
  :filter-config="filterConfig"
13
- :hide-label="true /*for static filters need to hide label and display placeholder (different presentation with dynamic filters)*/"
14
13
  :static-view="true"
15
14
  :model-value="filterValue"
16
- :placeholder="filterConfig.label"
17
15
  @update:model-value="onValueChange"
18
16
  />
19
17
  </div>
@@ -0,0 +1,97 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { reactive } from 'vue';
4
+
5
+ import {
6
+ createFiltersManager,
7
+ type IFiltersManager,
8
+ } from '../../../classes/FiltersManager';
9
+ import DynamicFilterSearch from '../dynamic-filter-search.vue';
10
+
11
+ const searchModeOptions = [
12
+ {
13
+ value: 'name',
14
+ text: 'Name',
15
+ },
16
+ {
17
+ value: 'about',
18
+ text: 'About',
19
+ },
20
+ ];
21
+
22
+ const newFiltersManager = () =>
23
+ reactive(createFiltersManager()) as IFiltersManager;
24
+
25
+ const mountSearch = (
26
+ filtersManager: IFiltersManager,
27
+ props: Record<string, unknown> = {},
28
+ ) =>
29
+ shallowMount(DynamicFilterSearch, {
30
+ props: {
31
+ filtersManager,
32
+ ...props,
33
+ },
34
+ });
35
+
36
+ /* wt-search-bar is an async component, shallowMount renders it as the root stub */
37
+ const searchBarValue = (wrapper: ReturnType<typeof mountSearch>) =>
38
+ wrapper.attributes('value');
39
+
40
+ describe('dynamic-filter-search', () => {
41
+ it('restores the value of the filter of the current search mode', async () => {
42
+ const filtersManager = newFiltersManager();
43
+
44
+ const wrapper = mountSearch(filtersManager, {
45
+ searchModeOptions,
46
+ searchMode: 'name',
47
+ isFiltersRestoring: true,
48
+ });
49
+
50
+ filtersManager.addFilter({
51
+ name: 'name',
52
+ value: 'john',
53
+ });
54
+ await wrapper.setProps({
55
+ isFiltersRestoring: false,
56
+ });
57
+
58
+ expect(searchBarValue(wrapper)).toBe('john');
59
+ });
60
+
61
+ it('switches the search mode to the restored search filter', async () => {
62
+ const filtersManager = newFiltersManager();
63
+
64
+ const wrapper = mountSearch(filtersManager, {
65
+ searchModeOptions,
66
+ searchMode: '',
67
+ isFiltersRestoring: true,
68
+ });
69
+
70
+ filtersManager.addFilter({
71
+ name: 'about',
72
+ value: 'manager',
73
+ });
74
+ await wrapper.setProps({
75
+ isFiltersRestoring: false,
76
+ });
77
+
78
+ expect(searchBarValue(wrapper)).toBe('manager');
79
+ expect(wrapper.emitted('update:searchMode')?.at(-1)).toEqual([
80
+ 'about',
81
+ ]);
82
+ });
83
+
84
+ it('restores the value of a single search filter', () => {
85
+ const filtersManager = newFiltersManager();
86
+ filtersManager.addFilter({
87
+ name: 'q',
88
+ value: 'john',
89
+ });
90
+
91
+ const wrapper = mountSearch(filtersManager, {
92
+ singleSearchName: 'q',
93
+ });
94
+
95
+ expect(searchBarValue(wrapper)).toBe('john');
96
+ });
97
+ });
@@ -155,12 +155,14 @@ watch(
155
155
  (next) => {
156
156
  if (next) return;
157
157
 
158
- const searchModes = [
159
- defaultSearchName,
160
- ];
158
+ const searchModes = hasSearchModes.value
159
+ ? (props.searchModeOptions?.map((option) => option.value) ?? [])
160
+ : [
161
+ defaultSearchName,
162
+ ];
163
+
161
164
  if (hasSearchModes.value && !searchMode.value) {
162
- searchMode.value =
163
- props.searchModeOptions?.map((option) => option.value)[0] || '';
165
+ searchMode.value = searchModes[0] || '';
164
166
  }
165
167
 
166
168
  for (const mode of searchModes) {
@@ -0,0 +1,40 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import { createFilterConfig } from '../../../../classes/createFilterConfig';
5
+ import { FilterOption } from '../../../../enums/FilterOption';
6
+ import HasOptionFilterValueField from '../has-option-filter-value-field.vue';
7
+
8
+ describe('HasOptionFilterValueField label', () => {
9
+ it('renders a name-based label by default (static-filter-field no longer forces hideLabel)', () => {
10
+ const filterConfig = createFilterConfig({
11
+ name: FilterOption.Rated,
12
+ showFilterName: true,
13
+ });
14
+
15
+ const wrapper = mount(HasOptionFilterValueField, {
16
+ props: {
17
+ filterConfig,
18
+ },
19
+ });
20
+
21
+ expect(wrapper.find('.wt-select__label').exists()).toBe(true);
22
+ expect(wrapper.find('.wt-select__label').text()).toContain('Rated');
23
+ });
24
+
25
+ it('still respects an explicit hideLabel, e.g. has-user-filter-value-field always passing it', () => {
26
+ const filterConfig = createFilterConfig({
27
+ name: FilterOption.Rated,
28
+ showFilterName: true,
29
+ });
30
+
31
+ const wrapper = mount(HasOptionFilterValueField, {
32
+ props: {
33
+ filterConfig,
34
+ hideLabel: true,
35
+ },
36
+ });
37
+
38
+ expect(wrapper.find('.wt-select__label').exists()).toBe(false);
39
+ });
40
+ });
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <wt-single-select
3
- :label="labelValue"
4
3
  :options="BooleanOptions"
5
4
  v-model:model-value="strModel"
6
5
  class="has-option-filter-value-field"
7
6
  data-key="value"
8
7
  option-value="value"
9
8
  v-bind="attrs"
9
+ :label="labelValue"
10
10
  />
11
11
  </template>
12
12
 
@@ -15,10 +15,13 @@ import { WtSingleSelect } from '@webitel/ui-sdk/components';
15
15
  import { computed, useAttrs } from 'vue';
16
16
  import { useI18n } from 'vue-i18n';
17
17
 
18
+ import { WtSysTypeFilterConfig } from '../../../classes/FilterConfig';
18
19
  import { BooleanOptions } from '../../../enums/options/BooleanFilterOptions';
19
20
 
20
21
  const props = defineProps<{
22
+ filterConfig?: WtSysTypeFilterConfig;
21
23
  hideLabel?: boolean;
24
+ label?: string;
22
25
  }>();
23
26
 
24
27
  const model = defineModel<boolean | null>();
@@ -27,9 +30,13 @@ const attrs = useAttrs();
27
30
 
28
31
  const { t } = useI18n();
29
32
 
30
- const labelValue = computed(() =>
31
- props?.hideLabel ? undefined : t('webitelUI.filters.filterValue'),
32
- );
33
+ const labelValue = computed(() => {
34
+ if (props?.hideLabel) return;
35
+ const value = props?.filterConfig?.showFilterName
36
+ ? props?.filterConfig.name
37
+ : 'filterValue';
38
+ return t(`webitelUI.filters.${value}`);
39
+ });
33
40
 
34
41
  const strModel = computed({
35
42
  get: () => {
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <has-option-filter-value-field
3
+ :filter-config="filterConfig"
3
4
  :model-value="model"
4
5
  :v="!disableValidation && v$.model"
5
6
  @update:model-value="model = $event"
@@ -11,9 +12,11 @@ import { useVuelidate } from '@vuelidate/core';
11
12
  import { required } from '@vuelidate/validators';
12
13
  import { computed, watch } from 'vue';
13
14
 
15
+ import { WtSysTypeFilterConfig } from '../../classes/FilterConfig';
14
16
  import HasOptionFilterValueField from '../_shared/has-options/has-option-filter-value-field.vue';
15
17
 
16
18
  const props = defineProps<{
19
+ filterConfig?: WtSysTypeFilterConfig;
17
20
  disableValidation?: boolean;
18
21
  }>();
19
22
 
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <has-option-filter-value-field
3
+ :filter-config="filterConfig"
3
4
  :model-value="model"
4
- :v="v$.model"
5
+ :v="!disableValidation && v$.model"
5
6
  @update:model-value="model = $event"
6
7
  />
7
8
  </template>
@@ -9,10 +10,16 @@
9
10
  <script lang="ts" setup>
10
11
  import { watch } from 'vue';
11
12
 
13
+ import { WtSysTypeFilterConfig } from '../../classes/FilterConfig';
12
14
  import { useBooleanFilterValueValidation } from '../../composables/booleanFilterToolkit';
13
15
  import { BooleanFilterModelValue } from '../../enums/options/BooleanFilterOptions';
14
16
  import HasOptionFilterValueField from '../_shared/has-options/has-option-filter-value-field.vue';
15
17
 
18
+ const props = defineProps<{
19
+ filterConfig?: WtSysTypeFilterConfig;
20
+ disableValidation?: boolean;
21
+ }>();
22
+
16
23
  const model = defineModel<BooleanFilterModelValue | null>();
17
24
 
18
25
  const { v$ } = useBooleanFilterValueValidation<BooleanFilterModelValue>(model);
@@ -26,7 +33,7 @@ const emit = defineEmits<{
26
33
  watch(
27
34
  () => v$.value.$invalid,
28
35
  (invalid) => {
29
- emit('update:invalid', invalid);
36
+ emit('update:invalid', props.disableValidation ? false : invalid);
30
37
  },
31
38
  {
32
39
  immediate: true,
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <has-option-filter-value-field
3
+ :filter-config="filterConfig"
3
4
  :model-value="model"
4
- :v="v$.model"
5
+ :v="!disableValidation && v$.model"
5
6
  @update:model-value="model = $event"
6
7
  />
7
8
  </template>
@@ -9,10 +10,16 @@
9
10
  <script lang="ts" setup>
10
11
  import { watch } from 'vue';
11
12
 
13
+ import { WtSysTypeFilterConfig } from '../../classes/FilterConfig';
12
14
  import { useBooleanFilterValueValidation } from '../../composables/booleanFilterToolkit';
13
15
  import { BooleanFilterModelValue } from '../../enums/options/BooleanFilterOptions';
14
16
  import HasOptionFilterValueField from '../_shared/has-options/has-option-filter-value-field.vue';
15
17
 
18
+ const props = defineProps<{
19
+ filterConfig?: WtSysTypeFilterConfig;
20
+ disableValidation?: boolean;
21
+ }>();
22
+
16
23
  const model = defineModel<BooleanFilterModelValue | null>();
17
24
 
18
25
  const { v$ } = useBooleanFilterValueValidation<BooleanFilterModelValue>(model);
@@ -26,7 +33,7 @@ const emit = defineEmits<{
26
33
  watch(
27
34
  () => v$.value.$invalid,
28
35
  (invalid) => {
29
- emit('update:invalid', invalid);
36
+ emit('update:invalid', props.disableValidation ? false : invalid);
30
37
  },
31
38
  {
32
39
  immediate: true,
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <has-option-filter-value-field
3
+ :filter-config="filterConfig"
3
4
  :model-value="model"
4
- :v="v$.model"
5
+ :v="!disableValidation && v$.model"
5
6
  @update:model-value="model = $event"
6
7
  />
7
8
  </template>
@@ -9,10 +10,16 @@
9
10
  <script lang="ts" setup>
10
11
  import { watch } from 'vue';
11
12
 
13
+ import { WtSysTypeFilterConfig } from '../../classes/FilterConfig';
12
14
  import { useBooleanFilterValueValidation } from '../../composables/booleanFilterToolkit';
13
15
  import { BooleanFilterModelValue } from '../../enums/options/BooleanFilterOptions';
14
16
  import HasOptionFilterValueField from '../_shared/has-options/has-option-filter-value-field.vue';
15
17
 
18
+ const props = defineProps<{
19
+ filterConfig?: WtSysTypeFilterConfig;
20
+ disableValidation?: boolean;
21
+ }>();
22
+
16
23
  const model = defineModel<BooleanFilterModelValue | null>();
17
24
 
18
25
  const { v$ } = useBooleanFilterValueValidation<BooleanFilterModelValue>(model);
@@ -26,7 +33,7 @@ const emit = defineEmits<{
26
33
  watch(
27
34
  () => v$.value.$invalid,
28
35
  (invalid) => {
29
- emit('update:invalid', invalid);
36
+ emit('update:invalid', props.disableValidation ? false : invalid);
30
37
  },
31
38
  {
32
39
  immediate: true,
@@ -0,0 +1,35 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+
4
+ import { createFilterConfig } from '../../../classes/createFilterConfig';
5
+ import { FilterOption } from '../../../enums/FilterOption';
6
+ import RatedByFilterValueField from '../rated-by-filter-value-field.vue';
7
+
8
+ vi.mock('@webitel/api-services/api', async (importOriginal) => ({
9
+ ...(await importOriginal()),
10
+ UsersAPI: {
11
+ getLookup: vi.fn(() =>
12
+ Promise.resolve({
13
+ items: [],
14
+ next: false,
15
+ }),
16
+ ),
17
+ },
18
+ }));
19
+
20
+ describe('RatedByFilterValueField label', () => {
21
+ it('shows the filter name, not the generic "Value" text, when showFilterName is set', () => {
22
+ const filterConfig = createFilterConfig({
23
+ name: FilterOption.RatedBy,
24
+ showFilterName: true,
25
+ });
26
+
27
+ const wrapper = mount(RatedByFilterValueField, {
28
+ props: {
29
+ filterConfig,
30
+ },
31
+ });
32
+
33
+ expect(wrapper.find('.wt-select__label').text()).not.toBe('Value');
34
+ });
35
+ });
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <wt-multi-select
3
- :label="t('webitelUI.filters.filterValue')"
3
+ :label="labelValue"
4
4
  :search-method="searchMethod"
5
5
  :model-value="model"
6
6
  :v="!disableValidation && v$.model"
@@ -16,11 +16,13 @@ import { WtMultiSelect } from '@webitel/ui-sdk/components';
16
16
  import { computed, watch } from 'vue';
17
17
  import { useI18n } from 'vue-i18n';
18
18
 
19
+ import { WtSysTypeFilterConfig } from '../../classes/FilterConfig';
19
20
  import { searchMethod } from './config.js';
20
21
 
21
22
  type ModelValue = number[];
22
23
 
23
24
  const props = defineProps<{
25
+ filterConfig?: WtSysTypeFilterConfig;
24
26
  disableValidation?: boolean;
25
27
  }>();
26
28
 
@@ -33,6 +35,13 @@ const emit = defineEmits<{
33
35
  }>();
34
36
  const { t } = useI18n();
35
37
 
38
+ const labelValue = computed(() => {
39
+ const value = props?.filterConfig?.showFilterName
40
+ ? props?.filterConfig.name
41
+ : 'filterValue';
42
+ return t(`webitelUI.filters.${value}`);
43
+ });
44
+
36
45
  const v$ = useVuelidate(
37
46
  computed(() => ({
38
47
  model: {