@vcmap/module-selector 2.0.2 → 2.0.4

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.
@@ -4,7 +4,7 @@
4
4
  v-if="localConfig"
5
5
  v-bind="{ ...$attrs, ...$props }"
6
6
  >
7
- <v-container v-if="currentGroup === undefined" class="py-0 px-0">
7
+ <v-container class="py-0 px-0">
8
8
  <VcsFormSection heading="moduleSelector.configEditor.general">
9
9
  <v-container class="py-0 px-1">
10
10
  <v-row no-gutters>
@@ -39,24 +39,6 @@
39
39
  </v-row>
40
40
  </v-container>
41
41
  </VcsFormSection>
42
- <VcsFormSection
43
- heading="moduleSelector.configEditor.windowPosition"
44
- :expandable="true"
45
- >
46
- <WindowPositionSettings
47
- v-model="localConfig.position!"
48
- :position-keys="[
49
- 'top',
50
- 'right',
51
- 'bottom',
52
- 'left',
53
- 'width',
54
- 'maxWidth',
55
- 'height',
56
- 'maxHeight',
57
- ]"
58
- />
59
- </VcsFormSection>
60
42
  <VcsFormSection heading="moduleSelector.configEditor.baseModule">
61
43
  <v-container class="py-0 px-1">
62
44
  <v-row no-gutters>
@@ -109,73 +91,116 @@
109
91
  />
110
92
  </v-col>
111
93
  </v-row>
94
+ <v-row v-if="basisModuleExists" no-gutters>
95
+ <v-col cols="6">
96
+ <VcsLabel html-for="basisModuleDescription">
97
+ {{ $st('moduleSelector.configEditor.moduleDescription') }}
98
+ </VcsLabel>
99
+ </v-col>
100
+ <v-col>
101
+ <VcsTextArea
102
+ id="basisModuleDescription"
103
+ v-model="basisModule.description"
104
+ />
105
+ </v-col>
106
+ </v-row>
112
107
  </v-container>
113
108
  </VcsFormSection>
114
109
  </v-container>
115
- <v-container v-else class="py-0 px-1">
116
- <v-breadcrumbs :items="breadcrumbItems" divider="/">
117
- <template #item="{ item }">
118
- <v-breadcrumbs-item
119
- :key="item.title"
120
- :disabled="item.disabled"
121
- :href="item.href"
122
- @click="item.disabled ? null : returnLevel()"
123
- >
124
- {{ item.title }}
125
- </v-breadcrumbs-item>
126
- </template>
127
- </v-breadcrumbs>
128
-
129
- <v-row no-gutters>
130
- <v-col cols="6">
131
- <VcsLabel required html-for="groupModuleName">
132
- {{ $st('moduleSelector.configEditor.groupName') }}
133
- </VcsLabel>
134
- </v-col>
135
- <v-col>
136
- <VcsTextField
137
- id="groupModuleName"
138
- placeholder="Module Name"
139
- v-model="currentGroup!.title"
140
- :rules="[(v: string) => !!v || 'moduleSelector.configEditor.error']"
141
- />
142
- </v-col>
143
- </v-row>
144
- <v-row no-gutters>
145
- <v-col cols="6">
146
- <VcsLabel required html-for="groupModuleIcon">
147
- {{ $st('moduleSelector.configEditor.moduleIcon') }}
148
- </VcsLabel>
149
- </v-col>
150
- <v-col>
151
- <VcsTextField
152
- id="groupModuleIcon"
153
- placeholder="Module Icon"
154
- v-model="currentGroup!.icon"
155
- :rules="[
156
- (v: string) => !!v || 'moduleSelector.configEditor.editorError',
157
- ]"
110
+ <v-dialog v-model="groupItemDialogVisible" width="800" :persistent="true">
111
+ <v-sheet v-if="currentGroup">
112
+ <VcsFormSection
113
+ heading="moduleSelector.configEditor.groupHeading"
114
+ :start-open="true"
115
+ >
116
+ <v-form v-model="isFormValid">
117
+ <v-container class="py-0 px-1">
118
+ <v-row no-gutters>
119
+ <v-col cols="6">
120
+ <VcsLabel required html-for="groupModuleName">
121
+ {{ $st('moduleSelector.configEditor.groupName') }}
122
+ </VcsLabel>
123
+ </v-col>
124
+ <v-col>
125
+ <VcsTextField
126
+ id="groupModuleName"
127
+ placeholder="Module Name"
128
+ v-model="currentGroup.title"
129
+ :rules="[isRequired]"
130
+ />
131
+ </v-col>
132
+ </v-row>
133
+ <v-row no-gutters>
134
+ <v-col cols="6">
135
+ <VcsLabel required html-for="groupModuleIcon">
136
+ {{ $st('moduleSelector.configEditor.moduleIcon') }}
137
+ </VcsLabel>
138
+ </v-col>
139
+ <v-col>
140
+ <VcsTextField
141
+ id="groupModuleIcon"
142
+ placeholder="Module Icon"
143
+ v-model="currentGroup.icon"
144
+ :rules="[isRequired]"
145
+ />
146
+ </v-col>
147
+ </v-row>
148
+ <v-row no-gutters>
149
+ <v-col cols="6">
150
+ <VcsLabel html-for="groupModuleDescription">
151
+ {{ $st('moduleSelector.configEditor.groupDescription') }}
152
+ </VcsLabel>
153
+ </v-col>
154
+ <v-col>
155
+ <VcsTextArea
156
+ id="groupModuleDescription"
157
+ placeholder=""
158
+ v-model="currentGroup.description"
159
+ />
160
+ </v-col>
161
+ </v-row>
162
+ </v-container>
163
+ </v-form>
164
+ </VcsFormSection>
165
+ <VcsFormSection
166
+ heading="moduleSelector.configEditor.heading"
167
+ :start-open="true"
168
+ :header-actions="headerActions"
169
+ >
170
+ <VcsList
171
+ class="draggable-list"
172
+ :items="currentGroup.cards"
173
+ :draggable="true"
174
+ @item-moved="moveCard"
158
175
  />
159
- </v-col>
160
- </v-row>
161
- </v-container>
176
+ </VcsFormSection>
177
+ <div class="d-flex px-2 justify-end w-100">
178
+ <VcsFormButton
179
+ variant="filled"
180
+ class="ma-2"
181
+ :disabled="!isFormValid"
182
+ @click="returnLevel()"
183
+ >
184
+ {{ $t('components.apply') }}
185
+ </VcsFormButton>
186
+ <VcsFormButton class="ma-2" @click="cancelCurrentGroup()">
187
+ {{ $t('components.cancel') }}
188
+ </VcsFormButton>
189
+ </div>
190
+ </v-sheet>
191
+ </v-dialog>
192
+
162
193
  <VcsFormSection
163
194
  heading="moduleSelector.configEditor.heading"
164
195
  :start-open="true"
165
196
  :header-actions="headerActions"
166
197
  >
167
198
  <VcsList
168
- v-if="currentGroup === undefined"
169
199
  :items="listItemArray"
170
200
  :draggable="true"
171
- @item-moved="move"
172
- />
173
- <VcsList
174
- v-else
175
- :items="currentGroup.cards"
176
- :draggable="true"
177
- @item-moved="move"
201
+ @item-moved="moveItem"
178
202
  />
203
+
179
204
  <v-dialog
180
205
  v-model="editingItemDialogVisible"
181
206
  width="400"
@@ -199,6 +224,24 @@
199
224
  />
200
225
  </v-dialog>
201
226
  </VcsFormSection>
227
+ <VcsFormSection
228
+ heading="moduleSelector.configEditor.windowPosition"
229
+ :expandable="true"
230
+ >
231
+ <WindowPositionSettings
232
+ v-model="localConfig.position!"
233
+ :position-keys="[
234
+ 'top',
235
+ 'right',
236
+ 'bottom',
237
+ 'left',
238
+ 'width',
239
+ 'maxWidth',
240
+ 'height',
241
+ 'maxHeight',
242
+ ]"
243
+ />
244
+ </VcsFormSection>
202
245
  </AbstractConfigEditor>
203
246
  </template>
204
247
 
@@ -212,25 +255,26 @@
212
255
  VcsList,
213
256
  VcsListItem,
214
257
  VcsTextField,
215
- VcsUiApp,
258
+ VcsTextArea,
259
+ VcsFormButton,
216
260
  } from '@vcmap/ui';
217
261
  import {
218
262
  computed,
219
263
  defineComponent,
220
- inject,
221
264
  PropType,
222
265
  reactive,
223
266
  Ref,
224
267
  ref,
268
+ toRaw,
225
269
  watch,
226
270
  } from 'vue';
227
271
  import {
228
- VBreadcrumbs,
229
- VBreadcrumbsItem,
230
272
  VCol,
231
273
  VContainer,
232
274
  VDialog,
233
275
  VRow,
276
+ VSheet,
277
+ VForm,
234
278
  } from 'vuetify/components';
235
279
  import ModuleEditor from './ModuleEditor.vue';
236
280
  import { Module, ModuleSelectorConfig, ModuleType } from '../index';
@@ -244,28 +288,38 @@
244
288
  icon: string;
245
289
  type: string;
246
290
  moduleUrl?: string;
291
+ description?: string;
247
292
  cards?: VcsListItemWithLabel[];
248
293
  }
294
+ interface ModuleItem {
295
+ id: string;
296
+ title: string;
297
+ icon: string;
298
+ moduleUrl: string;
299
+ description?: string;
300
+ }
249
301
 
250
302
  export const windowIdConfigEditor = 'configEditor_window_id';
251
303
  export default defineComponent({
252
304
  name: 'ModuleSelectorConfigEditor',
253
305
  components: {
306
+ VForm,
307
+ VcsFormButton,
254
308
  VcsCheckbox,
255
309
  VDialog,
256
310
  VcsList,
257
311
  VcsFormSection,
258
312
  VRow,
313
+ VSheet,
259
314
  VcsLabel,
260
315
  AbstractConfigEditor,
261
316
  VcsTextField,
262
317
  VCol,
263
318
  VContainer,
264
319
  ModuleEditor,
265
- VBreadcrumbs,
266
- VBreadcrumbsItem,
267
320
  WindowPositionSettings,
268
321
  VcsModuleTable: CloudModuleSelector,
322
+ VcsTextArea,
269
323
  },
270
324
  props: {
271
325
  getConfig: {
@@ -278,24 +332,34 @@
278
332
  },
279
333
  },
280
334
  setup(props) {
281
- const app = inject('vcsApp') as VcsUiApp;
282
335
  const level = ref<number>(0);
283
336
  const localConfig = ref<ModuleSelectorConfig | undefined>(undefined);
284
337
  const listItemArray: Ref<VcsListItemWithLabel[]> = ref([]);
285
338
  const currentGroup: Ref<VcsListItemWithLabel | undefined> =
286
339
  ref(undefined);
287
- const editingItem: Ref<{
288
- id: string;
289
- title: string;
290
- icon: string;
291
- moduleUrl: string;
292
- }> = ref({ id: '', title: '', icon: '', moduleUrl: '' });
293
- const selectCloudItem: Ref<{
294
- id: string;
295
- title: string;
296
- icon: string;
297
- moduleUrl: string;
298
- }> = ref({ id: '', title: '', icon: '', moduleUrl: '' });
340
+ const editingItem: Ref<ModuleItem> = ref({
341
+ id: '',
342
+ title: '',
343
+ icon: '',
344
+ moduleUrl: '',
345
+ description: '',
346
+ });
347
+ const selectCloudItem: Ref<ModuleItem> = ref({
348
+ id: '',
349
+ title: '',
350
+ icon: '',
351
+ moduleUrl: '',
352
+ description: '',
353
+ });
354
+
355
+ let selectedGroupItem: Module<ModuleType> = {
356
+ title: '',
357
+ icon: '',
358
+ type: 'group',
359
+ description: '',
360
+ cards: [],
361
+ };
362
+
299
363
  const selectCloudItemDialogVisible: Ref<boolean> = ref(false);
300
364
  const editingItemDialogVisible: Ref<boolean> = ref(false);
301
365
  const groupItemDialogVisible: Ref<boolean> = ref(false);
@@ -326,6 +390,36 @@
326
390
  });
327
391
  const headerActions = reactive<VcsAction[]>([]);
328
392
 
393
+ function removeIdAndActions(
394
+ item: VcsListItemWithLabel,
395
+ ): Module<ModuleType> {
396
+ if (item.type === 'url') {
397
+ const { actions, id, name, ...configItem } = item;
398
+ return {
399
+ ...configItem,
400
+ moduleUrl: item.moduleUrl || '',
401
+ } as Module<'url'>;
402
+ } else {
403
+ const updatedCards =
404
+ item.cards?.map((card) => {
405
+ const { actions, id, name, ...configItem } = card;
406
+ return {
407
+ ...configItem,
408
+ } as Module<'url'>;
409
+ }) || [];
410
+ const { actions, id, name, ...configItem } = item;
411
+ return {
412
+ ...configItem,
413
+ ...(updatedCards.length ? { cards: updatedCards } : {}),
414
+ } as Module<'group'>;
415
+ }
416
+ }
417
+
418
+ function removeIdAndActionsFromArray(
419
+ items: VcsListItemWithLabel[],
420
+ ): Module<ModuleType>[] {
421
+ return items.map(removeIdAndActions);
422
+ }
329
423
  function createListItem(
330
424
  moduleInfo: Module<ModuleType>,
331
425
  index: number,
@@ -336,6 +430,7 @@
336
430
  title: moduleInfo.title,
337
431
  icon: moduleInfo.icon,
338
432
  type: moduleInfo.type,
433
+ description: moduleInfo.description,
339
434
  actions: [],
340
435
  };
341
436
  if (moduleInfo.type === 'url') {
@@ -359,6 +454,7 @@
359
454
  title: item.title,
360
455
  icon: item.icon,
361
456
  moduleUrl: item.moduleUrl!,
457
+ description: item.description,
362
458
  };
363
459
  }
364
460
  } else {
@@ -372,6 +468,7 @@
372
468
  title: item.title,
373
469
  icon: item.icon,
374
470
  moduleUrl: item.moduleUrl!,
471
+ description: item.description,
375
472
  };
376
473
  }
377
474
  }
@@ -391,6 +488,15 @@
391
488
  );
392
489
  if (item) {
393
490
  currentGroup.value = item;
491
+ groupItemDialogVisible.value = true;
492
+ const [firstItem] = removeIdAndActionsFromArray([
493
+ currentGroup.value,
494
+ ]) as Module<'group'>[];
495
+ if (firstItem.cards.length === 0) {
496
+ firstItem.cards = [];
497
+ }
498
+ selectedGroupItem = structuredClone(firstItem);
499
+
394
500
  headerActions.splice(2, 1);
395
501
  if (headerActions.length > 1) {
396
502
  headerActions[1].icon = '$vcsPlus';
@@ -426,6 +532,7 @@
426
532
 
427
533
  headerActions.push({
428
534
  name: 'moduleSelector.configEditor.addFromCloud',
535
+ title: 'moduleSelector.configEditor.TooltipAddCloudModule',
429
536
  icon: '$vcsImport',
430
537
  callback(): void {
431
538
  selectCloudItem.value = {
@@ -433,36 +540,12 @@
433
540
  title: '',
434
541
  icon: '',
435
542
  moduleUrl: '',
543
+ description: '',
436
544
  };
437
545
  selectCloudItemDialogVisible.value = true;
438
546
  },
439
547
  });
440
548
 
441
- function removeIdAndActions(
442
- item: VcsListItemWithLabel,
443
- ): Module<ModuleType> {
444
- if (item.type === 'url') {
445
- const { actions, id, name, ...configItem } = item;
446
- return {
447
- ...configItem,
448
- moduleUrl: item.moduleUrl || '',
449
- } as Module<'url'>;
450
- } else {
451
- const updatedCards =
452
- item.cards?.map((card) => {
453
- const { actions, id, name, ...configItem } = card;
454
- return {
455
- ...configItem,
456
- } as Module<'url'>;
457
- }) || [];
458
- const { actions, id, name, ...configItem } = item;
459
- return {
460
- ...configItem,
461
- ...(updatedCards.length ? { cards: updatedCards } : {}),
462
- } as Module<'group'>;
463
- }
464
- }
465
-
466
549
  const headerGroupAction = {
467
550
  name: 'moduleSelector.configEditor.addGroup',
468
551
  callback(): void {
@@ -470,6 +553,7 @@
470
553
  type: 'group',
471
554
  title: '',
472
555
  icon: '',
556
+ description: '',
473
557
  cards: [],
474
558
  };
475
559
 
@@ -482,6 +566,7 @@
482
566
  );
483
567
 
484
568
  currentGroup.value = listItemArray.value[indexItem - 1];
569
+ groupItemDialogVisible.value = true;
485
570
 
486
571
  headerActions.splice(2, 1);
487
572
  if (headerActions.length > 1) {
@@ -491,13 +576,6 @@
491
576
  }
492
577
  },
493
578
  };
494
-
495
- function removeIdAndActionsFromArray(
496
- items: VcsListItemWithLabel[],
497
- ): Module<ModuleType>[] {
498
- return items.map(removeIdAndActions);
499
- }
500
-
501
579
  if (localConfig.value?.modules) {
502
580
  listItemArray.value = localConfig.value.modules.map(createListItem);
503
581
  }
@@ -511,6 +589,7 @@
511
589
  title: '',
512
590
  icon: '',
513
591
  moduleUrl: '',
592
+ description: '',
514
593
  };
515
594
  editingItemDialogVisible.value = true;
516
595
  },
@@ -528,11 +607,27 @@
528
607
  });
529
608
 
530
609
  const apply = (): void => {
531
- props.setConfig({
532
- ...localConfig.value,
610
+ const position = toRaw(localConfig.value?.position) as Record<
611
+ string,
612
+ unknown
613
+ >;
614
+ const isPositionDefined = Object.values(position).some(
615
+ (value) => value !== undefined,
616
+ );
617
+
618
+ const config = {
619
+ ...toRaw(localConfig.value),
533
620
  modules: removeIdAndActionsFromArray(listItemArray.value),
534
- basisModule: basisModule.value,
535
- });
621
+ basisModule: toRaw(basisModule.value),
622
+ };
623
+
624
+ if (isPositionDefined) {
625
+ config.position = position;
626
+ } else {
627
+ delete config.position;
628
+ }
629
+
630
+ props.setConfig(config);
536
631
  };
537
632
 
538
633
  const updateItem = (): void => {
@@ -605,6 +700,7 @@
605
700
  title: '',
606
701
  icon: '',
607
702
  moduleUrl: '',
703
+ description: '',
608
704
  };
609
705
  editingItemDialogVisible.value = false;
610
706
  };
@@ -619,6 +715,7 @@
619
715
  icon: selectCloudItem.value.icon,
620
716
  moduleUrl: selectCloudItem.value.moduleUrl,
621
717
  type: 'url',
718
+ description: selectCloudItem.value.description,
622
719
  },
623
720
  listItemArray.value.length,
624
721
  ),
@@ -651,11 +748,14 @@
651
748
  title: '',
652
749
  icon: '',
653
750
  moduleUrl: '',
751
+ description: '',
654
752
  };
655
753
  selectCloudItemDialogVisible.value = false;
656
754
  };
657
755
 
658
756
  const returnLevel = (): void => {
757
+ groupItemDialogVisible.value = false;
758
+
659
759
  currentGroup.value = undefined;
660
760
  if (headerActions.length > 1) {
661
761
  delete headerActions[1].icon;
@@ -664,34 +764,45 @@
664
764
  headerActions.push(headerGroupAction);
665
765
  };
666
766
 
667
- const breadcrumbItems = ref([
668
- {
669
- title: app.vueI18n.t(
670
- 'moduleSelector.configEditor.breadcrumbs.overview',
671
- ),
672
- disabled: false,
673
- href: '#',
674
- },
675
- {
676
- title: app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group'),
677
- disabled: true,
678
- href: '#',
679
- },
680
- ]);
681
- watch(currentGroup, (currentG) => {
682
- if (currentG && currentG.title) {
683
- breadcrumbItems.value[1].title = `${app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group')}: ${currentG.title}`;
684
- currentG.name = currentG.title;
767
+ const isRequired = (v: string): boolean | string => {
768
+ return v && v.trim() !== ''
769
+ ? true
770
+ : 'moduleSelector.configEditor.error';
771
+ };
772
+
773
+ const isFormValid = ref();
774
+
775
+ const cancelCurrentGroup = (): void => {
776
+ const groupIndex = listItemArray.value.findIndex(
777
+ (item) => item.id === currentGroup.value!.id,
778
+ );
779
+ if (selectedGroupItem.title !== '') {
780
+ const newGroupItem = createListItem(selectedGroupItem, groupIndex);
781
+ listItemArray.value.splice(groupIndex, 1, newGroupItem);
782
+ } else {
783
+ listItemArray.value.splice(groupIndex, 1);
685
784
  }
686
- });
785
+
786
+ groupItemDialogVisible.value = false;
787
+ currentGroup.value = undefined;
788
+ if (headerActions.length > 1) {
789
+ delete headerActions[1].icon;
790
+ delete headerActions[1].title;
791
+ }
792
+ headerActions.push(headerGroupAction);
793
+ };
794
+
687
795
  return {
796
+ isFormValid,
688
797
  editingItem,
798
+ selectedGroupItem,
799
+ groupItemDialogVisible,
800
+ cancelCurrentGroup,
689
801
  selectCloudItem,
690
802
  editingItemDialogVisible,
691
803
  selectCloudItemDialogVisible,
692
804
  localConfig,
693
805
  listItemArray,
694
- breadcrumbItems,
695
806
  currentGroup,
696
807
  apply,
697
808
  returnLevel,
@@ -702,37 +813,31 @@
702
813
  basisModule,
703
814
  basisModuleExists,
704
815
  headerActions,
705
- move({
816
+ isRequired,
817
+ moveItem({
706
818
  item,
707
819
  targetIndex,
708
820
  }: {
709
821
  item: VcsListItemWithLabel;
710
822
  targetIndex: number;
711
823
  }): void {
712
- if (listItemArray.value && currentGroup.value === undefined) {
713
- let target = targetIndex;
714
- target = target >= 0 ? target : 0;
715
- target =
716
- target < listItemArray.value?.length
717
- ? target
718
- : listItemArray.value.length - 1;
719
- const from = listItemArray.value?.indexOf(item);
720
- if (from !== target) {
721
- listItemArray.value?.splice(from, 1);
722
- listItemArray.value?.splice(target, 0, item);
723
- }
724
- } else if ((currentGroup.value?.cards?.length ?? 0) > 1) {
725
- let target = targetIndex;
726
- target = target >= 0 ? target : 0;
727
- target =
728
- target < currentGroup.value!.cards!.length
729
- ? target
730
- : currentGroup.value!.cards!.length - 1;
731
- const from = currentGroup.value!.cards!.indexOf(item);
732
- if (from && from !== target) {
733
- currentGroup.value!.cards!.splice(from, 1);
734
- currentGroup.value!.cards!.splice(target, 0, item);
735
- }
824
+ const from = listItemArray.value?.indexOf(item);
825
+ if (from !== targetIndex) {
826
+ listItemArray.value?.splice(from, 1);
827
+ listItemArray.value?.splice(targetIndex, 0, item);
828
+ }
829
+ },
830
+ moveCard({
831
+ item,
832
+ targetIndex,
833
+ }: {
834
+ item: VcsListItemWithLabel;
835
+ targetIndex: number;
836
+ }): void {
837
+ const from = currentGroup.value!.cards!.indexOf(item);
838
+ if (from !== targetIndex) {
839
+ currentGroup.value?.cards?.splice(from, 1);
840
+ currentGroup.value?.cards?.splice(targetIndex, 0, item);
736
841
  }
737
842
  },
738
843
  };
@@ -740,8 +845,4 @@
740
845
  });
741
846
  </script>
742
847
 
743
- <style scoped>
744
- .v-breadcrumbs {
745
- padding: 16px 0 4px 0;
746
- }
747
- </style>
848
+ <style scoped></style>