@vc-shell/framework 1.0.59 → 1.0.60

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 (52) hide show
  1. package/core/composables/index.ts +0 -1
  2. package/core/composables/useNotifications/index.ts +2 -2
  3. package/core/composables/usePermissions/index.ts +1 -1
  4. package/core/composables/useSettings/index.ts +2 -2
  5. package/core/composables/useUser/index.ts +2 -2
  6. package/dist/framework.mjs +1124 -327
  7. package/dist/index.css +1 -1
  8. package/dist/types/core/composables/index.d.ts +0 -1
  9. package/dist/types/core/composables/index.d.ts.map +1 -1
  10. package/dist/types/core/composables/useNotifications/index.d.ts +1 -1
  11. package/dist/types/core/composables/useNotifications/index.d.ts.map +1 -1
  12. package/dist/types/core/composables/useUser/index.d.ts +2 -2
  13. package/dist/types/core/composables/useUser/index.d.ts.map +1 -1
  14. package/dist/types/shared/modules/assets/components/assets-details/assets-details.vue.d.ts +1 -0
  15. package/dist/types/shared/modules/assets/components/assets-details/assets-details.vue.d.ts.map +1 -1
  16. package/dist/types/shared/modules/assets/components/assets-details/index.d.ts +2 -0
  17. package/dist/types/shared/modules/assets/components/assets-details/index.d.ts.map +1 -1
  18. package/dist/types/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts +3 -3
  19. package/dist/types/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts.map +1 -1
  20. package/dist/types/shared/modules/assets-manager/components/assets-manager/index.d.ts +6 -6
  21. package/dist/types/ui/components/molecules/vc-editor/vc-editor.vue.d.ts.map +1 -1
  22. package/dist/types/ui/components/molecules/vc-file-upload/index.d.ts +12 -12
  23. package/dist/types/ui/components/molecules/vc-select/index.d.ts +24 -0
  24. package/dist/types/ui/components/molecules/vc-select/index.d.ts.map +1 -1
  25. package/dist/types/ui/components/molecules/vc-select/vc-select.vue.d.ts +20 -0
  26. package/dist/types/ui/components/molecules/vc-select/vc-select.vue.d.ts.map +1 -1
  27. package/dist/types/ui/components/molecules/vc-textarea/index.d.ts +0 -4
  28. package/dist/types/ui/components/molecules/vc-textarea/index.d.ts.map +1 -1
  29. package/dist/types/ui/components/molecules/vc-textarea/vc-textarea.stories.d.ts +0 -4
  30. package/dist/types/ui/components/molecules/vc-textarea/vc-textarea.stories.d.ts.map +1 -1
  31. package/dist/types/ui/components/molecules/vc-textarea/vc-textarea.vue.d.ts +1 -1
  32. package/dist/types/ui/components/molecules/vc-textarea/vc-textarea.vue.d.ts.map +1 -1
  33. package/dist/types/ui/components/organisms/vc-dynamic-property/index.d.ts +12 -0
  34. package/dist/types/ui/components/organisms/vc-dynamic-property/index.d.ts.map +1 -1
  35. package/dist/types/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue.d.ts +7 -0
  36. package/dist/types/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue.d.ts.map +1 -1
  37. package/dist/types/ui/components/organisms/vc-gallery/index.d.ts +6 -6
  38. package/dist/types/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
  39. package/package.json +4 -4
  40. package/shared/modules/assets/components/assets-details/assets-details.vue +60 -22
  41. package/shared/modules/assets-manager/components/assets-manager/assets-manager.vue +38 -21
  42. package/tailwind.config.js +0 -2
  43. package/ui/components/atoms/vc-button/vc-button.vue +0 -1
  44. package/ui/components/molecules/vc-editor/vc-editor.vue +21 -0
  45. package/ui/components/molecules/vc-select/vc-select.vue +39 -8
  46. package/ui/components/molecules/vc-textarea/vc-textarea.vue +1 -1
  47. package/ui/components/organisms/vc-dynamic-property/index.ts +0 -1
  48. package/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.vue +14 -3
  49. package/ui/components/organisms/vc-table/vc-table.vue +26 -52
  50. package/core/composables/useAutosave/index.ts +0 -55
  51. package/dist/types/core/composables/useAutosave/index.d.ts +0 -9
  52. package/dist/types/core/composables/useAutosave/index.d.ts.map +0 -1
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <!-- Blade contents -->
11
11
  <div class="tw-flex tw-grow-1 tw-border-t tw-border-solid tw-border-t-[#eaedf3]">
12
- <div class="assets-details__content tw-grow tw-basis-0">
12
+ <div class="assets-details__content tw-grow tw-basis-0 tw-w-full">
13
13
  <VcContainer :no-padding="true">
14
14
  <div class="tw-p-4">
15
15
  <VcForm>
@@ -19,12 +19,13 @@
19
19
  :src="defaultAsset.url"
20
20
  size="xl"
21
21
  :bordered="true"
22
+ class="tw-shrink-0"
22
23
  ></VcImage>
23
24
  </template>
24
25
  <template v-else>
25
26
  <VcIcon
26
27
  :icon="getFileThumbnail(defaultAsset.name)"
27
- class="tw-text-[#a9bfd2] tw-text-[128px]"
28
+ class="tw-text-[#a9bfd2] tw-text-[128px] tw-shrink-0"
28
29
  ></VcIcon>
29
30
  </template>
30
31
  <VcCol class="tw-ml-6">
@@ -39,14 +40,16 @@
39
40
  (defaultAsset.createdDate && moment(defaultAsset.createdDate).fromNow()) || "N/A"
40
41
  }}</VcHint>
41
42
  </VcCol>
42
- <VcCol>
43
+ <VcCol class="tw-w-full">
43
44
  <VcLabel>{{ $t("ASSETS.PAGES.DETAILS.FIELDS.URL") }}</VcLabel>
44
- <VcRow>
45
- <VcLink
46
- class="vc-link tw-text-s tw-max-w-10 tw-truncate tw-w-max tw-max-w-[100px]"
47
- @click="openLink(defaultAsset.url)"
48
- >{{ defaultAsset.name }}</VcLink
49
- >
45
+ <div class="tw-flex tw-flex-row tw-justify-stretch tw-truncate">
46
+ <div class="tw-truncate">
47
+ <VcLink
48
+ class="vc-link tw-text-s tw-truncate tw-w-full"
49
+ @click="openLink(defaultAsset.url)"
50
+ >{{ props.options?.asset.name }}</VcLink
51
+ >
52
+ </div>
50
53
  <VcButton
51
54
  icon="far fa-copy"
52
55
  size="m"
@@ -55,20 +58,32 @@
55
58
  @click="copyLink(defaultAsset.url)"
56
59
  title="Copy link"
57
60
  ></VcButton>
58
- </VcRow>
61
+ </div>
59
62
  </VcCol>
60
63
  </VcCol>
61
64
  </VcCol>
62
65
  </VcRow>
63
66
 
64
- <VcInput
65
- class="tw-mb-4"
67
+ <Field
66
68
  :label="$t('ASSETS.PAGES.DETAILS.FIELDS.NAME.TITLE')"
67
- v-model="defaultAsset.name"
68
- clearable
69
- required
70
- :placeholder="$t('ASSETS.PAGES.DETAILS.FIELDS.NAME.PLACEHOLDER')"
71
- ></VcInput>
69
+ name="asset_name"
70
+ rules="required"
71
+ :modelValue="defaultAsset.name"
72
+ v-slot="{ errorMessage, handleChange, errors }"
73
+ >
74
+ <VcInput
75
+ class="tw-mb-4"
76
+ :label="$t('ASSETS.PAGES.DETAILS.FIELDS.NAME.TITLE')"
77
+ v-model="assetNameClean"
78
+ @update:modelValue="handleChange"
79
+ clearable
80
+ required
81
+ :error="!!errors.length"
82
+ :error-message="errorMessage"
83
+ :placeholder="$t('ASSETS.PAGES.DETAILS.FIELDS.NAME.PLACEHOLDER')"
84
+ :disabled="readonly"
85
+ ></VcInput>
86
+ </Field>
72
87
  <VcInput
73
88
  class="tw-mb-4"
74
89
  :label="$t('ASSETS.PAGES.DETAILS.FIELDS.ALT.TITLE')"
@@ -76,15 +91,15 @@
76
91
  clearable
77
92
  :placeholder="$t('ASSETS.PAGES.DETAILS.FIELDS.ALT.PLACEHOLDER')"
78
93
  :tooltip="$t('ASSETS.PAGES.DETAILS.FIELDS.ALT.TOOLTIP')"
79
- required
80
94
  v-if="assetType === 'Image'"
95
+ :disabled="readonly"
81
96
  ></VcInput>
82
97
  <VcTextarea
83
98
  class="tw-mb-4"
84
99
  :label="$t('ASSETS.PAGES.DETAILS.FIELDS.DESCRIPTION.TITLE')"
85
100
  v-model="defaultAsset.description"
86
101
  :placeholder="$t('ASSETS.PAGES.DETAILS.FIELDS.DESCRIPTION.PLACEHOLDER')"
87
- required
102
+ :disabled="readonly"
88
103
  ></VcTextarea>
89
104
  </VcForm>
90
105
  </div>
@@ -95,18 +110,20 @@
95
110
  </template>
96
111
 
97
112
  <script lang="ts" setup>
98
- import { Asset } from "./../../../../../core/types";
113
+ import { Asset, IBladeToolbar } from "./../../../../../core/types";
99
114
  import { computed, ref } from "vue";
100
115
  import { useI18n } from "vue-i18n";
101
116
  import { VcBlade, VcContainer, VcForm, VcImage, VcInput, VcTextarea } from "./../../../../../ui/components";
102
117
  import { isImage, getFileThumbnail, readableSize } from "./../../../../utilities/assets";
103
118
  import moment from "moment";
119
+ import { useIsFormValid, Field, useForm, useIsFormDirty } from "vee-validate";
104
120
 
105
121
  export interface Props {
106
122
  expanded?: boolean;
107
123
  closable?: boolean;
108
124
  options?: {
109
125
  asset: Asset;
126
+ disabled?: boolean;
110
127
  assetEditHandler?: (defaultAsset: Asset) => void;
111
128
  assetRemoveHandler?: (defaultAsset: Asset) => void;
112
129
  };
@@ -122,10 +139,29 @@ const props = withDefaults(defineProps<Props>(), {
122
139
  });
123
140
 
124
141
  const emit = defineEmits<Emits>();
142
+ useForm({ validateOnMount: false });
143
+ const isValid = useIsFormValid();
144
+ const isDirty = useIsFormDirty();
125
145
  const { t } = useI18n();
126
146
  const defaultAsset = ref<Asset>({ ...props.options?.asset });
127
147
 
128
- const bladeToolbar = [
148
+ const readonly = computed(() => props.options.disabled);
149
+
150
+ const assetNameClean = computed({
151
+ get() {
152
+ return defaultAsset.value.name.split(".").shift();
153
+ },
154
+ set(value: string) {
155
+ const fileExtension = defaultAsset.value.name.split(".").pop();
156
+ defaultAsset.value.name = value + "." + fileExtension;
157
+ },
158
+ });
159
+
160
+ const isDisabled = computed(() => {
161
+ return !isDirty.value || !isValid.value;
162
+ });
163
+
164
+ const bladeToolbar = ref<IBladeToolbar[]>([
129
165
  {
130
166
  id: "save",
131
167
  title: t("ASSETS.PAGES.DETAILS.TOOLBAR.SAVE"),
@@ -136,6 +172,7 @@ const bladeToolbar = [
136
172
  emit("close:blade");
137
173
  }
138
174
  },
175
+ disabled: computed(() => isDisabled.value || readonly.value),
139
176
  },
140
177
  {
141
178
  id: "delete",
@@ -147,8 +184,9 @@ const bladeToolbar = [
147
184
  emit("close:blade");
148
185
  }
149
186
  },
187
+ disabled: computed(() => readonly.value),
150
188
  },
151
- ];
189
+ ]);
152
190
 
153
191
  const assetType = computed(() => defaultAsset.value?.typeId);
154
192
 
@@ -18,12 +18,12 @@
18
18
  :columns="columns"
19
19
  :expanded="expanded"
20
20
  stateKey="assets_manager"
21
- :reorderableRows="true"
21
+ :reorderableRows="!readonly"
22
22
  :items="defaultAssets"
23
23
  :header="false"
24
24
  :footer="false"
25
- :itemActionBuilder="actionBuilder"
26
- multiselect
25
+ :itemActionBuilder="!readonly && actionBuilder"
26
+ :multiselect="!readonly"
27
27
  class="tw-h-full tw-w-full"
28
28
  @item-click="onItemClick"
29
29
  @row:reorder="sortAssets"
@@ -147,15 +147,16 @@ import { IBladeEvent, IParentCallArgs } from "./../../../../../shared";
147
147
  import moment from "moment";
148
148
  import Assets from "./../../../assets/components/assets-details/assets-details.vue";
149
149
  import { isImage, getFileThumbnail, readableSize } from "./../../../../utilities/assets";
150
+ import { cloneDeep, isEqual } from "lodash-es";
150
151
 
151
152
  export interface Props {
152
153
  expanded?: boolean;
153
154
  closable?: boolean;
154
155
  options: {
155
156
  assets: Asset[];
156
- assetsEditHandler: (assets: Asset[]) => void;
157
- assetsUploadHandler: (files: FileList) => void;
158
- assetsRemoveHandler: (assets: Asset[]) => void;
157
+ assetsEditHandler: (assets: Asset[]) => Asset[];
158
+ assetsUploadHandler: (files: FileList) => Promise<Asset[]>;
159
+ assetsRemoveHandler: (assets: Asset[]) => Asset[];
159
160
  disabled: boolean;
160
161
  };
161
162
  }
@@ -182,6 +183,9 @@ const isDragging = ref(false);
182
183
  const uploader = ref();
183
184
  const loading = ref(false);
184
185
  const selectedItems = ref([]);
186
+ const readonly = computed(() => props.options.disabled);
187
+ let assetsCopy;
188
+ const modified = ref(false);
185
189
 
186
190
  const bladeToolbar = ref<IBladeToolbar[]>([
187
191
  {
@@ -191,6 +195,7 @@ const bladeToolbar = ref<IBladeToolbar[]>([
191
195
  clickHandler() {
192
196
  emit("close:blade");
193
197
  },
198
+ disabled: computed(() => !modified.value || readonly.value),
194
199
  },
195
200
  {
196
201
  id: "add",
@@ -199,6 +204,7 @@ const bladeToolbar = ref<IBladeToolbar[]>([
199
204
  clickHandler() {
200
205
  toggleUploader();
201
206
  },
207
+ disabled: computed(() => readonly.value),
202
208
  },
203
209
  {
204
210
  id: "delete",
@@ -206,11 +212,10 @@ const bladeToolbar = ref<IBladeToolbar[]>([
206
212
  icon: "fas fa-trash",
207
213
  clickHandler() {
208
214
  if (props.options.assetsRemoveHandler && typeof props.options.assetsRemoveHandler === "function") {
209
- props.options.assetsRemoveHandler(selectedItems.value);
210
- defaultAssets.value = defaultAssets.value.filter((asset) => !selectedItems.value.includes(asset));
215
+ defaultAssets.value = props.options.assetsRemoveHandler(selectedItems.value);
211
216
  }
212
217
  },
213
- disabled: computed(() => !selectedItems.value.length),
218
+ disabled: computed(() => !selectedItems.value.length || readonly.value),
214
219
  },
215
220
  ]);
216
221
 
@@ -248,35 +253,48 @@ const columns = ref<ITableColumns[]>([
248
253
  },
249
254
  ]);
250
255
 
256
+ watch(
257
+ () => defaultAssets.value,
258
+ (newVal) => {
259
+ modified.value = !isEqual(newVal, assetsCopy);
260
+ },
261
+ { deep: true }
262
+ );
263
+
251
264
  onMounted(() => {
252
265
  defaultAssets.value = props.options?.assets;
266
+ assetsCopy = cloneDeep(props.options?.assets);
253
267
  });
254
268
 
255
269
  function sortAssets(event: { dragIndex: number; dropIndex: number; value: Asset[] }) {
256
- if (props.options.assetsEditHandler && typeof props.options.assetsEditHandler === "function") {
270
+ if (
271
+ props.options.assetsEditHandler &&
272
+ typeof props.options.assetsEditHandler === "function" &&
273
+ event.dragIndex !== event.dropIndex
274
+ ) {
257
275
  const sorted = event.value.map((item, index) => {
258
276
  item.sortOrder = index;
259
277
  return item;
260
278
  });
261
- defaultAssets.value = sorted;
262
- props.options.assetsEditHandler(sorted);
279
+
280
+ defaultAssets.value = props.options.assetsEditHandler(sorted);
263
281
  }
264
282
  }
265
283
 
266
284
  function dragOver() {
267
- if (!props.options.disabled) {
285
+ if (!readonly.value) {
268
286
  isDragging.value = true;
269
287
  }
270
288
  }
271
289
 
272
290
  function dragLeave() {
273
- if (!props.options.disabled) {
291
+ if (!readonly.value) {
274
292
  isDragging.value = false;
275
293
  }
276
294
  }
277
295
 
278
296
  async function onDrop(event: DragEvent) {
279
- if (!props.options.disabled) {
297
+ if (!readonly.value) {
280
298
  const fileList = event.dataTransfer?.files;
281
299
 
282
300
  if (fileList && fileList.length) {
@@ -295,7 +313,7 @@ async function upload(files: FileList) {
295
313
  if (files && files.length) {
296
314
  try {
297
315
  loading.value = true;
298
- await props.options.assetsUploadHandler(files);
316
+ defaultAssets.value = await props.options.assetsUploadHandler(files);
299
317
  } finally {
300
318
  loading.value = false;
301
319
  }
@@ -316,6 +334,7 @@ function onItemClick(item: Asset) {
316
334
  component: shallowRef(Assets),
317
335
  bladeOptions: {
318
336
  asset: unref(item),
337
+ disabled: readonly.value,
319
338
  assetEditHandler: (asset: Asset) => {
320
339
  const mutated = defaultAssets.value.map((x) => {
321
340
  if (x.id === asset.id || x.url === asset.url) {
@@ -325,12 +344,11 @@ function onItemClick(item: Asset) {
325
344
  });
326
345
 
327
346
  if (props.options.assetsEditHandler && typeof props.options.assetsEditHandler === "function") {
328
- defaultAssets.value = mutated;
329
- props.options.assetsEditHandler(mutated);
347
+ defaultAssets.value = props.options.assetsEditHandler(mutated);
330
348
  }
331
349
  },
332
350
  assetRemoveHandler: (asset: Asset) => {
333
- props.options.assetsRemoveHandler([asset]);
351
+ defaultAssets.value = props.options.assetsRemoveHandler([asset]);
334
352
  },
335
353
  },
336
354
  });
@@ -357,8 +375,7 @@ const actionBuilder = (): IActionBuilderResult[] => {
357
375
  variant: "danger",
358
376
  leftActions: true,
359
377
  clickHandler(item: Asset) {
360
- props.options.assetsRemoveHandler([item]);
361
- defaultAssets.value = defaultAssets.value.filter((asset) => asset !== item);
378
+ defaultAssets.value = props.options.assetsRemoveHandler([item]);
362
379
  selectedItems.value = [];
363
380
  },
364
381
  });
@@ -47,6 +47,4 @@ module.exports = {
47
47
  }
48
48
  },
49
49
  },
50
-
51
- plugins: [require("@tailwindcss/line-clamp")],
52
50
  }
@@ -150,7 +150,6 @@ $variants: primary, secondary, special, danger, widget;
150
150
  tw-shadow-[1px_4px_10px_rgba(197,206,214,0.24)]
151
151
  tw-rounded-[4px]
152
152
  tw-p-[15px]
153
- tw-border-[color:var(--button-widget-background-color)]
154
153
  hover:tw-bg-[color:var(--button-widget-background-color-hover)]
155
154
  focus:tw-bg-[color:var(--button-widget-background-color-active)]
156
155
  focus:tw-border-[color:var(--button-widget-border-color-active)]
@@ -25,6 +25,7 @@
25
25
  <!-- Editor field -->
26
26
  <QuillEditor
27
27
  class="quill-editor tw-border tw-border-solid tw-border-[color:var(--editor-border-color)] tw-rounded-b-[var(--editor-border-radius)] tw-h-[200px]"
28
+ :class="{ 'tw-bg-[#fafafa] tw-text-[#424242] tw-cursor-default': disabled }"
28
29
  v-model:content="content"
29
30
  theme="snow"
30
31
  :toolbar="toolbar"
@@ -147,11 +148,31 @@ function isQuillEmpty(value: string) {
147
148
  --editor-border-color: #d3dbe9;
148
149
  --editor-border-color-error: #f14e4e;
149
150
  --editor-placeholder-color: #a5a5a5;
151
+
152
+ --editor-scroll-width: 8px;
153
+ --editor-scroll-color-hover: #cce4f5;
150
154
  }
151
155
 
152
156
  .vc-editor {
153
157
  &_error .quill-editor {
154
158
  @apply tw-border tw-border-solid tw-border-[color:var(--editor-border-color-error)] #{!important};
155
159
  }
160
+
161
+ .quill-editor .ql-editor {
162
+ &::-webkit-scrollbar {
163
+ @apply tw-w-[var(--editor-scroll-width)] tw-bg-transparent;
164
+ }
165
+
166
+ &::-webkit-scrollbar-track {
167
+ @apply tw-bg-transparent;
168
+ }
169
+
170
+ &::-webkit-scrollbar-thumb {
171
+ @apply tw-bg-[color:var(--editor-scroll-color)]
172
+ tw-rounded-[calc(var(--editor-scroll-width)/2)]
173
+ tw-overflow-x-hidden
174
+ hover:tw-bg-[color:var(--editor-scroll-color-hover)];
175
+ }
176
+ }
156
177
  }
157
178
  </style>
@@ -90,7 +90,7 @@
90
90
  <div
91
91
  class="tw-bg-[#fbfdfe] tw-border tw-border-solid tw-border-[color:#bdd1df] tw-rounded-[2px] tw-flex tw-items-center tw-h-[28px] tw-box-border tw-px-2"
92
92
  >
93
- <span>{{ getOptionLabel(item.opt) }}</span>
93
+ <span>{{ getDisplayLabel(item.opt) }}</span>
94
94
  <VcIcon
95
95
  v-if="!disabled"
96
96
  class="tw-text-[#a9bfd2] tw-ml-2 tw-cursor-pointer hover:tw-text-[color:var(--select-clear-color-hover)]"
@@ -344,6 +344,26 @@ export interface Props {
344
344
  * @returns Label of the current option
345
345
  */
346
346
  optionLabel?: OptionProp;
347
+ /**
348
+ * @requires optionValue
349
+ * @description Similar to optionValue, but used only for displaying selection result in rare cases. **Can't be used without optionValue**
350
+ *
351
+ * Property of option which holds the 'value'
352
+ * Default value: id
353
+ * @param option The current option being processed
354
+ * @returns Value of the current option
355
+ */
356
+ displayValue?: OptionProp;
357
+ /**
358
+ * @requires optionLabel
359
+ * @description Similar to optionValue, but used only for displaying selection result in rare cases. **Can't be used without optionLabel**
360
+ *
361
+ * Property of option which holds the 'label'
362
+ * Default value: title
363
+ * @param option The current option being processed
364
+ * @returns Label of the current option
365
+ */
366
+ displayLabel?: OptionProp;
347
367
  /**
348
368
  * Update model with the value of the selected option instead of the whole option
349
369
  */
@@ -548,9 +568,13 @@ const hasNextPage = computed(() => {
548
568
  return optionsList.value.length < totalItems.value;
549
569
  });
550
570
 
551
- const getOptionValue = computed(() => getPropValueFn(props.optionValue, "value"));
571
+ const getOptionValue = computed(() => getPropValueFn(props.optionValue, "id"));
572
+
573
+ const getOptionLabel = computed(() => getPropValueFn(props.optionLabel, "title"));
574
+
575
+ const getDisplayValue = computed(() => getPropValueFn(props.displayValue, "id"));
552
576
 
553
- const getOptionLabel = computed(() => getPropValueFn(props.optionLabel, "label"));
577
+ const getDisplayLabel = computed(() => getPropValueFn(props.displayLabel, "title"));
554
578
 
555
579
  const innerValue = computed((): Record<string, unknown>[] | string[] => {
556
580
  const mapNull = props.mapOptions === true && props.multiple !== true;
@@ -593,7 +617,9 @@ const selectedScope = computed(() => {
593
617
 
594
618
  const hasValue = computed(() => fieldValueIsFilled(innerValue.value));
595
619
 
596
- const innerOptionsValue = computed(() => innerValue.value.map((opt) => getOptionValue.value(opt)));
620
+ const innerOptionsValue = computed(() =>
621
+ innerValue.value.map((opt) => getOptionValue.value(opt) || getDisplayValue.value(opt))
622
+ );
597
623
 
598
624
  const optionScope = computed(() => {
599
625
  return optionsTemp.value.map((opt, i) => {
@@ -601,7 +627,7 @@ const optionScope = computed(() => {
601
627
  index: i,
602
628
  opt,
603
629
  selected: isOptionSelected(opt) === true,
604
- label: getOptionLabel.value(opt),
630
+ label: getOptionLabel.value(opt) || getDisplayLabel.value(opt),
605
631
  toggleOption,
606
632
  };
607
633
  });
@@ -624,7 +650,7 @@ function getPropValueFn(propValue: OptionProp, defaultVal: OptionProp) {
624
650
  }
625
651
 
626
652
  function getOption(value: Record<string, unknown> | string, valueCache: Array<Record<string, unknown> | string>) {
627
- const fn = (opt) => isEqual(getOptionValue.value(opt), value);
653
+ const fn = (opt) => isEqual(getOptionValue.value(opt), value) || isEqual(getDisplayValue.value(opt), value);
628
654
  return defaultValue.value.find(fn) || optionsList.value.find(fn) || valueCache.find(fn) || value;
629
655
  }
630
656
 
@@ -649,7 +675,8 @@ function removeAtIndex(index: number) {
649
675
  }
650
676
 
651
677
  function isOptionSelected(opt: Record<string, unknown>) {
652
- const val = getOptionValue.value(opt);
678
+ const val = getOptionValue.value(opt) || getDisplayValue.value(opt);
679
+
653
680
  return innerOptionsValue.value.find((v) => isEqual(v, val)) !== void 0;
654
681
  }
655
682
 
@@ -722,7 +749,7 @@ function toggleOption(opt: { [x: string]: string }) {
722
749
  return;
723
750
  }
724
751
 
725
- const optValue = getOptionValue.value(opt);
752
+ const optValue = getOptionValue.value(opt) || getDisplayValue.value(opt);
726
753
 
727
754
  if (props.multiple !== true) {
728
755
  if (innerValue.value.length === 0 || isEqual(getOptionValue.value(innerValue.value[0]), optValue) !== true) {
@@ -796,6 +823,10 @@ function emitValue(val: string) {
796
823
  }
797
824
 
798
825
  function onReset() {
826
+ if (props.multiple) {
827
+ emit("update:modelValue", []);
828
+ return;
829
+ }
799
830
  emit("update:modelValue", null);
800
831
  }
801
832
  </script>
@@ -50,7 +50,7 @@ import { VcLabel } from "./../../../components";
50
50
 
51
51
  export interface Props {
52
52
  placeholder?: string;
53
- modelValue: string;
53
+ modelValue?: string;
54
54
  required?: boolean;
55
55
  disabled?: boolean;
56
56
  label?: string;
@@ -1,4 +1,3 @@
1
- import { VNode } from "vue";
2
1
  import _DynamicProperty from "./vc-dynamic-property.vue";
3
2
 
4
3
  export const VcDynamicProperty = _DynamicProperty as typeof _DynamicProperty;
@@ -58,9 +58,10 @@
58
58
  :disabled="disabled"
59
59
  option-label="alias"
60
60
  option-value="id"
61
+ :display-label="displayedValueLabel.label"
62
+ :display-value="displayedValueLabel.value"
61
63
  :multiple="true"
62
64
  :emit-value="false"
63
- :clearable="false"
64
65
  ></VcSelect>
65
66
  </Field>
66
67
 
@@ -92,11 +93,12 @@
92
93
  :options="items"
93
94
  option-label="alias"
94
95
  option-value="id"
96
+ :display-label="displayedValueLabel.label"
97
+ :display-value="displayedValueLabel.value"
95
98
  @search="onSearch"
96
99
  @close="onClose"
97
100
  :multiple="property.multivalue"
98
101
  :emit-value="false"
99
- :clearable="false"
100
102
  ></VcSelect>
101
103
  </Field>
102
104
 
@@ -154,6 +156,8 @@
154
156
  :options="items"
155
157
  option-value="id"
156
158
  :option-label="handleDisplayProperty"
159
+ :display-label="displayedValueLabel.label"
160
+ :display-value="displayedValueLabel.value"
157
161
  multiple
158
162
  ></VcSelect>
159
163
  </Field>
@@ -323,8 +327,8 @@
323
327
 
324
328
  <script lang="ts" setup>
325
329
  import { ref, onMounted, computed } from "vue";
326
- import { useI18n } from "./../../../../core/composables";
327
330
  import { Field } from "vee-validate";
331
+ import { useI18n } from "vue-i18n";
328
332
 
329
333
  export interface Props {
330
334
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -348,6 +352,13 @@ export interface Props {
348
352
  ) => void | undefined;
349
353
  culture?: string;
350
354
  disabled?: boolean;
355
+ /**
356
+ * @description Used only with multiple selection **only** in rare cases, where we need to display selection with other value-label pair
357
+ */
358
+ displayedValueLabel?: {
359
+ value: string;
360
+ label: string;
361
+ };
351
362
  }
352
363
 
353
364
  export interface PropertyItem {