@vcmap/module-selector 2.0.3 → 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>
@@ -91,73 +91,116 @@
91
91
  />
92
92
  </v-col>
93
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>
94
107
  </v-container>
95
108
  </VcsFormSection>
96
109
  </v-container>
97
- <v-container v-else class="py-0 px-1">
98
- <v-breadcrumbs :items="breadcrumbItems" divider="/">
99
- <template #item="{ item }">
100
- <v-breadcrumbs-item
101
- :key="item.title"
102
- :disabled="item.disabled"
103
- :href="item.href"
104
- @click="item.disabled ? null : returnLevel()"
105
- >
106
- {{ item.title }}
107
- </v-breadcrumbs-item>
108
- </template>
109
- </v-breadcrumbs>
110
-
111
- <v-row no-gutters>
112
- <v-col cols="6">
113
- <VcsLabel required html-for="groupModuleName">
114
- {{ $st('moduleSelector.configEditor.groupName') }}
115
- </VcsLabel>
116
- </v-col>
117
- <v-col>
118
- <VcsTextField
119
- id="groupModuleName"
120
- placeholder="Module Name"
121
- v-model="currentGroup!.title"
122
- :rules="[(v: string) => !!v || 'moduleSelector.configEditor.error']"
123
- />
124
- </v-col>
125
- </v-row>
126
- <v-row no-gutters>
127
- <v-col cols="6">
128
- <VcsLabel required html-for="groupModuleIcon">
129
- {{ $st('moduleSelector.configEditor.moduleIcon') }}
130
- </VcsLabel>
131
- </v-col>
132
- <v-col>
133
- <VcsTextField
134
- id="groupModuleIcon"
135
- placeholder="Module Icon"
136
- v-model="currentGroup!.icon"
137
- :rules="[
138
- (v: string) => !!v || 'moduleSelector.configEditor.editorError',
139
- ]"
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"
140
175
  />
141
- </v-col>
142
- </v-row>
143
- </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
+
144
193
  <VcsFormSection
145
194
  heading="moduleSelector.configEditor.heading"
146
195
  :start-open="true"
147
196
  :header-actions="headerActions"
148
197
  >
149
198
  <VcsList
150
- v-if="currentGroup === undefined"
151
199
  :items="listItemArray"
152
200
  :draggable="true"
153
- @item-moved="move"
154
- />
155
- <VcsList
156
- v-else
157
- :items="currentGroup.cards"
158
- :draggable="true"
159
- @item-moved="move"
201
+ @item-moved="moveItem"
160
202
  />
203
+
161
204
  <v-dialog
162
205
  v-model="editingItemDialogVisible"
163
206
  width="400"
@@ -212,12 +255,12 @@
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,
@@ -226,12 +269,12 @@
226
269
  watch,
227
270
  } from 'vue';
228
271
  import {
229
- VBreadcrumbs,
230
- VBreadcrumbsItem,
231
272
  VCol,
232
273
  VContainer,
233
274
  VDialog,
234
275
  VRow,
276
+ VSheet,
277
+ VForm,
235
278
  } from 'vuetify/components';
236
279
  import ModuleEditor from './ModuleEditor.vue';
237
280
  import { Module, ModuleSelectorConfig, ModuleType } from '../index';
@@ -245,28 +288,38 @@
245
288
  icon: string;
246
289
  type: string;
247
290
  moduleUrl?: string;
291
+ description?: string;
248
292
  cards?: VcsListItemWithLabel[];
249
293
  }
294
+ interface ModuleItem {
295
+ id: string;
296
+ title: string;
297
+ icon: string;
298
+ moduleUrl: string;
299
+ description?: string;
300
+ }
250
301
 
251
302
  export const windowIdConfigEditor = 'configEditor_window_id';
252
303
  export default defineComponent({
253
304
  name: 'ModuleSelectorConfigEditor',
254
305
  components: {
306
+ VForm,
307
+ VcsFormButton,
255
308
  VcsCheckbox,
256
309
  VDialog,
257
310
  VcsList,
258
311
  VcsFormSection,
259
312
  VRow,
313
+ VSheet,
260
314
  VcsLabel,
261
315
  AbstractConfigEditor,
262
316
  VcsTextField,
263
317
  VCol,
264
318
  VContainer,
265
319
  ModuleEditor,
266
- VBreadcrumbs,
267
- VBreadcrumbsItem,
268
320
  WindowPositionSettings,
269
321
  VcsModuleTable: CloudModuleSelector,
322
+ VcsTextArea,
270
323
  },
271
324
  props: {
272
325
  getConfig: {
@@ -279,24 +332,34 @@
279
332
  },
280
333
  },
281
334
  setup(props) {
282
- const app = inject('vcsApp') as VcsUiApp;
283
335
  const level = ref<number>(0);
284
336
  const localConfig = ref<ModuleSelectorConfig | undefined>(undefined);
285
337
  const listItemArray: Ref<VcsListItemWithLabel[]> = ref([]);
286
338
  const currentGroup: Ref<VcsListItemWithLabel | undefined> =
287
339
  ref(undefined);
288
- const editingItem: Ref<{
289
- id: string;
290
- title: string;
291
- icon: string;
292
- moduleUrl: string;
293
- }> = ref({ id: '', title: '', icon: '', moduleUrl: '' });
294
- const selectCloudItem: Ref<{
295
- id: string;
296
- title: string;
297
- icon: string;
298
- moduleUrl: string;
299
- }> = 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
+
300
363
  const selectCloudItemDialogVisible: Ref<boolean> = ref(false);
301
364
  const editingItemDialogVisible: Ref<boolean> = ref(false);
302
365
  const groupItemDialogVisible: Ref<boolean> = ref(false);
@@ -327,6 +390,36 @@
327
390
  });
328
391
  const headerActions = reactive<VcsAction[]>([]);
329
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
+ }
330
423
  function createListItem(
331
424
  moduleInfo: Module<ModuleType>,
332
425
  index: number,
@@ -337,6 +430,7 @@
337
430
  title: moduleInfo.title,
338
431
  icon: moduleInfo.icon,
339
432
  type: moduleInfo.type,
433
+ description: moduleInfo.description,
340
434
  actions: [],
341
435
  };
342
436
  if (moduleInfo.type === 'url') {
@@ -360,6 +454,7 @@
360
454
  title: item.title,
361
455
  icon: item.icon,
362
456
  moduleUrl: item.moduleUrl!,
457
+ description: item.description,
363
458
  };
364
459
  }
365
460
  } else {
@@ -373,6 +468,7 @@
373
468
  title: item.title,
374
469
  icon: item.icon,
375
470
  moduleUrl: item.moduleUrl!,
471
+ description: item.description,
376
472
  };
377
473
  }
378
474
  }
@@ -392,6 +488,15 @@
392
488
  );
393
489
  if (item) {
394
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
+
395
500
  headerActions.splice(2, 1);
396
501
  if (headerActions.length > 1) {
397
502
  headerActions[1].icon = '$vcsPlus';
@@ -427,6 +532,7 @@
427
532
 
428
533
  headerActions.push({
429
534
  name: 'moduleSelector.configEditor.addFromCloud',
535
+ title: 'moduleSelector.configEditor.TooltipAddCloudModule',
430
536
  icon: '$vcsImport',
431
537
  callback(): void {
432
538
  selectCloudItem.value = {
@@ -434,36 +540,12 @@
434
540
  title: '',
435
541
  icon: '',
436
542
  moduleUrl: '',
543
+ description: '',
437
544
  };
438
545
  selectCloudItemDialogVisible.value = true;
439
546
  },
440
547
  });
441
548
 
442
- function removeIdAndActions(
443
- item: VcsListItemWithLabel,
444
- ): Module<ModuleType> {
445
- if (item.type === 'url') {
446
- const { actions, id, name, ...configItem } = item;
447
- return {
448
- ...configItem,
449
- moduleUrl: item.moduleUrl || '',
450
- } as Module<'url'>;
451
- } else {
452
- const updatedCards =
453
- item.cards?.map((card) => {
454
- const { actions, id, name, ...configItem } = card;
455
- return {
456
- ...configItem,
457
- } as Module<'url'>;
458
- }) || [];
459
- const { actions, id, name, ...configItem } = item;
460
- return {
461
- ...configItem,
462
- ...(updatedCards.length ? { cards: updatedCards } : {}),
463
- } as Module<'group'>;
464
- }
465
- }
466
-
467
549
  const headerGroupAction = {
468
550
  name: 'moduleSelector.configEditor.addGroup',
469
551
  callback(): void {
@@ -471,6 +553,7 @@
471
553
  type: 'group',
472
554
  title: '',
473
555
  icon: '',
556
+ description: '',
474
557
  cards: [],
475
558
  };
476
559
 
@@ -483,6 +566,7 @@
483
566
  );
484
567
 
485
568
  currentGroup.value = listItemArray.value[indexItem - 1];
569
+ groupItemDialogVisible.value = true;
486
570
 
487
571
  headerActions.splice(2, 1);
488
572
  if (headerActions.length > 1) {
@@ -492,13 +576,6 @@
492
576
  }
493
577
  },
494
578
  };
495
-
496
- function removeIdAndActionsFromArray(
497
- items: VcsListItemWithLabel[],
498
- ): Module<ModuleType>[] {
499
- return items.map(removeIdAndActions);
500
- }
501
-
502
579
  if (localConfig.value?.modules) {
503
580
  listItemArray.value = localConfig.value.modules.map(createListItem);
504
581
  }
@@ -512,6 +589,7 @@
512
589
  title: '',
513
590
  icon: '',
514
591
  moduleUrl: '',
592
+ description: '',
515
593
  };
516
594
  editingItemDialogVisible.value = true;
517
595
  },
@@ -622,6 +700,7 @@
622
700
  title: '',
623
701
  icon: '',
624
702
  moduleUrl: '',
703
+ description: '',
625
704
  };
626
705
  editingItemDialogVisible.value = false;
627
706
  };
@@ -636,6 +715,7 @@
636
715
  icon: selectCloudItem.value.icon,
637
716
  moduleUrl: selectCloudItem.value.moduleUrl,
638
717
  type: 'url',
718
+ description: selectCloudItem.value.description,
639
719
  },
640
720
  listItemArray.value.length,
641
721
  ),
@@ -668,11 +748,14 @@
668
748
  title: '',
669
749
  icon: '',
670
750
  moduleUrl: '',
751
+ description: '',
671
752
  };
672
753
  selectCloudItemDialogVisible.value = false;
673
754
  };
674
755
 
675
756
  const returnLevel = (): void => {
757
+ groupItemDialogVisible.value = false;
758
+
676
759
  currentGroup.value = undefined;
677
760
  if (headerActions.length > 1) {
678
761
  delete headerActions[1].icon;
@@ -681,34 +764,45 @@
681
764
  headerActions.push(headerGroupAction);
682
765
  };
683
766
 
684
- const breadcrumbItems = ref([
685
- {
686
- title: app.vueI18n.t(
687
- 'moduleSelector.configEditor.breadcrumbs.overview',
688
- ),
689
- disabled: false,
690
- href: '#',
691
- },
692
- {
693
- title: app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group'),
694
- disabled: true,
695
- href: '#',
696
- },
697
- ]);
698
- watch(currentGroup, (currentG) => {
699
- if (currentG && currentG.title) {
700
- breadcrumbItems.value[1].title = `${app.vueI18n.t('moduleSelector.configEditor.breadcrumbs.group')}: ${currentG.title}`;
701
- 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);
702
784
  }
703
- });
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
+
704
795
  return {
796
+ isFormValid,
705
797
  editingItem,
798
+ selectedGroupItem,
799
+ groupItemDialogVisible,
800
+ cancelCurrentGroup,
706
801
  selectCloudItem,
707
802
  editingItemDialogVisible,
708
803
  selectCloudItemDialogVisible,
709
804
  localConfig,
710
805
  listItemArray,
711
- breadcrumbItems,
712
806
  currentGroup,
713
807
  apply,
714
808
  returnLevel,
@@ -719,37 +813,31 @@
719
813
  basisModule,
720
814
  basisModuleExists,
721
815
  headerActions,
722
- move({
816
+ isRequired,
817
+ moveItem({
723
818
  item,
724
819
  targetIndex,
725
820
  }: {
726
821
  item: VcsListItemWithLabel;
727
822
  targetIndex: number;
728
823
  }): void {
729
- if (listItemArray.value && currentGroup.value === undefined) {
730
- let target = targetIndex;
731
- target = target >= 0 ? target : 0;
732
- target =
733
- target < listItemArray.value?.length
734
- ? target
735
- : listItemArray.value.length - 1;
736
- const from = listItemArray.value?.indexOf(item);
737
- if (from !== target) {
738
- listItemArray.value?.splice(from, 1);
739
- listItemArray.value?.splice(target, 0, item);
740
- }
741
- } else if ((currentGroup.value?.cards?.length ?? 0) > 1) {
742
- let target = targetIndex;
743
- target = target >= 0 ? target : 0;
744
- target =
745
- target < currentGroup.value!.cards!.length
746
- ? target
747
- : currentGroup.value!.cards!.length - 1;
748
- const from = currentGroup.value!.cards!.indexOf(item);
749
- if (from && from !== target) {
750
- currentGroup.value!.cards!.splice(from, 1);
751
- currentGroup.value!.cards!.splice(target, 0, item);
752
- }
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);
753
841
  }
754
842
  },
755
843
  };
@@ -757,8 +845,4 @@
757
845
  });
758
846
  </script>
759
847
 
760
- <style scoped>
761
- .v-breadcrumbs {
762
- padding: 16px 0 4px 0;
763
- }
764
- </style>
848
+ <style scoped></style>
@@ -8,6 +8,7 @@ export default (): ModuleSelectorConfig => ({
8
8
  left: '33%',
9
9
  right: '33%',
10
10
  top: '10%',
11
+ maxHeight: '80%',
11
12
  },
12
13
  basisModule: undefined,
13
14
  modules: [],