glib-web 4.5.1 → 4.6.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/components/_responsive.vue +2 -1
- package/components/component.vue +1 -15
- package/components/composable/dirtyState.js +3 -3
- package/components/composable/file.js +1 -0
- package/components/composable/tree.js +1 -1
- package/components/composable/upload_delegator.js +6 -0
- package/components/fields/_select.vue +12 -2
- package/components/fields/multiUpload.vue +73 -34
- package/components/fields/selectAsset/doc-1.png +0 -0
- package/components/fields/selectAsset/pdf-1.png +0 -0
- package/components/fields/selectAsset/pic-1.png +0 -0
- package/components/mixins/generic.js +14 -0
- package/components/mixins/styles.js +6 -1
- package/components/panels/responsive.vue +1 -1
- package/components/panels/table.vue +3 -2
- package/components/panels/tree/TreeNode.js +1 -0
- package/components/panels/tree/standard.vue +28 -10
- package/components/panels/tree.vue +27 -3
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<component :is="componentName" :class="cssClasses" :style="$styles()" :href="$href()"
|
|
2
|
+
<component v-if="loadIf" :is="componentName" :class="cssClasses" :style="$styles()" :href="$href()"
|
|
3
|
+
@click="$onClick()">
|
|
3
4
|
<panels-responsive v-if="header" :spec="header" />
|
|
4
5
|
|
|
5
6
|
<!--
|
package/components/component.vue
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
<component :draggable="!!spec.dragData" ref="delegate" v-else-if="name" :is="name" :id="spec.id" :spec="spec"
|
|
26
26
|
@[menter]="handlePopover(spec.onMouseEnter)" @[mleave]="handlePopover(spec.onMouseLeave)"
|
|
27
|
-
@[dstart]="handleDragStart" />
|
|
27
|
+
@[dstart()]="handleDragStart" />
|
|
28
28
|
<div v-else>Unsupported view: {{ spec.view }}</div>
|
|
29
29
|
</Suspense>
|
|
30
30
|
</template>
|
|
@@ -228,17 +228,6 @@ export default {
|
|
|
228
228
|
// $passthrough: true
|
|
229
229
|
};
|
|
230
230
|
},
|
|
231
|
-
computed: {
|
|
232
|
-
menter() {
|
|
233
|
-
return this.spec.onMouseEnter ? 'mouseenter' : null;
|
|
234
|
-
},
|
|
235
|
-
mleave() {
|
|
236
|
-
return this.spec.onMouseLeave ? 'mouseleave' : null;
|
|
237
|
-
},
|
|
238
|
-
dstart() {
|
|
239
|
-
return this.spec.dragData ? 'dragstart' : null;
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
231
|
watch: {
|
|
243
232
|
spec: {
|
|
244
233
|
handler(spec) {
|
|
@@ -284,9 +273,6 @@ export default {
|
|
|
284
273
|
},
|
|
285
274
|
handlePopover(spec) {
|
|
286
275
|
GLib.action.execute(spec, this);
|
|
287
|
-
},
|
|
288
|
-
handleDragStart(event) {
|
|
289
|
-
event.dataTransfer.setData('text', JSON.stringify(this.spec.dragData));
|
|
290
276
|
}
|
|
291
277
|
},
|
|
292
278
|
};
|
|
@@ -12,14 +12,14 @@ export function useDirtyState() {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const clearDirtyState = (context) => {
|
|
15
|
-
|
|
15
|
+
context ||= ctx();
|
|
16
16
|
ctx.isFormDirty = false;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const setDirty = (context) => (context || ctx()).isFormDirty = true;
|
|
20
20
|
|
|
21
21
|
const updateDirtyState = (context) => {
|
|
22
|
-
|
|
22
|
+
context ||= ctx();
|
|
23
23
|
const clean = Object.keys(dirtySpecs).reduce((prev, curr) => {
|
|
24
24
|
if (dirtySpecs[curr].disable) return prev;
|
|
25
25
|
const initValue = dirtySpecs[curr].initValue || '';
|
|
@@ -27,7 +27,7 @@ export function useDirtyState() {
|
|
|
27
27
|
return prev && (currValue.toString() == initValue.toString() || !currValue.toString());
|
|
28
28
|
}, true);
|
|
29
29
|
|
|
30
|
-
clean ? clearDirtyState(
|
|
30
|
+
clean ? clearDirtyState(context) : setDirty(context);
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
return { clearDirtyState, setDirty, isDirty, updateDirtyState };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { vueApp } from "../../store";
|
|
2
2
|
import { useFileUtils } from "./file";
|
|
3
|
+
import Uploader from "../../utils/glibDirectUpload";
|
|
3
4
|
|
|
4
5
|
const { makeKey } = useFileUtils();
|
|
5
6
|
|
|
@@ -11,6 +12,11 @@ function uploadFiles(obj) {
|
|
|
11
12
|
files: Array.from(droppedFiles).reduce((prev, curr) => {
|
|
12
13
|
prev[makeKey()] = curr;
|
|
13
14
|
|
|
15
|
+
const uploader = new Uploader(curr, spec.directUploadUrl, undefined, spec.storagePrefix, spec.metadata, spec.tagging || spec.tags);
|
|
16
|
+
if (!uploader.validateFile({ accepts: spec.accepts })) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
14
20
|
return prev;
|
|
15
21
|
}, {}),
|
|
16
22
|
spec: spec
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="container" :style="$styles()" :class="$classes()" v-if="loadIf">
|
|
3
|
-
<
|
|
3
|
+
<component :is="compName" :color="gcolor" v-model="fieldModel" :label="label" :items="normalizedOptions"
|
|
4
4
|
:chips="spec.multiple" :multiple="spec.multiple" :readonly="spec.readOnly" :clearable="!spec.readOnly"
|
|
5
5
|
:placeholder="spec.placeholder" :rules="rules" persistent-hint :append-icon="append.icon" validate-on="blur"
|
|
6
6
|
item-title='text' :variant="variant" :closable-chips="spec.multiple" :density="density" persistent-placeholder
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<template v-slot:append-item v-if="spec.footer">
|
|
28
28
|
<common-responsive :spec="spec.footer" />
|
|
29
29
|
</template>
|
|
30
|
-
</
|
|
30
|
+
</component>
|
|
31
31
|
|
|
32
32
|
<input v-for="(item, index) in values" :key="index" type="hidden" :disabled="inputDisabled" :name="fieldName"
|
|
33
33
|
:value="item" />
|
|
@@ -54,6 +54,9 @@ export default {
|
|
|
54
54
|
};
|
|
55
55
|
},
|
|
56
56
|
computed: {
|
|
57
|
+
compName() {
|
|
58
|
+
return this.spec.searchable ? 'v-autocomplete' : 'v-select';
|
|
59
|
+
},
|
|
57
60
|
normalizedOptions() {
|
|
58
61
|
return this.spec.options.map(i => {
|
|
59
62
|
switch (i.type) {
|
|
@@ -123,3 +126,10 @@ export default {
|
|
|
123
126
|
}
|
|
124
127
|
};
|
|
125
128
|
</script>
|
|
129
|
+
|
|
130
|
+
<style lang="scss" scoped>
|
|
131
|
+
// This is to ensure that the text does not get clipped by the clear icon.
|
|
132
|
+
::v-deep .v-autocomplete__selection {
|
|
133
|
+
display: block;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -20,20 +20,29 @@
|
|
|
20
20
|
<template v-for="(file, index) in Object.entries(files)" :key="`added-${index}`">
|
|
21
21
|
<div :class="`file-container ${file[1].status == 'failed' ? 'opacity-50' : ''}`">
|
|
22
22
|
<div class="file">
|
|
23
|
-
<div @click.stop="handleRemoveFile(file[0])" class="close-btn">
|
|
24
|
-
<v-icon size="12" color="white">close</v-icon>
|
|
25
|
-
</div>
|
|
26
23
|
<div class="status">
|
|
27
|
-
<
|
|
24
|
+
<div class="image-icon">
|
|
25
|
+
<img v-if="file[1].isImage()" :src="pic" alt="img-icon" />
|
|
26
|
+
<img v-else-if="file[1].type.startsWith('application/pdf')" :src="pdf" alt="img-icon" />
|
|
27
|
+
<img v-else :src="doc" alt="img-icon" />
|
|
28
|
+
</div>
|
|
28
29
|
<div class="progress">
|
|
29
|
-
<div class="label"><a :href="file[1].url" target="_blank">{{ `${file[1].name}` }}</a
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<div class="value" :style="{ width: `${file[1].progress.value}%` }"></div>
|
|
30
|
+
<div class="label"><a :href="file[1].url" target="_blank">{{ `${file[1].name}` }}</a>
|
|
31
|
+
<span v-if="file[1].message" :class="file[1].message != 'Completed' ? 'text-error' : ''">
|
|
32
|
+
{{ file[1].message }}
|
|
33
|
+
</span>
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
|
+
<div @click.stop="handleRemoveFile(file[0])" class="close-btn">
|
|
37
|
+
<v-icon size="24" color="black">close</v-icon>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="percentage-wrapper" v-show="file[1].progress.value > 0 && file[1].progress.value < 100">
|
|
42
|
+
<div class="background">
|
|
43
|
+
<div class="value" :style="{ width: `${file[1].progress.value}%` }"></div>
|
|
36
44
|
</div>
|
|
45
|
+
<div class="percentage">{{ parseInt(file[1].progress.value) }}%</div>
|
|
37
46
|
</div>
|
|
38
47
|
</div>
|
|
39
48
|
</template>
|
|
@@ -73,12 +82,14 @@
|
|
|
73
82
|
.file-container {
|
|
74
83
|
display: flex;
|
|
75
84
|
align-items: center;
|
|
85
|
+
flex-direction: column;
|
|
76
86
|
border-radius: 6px;
|
|
77
87
|
background-color: #f3f4f6;
|
|
78
88
|
width: 100%;
|
|
79
89
|
padding: 16px;
|
|
80
90
|
margin-bottom: 16px;
|
|
81
91
|
min-height: 72px;
|
|
92
|
+
gap: 8px;
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
.file {
|
|
@@ -89,8 +100,24 @@
|
|
|
89
100
|
.status {
|
|
90
101
|
display: flex;
|
|
91
102
|
width: 100%;
|
|
103
|
+
gap: 8px;
|
|
92
104
|
align-items: center;
|
|
93
105
|
|
|
106
|
+
.image-icon {
|
|
107
|
+
width: 40px;
|
|
108
|
+
height: 40px;
|
|
109
|
+
background-color: #fff;
|
|
110
|
+
border-radius: 5px;
|
|
111
|
+
display: flex;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
align-items: center;
|
|
114
|
+
|
|
115
|
+
img {
|
|
116
|
+
width: 20px;
|
|
117
|
+
height: 20px;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
94
121
|
.icon {
|
|
95
122
|
margin-right: 8px;
|
|
96
123
|
}
|
|
@@ -104,14 +131,13 @@
|
|
|
104
131
|
.label {
|
|
105
132
|
/* mb-1 */
|
|
106
133
|
display: flex;
|
|
107
|
-
|
|
108
|
-
justify-content: space-between;
|
|
109
|
-
flex-wrap: nowrap;
|
|
134
|
+
flex-direction: column;
|
|
110
135
|
margin-bottom: 4px;
|
|
111
136
|
}
|
|
112
137
|
|
|
113
138
|
.label a {
|
|
114
139
|
color: #47495F;
|
|
140
|
+
font-weight: 600;
|
|
115
141
|
}
|
|
116
142
|
|
|
117
143
|
.label a:hover {
|
|
@@ -124,34 +150,41 @@
|
|
|
124
150
|
text-decoration: none !important;
|
|
125
151
|
}
|
|
126
152
|
|
|
127
|
-
.background {
|
|
128
|
-
width: 100%;
|
|
129
|
-
background-color: #e5e7eb;
|
|
130
|
-
border-radius: 9999px;
|
|
131
|
-
height: 6px;
|
|
132
|
-
|
|
133
|
-
.value {
|
|
134
|
-
background-color: #4b5563;
|
|
135
|
-
height: inherit;
|
|
136
|
-
border-radius: inherit;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
.close-btn {
|
|
143
|
-
border-radius: 9999px;
|
|
144
|
-
background-color: #6b7280;
|
|
145
|
-
position: absolute;
|
|
146
|
-
top: -24px;
|
|
147
|
-
right: -24px;
|
|
148
|
-
display: flex;
|
|
149
|
-
justify-content: center;
|
|
150
|
-
align-items: center;
|
|
151
|
-
padding: 2px;
|
|
152
157
|
cursor: pointer;
|
|
153
158
|
}
|
|
154
159
|
}
|
|
160
|
+
|
|
161
|
+
.background {
|
|
162
|
+
width: 100%;
|
|
163
|
+
background-color: #e6e6e6;
|
|
164
|
+
border-radius: 9999px;
|
|
165
|
+
height: 8px;
|
|
166
|
+
display: flex;
|
|
167
|
+
|
|
168
|
+
.value {
|
|
169
|
+
background-color: #0A2A9E;
|
|
170
|
+
height: inherit;
|
|
171
|
+
border-radius: inherit;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.percentage-wrapper {
|
|
176
|
+
width: 100%;
|
|
177
|
+
display: flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
justify-content: center;
|
|
180
|
+
gap: 8px;
|
|
181
|
+
|
|
182
|
+
.percentage {
|
|
183
|
+
font-size: 14px;
|
|
184
|
+
font-weight: 600;
|
|
185
|
+
margin-bottom: 2px;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
155
188
|
}
|
|
156
189
|
|
|
157
190
|
.gdrop-file {
|
|
@@ -201,6 +234,9 @@ import * as delegateUploader from "../composable/upload_delegator";
|
|
|
201
234
|
import { triggerOnChange } from "../composable/form";
|
|
202
235
|
import { nextTick } from "vue";
|
|
203
236
|
import { useFilesState, useFileUtils } from "../composable/file";
|
|
237
|
+
import doc from "./selectAsset/doc-1.png"
|
|
238
|
+
import pic from "./selectAsset/pic-1.png"
|
|
239
|
+
import pdf from "./selectAsset/pdf-1.png"
|
|
204
240
|
const { makeKey, Item, signedIds } = useFileUtils();
|
|
205
241
|
|
|
206
242
|
export default defineComponent({
|
|
@@ -336,7 +372,10 @@ export default defineComponent({
|
|
|
336
372
|
handleRemoveFile,
|
|
337
373
|
showUploadedFile,
|
|
338
374
|
uploadTitle,
|
|
339
|
-
props
|
|
375
|
+
props,
|
|
376
|
+
doc,
|
|
377
|
+
pic,
|
|
378
|
+
pdf,
|
|
340
379
|
};
|
|
341
380
|
}
|
|
342
381
|
})
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,7 +2,21 @@ import { vueApp } from "../../store";
|
|
|
2
2
|
import { ValidationFactory } from "../validation";
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
|
+
computed: {
|
|
6
|
+
menter() {
|
|
7
|
+
return this.spec.onMouseEnter ? 'mouseenter' : null;
|
|
8
|
+
},
|
|
9
|
+
mleave() {
|
|
10
|
+
return this.spec.onMouseLeave ? 'mouseleave' : null;
|
|
11
|
+
}
|
|
12
|
+
},
|
|
5
13
|
methods: {
|
|
14
|
+
dstart(dragData) {
|
|
15
|
+
return dragData || this.spec.dragData ? 'dragstart' : null;
|
|
16
|
+
},
|
|
17
|
+
handleDragStart(event, dragData) {
|
|
18
|
+
event.dataTransfer.setData('text', JSON.stringify(dragData || this.spec.dragData));
|
|
19
|
+
},
|
|
6
20
|
$componentName() { // Can be overridden
|
|
7
21
|
if (this.spec) {
|
|
8
22
|
return this.spec.view?.replace('-v1', '');
|
|
@@ -298,7 +298,12 @@ export default {
|
|
|
298
298
|
const vm = realComponent(this);
|
|
299
299
|
const val = vm.$sanitizeValue(vm.$externalizeValue(Utils.type.isNotNull(newSpec.value) ? newSpec.value : this.fieldModel));
|
|
300
300
|
newSpec.value = isNeedToBeFixed(val, vm) ? val.toFixed(vm.spec.precision || NUMBER_PRECISION) : val;
|
|
301
|
-
|
|
301
|
+
|
|
302
|
+
if (newSpec.value !== vm.fieldModel) {
|
|
303
|
+
vm.fieldModel = newSpec.value;
|
|
304
|
+
vm.$executeOnChange();
|
|
305
|
+
}
|
|
306
|
+
|
|
302
307
|
if (Utils.type.isNotNull(newSpec.displayed)) vm._show = newSpec.displayed;
|
|
303
308
|
vm._submitWhenNotDisplayed = newSpec.submitWhenNotDisplayed;
|
|
304
309
|
Object.assign(vm.spec, newSpec);
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<template v-if="importable">
|
|
12
12
|
<span>{{
|
|
13
13
|
rows(section).length + section.dataRows.length
|
|
14
|
-
|
|
14
|
+
}}
|
|
15
15
|
rows</span>
|
|
16
16
|
<input ref="fileInput" style="display: none;" type="file" accept=".csv"
|
|
17
17
|
@change="loadFile($event, section)" />
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
<tbody>
|
|
49
49
|
<!-- <tr v-for="(row, index) in section.rows" :key="`row_${index}`"> -->
|
|
50
50
|
<template v-for="(row, rowIndex) in section.rows" :key="`row_${rowIndex}`">
|
|
51
|
-
<tr :class="row.onClick ? 'clickable' : ''"
|
|
51
|
+
<tr :class="row.onClick ? 'clickable' : ''"
|
|
52
|
+
@[dstart(row.dragData)]="(e) => handleDragStart(e, row.dragData)" :draggable="!!row.dragData">
|
|
52
53
|
<td v-for="(cell, cellIndex) in row.cellViews" :key="`cell_${cellIndex}`"
|
|
53
54
|
:colSpan="colSpan(row, cellIndex)" :style="colStyles(row, cellIndex)">
|
|
54
55
|
<span>
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="gtree-row">
|
|
3
3
|
<div :class="`${node.selected ? 'node selected' : 'node'}`" @dragover="(e) => handleDragOver(e, node)"
|
|
4
|
-
@drop="(e) => handleDrop(e, node)" @dragleave="(e) => handleDragLeave(e, node)">
|
|
4
|
+
@drop="(e) => handleDrop(e, node)" @dragleave="(e) => handleDragLeave(e, node)" @click="handleClick(node)">
|
|
5
5
|
<div class="content">
|
|
6
|
-
<v-btn style="z-index: 11" size="24" :icon="node.expand ? 'arrow_drop_down' : 'arrow_right'"
|
|
7
|
-
v-if="props.node.rows" @click="node.expand = !node.expand" variant="plain"></v-btn>
|
|
6
|
+
<v-btn style="z-index: 11;" size="24" :icon="node.expand ? 'arrow_drop_down' : 'arrow_right'"
|
|
7
|
+
v-if="props.node.rows" @click="node.expand = !node.expand" variant="plain" @click.stop></v-btn>
|
|
8
8
|
<div style="width: 24px" v-else></div>
|
|
9
|
-
<div class="
|
|
10
|
-
<v-icon v-if="node.icon" size="
|
|
11
|
-
|
|
9
|
+
<div class="text">
|
|
10
|
+
<v-icon v-if="node.icon" :size="node.icon.size || 24" :icon="node.icon.name"
|
|
11
|
+
:color="node.icon.color"></v-icon>
|
|
12
|
+
<div style="display: flex; flex-direction: column; width: 100%">
|
|
13
|
+
<div class="title">{{ node.title }}</div>
|
|
14
|
+
<div class="subtitle" v-if="node.subtitle">{{ node.subtitle }}</div>
|
|
15
|
+
</div>
|
|
12
16
|
</div>
|
|
13
17
|
</div>
|
|
14
18
|
<div class="overlay"></div>
|
|
@@ -25,6 +29,7 @@
|
|
|
25
29
|
<style lang="scss">
|
|
26
30
|
.gtree-row .node {
|
|
27
31
|
position: relative;
|
|
32
|
+
width: 100%;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
.gtree-row .node .overlay {
|
|
@@ -34,7 +39,7 @@
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
.gtree-row .node .content {
|
|
37
|
-
padding:
|
|
42
|
+
padding: 8px 16px;
|
|
38
43
|
width: 100%;
|
|
39
44
|
display: flex;
|
|
40
45
|
align-items: center;
|
|
@@ -48,11 +53,25 @@
|
|
|
48
53
|
opacity: 0.04;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
.gtree-row .node .
|
|
56
|
+
.gtree-row .node .content .text {
|
|
57
|
+
width: 100%;
|
|
52
58
|
display: flex;
|
|
53
|
-
gap:
|
|
59
|
+
gap: 6px;
|
|
54
60
|
align-items: center;
|
|
55
61
|
z-index: 10;
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
|
|
65
|
+
.title,
|
|
66
|
+
.subtitle {
|
|
67
|
+
text-overflow: ellipsis;
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.subtitle {
|
|
72
|
+
font-weight: lighter;
|
|
73
|
+
font-size: smaller;
|
|
74
|
+
}
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
.gtree-row .child-0-row {
|
|
@@ -65,7 +84,6 @@
|
|
|
65
84
|
gap: 2px;
|
|
66
85
|
align-items: center;
|
|
67
86
|
cursor: pointer;
|
|
68
|
-
height: 40px;
|
|
69
87
|
}
|
|
70
88
|
</style>
|
|
71
89
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="$styles()" :class="$classes()" v-if="loadIf">
|
|
3
|
-
<template v-for="(section, index) in
|
|
3
|
+
<template v-for="(section, index) in sections" :key="`${index}-${compKey}`">
|
|
4
4
|
<panels-responsive :spec="section.header" v-if="section.header"></panels-responsive>
|
|
5
5
|
|
|
6
6
|
<component :is="template(row.template)" v-for="(row, index) in section.rows"
|
|
7
|
-
v-bind="{ node:
|
|
7
|
+
v-bind="{ node: treeNode(row), level: 0 }" :key="index">
|
|
8
8
|
</component>
|
|
9
9
|
|
|
10
10
|
<panels-responsive :spec="section.footer" v-if="section.footer"></panels-responsive>
|
|
@@ -24,14 +24,38 @@ function template(name) {
|
|
|
24
24
|
}[name];
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function treeNode(row) {
|
|
28
|
+
return new TreeNode(row);
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
const props = defineProps(['spec']);
|
|
28
32
|
const dropBox = ref({ data: {}, files: [] });
|
|
29
33
|
const selected = computed(() => props.spec.selected);
|
|
30
34
|
const currTreeNode = ref({});
|
|
35
|
+
const sections = ref(props.spec.sections);
|
|
36
|
+
const compKey = ref(0);
|
|
37
|
+
|
|
38
|
+
watch(props, (val) => {
|
|
39
|
+
sections.value = val.spec.sections;
|
|
40
|
+
compKey.value += 1;
|
|
41
|
+
});
|
|
31
42
|
|
|
32
43
|
watch(dropBox, (val) => {
|
|
33
44
|
if (!val) return;
|
|
34
|
-
|
|
45
|
+
|
|
46
|
+
if (val.files.length > 0) {
|
|
47
|
+
Action.execute(props.spec.onDropFile, {}, val);
|
|
48
|
+
} else {
|
|
49
|
+
delete val.files;
|
|
50
|
+
|
|
51
|
+
const params = {
|
|
52
|
+
[props.spec.paramNameForFormData || 'formData']: val.data
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const data = Object.assign({}, props.spec.onDropView, params);
|
|
56
|
+
// TODO: Need to pass the component as the second parameter
|
|
57
|
+
Action.execute(data, {});
|
|
58
|
+
}
|
|
35
59
|
});
|
|
36
60
|
|
|
37
61
|
provide('dropBox', dropBox);
|