@dative-gpi/foundation-shared-components 1.0.36 → 1.0.37-report-v1

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 (271) hide show
  1. package/components/FSBreadcrumbs.vue +21 -12
  2. package/components/FSButton.vue +10 -10
  3. package/components/FSCalendar.vue +52 -14
  4. package/components/FSCalendarTwin.vue +96 -40
  5. package/components/FSCard.vue +28 -7
  6. package/components/FSCardPlaceholder.vue +8 -5
  7. package/components/FSChip.vue +12 -2
  8. package/components/FSClickable.vue +12 -13
  9. package/components/FSClock.vue +16 -7
  10. package/components/FSColorIcon.vue +23 -5
  11. package/components/FSDialog.vue +2 -1
  12. package/components/FSDialogContent.vue +12 -11
  13. package/components/FSDialogForm.vue +22 -2
  14. package/components/FSDialogFormBody.vue +47 -28
  15. package/components/FSDialogMenu.vue +17 -8
  16. package/components/FSDialogMultiFormBody.vue +77 -54
  17. package/components/FSDialogRemove.vue +8 -8
  18. package/components/FSDialogSubmit.vue +17 -8
  19. package/components/FSEditImage.vue +1 -1
  20. package/components/FSEditImageUI.vue +20 -10
  21. package/components/FSFadeOut.vue +53 -21
  22. package/components/FSForm.vue +10 -8
  23. package/components/FSGrid.vue +1 -1
  24. package/components/FSIcon.vue +2 -1
  25. package/components/FSIconCard.vue +47 -7
  26. package/components/FSImage.vue +12 -4
  27. package/components/FSImageUI.vue +8 -15
  28. package/components/FSInstantPicker.vue +266 -0
  29. package/components/FSLink.vue +25 -9
  30. package/components/FSLoader.vue +28 -11
  31. package/components/FSOptionGroup.vue +51 -3
  32. package/components/FSPlayButtons.vue +72 -0
  33. package/components/FSProgressBar.vue +94 -0
  34. package/components/FSRouterLink.vue +42 -0
  35. package/components/FSSlideGroup.vue +19 -5
  36. package/components/FSSpan.vue +17 -7
  37. package/components/FSSwitch.vue +57 -27
  38. package/components/FSTab.vue +15 -13
  39. package/components/FSTabs.vue +32 -7
  40. package/components/FSTag.vue +14 -3
  41. package/components/FSTagGroup.vue +1 -1
  42. package/components/FSText.vue +11 -7
  43. package/components/FSWindow.vue +128 -4
  44. package/components/FSWrapGroup.vue +13 -1
  45. package/components/agenda/FSAgenda.vue +223 -0
  46. package/components/agenda/FSAgendaDialogCalendar.vue +76 -0
  47. package/components/agenda/FSAgendaHeader.vue +215 -0
  48. package/components/agenda/FSAgendaHorizontalEvent.vue +174 -0
  49. package/components/agenda/FSAgendaHorizontalTimeLineMarker.vue +46 -0
  50. package/components/agenda/FSAgendaHoursCol.vue +103 -0
  51. package/components/agenda/FSAgendaHoursRow.vue +164 -0
  52. package/components/agenda/FSAgendaVerticalEvent.vue +160 -0
  53. package/components/agenda/FSAgendaVerticalTimeLineMarker.vue +46 -0
  54. package/components/agenda/FSDayAgenda.vue +199 -0
  55. package/components/agenda/FSMonthAgenda.vue +252 -0
  56. package/components/agenda/FSSelectAgendaMode.vue +54 -0
  57. package/components/agenda/FSWeekAgenda.vue +323 -0
  58. package/components/autocompletes/FSAutoCompleteAddress.vue +22 -20
  59. package/components/autocompletes/FSAutocompleteLanguage.vue +7 -1
  60. package/components/autocompletes/FSAutocompleteTimeZone.vue +7 -1
  61. package/components/buttons/FSButtonAdd.vue +1 -1
  62. package/components/buttons/FSButtonAddLabel.vue +1 -1
  63. package/components/buttons/FSButtonCancel.vue +1 -1
  64. package/components/buttons/FSButtonCancelLabel.vue +1 -1
  65. package/components/buttons/FSButtonCopy.vue +1 -1
  66. package/components/buttons/FSButtonCopyLabel.vue +1 -1
  67. package/components/buttons/FSButtonDragIcon.vue +27 -0
  68. package/components/buttons/FSButtonDuplicate.vue +1 -1
  69. package/components/buttons/FSButtonDuplicateLabel.vue +1 -1
  70. package/components/buttons/FSButtonEdit.vue +1 -1
  71. package/components/buttons/FSButtonEditLabel.vue +1 -1
  72. package/components/buttons/FSButtonFile.vue +1 -1
  73. package/components/buttons/FSButtonFileLabel.vue +1 -1
  74. package/components/buttons/FSButtonNext.vue +1 -1
  75. package/components/buttons/FSButtonNextLabel.vue +1 -1
  76. package/components/buttons/FSButtonPrevious.vue +1 -1
  77. package/components/buttons/FSButtonPreviousLabel.vue +1 -1
  78. package/components/buttons/FSButtonRedo.vue +1 -1
  79. package/components/buttons/FSButtonRedoLabel.vue +1 -1
  80. package/components/buttons/FSButtonRemove.vue +1 -1
  81. package/components/buttons/FSButtonRemoveLabel.vue +1 -1
  82. package/components/buttons/FSButtonSave.vue +1 -1
  83. package/components/buttons/FSButtonSaveLabel.vue +1 -1
  84. package/components/buttons/FSButtonSearch.vue +1 -1
  85. package/components/buttons/FSButtonSearchLabel.vue +1 -1
  86. package/components/buttons/FSButtonUndo.vue +1 -1
  87. package/components/buttons/FSButtonUndoLabel.vue +1 -1
  88. package/components/buttons/FSButtonUpdate.vue +1 -1
  89. package/components/buttons/FSButtonUpdateLabel.vue +1 -1
  90. package/components/buttons/FSButtonValidate.vue +1 -1
  91. package/components/buttons/FSButtonValidateLabel.vue +1 -1
  92. package/components/calendar/FSSimpleCalendar.vue +145 -0
  93. package/components/calendar/FSSimpleCalendarHeader.vue +60 -0
  94. package/components/calendar/FSSimpleMonthSelector.vue +138 -0
  95. package/components/deviceOrganisations/FSConnectivity.vue +11 -1
  96. package/components/deviceOrganisations/FSConnectivityCard.vue +19 -47
  97. package/components/deviceOrganisations/FSStatus.vue +11 -1
  98. package/components/deviceOrganisations/FSStatusCard.vue +35 -61
  99. package/components/deviceOrganisations/FSStatusesCarousel.vue +1 -0
  100. package/components/deviceOrganisations/FSStatusesRow.vue +9 -3
  101. package/components/deviceOrganisations/FSWorstAlert.vue +30 -37
  102. package/components/deviceOrganisations/FSWorstAlertCard.vue +36 -85
  103. package/components/fields/FSAutocompleteField.vue +445 -463
  104. package/components/fields/FSAutocompleteTag.vue +1 -1
  105. package/components/fields/FSBaseField.vue +44 -27
  106. package/components/fields/FSColorField.vue +42 -39
  107. package/components/fields/FSCommentField.vue +105 -0
  108. package/components/fields/FSDateField.vue +3 -2
  109. package/components/fields/FSDateRangeField.vue +3 -2
  110. package/components/fields/FSDateTimeField.vue +4 -3
  111. package/components/fields/FSDateTimeRangeField.vue +8 -6
  112. package/components/fields/FSEntityFieldUI.vue +271 -0
  113. package/components/fields/FSGradientField.vue +27 -33
  114. package/components/fields/FSIconField.vue +0 -1
  115. package/components/fields/FSMagicConfigField.vue +10 -3
  116. package/components/fields/FSMagicField.vue +9 -4
  117. package/components/fields/FSNumberField.vue +6 -1
  118. package/components/fields/FSRichTextField.vue +102 -52
  119. package/components/fields/FSSearchField.vue +9 -115
  120. package/components/fields/FSSelectField.vue +477 -252
  121. package/components/fields/FSTagField.vue +1 -1
  122. package/components/fields/FSTermField.vue +42 -17
  123. package/components/fields/FSTextArea.vue +26 -7
  124. package/components/fields/FSTextField.vue +8 -3
  125. package/components/fields/FSTimeRangeField.vue +304 -0
  126. package/components/fields/FSTimeStepField.vue +3 -3
  127. package/components/fields/FSTranslateField.vue +4 -3
  128. package/components/fields/FSTranslateRichTextField.vue +32 -12
  129. package/components/fields/FSTranslateTextArea.vue +233 -0
  130. package/components/fields/periodicField/FSPeriodicDailyField.vue +2 -2
  131. package/components/fields/periodicField/FSPeriodicField.vue +8 -8
  132. package/components/fields/periodicField/FSPeriodicMonthlyField.vue +8 -8
  133. package/components/fields/periodicField/FSPeriodicWeeklyField.vue +23 -13
  134. package/components/fields/periodicField/FSPeriodicYearlyField.vue +6 -6
  135. package/components/lists/FSDataTableUI.vue +173 -103
  136. package/components/lists/FSDraggable.vue +2 -2
  137. package/components/lists/FSFilterButton.vue +7 -11
  138. package/components/lists/FSHeaderButton.vue +4 -4
  139. package/components/lists/FSHiddenButton.vue +3 -5
  140. package/components/lists/FSLoadDataTable.vue +10 -7
  141. package/components/lists/FSSimpleList.vue +234 -0
  142. package/components/lists/FSSimpleListItem.vue +132 -0
  143. package/components/map/FSMap.vue +83 -33
  144. package/components/map/FSMapFeatureGroup.vue +2 -2
  145. package/components/map/FSMapLayerButton.vue +3 -3
  146. package/components/map/FSMapMarker.vue +11 -7
  147. package/components/map/FSMapMarkerClusterGroup.vue +8 -3
  148. package/components/map/FSMapOverlay.vue +37 -20
  149. package/components/map/FSMapPolygon.vue +5 -5
  150. package/components/map/FSMapTileLayer.vue +2 -2
  151. package/components/map/keys.ts +3 -3
  152. package/components/selects/FSSelectAutoRefresh.vue +9 -9
  153. package/components/selects/FSSelectDashboardVariableType.vue +5 -4
  154. package/components/selects/FSSelectDateSetting.vue +3 -2
  155. package/components/selects/FSSelectDays.vue +9 -9
  156. package/components/selects/FSSelectListMode.vue +51 -0
  157. package/components/selects/FSSelectMonths.vue +14 -14
  158. package/components/selects/chartSelectors/FSAggregationSelector.vue +52 -0
  159. package/components/selects/chartSelectors/FSAxisTypeSelector.vue +49 -0
  160. package/components/selects/chartSelectors/FSDisplayAsSelector.vue +53 -0
  161. package/components/selects/chartSelectors/FSFilterTypeSelector.vue +54 -0
  162. package/components/selects/chartSelectors/FSHeatmapRuleSelector.vue +54 -0
  163. package/components/selects/chartSelectors/FSOperationOnSelector.vue +53 -0
  164. package/components/selects/chartSelectors/FSPlanningTypeSelector.vue +53 -0
  165. package/components/selects/chartSelectors/FSPlotPerSelector.vue +52 -0
  166. package/components/selects/chartSelectors/FSSelectEntityType.vue +59 -0
  167. package/components/selects/chartSelectors/FSSerieTypeSelector.vue +53 -0
  168. package/components/tiles/FSAlertTileUI.vue +90 -0
  169. package/components/tiles/FSChartTileUI.vue +111 -0
  170. package/components/tiles/FSCommentTileUI.vue +174 -0
  171. package/components/tiles/FSDeviceOrganisationTileUI.vue +6 -0
  172. package/components/tiles/FSGroupTileUI.vue +2 -2
  173. package/components/tiles/FSLoadTile.vue +2 -0
  174. package/components/tiles/FSLocationTileUI.vue +192 -0
  175. package/components/tiles/FSModelTileUI.vue +18 -0
  176. package/components/tiles/FSSimpleTileUI.vue +9 -4
  177. package/components/tiles/FSTile.vue +93 -74
  178. package/components/tiles/FSUserOrganisationTileUI.vue +1 -1
  179. package/components/toggleSets/FSToggleSetPosition.vue +2 -2
  180. package/components/views/FSBaseView.vue +64 -0
  181. package/components/views/FSEntityView.vue +12 -140
  182. package/components/views/FSSimpleView.vue +29 -0
  183. package/components/views/desktop/FSBaseDefaultDesktopView.vue +135 -0
  184. package/components/views/desktop/FSBaseDesktopView.vue +53 -0
  185. package/components/views/desktop/FSBaseEntityDesktopView.vue +209 -0
  186. package/components/views/mobile/FSBaseDefaultMobileView.vue +133 -0
  187. package/components/views/mobile/FSBaseEntityMobileView.vue +199 -0
  188. package/components/views/mobile/FSBaseMobileView.vue +53 -0
  189. package/composables/useBreakpoints.ts +39 -3
  190. package/composables/useColors.ts +3 -2
  191. package/composables/useMagicFieldProvider.ts +1 -0
  192. package/composables/useSlots.ts +2 -1
  193. package/models/agenda.ts +9 -0
  194. package/models/deviceAlerts.ts +1 -1
  195. package/models/deviceConnectivities.ts +1 -1
  196. package/models/index.ts +1 -0
  197. package/models/magicFields.ts +1 -0
  198. package/models/map.ts +2 -2
  199. package/models/rules.ts +8 -5
  200. package/models/tables.ts +5 -2
  201. package/models/variableNode.ts +8 -5
  202. package/package.json +5 -5
  203. package/styles/components/fs_agenda.scss +36 -0
  204. package/styles/components/fs_agenda_event.scss +41 -0
  205. package/styles/components/fs_agenda_hours_col.scss +4 -0
  206. package/styles/components/fs_agenda_hours_row.scss +5 -0
  207. package/styles/components/fs_agenda_time_line_marker.scss +19 -0
  208. package/styles/components/fs_autocomplete_field.scss +0 -13
  209. package/styles/components/fs_breadcrumbs.scss +18 -36
  210. package/styles/components/fs_button.scss +7 -5
  211. package/styles/components/fs_chip.scss +8 -6
  212. package/styles/components/fs_clickable.scss +18 -23
  213. package/styles/components/fs_clock.scss +0 -10
  214. package/styles/components/fs_color_field.scss +1 -4
  215. package/styles/components/fs_data_iterator_item.scss +12 -10
  216. package/styles/components/fs_data_table.scss +6 -9
  217. package/styles/components/fs_dialog.scss +7 -17
  218. package/styles/components/fs_dialog_menu.scss +4 -2
  219. package/styles/components/fs_edit_image.scss +8 -0
  220. package/styles/components/fs_fade_out.scss +10 -2
  221. package/styles/components/fs_filter_button.scss +1 -6
  222. package/styles/components/fs_gradient_field.scss +11 -11
  223. package/styles/components/fs_hidden_button.scss +2 -7
  224. package/styles/components/fs_image_card.scss +6 -4
  225. package/styles/components/fs_magic_config_field.scss +1 -2
  226. package/styles/components/fs_map.scss +11 -7
  227. package/styles/components/fs_meta_field.scss +3 -5
  228. package/styles/components/fs_option_group.scss +15 -5
  229. package/styles/components/fs_password_field.scss +4 -2
  230. package/styles/components/fs_progress_bar.scss +14 -0
  231. package/styles/components/fs_radio.scss +0 -11
  232. package/styles/components/fs_rich_text_field.scss +1 -9
  233. package/styles/components/fs_select_date_settings.scss +3 -0
  234. package/styles/components/fs_select_field.scss +4 -13
  235. package/styles/components/fs_slide_group.scss +7 -0
  236. package/styles/components/fs_span.scss +13 -4
  237. package/styles/components/fs_switch.scss +1 -0
  238. package/styles/components/fs_tabs.scss +19 -33
  239. package/styles/components/fs_tag.scss +8 -22
  240. package/styles/components/fs_text_area.scss +13 -17
  241. package/styles/components/fs_tile.scss +21 -15
  242. package/styles/components/fs_window.scss +7 -0
  243. package/styles/components/fs_wrap_group.scss +7 -0
  244. package/styles/components/index.scss +6 -4
  245. package/styles/globals/index.scss +1 -5
  246. package/styles/globals/overrides.scss +28 -61
  247. package/styles/globals/scrollbars.scss +10 -0
  248. package/styles/globals/text_fonts.scss +18 -66
  249. package/tools/alertsTools.ts +69 -0
  250. package/tools/chartsTools.ts +427 -0
  251. package/tools/index.ts +4 -0
  252. package/tools/reportsTools.ts +38 -0
  253. package/tools/timeRangeTools.ts +125 -0
  254. package/utils/filter.ts +18 -0
  255. package/utils/index.ts +2 -0
  256. package/utils/leafletMarkers.ts +4 -4
  257. package/utils/operations.ts +69 -0
  258. package/utils/sort.ts +2 -2
  259. package/utils/statuses.ts +1 -1
  260. package/utils/time.ts +17 -17
  261. package/components/fields/FSTimeSlotField.vue +0 -250
  262. package/components/views/FSEntityHeader.vue +0 -350
  263. package/components/views/FSListHeader.vue +0 -83
  264. package/components/views/FSListView.vue +0 -83
  265. package/components/views/FSSkeletonView.vue +0 -100
  266. package/styles/components/fs_icon_field.scss +0 -12
  267. package/styles/components/fs_tag_field.scss +0 -8
  268. package/styles/components/fs_time_field.scss +0 -12
  269. package/styles/components/fs_timeslot_field.scss +0 -12
  270. package/styles/globals/breakpoints.scss +0 -20
  271. package/styles/globals/fixes.scss +0 -5
@@ -40,14 +40,16 @@
40
40
  <FSMapMarkerClusterGroup
41
41
  v-if="$props.locations"
42
42
  :expected-layers="$props.locations.length"
43
+ :disableClusteringAtZoom="defaultZoom"
43
44
  @update:bounds="(bounds) => locationGroupBounds = bounds"
44
45
  >
45
46
  <FSMapMarker
46
47
  v-for="location in $props.locations"
47
48
  :selected="location.id === $props.selectedLocationId"
48
49
  :key="location.id"
49
- :color="location.color"
50
- :icon="location.icon"
50
+ :label="location.label"
51
+ :color="location.color ?? ColorEnum.Primary"
52
+ :icon="location.icon ?? 'mdi-map-marker'"
51
53
  :latlng="{lat: location.address.latitude, lng: location.address.longitude}"
52
54
  @click="$emit('update:selectedLocationId', location.id)"
53
55
  />
@@ -98,17 +100,18 @@
98
100
  </FSCol>
99
101
 
100
102
  <FSMapOverlay
101
- v-if="$slots['overlay']"
102
103
  :mode="$props.overlayMode"
103
104
  @update:mode="$emit('update:overlayMode', $event)"
104
105
  @update:height="(height) => overlayHeight = height"
105
106
  @update:width="(width) => overlayWidth = width"
106
107
  >
107
108
  <template
108
- #body
109
+ v-for="(_, name) in overlaySlots"
110
+ v-slot:[name]="slotData"
109
111
  >
110
112
  <slot
111
- name="overlay"
113
+ :name="'overlay-' + name"
114
+ v-bind="slotData"
112
115
  />
113
116
  </template>
114
117
  </FSMapOverlay>
@@ -116,15 +119,15 @@
116
119
  </template>
117
120
 
118
121
  <script lang="ts">
119
- import { computed, defineComponent, onMounted, type Ref, provide, type PropType, ref, type StyleValue, watch } from "vue";
122
+ import { computed, defineComponent, onMounted, type Ref, provide, type PropType, ref, type StyleValue, watch, onUnmounted, markRaw } from "vue";
120
123
 
121
124
  import type {} from "leaflet.markercluster";
122
- import { map as createMap, control, tileLayer, latLngBounds, latLng, type LatLng, LatLngBounds, type FitBoundsOptions } from "leaflet";
125
+ import { map as createMap, control, tileLayer, latLngBounds, latLng, type LatLng, type FitBoundsOptions, type ZoomPanOptions, type LatLngBounds } from "leaflet";
123
126
 
124
127
  import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
125
128
  import { type FSArea } from '@dative-gpi/foundation-shared-domain/models';
126
129
 
127
- import { useBreakpoints, useColors } from "../../composables";
130
+ import { useBreakpoints, useColors, useSlots } from "../../composables";
128
131
  import { ColorEnum, type FSLocation, type MapLayer } from "../../models";
129
132
 
130
133
  import FSMapLayerButton from "./FSMapLayerButton.vue";
@@ -229,8 +232,9 @@ export default defineComponent({
229
232
  emits: ["update:modelValue", "update:selectedLocationId", "update:selectedAreaId", 'update:overlayMode', 'update:currentLayer', "click:latlng"],
230
233
  setup(props, { emit }) {
231
234
  const { $tr } = useTranslationsProvider();
232
- const { getColors } = useColors();
233
235
  const { isExtraSmall } = useBreakpoints();
236
+ const { getColors } = useColors();
237
+ const { slots } = useSlots();
234
238
 
235
239
  const leafletContainer = ref<HTMLElement>();
236
240
  const locationGroupBounds = ref<LatLngBounds>();
@@ -240,16 +244,22 @@ export default defineComponent({
240
244
  const overlayHeight = ref<number>();
241
245
  const overlayWidth = ref<number>();
242
246
 
243
- const defaultZoom = 15;
244
-
245
247
  provide('map', map);
246
248
 
249
+ const defaultZoom = 16;
250
+ const mapResizeObserver = new ResizeObserver(() => {
251
+ if(!map.value) {
252
+ return;
253
+ }
254
+ map.value.invalidateSize();
255
+ });
256
+
247
257
  const mapLayers: MapLayer[] = [
248
258
  {
249
259
  name: "map",
250
- label: $tr("ui.map.layer.map", "Map"),
260
+ label: $tr("ui.map-layer.map", "Map"),
251
261
  image: new URL("../../assets/images/map/map.png", import.meta.url).href,
252
- layer: tileLayer(`http://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
262
+ layer: tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
253
263
  maxZoom: 22,
254
264
  subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
255
265
  attribution: '© Google Map Data'
@@ -257,9 +267,9 @@ export default defineComponent({
257
267
  },
258
268
  {
259
269
  name: "imagery",
260
- label: $tr("ui.map.layer.imagery", "Imagery"),
270
+ label: $tr("ui.map-layer.imagery", "Imagery"),
261
271
  image: new URL("../../assets/images/map/imagery.png", import.meta.url).href,
262
- layer: tileLayer(`http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
272
+ layer: tileLayer(`https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
263
273
  maxZoom: 22,
264
274
  subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
265
275
  attribution: '© Google Map Data'
@@ -306,20 +316,44 @@ export default defineComponent({
306
316
  return bounds as LatLngBounds;
307
317
  });
308
318
 
309
- const calculateTargetPosition = (target: L.LatLng) => {
319
+ const overlaySlots = computed(() => {
320
+ return Object.keys(slots).filter((slot) => slot.startsWith("overlay-")).reduce((acc, slot) => {
321
+ acc[slot.replace("overlay-", "")] = slots[slot];
322
+ return acc;
323
+ }, {} as Record<string, unknown>);
324
+ });
325
+
326
+ const calculateTargetPosition = (target: L.LatLng, zoom?: number) => {
310
327
  if(!map.value) {
311
328
  return target;
312
329
  }
313
- const zoom = map.value.getZoom();
330
+ zoom = zoom ?? map.value.getZoom();
314
331
  const targetPoint = map.value.project(target, zoom).subtract([leftOffset.value / 2, -bottomOffset.value / 2]);
315
332
  return map.value.unproject(targetPoint, zoom);
316
333
  }
317
334
 
318
- const panTo = (lat: number, lng: number) => {
335
+ const flyTo = (lat: number, lng: number, zoom: number = defaultZoom, options?: ZoomPanOptions) => {
319
336
  if(!map.value) {
320
337
  return;
321
338
  }
322
- map.value.panTo(calculateTargetPosition(latLng(lat, lng)));
339
+
340
+ if(isExtraSmall.value) {
341
+ // We wait for bottom offset to be calculated and stable to focus on the right position
342
+ let tries = 0;
343
+ let oldBottomOffset = bottomOffset.value;
344
+ const interval = setInterval(() => {
345
+ if(oldBottomOffset === bottomOffset.value || tries >= 30) {
346
+ clearInterval(interval);
347
+ map.value!.flyTo(calculateTargetPosition(latLng(lat, lng), zoom), zoom, options);
348
+ }
349
+ oldBottomOffset = bottomOffset.value;
350
+ tries++;
351
+ }, 20);
352
+
353
+ } else {
354
+ map.value.flyTo(calculateTargetPosition(latLng(lat, lng), zoom), zoom, options);
355
+ }
356
+
323
357
  }
324
358
 
325
359
  const setView = (lat: number, lng: number, zoom: number) => {
@@ -330,15 +364,24 @@ export default defineComponent({
330
364
  }
331
365
 
332
366
  const fitBounds = (bounds: LatLngBounds, options?: FitBoundsOptions) => {
333
- if(!map.value) {
334
- return;
335
- }
336
- const calculatedBounds = new LatLngBounds(
337
- calculateTargetPosition(bounds.getSouthWest()),
338
- calculateTargetPosition(bounds.getNorthEast())
339
- );
340
- map.value.fitBounds(calculatedBounds, options);
341
- }
367
+ if (!map.value) {return;}
368
+ const paddingTopLeft: [number, number] = [
369
+ leftOffset.value,
370
+ 0
371
+ ];
372
+
373
+ const paddingBottomRight: [number, number] = [
374
+ 0,
375
+ bottomOffset.value
376
+ ];
377
+ const paddingOptions = {
378
+ paddingTopLeft,
379
+ paddingBottomRight,
380
+ ...options,
381
+ };
382
+
383
+ map.value.fitBounds(bounds, paddingOptions);
384
+ };
342
385
 
343
386
  onMounted(() => {
344
387
  if(!leafletContainer.value) {
@@ -354,7 +397,7 @@ export default defineComponent({
354
397
  maxBoundsViscosity: 1.0
355
398
  };
356
399
 
357
- map.value = createMap(leafletContainer.value, mapOptions);
400
+ map.value = markRaw(createMap(leafletContainer.value, mapOptions));
358
401
  setView(props.center[0], props.center[1], defaultZoom);
359
402
 
360
403
  map.value.on('click', (e: L.LeafletMouseEvent) => {
@@ -362,7 +405,6 @@ export default defineComponent({
362
405
  });
363
406
 
364
407
  map.value.attributionControl.remove();
365
- // to display google attribution in bottom left corner
366
408
  control.attribution({ position: 'bottomleft' }).addTo(map.value);
367
409
 
368
410
  map.value.on('locationfound', (e: L.LocationEvent) => {
@@ -376,8 +418,14 @@ export default defineComponent({
376
418
  return;
377
419
  }
378
420
 
379
- panTo(e.latlng.lat, e.latlng.lng);
421
+ flyTo(e.latlng.lat, e.latlng.lng);
380
422
  });
423
+
424
+ mapResizeObserver.observe(leafletContainer.value);
425
+ });
426
+
427
+ onUnmounted(() => {
428
+ mapResizeObserver.disconnect();
381
429
  });
382
430
 
383
431
  watch (() => props.center, (center) => {
@@ -395,7 +443,7 @@ export default defineComponent({
395
443
  if(!selectedLocation) {
396
444
  return;
397
445
  }
398
- panTo(selectedLocation?.address.latitude, selectedLocation?.address.longitude);
446
+ flyTo(selectedLocation?.address.latitude, selectedLocation?.address.longitude, defaultZoom, { animate: false });
399
447
  }, { immediate: true });
400
448
 
401
449
  watch(() => props.selectedAreaId, (selectedAreaId) => {
@@ -419,6 +467,7 @@ export default defineComponent({
419
467
 
420
468
  return {
421
469
  ColorEnum,
470
+ defaultZoom,
422
471
  leafletContainer,
423
472
  locationGroupBounds,
424
473
  overlayHeight,
@@ -428,7 +477,8 @@ export default defineComponent({
428
477
  actualLayer,
429
478
  mapLayers,
430
479
  gpsPosition,
431
- style
480
+ style,
481
+ overlaySlots
432
482
  };
433
483
  }
434
484
  });
@@ -6,7 +6,7 @@
6
6
  import { inject, provide, ref, type Ref } from 'vue';
7
7
 
8
8
  import { type Map, FeatureGroup } from 'leaflet';
9
- import { INJECTION_FSMAP_MAP } from './keys';
9
+ import { MAP } from './keys';
10
10
 
11
11
  export default {
12
12
  name: 'FSMapFeatureGroup',
@@ -18,7 +18,7 @@ export default {
18
18
  }
19
19
  },
20
20
  setup(props, { emit }) {
21
- const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
21
+ const map = inject<Ref<Map | null>>(MAP);
22
22
  let added = false;
23
23
 
24
24
  if(!map) {
@@ -7,15 +7,15 @@
7
7
  />
8
8
  <FSDialog
9
9
  v-model="dialog"
10
- width="500px"
11
- :title="$tr('ui.map.select-layer', 'Select layer')"
10
+ :title="$tr('ui.map-layer.select', 'Select layer')"
11
+ :contained="true"
12
12
  >
13
13
  <template
14
14
  v-slot:body
15
15
  >
16
16
  <FSRow
17
17
  align="center-center"
18
- padding="0 16px 0 0"
18
+ :wrap="false"
19
19
  >
20
20
  <FSImageCard
21
21
  v-for="layer in layers"
@@ -5,12 +5,12 @@
5
5
  <script lang="ts">
6
6
  import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
7
7
 
8
- import { type Map, type DivIcon, divIcon, type LatLng, marker, type Marker, type MarkerClusterGroup, type Layer } from 'leaflet';
8
+ import { type Map, type DivIcon, divIcon, type LatLng, marker, type Marker, type MarkerClusterGroup } from 'leaflet';
9
9
 
10
10
  import { useColors } from "../../composables";
11
11
 
12
12
  import { gpsMarkerHtml, locationMarkerHtml, pinMarkerHtml } from '../../utils/leafletMarkers';
13
- import { INJECTION_FSMAP_MAP, INJECTION_FSMAP_MARKERCLUSTERGROUP } from './keys';
13
+ import { MAP, MARKERCLUSTERGROUP } from './keys';
14
14
 
15
15
  export default {
16
16
  name: 'FSMapMarker',
@@ -37,12 +37,16 @@ export default {
37
37
  type: Boolean,
38
38
  default: false,
39
39
  required: false
40
+ },
41
+ label: {
42
+ type: String,
43
+ required: false
40
44
  }
41
45
  },
42
46
  emits: ['click'],
43
47
  setup(props, { emit }) {
44
- const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
45
- const markerClusterGroup = inject<Ref<MarkerClusterGroup | null>>(INJECTION_FSMAP_MARKERCLUSTERGROUP, ref(null));
48
+ const map = inject<Ref<Map | null>>(MAP);
49
+ const markerClusterGroup = inject<Ref<MarkerClusterGroup | null>>(MARKERCLUSTERGROUP, ref(null));
46
50
 
47
51
  const { getColors } = useColors();
48
52
 
@@ -63,9 +67,9 @@ export default {
63
67
 
64
68
  if(lastMarker.value) {
65
69
  if(markerClusterGroup && markerClusterGroup.value) {
66
- markerClusterGroup.value.removeLayer(lastMarker.value);
70
+ markerClusterGroup.value.removeLayer(lastMarker.value as Marker);
67
71
  } else {
68
- map.value.removeLayer(lastMarker.value as Layer);
72
+ map.value.removeLayer(lastMarker.value as Marker);
69
73
  }
70
74
  }
71
75
 
@@ -81,7 +85,7 @@ export default {
81
85
  } else if(props.variant === 'location' && props.icon) {
82
86
  const size = 36;
83
87
  icon = divIcon({
84
- html: locationMarkerHtml(props.icon, getColors(props.color).base),
88
+ html: locationMarkerHtml(props.icon, getColors(props.color).base, props.label),
85
89
  iconSize: [size, size],
86
90
  className: props.selected ? 'fs-map-location fs-map-location-selected' : 'fs-map-location',
87
91
  iconAnchor: [size / 2, size / 2],
@@ -8,7 +8,7 @@ import { inject, provide, ref, type Ref } from 'vue';
8
8
  import { type Map, MarkerClusterGroup, divIcon } from 'leaflet';
9
9
 
10
10
  import { clusterMarkerHtml } from '../../utils/leafletMarkers';
11
- import { INJECTION_FSMAP_MAP } from './keys';
11
+ import { MAP } from './keys';
12
12
 
13
13
  export default {
14
14
  name: 'FSMapMarkerClusterGroup',
@@ -17,10 +17,15 @@ export default {
17
17
  type: Number,
18
18
  default: 0,
19
19
  required: false
20
+ },
21
+ disableClusteringAtZoom: {
22
+ type: Number,
23
+ default: 17,
24
+ required: false
20
25
  }
21
26
  },
22
27
  setup(props, { emit }) {
23
- const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
28
+ const map = inject<Ref<Map | null>>(MAP);
24
29
  let added = false;
25
30
 
26
31
  if(!map) {
@@ -34,7 +39,7 @@ export default {
34
39
  const markerClusterGroup = ref<MarkerClusterGroup>(new MarkerClusterGroup({
35
40
  spiderfyOnMaxZoom: false,
36
41
  showCoverageOnHover: false,
37
- disableClusteringAtZoom: 17,
42
+ disableClusteringAtZoom: props.disableClusteringAtZoom,
38
43
  iconCreateFunction: function (cluster: any) {
39
44
  const size = 36;
40
45
 
@@ -10,7 +10,7 @@
10
10
  v-show="isExtraSmall"
11
11
  ref="mobileOverlayWrapper"
12
12
  class="fs-map-overlay-mobile"
13
- :style="{ height: $props.mode === 'expand' ? '90%' : ($props.mode === 'half' ? '50%' : '20px') }"
13
+ :style="{ height: $props.mode === 'expand' ? '90%' : ($props.mode === 'half' ? '60%' : 'auto') }"
14
14
  >
15
15
  <FSCard
16
16
  width="100%"
@@ -24,14 +24,18 @@
24
24
  >
25
25
  <FSRow
26
26
  align="center-center"
27
- @touchstart="$props.mode === 'expand' ? $emit('update:mode', 'collapse') : $emit('update:mode', 'expand')"
27
+ style="cursor: pointer;"
28
+ @touchstart="onClick"
29
+ @mousedown="onClick"
28
30
  >
29
- <FSButton
30
- variant="icon"
31
- :icon="$props.mode === 'expand' ? 'mdi-chevron-down' : 'mdi-chevron-up'"
32
- @click="$props.mode === 'expand' ? $emit('update:mode', 'collapse') : $emit('update:mode', 'expand')"
33
- />
31
+ <FSIcon>
32
+ {{ $props.mode === 'expand' ? 'mdi-chevron-down' : 'mdi-chevron-up' }}
33
+ </FSIcon>
34
34
  </FSRow>
35
+ <slot
36
+ v-if="$props.mode === 'collapse'"
37
+ name="collapsed"
38
+ />
35
39
  <FSCol
36
40
  v-if="$props.mode !== 'collapse'"
37
41
  height="fill"
@@ -44,7 +48,6 @@
44
48
  </FSCol>
45
49
  </FSCard>
46
50
  </div>
47
-
48
51
  <FSCard
49
52
  v-show="!isExtraSmall"
50
53
  class="fs-map-overlay-desktop"
@@ -64,14 +67,22 @@
64
67
 
65
68
  <script lang="ts">
66
69
  import { defineComponent, type PropType, onUnmounted, onMounted, ref } from "vue";
70
+
67
71
  import { useBreakpoints } from "../../composables";
68
- import FSButton from "../FSButton.vue";
72
+
69
73
  import FSCard from "../FSCard.vue";
74
+ import FSIcon from "../FSIcon.vue";
70
75
  import FSCol from "../FSCol.vue";
71
76
  import FSRow from "../FSRow.vue";
72
77
 
73
78
  export default defineComponent({
74
79
  name: "FSMapOverlay",
80
+ components: {
81
+ FSCard,
82
+ FSIcon,
83
+ FSCol,
84
+ FSRow
85
+ },
75
86
  props: {
76
87
  mode: {
77
88
  type: String as PropType<"collapse" | "half" | "expand">,
@@ -79,15 +90,9 @@ export default defineComponent({
79
90
  default: "collapse"
80
91
  }
81
92
  },
82
- components: {
83
- FSButton,
84
- FSCard,
85
- FSCol,
86
- FSRow
87
- },
88
93
  emits: ["update:mode", "update:height", "update:width"],
89
- setup(_, { emit }) {
90
- const { isExtraSmall } = useBreakpoints();
94
+ setup(props, { emit }) {
95
+ const { isExtraSmall, isTouchScreenEnabled } = useBreakpoints();
91
96
 
92
97
  const mobileOverlayWrapper = ref<HTMLDivElement | null>(null);
93
98
  const desktopOverlay = ref<InstanceType<typeof FSCard> | null>(null);
@@ -95,6 +100,14 @@ export default defineComponent({
95
100
  const mobileResizeObserver = ref<ResizeObserver | null>(null);
96
101
  const desktopResizeObserver = ref<ResizeObserver | null>(null);
97
102
 
103
+ const onClick = (): void => {
104
+ if (props.mode === "expand") {
105
+ emit("update:mode", "collapse");
106
+ return;
107
+ }
108
+ emit("update:mode", "expand");
109
+ }
110
+
98
111
  onMounted(() => {
99
112
  mobileResizeObserver.value = new ResizeObserver(entries => {
100
113
  entries.forEach((entry) => {
@@ -110,10 +123,12 @@ export default defineComponent({
110
123
 
111
124
  if (mobileOverlayWrapper.value) {
112
125
  mobileResizeObserver.value.observe(mobileOverlayWrapper.value);
126
+ emit("update:height", mobileOverlayWrapper.value.offsetHeight);
113
127
  }
114
128
 
115
129
  if (desktopOverlay.value) {
116
130
  desktopResizeObserver.value.observe(desktopOverlay.value.$el);
131
+ emit("update:width", desktopOverlay.value.$el.offsetWidth);
117
132
  }
118
133
  });
119
134
 
@@ -127,10 +142,12 @@ export default defineComponent({
127
142
  });
128
143
 
129
144
  return {
130
- isExtraSmall,
131
145
  mobileOverlayWrapper,
132
- desktopOverlay
146
+ isTouchScreenEnabled,
147
+ desktopOverlay,
148
+ isExtraSmall,
149
+ onClick
133
150
  };
134
151
  }
135
152
  });
136
- </script>
153
+ </script>
@@ -8,7 +8,7 @@ import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
8
8
  import { type Map, type LatLng, type Polygon, type FeatureGroup, polygon } from 'leaflet';
9
9
 
10
10
  import { useColors } from "../../composables";
11
- import { INJECTION_FSMAP_FEATUREGROUP, INJECTION_FSMAP_MAP } from './keys';
11
+ import { FEATUREGROUP, MAP } from './keys';
12
12
 
13
13
  export default {
14
14
  name: 'FSMapPolygon',
@@ -25,8 +25,8 @@ export default {
25
25
  },
26
26
  emits: ['click'],
27
27
  setup(props, { emit }) {
28
- const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
29
- const featureGroup = inject<Ref<FeatureGroup | null>>(INJECTION_FSMAP_FEATUREGROUP, ref(null));
28
+ const map = inject<Ref<Map | null>>(MAP);
29
+ const featureGroup = inject<Ref<FeatureGroup | null>>(FEATUREGROUP, ref(null));
30
30
 
31
31
  const { getColors } = useColors();
32
32
 
@@ -47,9 +47,9 @@ export default {
47
47
 
48
48
  if(lastPolygon.value) {
49
49
  if(featureGroup && featureGroup.value) {
50
- featureGroup.value.removeLayer(lastPolygon.value);
50
+ featureGroup.value.removeLayer(lastPolygon.value as Polygon);
51
51
  } else {
52
- map.value.removeLayer(lastPolygon.value);
52
+ map.value.removeLayer(lastPolygon.value as Polygon);
53
53
  }
54
54
  }
55
55
 
@@ -7,7 +7,7 @@ import { inject, type PropType, onMounted, type Ref, watch } from 'vue';
7
7
 
8
8
  import type { Map, Layer } from 'leaflet';
9
9
 
10
- import { INJECTION_FSMAP_MAP } from './keys';
10
+ import { MAP } from './keys';
11
11
 
12
12
  export default {
13
13
  name: 'FSMapTileLayer',
@@ -18,7 +18,7 @@ export default {
18
18
  }
19
19
  },
20
20
  setup(props) {
21
- const map = inject<Ref<Map | null>>(INJECTION_FSMAP_MAP);
21
+ const map = inject<Ref<Map | null>>(MAP);
22
22
 
23
23
  const lastLayer = props.layer;
24
24
 
@@ -1,4 +1,4 @@
1
- export const INJECTION_FSMAP_FEATUREGROUP = 'featureGroup';
2
- export const INJECTION_FSMAP_MAP = 'map';
3
- export const INJECTION_FSMAP_MARKERCLUSTERGROUP = 'markerClusterGroup';
1
+ export const FEATUREGROUP = 'featureGroup';
2
+ export const MAP = 'map';
3
+ export const MARKERCLUSTERGROUP = 'markerClusterGroup';
4
4
 
@@ -13,7 +13,7 @@ import type { PropType} from "vue";
13
13
  import { computed, defineComponent } from "vue";
14
14
 
15
15
  import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
16
- import { AutoRefresh } from "@dative-gpi/foundation-shared-domain/models";
16
+ import { AutoRefresh } from "@dative-gpi/foundation-shared-domain/enums";
17
17
 
18
18
  import FSSelectField from "../fields/FSSelectField.vue";
19
19
 
@@ -40,16 +40,16 @@ export default defineComponent({
40
40
 
41
41
  const autoRefreshes = computed((): { id: AutoRefresh; label: string }[] => {
42
42
  const items = [
43
- { id: AutoRefresh.FifteenSeconds, label: $tr("ui.auto-refresh.fifteen-seconds", "Fifteen seconds") },
44
- { id: AutoRefresh.ThirtySeconds, label: $tr("ui.auto-refresh.thirty-seconds", "Thirty seconds") },
45
- { id: AutoRefresh.OneMinute, label: $tr("ui.auto-refresh.one-minute", "One minute") },
46
- { id: AutoRefresh.FiveMinutes, label: $tr("ui.auto-refresh.five-minutes", "Five minutes") },
47
- { id: AutoRefresh.FifteenMinutes, label: $tr("ui.auto-refresh.fifteen-minutes", "Fifteen minutes") },
48
- { id: AutoRefresh.ThirtyMinutes, label: $tr("ui.auto-refresh.thirty-minutes", "Thirty minutes") },
49
- { id: AutoRefresh.OneHour, label: $tr("ui.auto-refresh.one-hour", "One hour") },
43
+ { id: AutoRefresh.FifteenSeconds, label: $tr("ui.common.fifteen-seconds", "Fifteen seconds") },
44
+ { id: AutoRefresh.ThirtySeconds, label: $tr("ui.common.thirty-seconds", "Thirty seconds") },
45
+ { id: AutoRefresh.OneMinute, label: $tr("ui.common.one-minute", "One minute") },
46
+ { id: AutoRefresh.FiveMinutes, label: $tr("ui.common.five-minutes", "Five minutes") },
47
+ { id: AutoRefresh.FifteenMinutes, label: $tr("ui.common.fifteen-minutes", "Fifteen minutes") },
48
+ { id: AutoRefresh.ThirtyMinutes, label: $tr("ui.common.thirty-minutes", "Thirty minutes") },
49
+ { id: AutoRefresh.OneHour, label: $tr("ui.common.one-hour", "One hour") },
50
50
  ];
51
51
  if (props.useNone) {
52
- items.unshift({ id: AutoRefresh.None, label: $tr("ui.auto-refresh.none", "None") });
52
+ items.unshift({ id: AutoRefresh.None, label: $tr("ui.common.none", "None") });
53
53
  }
54
54
  return items;
55
55
  });
@@ -13,7 +13,7 @@ import type { PropType} from "vue";
13
13
  import { computed, defineComponent } from "vue";
14
14
 
15
15
  import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
16
- import { DashboardVariableType } from "@dative-gpi/foundation-shared-domain/models";
16
+ import { DashboardVariableType } from "@dative-gpi/foundation-shared-domain/enums";
17
17
 
18
18
  import FSSelectField from "../fields/FSSelectField.vue";
19
19
 
@@ -34,9 +34,10 @@ export default defineComponent({
34
34
  const { $tr } = useTranslationsProvider();
35
35
 
36
36
  const dashboardVariableTypes = computed((): { id: DashboardVariableType; label: string }[] => ([
37
- { id: DashboardVariableType.Number, label: $tr("ui.dashboard-variable-type.number", "Number") },
38
- { id: DashboardVariableType.String, label: $tr("ui.dashboard-variable-type.string", "String") },
39
- { id: DashboardVariableType.TimeStep, label: $tr("ui.dashboard-variable-type.time-step", "Time step") }
37
+ { id: DashboardVariableType.Number, label: $tr("ui.common.number", "Number") },
38
+ { id: DashboardVariableType.String, label: $tr("ui.common.string", "String") },
39
+ { id: DashboardVariableType.TimeStep, label: $tr("ui.common.time-step", "Time step")},
40
+ { id: DashboardVariableType.PlotPer, label: $tr("ui.common.plot-per", "Plot per")}
40
41
  ]));
41
42
 
42
43
  return {
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <FSSelectField
3
+ class="select.date-setting.label"
3
4
  :items="dateSettings"
4
5
  :clearable="false"
5
6
  :modelValue="$props.modelValue"
@@ -12,7 +13,7 @@
12
13
  import { computed, defineComponent, type PropType } from "vue";
13
14
 
14
15
  import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
15
- import { DateSetting } from "@dative-gpi/foundation-shared-domain/models";
16
+ import { DateSetting } from "@dative-gpi/foundation-shared-domain/enums";
16
17
 
17
18
  import FSSelectField from "../fields/FSSelectField.vue";
18
19
 
@@ -87,7 +88,7 @@ export default defineComponent({
87
88
  dateSettings.push({ id: DateSetting.LastPeriod, label: $tr("ui.date-setting.last-period", "Last period") });
88
89
  }
89
90
  if (props.useNone) {
90
- dateSettings.unshift({ id: DateSetting.None, label: $tr("ui.date-setting.none", "None") });
91
+ dateSettings.unshift({ id: DateSetting.None, label: $tr("ui.common.none", "None") });
91
92
  }
92
93
  return dateSettings;
93
94
  })