@kalisio/kdk 2.1.9 → 2.2.1
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.
- package/.travis.test.sh +42 -10
- package/README.md +2 -2
- package/core/api/application.js +7 -2
- package/core/api/authentication.js +17 -1
- package/core/api/db.js +7 -2
- package/core/api/hooks/hooks.authentication.js +4 -2
- package/core/api/hooks/hooks.authorisations.js +12 -2
- package/core/api/hooks/hooks.model.js +5 -5
- package/core/api/hooks/hooks.organisations.js +0 -4
- package/core/api/services/account/account.hooks.js +10 -6
- package/core/api/services/account/account.service.js +1 -1
- package/{map/api/services/geocoder/geocoder.hooks.js → core/api/services/import-export/import-export.hooks.js} +7 -5
- package/core/api/services/import-export/import-export.service.js +11 -0
- package/core/api/services/index.js +13 -1
- package/core/api/services/users/users.hooks.js +2 -3
- package/core/client/api.js +16 -14
- package/core/client/capabilities.js +6 -2
- package/core/client/components/KContent.vue +11 -1
- package/core/client/components/KDialog.vue +17 -15
- package/core/client/components/KModal.vue +1 -1
- package/core/client/components/KSponsor.vue +1 -1
- package/core/client/components/KTextArea.vue +5 -1
- package/core/client/components/app/KAbout.vue +1 -2
- package/core/client/components/app/KWelcome.vue +3 -5
- package/core/client/components/chart/KTimeSeriesChart.vue +24 -37
- package/core/client/components/collection/KColumn.vue +20 -17
- package/core/client/components/editor/KModalEditor.vue +0 -2
- package/core/client/components/form/KChipsField.vue +12 -2
- package/core/client/components/form/KColorField.vue +12 -2
- package/core/client/components/form/KColorScaleField.vue +12 -2
- package/core/client/components/form/KDateTimeRangeField.vue +12 -2
- package/core/client/components/form/KDatetimeField.vue +12 -2
- package/core/client/components/form/KEmailField.vue +12 -2
- package/core/client/components/form/KFileField.vue +12 -2
- package/core/client/components/form/KForm.vue +47 -9
- package/core/client/components/form/KIconField.vue +12 -2
- package/core/client/components/form/KItemField.vue +25 -4
- package/core/client/components/form/KNumberField.vue +12 -2
- package/core/client/components/form/KOptionsField.vue +12 -2
- package/core/client/components/form/KPasswordField.vue +12 -2
- package/core/client/components/form/KPhoneField.vue +13 -3
- package/core/client/components/form/KPropertyItemField.vue +12 -2
- package/core/client/components/form/KResolutionField.vue +126 -0
- package/core/client/components/form/KRoleField.vue +12 -2
- package/core/client/components/form/KSelectField.vue +14 -4
- package/core/client/components/form/KTextField.vue +12 -2
- package/core/client/components/form/KTextareaField.vue +13 -3
- package/core/client/components/form/KToggleField.vue +12 -2
- package/core/client/components/form/KTokenField.vue +12 -2
- package/core/client/components/form/KUnitField.vue +12 -2
- package/core/client/components/form/KUrlField.vue +12 -2
- package/core/client/components/input/KIconChooser.vue +10 -12
- package/core/client/components/input/KPalette.vue +2 -1
- package/core/client/components/layout/KPage.vue +5 -4
- package/core/client/components/layout/KWindow.vue +10 -10
- package/core/client/components/media/KColorScale.vue +25 -19
- package/core/client/components/media/KImageViewer.vue +57 -33
- package/core/client/components/media/KShape.vue +14 -103
- package/core/client/components/screen/KRegisterScreen.vue +0 -1
- package/core/client/components/screen/KScreenFooter.vue +0 -18
- package/core/client/components/team/KAddMember.vue +16 -22
- package/core/client/components/team/KGroupsActivity.vue +14 -0
- package/core/client/components/team/KMembersActivity.vue +12 -0
- package/core/client/components/team/KTagsActivity.vue +14 -0
- package/core/client/components/time/KDateTime.vue +23 -7
- package/core/client/components/time/KTimeControl.vue +142 -0
- package/core/client/components/tool/KExportTool.vue +57 -0
- package/core/client/composables/collection.js +0 -1
- package/core/client/composables/pwa.js +0 -1
- package/core/client/composables/schema.js +1 -1
- package/core/client/composables/session.js +30 -6
- package/core/client/exporter.js +147 -0
- package/core/client/i18n/core_en.json +91 -23
- package/core/client/i18n/core_fr.json +92 -23
- package/core/client/index.js +3 -0
- package/core/client/layout.js +34 -14
- package/core/client/local-storage.js +8 -6
- package/core/client/mixins/index.js +0 -1
- package/core/client/mixins/mixin.base-field.js +24 -2
- package/core/client/mixins/mixin.object-proxy.js +0 -1
- package/core/client/search.js +2 -1
- package/core/client/services/index.js +2 -1
- package/core/client/services/local-settings.service.js +4 -4
- package/core/client/theme.js +3 -3
- package/core/client/time.js +4 -0
- package/core/client/units.js +150 -5
- package/core/client/utils/index.js +13 -6
- package/core/client/utils/utils.account.js +1 -1
- package/core/client/utils/utils.colors.js +43 -0
- package/core/client/utils/utils.platform.js +0 -1
- package/core/client/utils/utils.pwa.js +14 -14
- package/core/client/utils/utils.session.js +1 -1
- package/core/client/utils/utils.shapes.js +270 -0
- package/core/client/utils/utils.time.js +37 -0
- package/core/common/permissions.js +3 -0
- package/core/common/schemas/settings.update.json +50 -29
- package/extras/css/core.variables.scss +3 -1
- package/extras/icons/wind-speed-0.svg +8 -0
- package/extras/icons/wind-speed-10.svg +8 -0
- package/extras/icons/wind-speed-100.svg +12 -0
- package/extras/icons/wind-speed-105.svg +13 -0
- package/extras/icons/wind-speed-15.svg +9 -0
- package/extras/icons/wind-speed-20.svg +9 -0
- package/extras/icons/wind-speed-25.svg +10 -0
- package/extras/icons/wind-speed-30.svg +10 -0
- package/extras/icons/wind-speed-35.svg +11 -0
- package/extras/icons/wind-speed-40.svg +11 -0
- package/extras/icons/wind-speed-45.svg +12 -0
- package/extras/icons/wind-speed-5.svg +9 -0
- package/extras/icons/wind-speed-50.svg +9 -0
- package/extras/icons/wind-speed-55.svg +10 -0
- package/extras/icons/wind-speed-60.svg +10 -0
- package/extras/icons/wind-speed-65.svg +11 -0
- package/extras/icons/wind-speed-70.svg +11 -0
- package/extras/icons/wind-speed-75.svg +12 -0
- package/extras/icons/wind-speed-80.svg +12 -0
- package/extras/icons/wind-speed-85.svg +13 -0
- package/extras/icons/wind-speed-90.svg +13 -0
- package/extras/icons/wind-speed-95.svg +14 -0
- package/extras/tours/map/navigation-bar.js +17 -15
- package/extras/tours/map/timeline.js +33 -33
- package/map/api/config/categories.cjs +4 -1
- package/map/api/hooks/hooks.catalog.js +39 -0
- package/map/api/hooks/hooks.features.js +23 -3
- package/map/api/hooks/hooks.query.js +65 -21
- package/map/api/models/projects.model.mongodb.js +8 -0
- package/map/api/services/catalog/catalog.hooks.js +5 -3
- package/map/api/services/features/features.hooks.js +18 -6
- package/map/api/services/index.js +22 -6
- package/map/api/services/projects/projects.hooks.js +118 -0
- package/map/client/capture.js +16 -0
- package/map/client/cesium/utils/index.js +4 -0
- package/map/client/cesium/utils/utils.events.js +30 -0
- package/map/client/cesium/utils/utils.features.js +8 -0
- package/map/client/cesium/utils/utils.popup.js +17 -0
- package/map/client/cesium/utils/utils.style.js +137 -0
- package/map/client/components/KCapture.vue +50 -0
- package/map/client/components/KCaptureTextArea.vue +53 -0
- package/map/client/components/KCompass.vue +2 -2
- package/map/client/components/KFeaturesChart.vue +1 -1
- package/map/client/components/KFeaturesFilter.vue +2 -2
- package/map/client/components/KLayerStyleForm.vue +288 -454
- package/map/client/components/KLevelSlider.vue +1 -1
- package/map/client/components/KNorth.vue +31 -0
- package/map/client/components/KProjectMenu.vue +88 -0
- package/map/client/components/KTimezoneMap.vue +36 -24
- package/map/client/components/catalog/KAddLayer.vue +3 -4
- package/map/client/components/catalog/KConnectLayer.vue +20 -4
- package/map/client/components/catalog/KCreateLayer.vue +1 -2
- package/map/client/components/catalog/KCreateProject.vue +100 -0
- package/map/client/components/catalog/KCreateView.vue +25 -2
- package/map/client/components/catalog/KLayersPanel.vue +24 -27
- package/map/client/components/catalog/KLayersSelector.vue +1 -1
- package/map/client/components/catalog/KProjectEditor.vue +91 -0
- package/map/client/components/catalog/KProjectManager.vue +60 -0
- package/map/client/components/catalog/KProjectSelector.vue +38 -0
- package/map/client/components/catalog/KProjectsPanel.vue +153 -0
- package/map/client/components/catalog/KSelectLayers.vue +96 -0
- package/map/client/components/catalog/KSelectViews.vue +96 -0
- package/map/client/components/catalog/KViewsPanel.vue +66 -30
- package/map/client/components/form/KDirectionField.vue +24 -5
- package/map/client/components/form/KLayerCategoryField.vue +12 -2
- package/map/client/components/form/KLocationField.vue +20 -5
- package/map/client/components/form/KOwsLayerField.vue +12 -2
- package/map/client/components/form/KOwsServiceField.vue +12 -2
- package/map/client/components/form/KSelectLayersField.vue +159 -0
- package/map/client/components/form/KSelectViewsField.vue +121 -0
- package/map/client/components/form/KTimezoneField.vue +24 -17
- package/map/client/components/legend/KColorScaleLegend.vue +6 -2
- package/map/client/components/legend/KLayerLegend.vue +71 -0
- package/map/client/components/legend/KLegend.vue +54 -51
- package/map/client/components/legend/KLegendRenderer.vue +5 -3
- package/map/client/components/legend/KSymbolsLegend.vue +12 -10
- package/map/client/components/legend/KVariablesLegend.vue +78 -0
- package/map/client/components/location/KGeocodersFilter.vue +2 -4
- package/map/client/components/location/KLocationCardSection.vue +8 -4
- package/map/client/components/location/KLocationMap.vue +48 -17
- package/map/client/components/location/KLocationSearch.vue +13 -3
- package/map/client/components/tools/KSearchTool.vue +17 -12
- package/map/client/components/widget/KElevationProfile.vue +16 -19
- package/map/client/components/widget/KMapillaryViewer.vue +21 -22
- package/map/client/components/widget/KTimeSeries.vue +35 -29
- package/map/client/composables/activity.js +15 -2
- package/map/client/composables/catalog.js +81 -0
- package/map/client/composables/highlight.js +45 -30
- package/map/client/composables/index.js +2 -0
- package/map/client/composables/location.js +25 -18
- package/map/client/composables/probe.js +4 -1
- package/map/client/composables/project.js +122 -0
- package/map/client/composables/weather.js +3 -3
- package/map/client/geolocation.js +1 -1
- package/map/client/globe.js +2 -0
- package/map/client/i18n/map_en.json +127 -76
- package/map/client/i18n/map_fr.json +128 -72
- package/map/client/index.js +3 -0
- package/map/client/init.js +17 -0
- package/map/client/leaflet/GSMaPLayer.js +16 -17
- package/map/client/leaflet/ShapeMarker.js +51 -0
- package/map/client/leaflet/TiledFeatureLayer.js +39 -9
- package/map/client/leaflet/TiledMeshLayer.js +13 -15
- package/map/client/leaflet/TiledWindLayer.js +6 -10
- package/map/client/leaflet/utils/index.js +4 -0
- package/map/client/leaflet/utils/utils.events.js +41 -0
- package/map/client/leaflet/utils/utils.popup.js +21 -0
- package/map/client/leaflet/utils/utils.style.js +195 -0
- package/map/client/leaflet/utils/utils.tiles.js +87 -0
- package/map/client/map.js +2 -0
- package/map/client/mixins/globe/mixin.base-globe.js +39 -18
- package/map/client/mixins/globe/mixin.geojson-layers.js +139 -69
- package/map/client/mixins/globe/mixin.popup.js +2 -1
- package/map/client/mixins/globe/mixin.style.js +6 -4
- package/map/client/mixins/globe/mixin.tooltip.js +8 -3
- package/map/client/mixins/map/mixin.base-map.js +53 -28
- package/map/client/mixins/map/mixin.edit-layers.js +15 -15
- package/map/client/mixins/map/mixin.forecast-layers.js +3 -1
- package/map/client/mixins/map/mixin.geojson-layers.js +60 -20
- package/map/client/mixins/map/mixin.georaster-layers.js +4 -11
- package/map/client/mixins/map/mixin.heatmap-layers.js +1 -1
- package/map/client/mixins/map/mixin.popup.js +2 -1
- package/map/client/mixins/map/mixin.style.js +4 -67
- package/map/client/mixins/map/mixin.tiled-mesh-layers.js +2 -1
- package/map/client/mixins/map/mixin.tiled-wind-layers.js +4 -2
- package/map/client/mixins/map/mixin.tooltip.js +2 -1
- package/map/client/mixins/mixin.activity.js +71 -192
- package/map/client/mixins/mixin.catalog-panel.js +6 -6
- package/map/client/mixins/mixin.context.js +12 -9
- package/map/client/mixins/mixin.feature-service.js +29 -300
- package/map/client/mixins/mixin.weacast.js +11 -17
- package/map/client/pixi-utils.js +1 -1
- package/map/client/planets.js +66 -0
- package/map/client/utils/index.js +6 -0
- package/map/client/utils/utils.capture.js +176 -0
- package/map/client/utils/utils.catalog.js +166 -0
- package/map/client/utils/utils.features.js +364 -0
- package/map/client/utils/utils.js +0 -151
- package/map/client/utils/utils.layers.js +175 -0
- package/map/client/utils/utils.location.js +91 -23
- package/map/client/utils/utils.project.js +8 -0
- package/map/client/utils/utils.schema.js +0 -1
- package/map/client/utils/utils.style.js +309 -0
- package/map/client/utils.all.js +2 -2
- package/map/client/utils.globe.js +1 -1
- package/map/client/utils.map.js +1 -1
- package/map/common/permissions.js +2 -0
- package/map/common/schemas/capture.create.json +132 -0
- package/map/common/schemas/projects.create.json +52 -0
- package/map/common/schemas/projects.update.json +52 -0
- package/map/common/wms-utils.js +8 -3
- package/package.json +6 -5
- package/test/api/core/account.test.js +20 -0
- package/test/api/core/config/default.cjs +16 -3
- package/test/api/core/import-export.test.js +86 -0
- package/test/api/core/test-log-2024-01-04.log +14 -0
- package/test/api/map/catalog.test.js +164 -0
- package/test/api/map/index.test.js +25 -61
- package/test/api/map/test-log-2024-01-04.log +2 -0
- package/test/api/map/test-log-2024-01-11.log +1 -0
- package/test/api/map/test-log-2024-01-25.log +19 -0
- package/test/client/core/layout.js +24 -5
- package/test/client/core/utils.js +7 -0
- package/test/client/map/catalog.js +78 -1
- package/test/client/map/time.js +2 -1
- package/core/client/components/screen/KEndpointScreen.vue +0 -80
- package/core/client/mixins/mixin.account.js +0 -61
- package/extras/icons/kdk.png +0 -0
- package/map/api/services/geocoder/geocoder.service.js +0 -79
- package/map/client/cesium/utils.js +0 -133
- package/map/client/components/KCaptureToolbar.vue +0 -155
- package/map/client/components/KColorLegend.vue +0 -349
- package/map/client/components/KTimeline.vue +0 -293
- package/map/client/components/KUrlLegend.vue +0 -122
- package/map/client/leaflet/utils.js +0 -246
|
@@ -26,11 +26,7 @@ import { i18n } from '../../i18n'
|
|
|
26
26
|
// unit:
|
|
27
27
|
// }
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
let chart = null
|
|
31
|
-
const unit2axis = new Map()
|
|
32
|
-
|
|
33
|
-
const emit = defineEmits(['zoom-start', 'zoom-end', 'legend-click'])
|
|
29
|
+
// Props
|
|
34
30
|
const props = defineProps({
|
|
35
31
|
timeSeries: { type: Array, default: () => [] },
|
|
36
32
|
xAxisKey: { type: String, default: 'x' },
|
|
@@ -44,19 +40,19 @@ const props = defineProps({
|
|
|
44
40
|
options: { type: Object, default: () => ({}) }
|
|
45
41
|
})
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
getZoom,
|
|
50
|
-
exportSeries
|
|
51
|
-
})
|
|
43
|
+
// Emits
|
|
44
|
+
const emit = defineEmits(['zoom-start', 'zoom-end', 'legend-click'])
|
|
52
45
|
|
|
53
|
-
//
|
|
46
|
+
// Data
|
|
47
|
+
let canvas = null
|
|
48
|
+
let chart = null
|
|
49
|
+
const unit2axis = new Map()
|
|
54
50
|
const startTime = ref(props.startTime ? moment.utc(props.startTime) : null)
|
|
55
51
|
const endTime = ref(props.endTime ? moment.utc(props.endTime) : null)
|
|
56
52
|
let min = null
|
|
57
53
|
let max = null
|
|
58
54
|
|
|
59
|
-
//
|
|
55
|
+
// Watch
|
|
60
56
|
watch(() => props.timeSeries, update)
|
|
61
57
|
watch(() => props.xAxisKey, update)
|
|
62
58
|
watch(() => props.yAxisKey, update)
|
|
@@ -67,7 +63,7 @@ watch(() => props.logarithmic, update)
|
|
|
67
63
|
watch(() => props.currentTime, update)
|
|
68
64
|
watch(() => props.options, update)
|
|
69
65
|
|
|
70
|
-
//
|
|
66
|
+
// Functions
|
|
71
67
|
async function onCanvasRef (ref) {
|
|
72
68
|
if (ref) {
|
|
73
69
|
if (!chart) {
|
|
@@ -82,14 +78,10 @@ async function onCanvasRef (ref) {
|
|
|
82
78
|
}
|
|
83
79
|
canvas = ref
|
|
84
80
|
}
|
|
85
|
-
|
|
86
|
-
function getUnits (timeSerie) {
|
|
81
|
+
function getUnit (timeSerie) {
|
|
87
82
|
// Falback to base unit
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
const defaultUnit = Units.getDefaultUnit(baseUnit)
|
|
91
|
-
const unit = (timeSerie.variable.units.includes(defaultUnit) ? defaultUnit : baseUnit)
|
|
92
|
-
return { unit, baseUnit }
|
|
83
|
+
const unit = _.get(timeSerie, 'variable.unit')
|
|
84
|
+
return unit
|
|
93
85
|
}
|
|
94
86
|
function getZoom () {
|
|
95
87
|
const start = moment.utc(_.get(chart, 'scales.x.min'))
|
|
@@ -113,13 +105,11 @@ function computeScaleBound (scale, property, min, max) {
|
|
|
113
105
|
_.set(scale, property, scaleBound(min, max))
|
|
114
106
|
}
|
|
115
107
|
}
|
|
116
|
-
|
|
117
108
|
async function makeChartConfig () {
|
|
118
109
|
// Order matters as we compute internals like data time range
|
|
119
110
|
const datasets = await makeDatasets()
|
|
120
111
|
const scales = makeScales()
|
|
121
112
|
const annotation = makeAnnotation()
|
|
122
|
-
|
|
123
113
|
const config = {
|
|
124
114
|
type: 'line',
|
|
125
115
|
data: { datasets },
|
|
@@ -145,9 +135,9 @@ async function makeChartConfig () {
|
|
|
145
135
|
return (x ? `${Time.format(x, 'date.short')} - ${Time.format(x, 'time.long')}` : '')
|
|
146
136
|
},
|
|
147
137
|
label: (context) => {
|
|
148
|
-
const {
|
|
138
|
+
const { unit, label } = context.dataset
|
|
149
139
|
const y = _.get(context, 'parsed.y')
|
|
150
|
-
return label + ': ' + Units.format(y,
|
|
140
|
+
return label + ': ' + Units.format(y, unit)
|
|
151
141
|
}
|
|
152
142
|
}
|
|
153
143
|
},
|
|
@@ -200,7 +190,6 @@ async function makeChartConfig () {
|
|
|
200
190
|
computeScaleBound(scales.x, 'suggestedMax', startTime.value, endTime.value)
|
|
201
191
|
return config
|
|
202
192
|
}
|
|
203
|
-
|
|
204
193
|
function makeScales () {
|
|
205
194
|
// Setup time ticks unit
|
|
206
195
|
const hours = endTime.value.diff(startTime.value, 'hours')
|
|
@@ -248,19 +237,16 @@ function makeScales () {
|
|
|
248
237
|
}
|
|
249
238
|
}
|
|
250
239
|
}
|
|
251
|
-
|
|
252
240
|
const scales = { x }
|
|
253
|
-
|
|
254
241
|
// Build a scale per unit
|
|
255
242
|
unit2axis.clear()
|
|
256
243
|
let axisId = 0
|
|
257
244
|
for (const timeSerie of props.timeSeries) {
|
|
258
|
-
const
|
|
245
|
+
const unit = getUnit(timeSerie)
|
|
259
246
|
if (!unit2axis.has(unit)) {
|
|
260
247
|
const axis = `y${axisId}`
|
|
261
248
|
unit2axis.set(unit, axis)
|
|
262
249
|
scales[axis] = _.merge({
|
|
263
|
-
baseUnit,
|
|
264
250
|
unit,
|
|
265
251
|
type: props.logarithmic ? 'logarithmic' : 'linear',
|
|
266
252
|
position: (axisId + 1) % 2 ? 'left' : 'right',
|
|
@@ -271,7 +257,7 @@ function makeScales () {
|
|
|
271
257
|
ticks: {
|
|
272
258
|
callback: function (value, index, values) {
|
|
273
259
|
if (values[index] !== undefined) {
|
|
274
|
-
return Units.format(values[index].value,
|
|
260
|
+
return Units.format(values[index].value, unit, null, { symbol: false })
|
|
275
261
|
}
|
|
276
262
|
}
|
|
277
263
|
}
|
|
@@ -285,17 +271,15 @@ function makeScales () {
|
|
|
285
271
|
}
|
|
286
272
|
return scales
|
|
287
273
|
}
|
|
288
|
-
|
|
289
274
|
async function makeDatasets () {
|
|
290
275
|
const datasets = []
|
|
291
276
|
for (const timeSerie of props.timeSeries) {
|
|
292
277
|
const label = _.get(timeSerie, 'variable.label')
|
|
293
|
-
const
|
|
278
|
+
const unit = getUnit(timeSerie)
|
|
294
279
|
const data = await timeSerie.data
|
|
295
280
|
const dataset = Object.assign({
|
|
296
281
|
label,
|
|
297
282
|
data,
|
|
298
|
-
baseUnit,
|
|
299
283
|
unit,
|
|
300
284
|
yAxisID: unit2axis.get(unit)
|
|
301
285
|
}, _.omit(_.get(timeSerie, 'variable.chartjs', {}), 'yAxis'))
|
|
@@ -332,7 +316,6 @@ async function makeDatasets () {
|
|
|
332
316
|
|
|
333
317
|
return datasets
|
|
334
318
|
}
|
|
335
|
-
|
|
336
319
|
function makeAnnotation () {
|
|
337
320
|
let annotation = {}
|
|
338
321
|
// Is current time visible in chart ?
|
|
@@ -360,7 +343,6 @@ function makeAnnotation () {
|
|
|
360
343
|
}
|
|
361
344
|
return annotation
|
|
362
345
|
}
|
|
363
|
-
|
|
364
346
|
async function exportSeries (options = {}) {
|
|
365
347
|
let times = []
|
|
366
348
|
for (let i = 0; i < props.timeSeries.length; i++) {
|
|
@@ -398,7 +380,6 @@ async function exportSeries (options = {}) {
|
|
|
398
380
|
downloadAsBlob(csv, _.template(options.filename || i18n.t('KTimeSeriesChart.SERIES_EXPORT_FILE'))(),
|
|
399
381
|
'text/csv;charset=utf-8;')
|
|
400
382
|
}
|
|
401
|
-
|
|
402
383
|
async function update () {
|
|
403
384
|
if (!canvas) return
|
|
404
385
|
// Reset time/value range
|
|
@@ -415,7 +396,6 @@ async function update () {
|
|
|
415
396
|
chart.update()
|
|
416
397
|
}
|
|
417
398
|
}
|
|
418
|
-
|
|
419
399
|
async function updateCurrentTime () {
|
|
420
400
|
if (!props.currentTime) return
|
|
421
401
|
update()
|
|
@@ -428,4 +408,11 @@ onMounted(() => {
|
|
|
428
408
|
onBeforeUnmount(() => {
|
|
429
409
|
Events.off('time-current-time-changed', updateCurrentTime)
|
|
430
410
|
})
|
|
411
|
+
|
|
412
|
+
// Expose
|
|
413
|
+
defineExpose({
|
|
414
|
+
update,
|
|
415
|
+
getZoom,
|
|
416
|
+
exportSeries
|
|
417
|
+
})
|
|
431
418
|
</script>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
-->
|
|
17
17
|
<div v-if="items.length > 0">
|
|
18
18
|
<KScrollArea
|
|
19
|
-
ref="
|
|
19
|
+
ref="scrollAreaRef"
|
|
20
20
|
:max-height="scrollHeight"
|
|
21
21
|
@scrolled="onScrolled"
|
|
22
22
|
>
|
|
@@ -38,22 +38,22 @@
|
|
|
38
38
|
v-bind="renderer"
|
|
39
39
|
@item-selected="onItemSelected"
|
|
40
40
|
:class="{
|
|
41
|
-
'q-pr-xs': dense,
|
|
42
|
-
'q-pr-sm': !dense
|
|
41
|
+
'q-pr-xs': hasScrollArea && dense,
|
|
42
|
+
'q-pr-sm': hasScrollArea && !dense
|
|
43
43
|
}"
|
|
44
44
|
/>
|
|
45
45
|
</template>
|
|
46
46
|
</div>
|
|
47
47
|
</KScrollArea>
|
|
48
48
|
<div
|
|
49
|
-
v-if="
|
|
49
|
+
v-if="hasScrollAction"
|
|
50
50
|
class="row justify-center"
|
|
51
51
|
>
|
|
52
52
|
<KAction
|
|
53
53
|
id="scroll-action"
|
|
54
54
|
icon="las la-angle-double-down"
|
|
55
55
|
color="accent"
|
|
56
|
-
size="
|
|
56
|
+
size="0.8rem"
|
|
57
57
|
:handler="scrollDown"
|
|
58
58
|
/>
|
|
59
59
|
</div>
|
|
@@ -90,7 +90,7 @@ const emit = defineEmits(['selection-changed', 'collection-refreshed'])
|
|
|
90
90
|
const props = defineProps({
|
|
91
91
|
name: {
|
|
92
92
|
type: String,
|
|
93
|
-
|
|
93
|
+
default: undefined
|
|
94
94
|
},
|
|
95
95
|
header: {
|
|
96
96
|
type: Array,
|
|
@@ -151,8 +151,9 @@ const props = defineProps({
|
|
|
151
151
|
})
|
|
152
152
|
|
|
153
153
|
// Data
|
|
154
|
-
const
|
|
155
|
-
const
|
|
154
|
+
const scrollAreaRef = ref(null)
|
|
155
|
+
const hasScrollArea = ref(false)
|
|
156
|
+
const hasScrollAction = ref(false)
|
|
156
157
|
const headerHeight = ref(0)
|
|
157
158
|
// Configuration
|
|
158
159
|
const scrollOffset = 350
|
|
@@ -160,7 +161,7 @@ const scrollDuration = 250
|
|
|
160
161
|
|
|
161
162
|
// Computed
|
|
162
163
|
const rendererComponent = computed(() => loadComponent(props.renderer.component))
|
|
163
|
-
const scrollHeight = computed(() => props.height - headerHeight.value)
|
|
164
|
+
const scrollHeight = computed(() => props.height - headerHeight.value - (hasScrollAction.value ? 24 : 0))
|
|
164
165
|
|
|
165
166
|
// Always use append mode for columns
|
|
166
167
|
const { items, nbTotalItems, nbPages, currentPage, refreshCollection, resetCollection } =
|
|
@@ -171,25 +172,26 @@ function onHeaderResized (size) {
|
|
|
171
172
|
headerHeight.value = size.height
|
|
172
173
|
}
|
|
173
174
|
function onScrolled (info) {
|
|
175
|
+
hasScrollArea.value = info.verticalSize > scrollHeight.value
|
|
174
176
|
if (items.value.length < nbTotalItems.value) {
|
|
175
177
|
if (info.verticalPercentage === 1) {
|
|
176
178
|
if (items.value.length === currentPage.value * props.nbItemsPerPage) currentPage.value++
|
|
177
179
|
refreshCollection()
|
|
178
|
-
|
|
180
|
+
hasScrollAction.value = true
|
|
179
181
|
} else {
|
|
180
|
-
|
|
182
|
+
hasScrollAction.value = hasScrollArea.value
|
|
181
183
|
}
|
|
182
184
|
} else {
|
|
183
185
|
if (info.verticalPercentage === 1) {
|
|
184
|
-
|
|
186
|
+
hasScrollAction.value = false
|
|
185
187
|
} else {
|
|
186
|
-
|
|
188
|
+
hasScrollAction.value = hasScrollArea.value
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
192
|
function scrollDown () {
|
|
191
|
-
const position =
|
|
192
|
-
|
|
193
|
+
const position = scrollAreaRef.value.getScrollPosition('vertical')
|
|
194
|
+
scrollAreaRef.value.setScrollPosition('vertical', position + scrollOffset, scrollDuration)
|
|
193
195
|
}
|
|
194
196
|
function onItemSelected (item, section) {
|
|
195
197
|
emit('selection-changed', item, section)
|
|
@@ -198,14 +200,15 @@ function onCollectionRefreshed () {
|
|
|
198
200
|
emit('collection-refreshed', items.value)
|
|
199
201
|
}
|
|
200
202
|
|
|
201
|
-
//
|
|
203
|
+
// Watch
|
|
202
204
|
watch(items, () => {
|
|
203
205
|
// On reset, reset as well scroll area
|
|
204
|
-
if (_.isEmpty(items.value) &&
|
|
206
|
+
if (_.isEmpty(items.value) && scrollAreaRef.value) scrollAreaRef.value.setScrollPosition('vertical', 0)
|
|
205
207
|
// Emit events so that embbeding components can be aware of it
|
|
206
208
|
onCollectionRefreshed()
|
|
207
209
|
})
|
|
208
210
|
|
|
211
|
+
// Hooks
|
|
209
212
|
onBeforeMount(() => {
|
|
210
213
|
refreshCollection()
|
|
211
214
|
// Whenever the user abilities are updated, update collection as well
|
|
@@ -16,14 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
<script>
|
|
18
18
|
import KModal from '../KModal.vue'
|
|
19
|
-
import KScrollArea from '../KScrollArea.vue'
|
|
20
19
|
import KForm from '../form/KForm.vue'
|
|
21
20
|
import { baseModal, service, objectProxy, schemaProxy, baseEditor } from '../../mixins'
|
|
22
21
|
|
|
23
22
|
export default {
|
|
24
23
|
components: {
|
|
25
24
|
KModal,
|
|
26
|
-
KScrollArea,
|
|
27
25
|
KForm
|
|
28
26
|
},
|
|
29
27
|
mixins: [
|
|
@@ -53,8 +53,18 @@
|
|
|
53
53
|
</div>
|
|
54
54
|
</template>
|
|
55
55
|
<!-- Helper -->
|
|
56
|
-
<template v-if="
|
|
57
|
-
<
|
|
56
|
+
<template v-if="hasHelper" v-slot:append>
|
|
57
|
+
<k-action
|
|
58
|
+
:id="properties.name + '-helper'"
|
|
59
|
+
:label="helperLabel"
|
|
60
|
+
:icon="helperIcon"
|
|
61
|
+
:tooltip="helperTooltip"
|
|
62
|
+
:url="helperUrl"
|
|
63
|
+
:dialog="helperDialog"
|
|
64
|
+
:context="helperContext"
|
|
65
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
66
|
+
color="primary"
|
|
67
|
+
/>
|
|
58
68
|
</template>
|
|
59
69
|
</q-field>
|
|
60
70
|
<k-icon-chooser
|
|
@@ -29,8 +29,18 @@
|
|
|
29
29
|
</q-dialog>
|
|
30
30
|
</template>
|
|
31
31
|
<!-- Helper -->
|
|
32
|
-
<template v-if="
|
|
33
|
-
<
|
|
32
|
+
<template v-if="hasHelper" v-slot:append>
|
|
33
|
+
<k-action
|
|
34
|
+
:id="properties.name + '-helper'"
|
|
35
|
+
:label="helperLabel"
|
|
36
|
+
:icon="helperIcon"
|
|
37
|
+
:tooltip="helperTooltip"
|
|
38
|
+
:url="helperUrl"
|
|
39
|
+
:dialog="helperDialog"
|
|
40
|
+
:context="helperContext"
|
|
41
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
42
|
+
color="primary"
|
|
43
|
+
/>
|
|
34
44
|
</template>
|
|
35
45
|
</q-field>
|
|
36
46
|
</div>
|
|
@@ -50,8 +50,18 @@
|
|
|
50
50
|
</q-item>
|
|
51
51
|
</template>
|
|
52
52
|
<!-- Helper -->
|
|
53
|
-
<template v-if="
|
|
54
|
-
<
|
|
53
|
+
<template v-if="hasHelper" v-slot:append>
|
|
54
|
+
<k-action
|
|
55
|
+
:id="properties.name + '-helper'"
|
|
56
|
+
:label="helperLabel"
|
|
57
|
+
:icon="helperIcon"
|
|
58
|
+
:tooltip="helperTooltip"
|
|
59
|
+
:url="helperUrl"
|
|
60
|
+
:dialog="helperDialog"
|
|
61
|
+
:context="helperContext"
|
|
62
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
63
|
+
color="primary"
|
|
64
|
+
/>
|
|
55
65
|
</template>
|
|
56
66
|
</q-select>
|
|
57
67
|
</template>
|
|
@@ -25,8 +25,18 @@
|
|
|
25
25
|
/>
|
|
26
26
|
</template>
|
|
27
27
|
<!-- Helper -->
|
|
28
|
-
<template v-if="
|
|
29
|
-
<
|
|
28
|
+
<template v-if="hasHelper" v-slot:append>
|
|
29
|
+
<k-action
|
|
30
|
+
:id="properties.name + '-helper'"
|
|
31
|
+
:label="helperLabel"
|
|
32
|
+
:icon="helperIcon"
|
|
33
|
+
:tooltip="helperTooltip"
|
|
34
|
+
:url="helperUrl"
|
|
35
|
+
:dialog="helperDialog"
|
|
36
|
+
:context="helperContext"
|
|
37
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
38
|
+
color="primary"
|
|
39
|
+
/>
|
|
30
40
|
</template>
|
|
31
41
|
</q-field>
|
|
32
42
|
</template>
|
|
@@ -25,8 +25,18 @@
|
|
|
25
25
|
/>
|
|
26
26
|
</template>
|
|
27
27
|
<!-- Helper -->
|
|
28
|
-
<template v-if="
|
|
29
|
-
<
|
|
28
|
+
<template v-if="hasHelper" v-slot:append>
|
|
29
|
+
<k-action
|
|
30
|
+
:id="properties.name + '-helper'"
|
|
31
|
+
:label="helperLabel"
|
|
32
|
+
:icon="helperIcon"
|
|
33
|
+
:tooltip="helperTooltip"
|
|
34
|
+
:url="helperUrl"
|
|
35
|
+
:dialog="helperDialog"
|
|
36
|
+
:context="helperContext"
|
|
37
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
38
|
+
color="primary"
|
|
39
|
+
/>
|
|
30
40
|
</template>
|
|
31
41
|
</q-field>
|
|
32
42
|
</template>
|
|
@@ -18,8 +18,18 @@
|
|
|
18
18
|
@update:model-value="onChanged"
|
|
19
19
|
>
|
|
20
20
|
<!-- Helper -->
|
|
21
|
-
<template v-if="
|
|
22
|
-
<
|
|
21
|
+
<template v-if="hasHelper" v-slot:append>
|
|
22
|
+
<k-action
|
|
23
|
+
:id="properties.name + '-helper'"
|
|
24
|
+
:label="helperLabel"
|
|
25
|
+
:icon="helperIcon"
|
|
26
|
+
:tooltip="helperTooltip"
|
|
27
|
+
:url="helperUrl"
|
|
28
|
+
:dialog="helperDialog"
|
|
29
|
+
:context="helperContext"
|
|
30
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
31
|
+
color="primary"
|
|
32
|
+
/>
|
|
23
33
|
</template>
|
|
24
34
|
</q-input>
|
|
25
35
|
</template>
|
|
@@ -30,8 +30,18 @@
|
|
|
30
30
|
@update:model-value="onFileChanged"
|
|
31
31
|
@rejected="onFileRejected">
|
|
32
32
|
<!-- Helper -->
|
|
33
|
-
<template v-if="
|
|
34
|
-
<
|
|
33
|
+
<template v-if="hasHelper" v-slot:append>
|
|
34
|
+
<k-action
|
|
35
|
+
:id="properties.name + '-helper'"
|
|
36
|
+
:label="helperLabel"
|
|
37
|
+
:icon="helperIcon"
|
|
38
|
+
:tooltip="helperTooltip"
|
|
39
|
+
:url="helperUrl"
|
|
40
|
+
:dialog="helperDialog"
|
|
41
|
+
:context="helperContext"
|
|
42
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
43
|
+
color="primary"
|
|
44
|
+
/>
|
|
35
45
|
</template>
|
|
36
46
|
</q-file>
|
|
37
47
|
</template>
|
|
@@ -22,13 +22,32 @@
|
|
|
22
22
|
<!--
|
|
23
23
|
Grouped fields
|
|
24
24
|
-->
|
|
25
|
-
<template v-for="group in groups" :key="
|
|
26
|
-
<q-expansion-item icon="las la-file-alt" :group="
|
|
25
|
+
<template v-for="(group, id) in groups" :key="id">
|
|
26
|
+
<q-expansion-item v-show="group.hasFields" icon="las la-file-alt" :group="id">
|
|
27
|
+
<template v-slot:header>
|
|
28
|
+
<!-- Label -->
|
|
29
|
+
<q-item-section>
|
|
30
|
+
{{ $t(group.label) }}
|
|
31
|
+
</q-item-section>
|
|
32
|
+
<!-- Helper -->
|
|
33
|
+
<q-item-section v-if="group.helper" side >
|
|
34
|
+
<k-action
|
|
35
|
+
:id="id + '-helper'"
|
|
36
|
+
color="primary"
|
|
37
|
+
:propagate="false"
|
|
38
|
+
:icon="getHelperIcon(group.helper)"
|
|
39
|
+
:tooltip="getHelperTooltip(group.helper)"
|
|
40
|
+
:url="getHelperUrl(group.helper)"
|
|
41
|
+
:dialog="getHelperDialog(group.helper)"
|
|
42
|
+
/>
|
|
43
|
+
</q-item-section>
|
|
44
|
+
</template>
|
|
45
|
+
<!-- Content -->
|
|
27
46
|
<q-card>
|
|
28
47
|
<q-card-section>
|
|
29
48
|
<template v-for="field in fields" :key="field.name">
|
|
30
|
-
<slot v-if="field.group ===
|
|
31
|
-
<slot v-if="field.group ===
|
|
49
|
+
<slot v-if="field.group === id" :name="'before-' + field.name"/>
|
|
50
|
+
<slot v-if="field.group === id" :name="field.name">
|
|
32
51
|
<component
|
|
33
52
|
:ref="onFieldRefCreated"
|
|
34
53
|
:is="field.component"
|
|
@@ -38,7 +57,7 @@
|
|
|
38
57
|
:dense="dense"
|
|
39
58
|
@field-changed="onFieldChanged" />
|
|
40
59
|
</slot>
|
|
41
|
-
<slot v-if="field.group ===
|
|
60
|
+
<slot v-if="field.group === id" :name="'after-' + field.name"/>
|
|
42
61
|
</template>
|
|
43
62
|
</q-card-section>
|
|
44
63
|
</q-card>
|
|
@@ -50,7 +69,7 @@
|
|
|
50
69
|
<script setup>
|
|
51
70
|
import _ from 'lodash'
|
|
52
71
|
import logger from 'loglevel'
|
|
53
|
-
import { ref, watch, onMounted } from 'vue'
|
|
72
|
+
import { ref, watch, computed, onMounted } from 'vue'
|
|
54
73
|
import { loadComponent } from '../../utils/index.js'
|
|
55
74
|
import { useSchema } from '../../composables'
|
|
56
75
|
|
|
@@ -80,11 +99,20 @@ const emit = defineEmits(['field-changed', 'form-ready'])
|
|
|
80
99
|
// Data
|
|
81
100
|
const { schema, compile: compileSchema, validate: validateSchema } = useSchema()
|
|
82
101
|
const fields = ref([])
|
|
83
|
-
const groups = ref([])
|
|
84
102
|
const isReady = ref(false)
|
|
85
103
|
const nbReadyFields = ref(0)
|
|
86
104
|
let buildInProgress = false
|
|
87
105
|
|
|
106
|
+
// Computed
|
|
107
|
+
const groups = computed(() => {
|
|
108
|
+
if (schema.value && schema.value.groups) {
|
|
109
|
+
return _.mapValues(schema.value.groups, (group, id) => Object.assign({
|
|
110
|
+
hasFields: _.find(fields.value, { group: id })
|
|
111
|
+
}, group))
|
|
112
|
+
}
|
|
113
|
+
return {}
|
|
114
|
+
})
|
|
115
|
+
|
|
88
116
|
// Watch
|
|
89
117
|
watch(() => props.schema, async (value) => {
|
|
90
118
|
logger.debug('[KDK] Schema changed', value)
|
|
@@ -146,7 +174,6 @@ function hasFieldError (field, errors) {
|
|
|
146
174
|
}
|
|
147
175
|
async function build () {
|
|
148
176
|
fields.value = []
|
|
149
|
-
groups.value = []
|
|
150
177
|
nbReadyFields.value = 0
|
|
151
178
|
isReady.value = false
|
|
152
179
|
if (!props.schema) throw new Error('Cannot build the form without schema')
|
|
@@ -165,7 +192,6 @@ async function build () {
|
|
|
165
192
|
cloneField.required = _.includes(schema.value.required, property) // add extra required info
|
|
166
193
|
// add the field to the list of fields to be rendered
|
|
167
194
|
fields.value.push(cloneField)
|
|
168
|
-
if (cloneField.group && !groups.value.includes(cloneField.group)) groups.value.push(cloneField.group)
|
|
169
195
|
})
|
|
170
196
|
buildInProgress = false
|
|
171
197
|
}
|
|
@@ -226,6 +252,18 @@ async function submitted (object) {
|
|
|
226
252
|
await field.reference.submitted(object, field.name)
|
|
227
253
|
}
|
|
228
254
|
}
|
|
255
|
+
function getHelperIcon (helper) {
|
|
256
|
+
return _.get(helper, 'icon', undefined)
|
|
257
|
+
}
|
|
258
|
+
function getHelperTooltip (helper) {
|
|
259
|
+
return _.get(helper, 'tooltip', '')
|
|
260
|
+
}
|
|
261
|
+
function getHelperUrl (helper) {
|
|
262
|
+
return _.get(helper, 'url', null)
|
|
263
|
+
}
|
|
264
|
+
function getHelperDialog (helper) {
|
|
265
|
+
return _.get(helper, 'dialog', null)
|
|
266
|
+
}
|
|
229
267
|
|
|
230
268
|
// Hooks
|
|
231
269
|
onMounted(async () => {
|
|
@@ -39,8 +39,18 @@
|
|
|
39
39
|
:color="iconColor" />
|
|
40
40
|
</template>
|
|
41
41
|
<!-- Helper -->
|
|
42
|
-
<template v-if="
|
|
43
|
-
<
|
|
42
|
+
<template v-if="hasHelper" v-slot:append>
|
|
43
|
+
<k-action
|
|
44
|
+
:id="properties.name + '-helper'"
|
|
45
|
+
:label="helperLabel"
|
|
46
|
+
:icon="helperIcon"
|
|
47
|
+
:tooltip="helperTooltip"
|
|
48
|
+
:url="helperUrl"
|
|
49
|
+
:dialog="helperDialog"
|
|
50
|
+
:context="helperContext"
|
|
51
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
52
|
+
color="primary"
|
|
53
|
+
/>
|
|
44
54
|
</template>
|
|
45
55
|
</q-field>
|
|
46
56
|
</div>
|
|
@@ -52,8 +52,18 @@
|
|
|
52
52
|
</q-item>
|
|
53
53
|
</template>
|
|
54
54
|
<!-- Helper -->
|
|
55
|
-
<template v-if="
|
|
56
|
-
<
|
|
55
|
+
<template v-if="hasHelper" v-slot:append>
|
|
56
|
+
<k-action
|
|
57
|
+
:id="properties.name + '-helper'"
|
|
58
|
+
:label="helperLabel"
|
|
59
|
+
:icon="helperIcon"
|
|
60
|
+
:tooltip="helperTooltip"
|
|
61
|
+
:url="helperUrl"
|
|
62
|
+
:dialog="helperDialog"
|
|
63
|
+
:context="helperContext"
|
|
64
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
65
|
+
color="primary"
|
|
66
|
+
/>
|
|
57
67
|
</template>
|
|
58
68
|
</q-select>
|
|
59
69
|
</template>
|
|
@@ -71,16 +81,27 @@ export default {
|
|
|
71
81
|
options: []
|
|
72
82
|
}
|
|
73
83
|
},
|
|
84
|
+
computed: {
|
|
85
|
+
hasSingleService () {
|
|
86
|
+
const services = _.uniqBy(this.properties.services, 'service')
|
|
87
|
+
return services.length === 1
|
|
88
|
+
}
|
|
89
|
+
},
|
|
74
90
|
methods: {
|
|
91
|
+
getServiceForItem (item) {
|
|
92
|
+
return (this.hasSingleService
|
|
93
|
+
? this.properties.services[0]
|
|
94
|
+
: _.find(this.properties.services, { service: item.service }))
|
|
95
|
+
},
|
|
75
96
|
getId (item) {
|
|
76
97
|
return _.kebabCase(this.getLabel(item))
|
|
77
98
|
},
|
|
78
99
|
getLabel (item) {
|
|
79
|
-
const service =
|
|
100
|
+
const service = this.getServiceForItem(item)
|
|
80
101
|
return _.get(item, service.field || 'name', '')
|
|
81
102
|
},
|
|
82
103
|
getDescription (item) {
|
|
83
|
-
const service =
|
|
104
|
+
const service = this.getServiceForItem(item)
|
|
84
105
|
return _.get(item, service.description || 'description', '')
|
|
85
106
|
},
|
|
86
107
|
getIcon (item) {
|
|
@@ -18,8 +18,18 @@
|
|
|
18
18
|
|
|
19
19
|
>
|
|
20
20
|
<!-- Helper -->
|
|
21
|
-
<template v-if="
|
|
22
|
-
<
|
|
21
|
+
<template v-if="hasHelper" v-slot:append>
|
|
22
|
+
<k-action
|
|
23
|
+
:id="properties.name + '-helper'"
|
|
24
|
+
:label="helperLabel"
|
|
25
|
+
:icon="helperIcon"
|
|
26
|
+
:tooltip="helperTooltip"
|
|
27
|
+
:url="helperUrl"
|
|
28
|
+
:dialog="helperDialog"
|
|
29
|
+
:context="helperContext"
|
|
30
|
+
@dialog-confirmed="onHelperDialogConfirmed"
|
|
31
|
+
color="primary"
|
|
32
|
+
/>
|
|
23
33
|
</template>
|
|
24
34
|
</q-input>
|
|
25
35
|
</template>
|