adminforth 1.3.56-next.8 → 1.3.56
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/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +8 -4
- package/dist/auth.js.map +1 -1
- package/dist/basePlugin.d.ts +4 -0
- package/dist/basePlugin.d.ts.map +1 -1
- package/dist/basePlugin.js +4 -0
- package/dist/basePlugin.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +3 -1
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +15 -2
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +15 -3
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.js +2 -2
- package/dist/modules/styles.js.map +1 -1
- package/dist/servers/express.js +2 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +2 -2
- package/dist/spa/package-lock.json +16 -0
- package/dist/spa/package.json +1 -0
- package/dist/spa/src/App.vue +13 -31
- package/dist/spa/src/components/AfTooltip.vue +43 -0
- package/dist/spa/src/components/BreadcrumbsWithButtons.vue +3 -4
- package/dist/spa/src/components/CustomDatePicker.vue +2 -2
- package/dist/spa/src/components/Dropdown.vue +2 -2
- package/dist/spa/src/components/GroupsTable.vue +170 -0
- package/dist/spa/src/components/ResourceForm.vue +70 -156
- package/dist/spa/src/components/ResourceListTable.vue +121 -124
- package/dist/spa/src/renderers/CompactField.vue +45 -0
- package/dist/spa/src/renderers/CompactUUID.vue +12 -15
- package/dist/spa/src/renderers/CountryFlag.vue +16 -21
- package/dist/spa/src/renderers/HumanNumber.vue +11 -16
- package/dist/spa/src/renderers/RelativeTime.vue +41 -0
- package/dist/spa/src/renderers/URL.vue +18 -0
- package/dist/spa/src/stores/user.ts +0 -5
- package/dist/spa/src/types/AdminForthConfig.ts +26 -12
- package/dist/spa/src/views/CreateView.vue +1 -1
- package/dist/spa/src/views/EditView.vue +1 -1
- package/dist/spa/src/views/ListView.vue +3 -8
- package/dist/spa/src/views/ResourceParent.vue +36 -2
- package/dist/spa/src/views/ShowView.vue +16 -15
- package/dist/types/AdminForthConfig.d.ts +28 -12
- package/dist/types/AdminForthConfig.d.ts.map +1 -1
- package/dist/types/AdminForthConfig.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="shadow-resourseFormShadow dark:shadow-darkResourseFormShadow dark:shadow-2xl">
|
|
3
|
+
<div v-if="group.groupName" class="text-md font-semibold px-6 py-3 flex flex-1 items-center dark:border-gray-600 text-gray-700 bg-lightFormHeading dark:bg-gray-700 dark:text-gray-400 rounded-t-lg">
|
|
4
|
+
{{ group.groupName }}
|
|
5
|
+
</div>
|
|
6
|
+
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
|
7
|
+
<thead class="text-xs text-gray-700 uppercase dark:text-gray-400 bg-lightFormHeading dark:bg-gray-700 block md:table-row-group ">
|
|
8
|
+
<tr>
|
|
9
|
+
<th scope="col" class="px-6 py-3 hidden md:w-52 md:table-cell">
|
|
10
|
+
Field
|
|
11
|
+
</th>
|
|
12
|
+
<th scope="col" class="px-6 py-3 hidden md:table-cell">
|
|
13
|
+
Value
|
|
14
|
+
</th>
|
|
15
|
+
</tr>
|
|
16
|
+
</thead>
|
|
17
|
+
<tbody>
|
|
18
|
+
<tr
|
|
19
|
+
v-for="(column, i) in group.columns"
|
|
20
|
+
:key="column.name"
|
|
21
|
+
v-if="currentValues !== null"
|
|
22
|
+
class="bg-ligftForm dark:bg-gray-800 dark:border-gray-700 block md:table-row"
|
|
23
|
+
:class="{ 'border-b': i !== group.columns.length - 1 }"
|
|
24
|
+
>
|
|
25
|
+
<td class="px-6 py-4 flex items-center block md:table-cell pb-0 md:pb-4"
|
|
26
|
+
:class="{'rounded-bl-lg border-b-none': i === group.columns.length - 1}"> <!--align-top-->
|
|
27
|
+
<span class="flex items-center gap-1">
|
|
28
|
+
{{ column.label }}
|
|
29
|
+
<AfTooltip v-if="column.required[mode]">
|
|
30
|
+
|
|
31
|
+
<IconExclamationCircleSolid v-if="column.required[mode]" class="w-4 h-4"
|
|
32
|
+
:class="(columnError(column) && validating) ? 'text-red-500 dark:text-red-400' : 'text-gray-400 dark:text-gray-500'"
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
<template #tooltip>
|
|
36
|
+
Required field
|
|
37
|
+
</template>
|
|
38
|
+
</AfTooltip>
|
|
39
|
+
</span>
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
</td>
|
|
43
|
+
<td class="px-6 py-4 whitespace-pre-wrap relative block md:table-cell rounded-br-lg "
|
|
44
|
+
:class="{'rounded-br-lg': i === group.columns.length - 1}">
|
|
45
|
+
<template v-if="column?.components?.[props.source]?.file">
|
|
46
|
+
<component
|
|
47
|
+
:is="getCustomComponent(column.components[props.source])"
|
|
48
|
+
:column="column"
|
|
49
|
+
:value="currentValues[column.name]"
|
|
50
|
+
@update:value="setCurrentValue(column.name, $event)"
|
|
51
|
+
:meta="column.components[props.source].meta"
|
|
52
|
+
:record="currentValues"
|
|
53
|
+
@update:inValidity="customComponentsInValidity[column.name] = $event"
|
|
54
|
+
@update:emptiness="customComponentsEmptiness[column.name] = $event"
|
|
55
|
+
/>
|
|
56
|
+
</template>
|
|
57
|
+
<template v-else>
|
|
58
|
+
<Dropdown
|
|
59
|
+
single
|
|
60
|
+
v-if="column.foreignResource"
|
|
61
|
+
:options="columnOptions[column.name] || []"
|
|
62
|
+
:placeholder = "columnOptions[column.name]?.length ?'Select...': 'There are no options available'"
|
|
63
|
+
:modelValue="currentValues[column.name]"
|
|
64
|
+
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
65
|
+
></Dropdown>
|
|
66
|
+
<Dropdown
|
|
67
|
+
single
|
|
68
|
+
v-else-if="column.enum"
|
|
69
|
+
:options="column.enum"
|
|
70
|
+
:modelValue="currentValues[column.name]"
|
|
71
|
+
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
72
|
+
/>
|
|
73
|
+
<Dropdown
|
|
74
|
+
single
|
|
75
|
+
v-else-if="column.type === 'boolean'"
|
|
76
|
+
:options="[{ label: 'Yes', value: true }, { label: 'No', value: false }, { label: 'Unset', value: null }]"
|
|
77
|
+
:modelValue="currentValues[column.name]"
|
|
78
|
+
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
79
|
+
/>
|
|
80
|
+
<input
|
|
81
|
+
v-else-if="['integer'].includes(column.type)"
|
|
82
|
+
type="number"
|
|
83
|
+
step="1"
|
|
84
|
+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
85
|
+
placeholder="0"
|
|
86
|
+
:value="currentValues[column.name]"
|
|
87
|
+
@input="setCurrentValue(column.name, $event.target.value)"
|
|
88
|
+
>
|
|
89
|
+
<CustomDatePicker
|
|
90
|
+
v-else-if="['datetime'].includes(column.type)"
|
|
91
|
+
:column="column"
|
|
92
|
+
:valueStart="currentValues[column.name]"
|
|
93
|
+
auto-hide
|
|
94
|
+
@update:valueStart="setCurrentValue(column.name, $event)"
|
|
95
|
+
/>
|
|
96
|
+
<input
|
|
97
|
+
v-else-if="['decimal', 'float'].includes(column.type)"
|
|
98
|
+
type="number"
|
|
99
|
+
step="0.1"
|
|
100
|
+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
101
|
+
placeholder="0.0"
|
|
102
|
+
:value="currentValues[column.name]"
|
|
103
|
+
@input="setCurrentValue(column.name, $event.target.value)"
|
|
104
|
+
/>
|
|
105
|
+
<textarea
|
|
106
|
+
v-else-if="['text', 'richtext'].includes(column.type)"
|
|
107
|
+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
108
|
+
placeholder="Text"
|
|
109
|
+
:value="currentValues[column.name]"
|
|
110
|
+
@input="setCurrentValue(column.name, $event.target.value)"
|
|
111
|
+
>
|
|
112
|
+
</textarea>
|
|
113
|
+
<textarea
|
|
114
|
+
v-else-if="['json'].includes(column.type)"
|
|
115
|
+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
116
|
+
placeholder="Text"
|
|
117
|
+
:value="currentValues[column.name]"
|
|
118
|
+
@input="setCurrentValue(column.name, $event.target.value)"
|
|
119
|
+
>
|
|
120
|
+
</textarea>
|
|
121
|
+
<input
|
|
122
|
+
v-else
|
|
123
|
+
:type="!column.masked || unmasked[column.name] ? 'text' : 'password'"
|
|
124
|
+
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
125
|
+
placeholder="Text"
|
|
126
|
+
:value="currentValues[column.name]"
|
|
127
|
+
@input="setCurrentValue(column.name, $event.target.value)"
|
|
128
|
+
autocomplete="false"
|
|
129
|
+
data-lpignore="true"
|
|
130
|
+
readonly
|
|
131
|
+
onfocus="this.removeAttribute('readonly');"
|
|
132
|
+
>
|
|
133
|
+
|
|
134
|
+
<button
|
|
135
|
+
v-if="column.masked"
|
|
136
|
+
type="button"
|
|
137
|
+
@click="unmasked[column.name] = !unmasked[column.name]"
|
|
138
|
+
class="h-6 absolute inset-y-2 top-6 right-6 flex items-center pr-2 z-index-100 focus:outline-none"
|
|
139
|
+
>
|
|
140
|
+
<IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]" />
|
|
141
|
+
<IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
|
|
142
|
+
</button>
|
|
143
|
+
</template>
|
|
144
|
+
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
145
|
+
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
146
|
+
</td>
|
|
147
|
+
</tr>
|
|
148
|
+
</tbody>
|
|
149
|
+
</table>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
152
|
+
|
|
153
|
+
<script setup>
|
|
154
|
+
import { defineProps } from 'vue';
|
|
155
|
+
import { IconExclamationCircleSolid, IconEyeSlashSolid, IconEyeSolid } from '@iconify-prerendered/vue-flowbite';
|
|
156
|
+
import CustomDatePicker from "@/components/CustomDatePicker.vue";
|
|
157
|
+
import Dropdown from '@/components/Dropdown.vue';
|
|
158
|
+
import AfTooltip from "./AfTooltip.vue";
|
|
159
|
+
|
|
160
|
+
const props = defineProps({
|
|
161
|
+
group: Object,
|
|
162
|
+
mode: String,
|
|
163
|
+
validating: Boolean,
|
|
164
|
+
currentValues: Object,
|
|
165
|
+
unmasked: Object,
|
|
166
|
+
columnError: Function,
|
|
167
|
+
setCurrentValue: Function,
|
|
168
|
+
columnOptions: Object
|
|
169
|
+
});
|
|
170
|
+
</script>
|
|
@@ -1,164 +1,62 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="rounded-default">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
:record="currentValues"
|
|
47
|
-
@update:inValidity="customComponentsInValidity[column.name] = $event"
|
|
48
|
-
@update:emptiness="customComponentsEmptiness[column.name] = $event"
|
|
49
|
-
/>
|
|
50
|
-
</template>
|
|
51
|
-
<template v-else>
|
|
52
|
-
<Dropdown
|
|
53
|
-
single
|
|
54
|
-
v-if="column.foreignResource"
|
|
55
|
-
:options="columnOptions[column.name] || []"
|
|
56
|
-
:placeholder = "columnOptions[column.name]?.length ?'Select...': 'There are no options available'"
|
|
57
|
-
:modelValue="currentValues[column.name]"
|
|
58
|
-
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
59
|
-
></Dropdown>
|
|
60
|
-
<Dropdown
|
|
61
|
-
single
|
|
62
|
-
v-else-if="column.enum"
|
|
63
|
-
:options="column.enum"
|
|
64
|
-
:modelValue="currentValues[column.name]"
|
|
65
|
-
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
66
|
-
/>
|
|
67
|
-
<Dropdown
|
|
68
|
-
single
|
|
69
|
-
v-else-if="column.type === 'boolean'"
|
|
70
|
-
:options="[{ label: 'Yes', value: true }, { label: 'No', value: false }, { label: 'Unset', value: null }]"
|
|
71
|
-
:modelValue="currentValues[column.name]"
|
|
72
|
-
@update:modelValue="setCurrentValue(column.name, $event)"
|
|
73
|
-
/>
|
|
74
|
-
<input
|
|
75
|
-
v-else-if="['integer'].includes(column.type)"
|
|
76
|
-
type="number"
|
|
77
|
-
step="1"
|
|
78
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
79
|
-
placeholder="0"
|
|
80
|
-
:value="currentValues[column.name]"
|
|
81
|
-
@input="setCurrentValue(column.name, $event.target.value)"
|
|
82
|
-
>
|
|
83
|
-
<CustomDatePicker
|
|
84
|
-
v-else-if="['datetime'].includes(column.type)"
|
|
85
|
-
:column="column"
|
|
86
|
-
:valueStart="currentValues[column.name]"
|
|
87
|
-
auto-hide
|
|
88
|
-
@update:valueStart="setCurrentValue(column.name, $event)"
|
|
89
|
-
/>
|
|
90
|
-
<input
|
|
91
|
-
v-else-if="['decimal', 'float'].includes(column.type)"
|
|
92
|
-
type="number"
|
|
93
|
-
step="0.1"
|
|
94
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-40 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
95
|
-
placeholder="0.0"
|
|
96
|
-
:value="currentValues[column.name]"
|
|
97
|
-
@input="setCurrentValue(column.name, $event.target.value)"
|
|
98
|
-
/>
|
|
99
|
-
<textarea
|
|
100
|
-
v-else-if="['text', 'richtext'].includes(column.type)"
|
|
101
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
102
|
-
placeholder="Text"
|
|
103
|
-
:value="currentValues[column.name]"
|
|
104
|
-
@input="setCurrentValue(column.name, $event.target.value)"
|
|
105
|
-
>
|
|
106
|
-
</textarea>
|
|
107
|
-
<textarea
|
|
108
|
-
v-else-if="['json'].includes(column.type)"
|
|
109
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
110
|
-
placeholder="Text"
|
|
111
|
-
:value="currentValues[column.name]"
|
|
112
|
-
@input="setCurrentValue(column.name, $event.target.value)"
|
|
113
|
-
>
|
|
114
|
-
</textarea>
|
|
115
|
-
<input
|
|
116
|
-
v-else
|
|
117
|
-
:type="!column.masked || unmasked[column.name] ? 'text' : 'password'"
|
|
118
|
-
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
119
|
-
placeholder="Text"
|
|
120
|
-
:value="currentValues[column.name]"
|
|
121
|
-
@input="setCurrentValue(column.name, $event.target.value)"
|
|
122
|
-
autocomplete="false"
|
|
123
|
-
data-lpignore="true"
|
|
124
|
-
readonly
|
|
125
|
-
onfocus="this.removeAttribute('readonly');"
|
|
126
|
-
>
|
|
127
|
-
|
|
128
|
-
<button
|
|
129
|
-
v-if="column.masked"
|
|
130
|
-
type="button"
|
|
131
|
-
@click="unmasked[column.name] = !unmasked[column.name]"
|
|
132
|
-
class="h-6 absolute inset-y-2 top-6 right-6 flex items-center pr-2 z-index-100 focus:outline-none"
|
|
133
|
-
>
|
|
134
|
-
<IconEyeSolid class="w-6 h-6 text-gray-400" v-if="!unmasked[column.name]" />
|
|
135
|
-
<IconEyeSlashSolid class="w-6 h-6 text-gray-400" v-else />
|
|
136
|
-
</button>
|
|
137
|
-
</template>
|
|
138
|
-
<div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
|
|
139
|
-
<div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
|
|
140
|
-
|
|
141
|
-
</td>
|
|
142
|
-
</tr>
|
|
143
|
-
|
|
144
|
-
</tbody>
|
|
145
|
-
</table>
|
|
146
|
-
</form>
|
|
147
|
-
</div>
|
|
3
|
+
<form autocomplete="off" @submit.prevent>
|
|
4
|
+
<div v-if="!coreStore.resource.options.createEditGroups || coreStore.resource.options.createEditGroups.length === 0">
|
|
5
|
+
<GroupsTable
|
|
6
|
+
:group="{groupName: '', columns: editableColumns}"
|
|
7
|
+
:currentValues="currentValues"
|
|
8
|
+
:editableColumns="editableColumns"
|
|
9
|
+
:mode="mode"
|
|
10
|
+
:unmasked="unmasked"
|
|
11
|
+
:columnOptions="columnOptions"
|
|
12
|
+
:validating="validating"
|
|
13
|
+
:columnError="columnError"
|
|
14
|
+
:setCurrentValue="setCurrentValue"
|
|
15
|
+
/>
|
|
16
|
+
</div>
|
|
17
|
+
<div v-else class="flex flex-col gap-4">
|
|
18
|
+
<template v-for="group in groupedColumns" :key="group.groupName" class="flex flex-col gap-4">
|
|
19
|
+
<GroupsTable
|
|
20
|
+
:group="group"
|
|
21
|
+
:currentValues="currentValues"
|
|
22
|
+
:editableColumns="editableColumns"
|
|
23
|
+
:mode="mode"
|
|
24
|
+
:unmasked="unmasked"
|
|
25
|
+
:columnOptions="columnOptions"
|
|
26
|
+
:validating="validating"
|
|
27
|
+
:columnError="columnError"
|
|
28
|
+
:setCurrentValue="setCurrentValue"
|
|
29
|
+
/>
|
|
30
|
+
</template>
|
|
31
|
+
<div v-if="otherColumns.length > 0">
|
|
32
|
+
<GroupsTable
|
|
33
|
+
:group="{groupName: 'Other', columns: otherColumns}"
|
|
34
|
+
:currentValues="currentValues"
|
|
35
|
+
:editableColumns="editableColumns"
|
|
36
|
+
:mode="mode"
|
|
37
|
+
:unmasked="unmasked"
|
|
38
|
+
:columnOptions="columnOptions"
|
|
39
|
+
:validating="validating"
|
|
40
|
+
:columnError="columnError"
|
|
41
|
+
:setCurrentValue="setCurrentValue"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</form>
|
|
148
46
|
</div>
|
|
149
47
|
|
|
150
48
|
</template>
|
|
151
49
|
|
|
152
50
|
<script setup>
|
|
153
51
|
|
|
154
|
-
import
|
|
155
|
-
import Dropdown from '@/components/Dropdown.vue';
|
|
156
|
-
import { applyRegexValidation, callAdminForthApi, getCustomComponent } from '@/utils';
|
|
157
|
-
import { IconExclamationCircleSolid, IconEyeSlashSolid, IconEyeSolid } from '@iconify-prerendered/vue-flowbite';
|
|
52
|
+
import { applyRegexValidation, callAdminForthApi} from '@/utils';
|
|
158
53
|
import { computedAsync } from '@vueuse/core';
|
|
159
|
-
import { initFlowbite } from 'flowbite';
|
|
160
54
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
161
55
|
import { useRouter, useRoute } from 'vue-router';
|
|
56
|
+
import { useCoreStore } from "@/stores/core";
|
|
57
|
+
import GroupsTable from '@/components/GroupsTable.vue';
|
|
58
|
+
|
|
59
|
+
const coreStore = useCoreStore();
|
|
162
60
|
|
|
163
61
|
const router = useRouter();
|
|
164
62
|
const route = useRoute();
|
|
@@ -179,7 +77,6 @@ const currentValues = ref(null);
|
|
|
179
77
|
|
|
180
78
|
const customComponentsInValidity = ref({});
|
|
181
79
|
const customComponentsEmptiness = ref({});
|
|
182
|
-
|
|
183
80
|
|
|
184
81
|
const columnError = (column) => {
|
|
185
82
|
const val = computed(() => {
|
|
@@ -281,9 +178,6 @@ onMounted(() => {
|
|
|
281
178
|
currentValues.value[column.name] = JSON.stringify(currentValues.value[column.name], null, 2);
|
|
282
179
|
}
|
|
283
180
|
});
|
|
284
|
-
console.log('currentValues', currentValues.value);
|
|
285
|
-
|
|
286
|
-
initFlowbite();
|
|
287
181
|
emit('update:isValid', isValid.value);
|
|
288
182
|
});
|
|
289
183
|
|
|
@@ -310,14 +204,34 @@ const columnOptions = computedAsync(async () => {
|
|
|
310
204
|
|
|
311
205
|
|
|
312
206
|
const editableColumns = computed(() => {
|
|
313
|
-
|
|
314
|
-
return props.resource?.columns?.filter(column => column.showIn.includes(mode));
|
|
207
|
+
return props.resource?.columns?.filter(column => column.showIn.includes(mode.value));
|
|
315
208
|
});
|
|
316
209
|
|
|
317
210
|
const isValid = computed(() => {
|
|
318
211
|
return editableColumns.value?.every(column => !columnError(column));
|
|
319
212
|
});
|
|
320
213
|
|
|
214
|
+
|
|
215
|
+
const groups = coreStore.resource.options.createEditGroups;
|
|
216
|
+
|
|
217
|
+
const groupedColumns = computed(() => {
|
|
218
|
+
if (!groups || groups.length === 0) return [];
|
|
219
|
+
|
|
220
|
+
return groups.map(group => ({
|
|
221
|
+
...group,
|
|
222
|
+
columns: props.resource.columns.filter(col => group.columns.includes(col.name) && editableColumns.value.includes(col))
|
|
223
|
+
}));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const getOtherColumns = () => {
|
|
227
|
+
if (!groups || groups.length === 0) return;
|
|
228
|
+
|
|
229
|
+
const groupedColumnNames = new Set(groupedColumns.value.flatMap(group => group.columns.map(col => col.name)));
|
|
230
|
+
return editableColumns.value.filter(col => !groupedColumnNames.has(col.name));
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const otherColumns = getOtherColumns();
|
|
234
|
+
|
|
321
235
|
watch(() => isValid.value, (value) => {
|
|
322
236
|
emit('update:isValid', value);
|
|
323
237
|
});
|