adminforth 2.4.0-next.31 → 2.4.0-next.310
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/commands/callTsProxy.js +14 -4
- package/commands/createApp/templates/api.ts.hbs +10 -0
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +12 -1
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/templates/prisma.config.ts.hbs +8 -0
- package/commands/createApp/templates/schema.prisma.hbs +0 -1
- package/commands/createApp/utils.js +10 -0
- package/commands/createCustomComponent/configLoader.js +17 -4
- package/commands/createCustomComponent/main.js +13 -7
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/commands/createCustomComponent/templates/customCrud/saveButton.vue.hbs +28 -0
- package/commands/createPlugin/templates/custom/tsconfig.json.hbs +2 -5
- package/commands/createPlugin/templates/package.json.hbs +1 -1
- package/commands/generateModels.js +30 -22
- package/dist/auth.d.ts +9 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +21 -2
- package/dist/auth.js.map +1 -1
- package/dist/dataConnectors/baseConnector.d.ts +1 -1
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +69 -17
- package/dist/dataConnectors/baseConnector.js.map +1 -1
- package/dist/dataConnectors/clickhouse.d.ts.map +1 -1
- package/dist/dataConnectors/clickhouse.js +15 -0
- package/dist/dataConnectors/clickhouse.js.map +1 -1
- package/dist/dataConnectors/mongo.d.ts.map +1 -1
- package/dist/dataConnectors/mongo.js +50 -15
- package/dist/dataConnectors/mongo.js.map +1 -1
- package/dist/dataConnectors/mysql.d.ts.map +1 -1
- package/dist/dataConnectors/mysql.js +11 -0
- package/dist/dataConnectors/mysql.js.map +1 -1
- package/dist/dataConnectors/postgres.d.ts.map +1 -1
- package/dist/dataConnectors/postgres.js +43 -14
- package/dist/dataConnectors/postgres.js.map +1 -1
- package/dist/dataConnectors/sqlite.d.ts.map +1 -1
- package/dist/dataConnectors/sqlite.js +11 -0
- package/dist/dataConnectors/sqlite.js.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -22
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts +2 -0
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +62 -6
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts +6 -0
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +202 -25
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +172 -31
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +499 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +555 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +7 -15
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +45 -68
- package/dist/modules/utils.js.map +1 -1
- package/dist/servers/express.d.ts +5 -0
- package/dist/servers/express.d.ts.map +1 -1
- package/dist/servers/express.js +40 -1
- package/dist/servers/express.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/package-lock.json +1208 -708
- package/dist/spa/package.json +34 -34
- package/dist/spa/src/App.vue +59 -174
- package/dist/spa/src/adminforth.ts +42 -18
- package/dist/spa/src/afcl/AreaChart.vue +0 -1
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +6 -6
- package/dist/spa/src/afcl/ButtonGroup.vue +91 -0
- package/dist/spa/src/afcl/Card.vue +25 -0
- package/dist/spa/src/afcl/Checkbox.vue +21 -13
- package/dist/spa/src/afcl/CountryFlag.vue +4 -1
- package/dist/spa/src/{components/CustomDatePicker.vue → afcl/DatePicker.vue} +95 -9
- package/dist/spa/src/afcl/Dialog.vue +47 -27
- package/dist/spa/src/afcl/Dropzone.vue +127 -48
- package/dist/spa/src/afcl/Input.vue +14 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +3 -3
- package/dist/spa/src/afcl/PieChart.vue +5 -5
- package/dist/spa/src/afcl/ProgressBar.vue +7 -7
- package/dist/spa/src/afcl/Select.vue +82 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +315 -73
- package/dist/spa/src/afcl/Textarea.vue +31 -0
- package/dist/spa/src/afcl/Toggle.vue +32 -0
- package/dist/spa/src/afcl/Tooltip.vue +28 -18
- package/dist/spa/src/afcl/VerticalTabs.vue +16 -7
- package/dist/spa/src/afcl/index.ts +6 -3
- package/dist/spa/src/components/AcceptModal.vue +48 -14
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- package/dist/spa/src/components/CallActionWrapper.vue +15 -0
- package/dist/spa/src/components/ColumnValueInput.vue +38 -18
- package/dist/spa/src/components/ColumnValueInputWrapper.vue +4 -3
- package/dist/spa/src/components/CustomDateRangePicker.vue +9 -8
- package/dist/spa/src/components/CustomRangePicker.vue +37 -21
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +195 -132
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +90 -23
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +115 -85
- package/dist/spa/src/components/ResourceListTableVirtual.vue +114 -80
- package/dist/spa/src/components/ShowTable.vue +21 -15
- package/dist/spa/src/components/Sidebar.vue +470 -0
- package/dist/spa/src/components/SingleSkeletLoader.vue +6 -6
- package/dist/spa/src/components/SkeleteLoader.vue +3 -3
- package/dist/spa/src/components/ThreeDotsMenu.vue +84 -15
- package/dist/spa/src/components/Toast.vue +40 -29
- package/dist/spa/src/components/UserMenuSettingsButton.vue +69 -0
- package/dist/spa/src/components/ValueRenderer.vue +44 -17
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +5 -3
- package/dist/spa/src/main.ts +1 -1
- package/dist/spa/src/renderers/CompactField.vue +1 -1
- package/dist/spa/src/renderers/CompactUUID.vue +1 -1
- package/dist/spa/src/router/index.ts +8 -0
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +13 -1
- package/dist/spa/src/stores/core.ts +13 -1
- package/dist/spa/src/stores/filters.ts +33 -2
- package/dist/spa/src/stores/modal.ts +6 -1
- package/dist/spa/src/stores/toast.ts +22 -3
- package/dist/spa/src/types/Back.ts +163 -23
- package/dist/spa/src/types/Common.ts +91 -32
- package/dist/spa/src/types/FrontendAPI.ts +31 -5
- package/dist/spa/src/types/adapters/CaptchaAdapter.ts +34 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +2 -2
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/KeyValueAdapter.ts +16 -0
- package/dist/spa/src/types/adapters/index.ts +8 -0
- package/dist/spa/src/utils.ts +291 -11
- package/dist/spa/src/views/CreateView.vue +63 -21
- package/dist/spa/src/views/EditView.vue +55 -22
- package/dist/spa/src/views/ListView.vue +144 -87
- package/dist/spa/src/views/LoginView.vue +26 -35
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/SettingsView.vue +121 -0
- package/dist/spa/src/views/ShowView.vue +83 -53
- package/dist/spa/src/websocket.ts +6 -1
- package/dist/spa/tsconfig.app.json +1 -1
- package/dist/spa/vite.config.ts +45 -2
- package/dist/types/Back.d.ts +146 -14
- package/dist/types/Back.d.ts.map +1 -1
- package/dist/types/Back.js +15 -0
- package/dist/types/Back.js.map +1 -1
- package/dist/types/Common.d.ts +106 -29
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +31 -3
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CaptchaAdapter.d.ts +30 -0
- package/dist/types/adapters/CaptchaAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CaptchaAdapter.js +5 -0
- package/dist/types/adapters/CaptchaAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +1 -1
- package/dist/types/adapters/ImageVisionAdapter.d.ts +25 -0
- package/dist/types/adapters/ImageVisionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageVisionAdapter.js +2 -0
- package/dist/types/adapters/ImageVisionAdapter.js.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts +10 -0
- package/dist/types/adapters/KeyValueAdapter.d.ts.map +1 -0
- package/dist/types/adapters/KeyValueAdapter.js +2 -0
- package/dist/types/adapters/KeyValueAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +9 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/index.js +2 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/package.json +4 -2
- package/dist/spa/src/types/adapters/index.js +0 -5
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<component
|
|
5
5
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.beforeBreadcrumbs || []"
|
|
6
6
|
:is="getCustomComponent(c)"
|
|
7
|
-
:meta="c.meta"
|
|
7
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
8
8
|
:record="coreStore.record"
|
|
9
9
|
:resource="coreStore.resource"
|
|
10
10
|
:adminUser="coreStore.adminUser"
|
|
@@ -13,25 +13,42 @@
|
|
|
13
13
|
<BreadcrumbsWithButtons>
|
|
14
14
|
<!-- save and cancle -->
|
|
15
15
|
<button @click="$router.back()"
|
|
16
|
-
class="af-cancel-button flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-
|
|
16
|
+
class="af-cancel-button flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-lightCreateViewButtonText focus:outline-none bg-lightCreateViewButtonBackground rounded border border-lightCreateViewButtonBorder hover:bg-lightCreateViewButtonBackgroundHover hover:text-lightCreateViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightCreateViewButtonFocusRing dark:focus:ring-darkCreateViewButtonFocusRing dark:bg-darkCreateViewButtonBackground dark:text-darkCreateViewButtonText dark:border-darkCreateViewButtonBorder dark:hover:text-darkCreateViewButtonTextHover dark:hover:bg-darkCreateViewButtonBackgroundHover"
|
|
17
17
|
>
|
|
18
18
|
{{ $t('Cancel') }}
|
|
19
19
|
</button>
|
|
20
20
|
|
|
21
|
+
<!-- Custom Save Button injection -->
|
|
22
|
+
<component
|
|
23
|
+
v-if="createSaveButtonInjection"
|
|
24
|
+
:is="getCustomComponent(createSaveButtonInjection)"
|
|
25
|
+
:meta="createSaveButtonInjection.meta"
|
|
26
|
+
:record="record"
|
|
27
|
+
:resource="coreStore.resource"
|
|
28
|
+
:adminUser="coreStore.adminUser"
|
|
29
|
+
:saving="saving"
|
|
30
|
+
:validating="validating"
|
|
31
|
+
:isValid="isValid"
|
|
32
|
+
:disabled="saving || (validating && !isValid)"
|
|
33
|
+
:saveRecord="saveRecord"
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
<!-- Default Save Button fallback -->
|
|
21
37
|
<button
|
|
22
|
-
|
|
23
|
-
|
|
38
|
+
v-else
|
|
39
|
+
@click="() => saveRecord()"
|
|
40
|
+
class="af-save-button flex items-center py-1 px-3 text-sm font-medium rounded-default text-lightCreateViewSaveButtonText focus:outline-none bg-lightCreateViewButtonBackground rounded border border-lightCreateViewButtonBorder hover:bg-lightCreateViewButtonBackgroundHover hover:text-lightCreateViewSaveButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightCreateViewButtonFocusRing dark:focus:ring-darkCreateViewButtonFocusRing dark:bg-darkCreateViewButtonBackground dark:text-darkCreateViewSaveButtonText dark:border-darkCreateViewButtonBorder dark:hover:text-darkCreateViewSaveButtonTextHover dark:hover:bg-darkCreateViewButtonBackgroundHover disabled:opacity-50 gap-1"
|
|
24
41
|
:disabled="saving || (validating && !isValid)"
|
|
25
42
|
>
|
|
26
43
|
<svg v-if="saving"
|
|
27
|
-
aria-hidden="true" class="w-4 h-4 mr-1 text-gray-200 animate-spin dark:text-gray-600 fill-
|
|
44
|
+
aria-hidden="true" class="w-4 h-4 mr-1 text-gray-200 animate-spin dark:text-gray-600 fill-lightCreateViewSaveButtonText" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/><path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/></svg>
|
|
28
45
|
|
|
29
|
-
<IconFloppyDiskSolid v-else class="w-4 h-4
|
|
46
|
+
<IconFloppyDiskSolid v-else class="w-4 h-4" />
|
|
30
47
|
{{ $t('Save') }}
|
|
31
48
|
</button>
|
|
32
49
|
|
|
33
50
|
<ThreeDotsMenu
|
|
34
|
-
:threeDotsDropdownItems="coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems"
|
|
51
|
+
:threeDotsDropdownItems="(coreStore.resourceOptions?.pageInjections?.create?.threeDotsDropdownItems as [])"
|
|
35
52
|
></ThreeDotsMenu>
|
|
36
53
|
|
|
37
54
|
</BreadcrumbsWithButtons>
|
|
@@ -39,7 +56,7 @@
|
|
|
39
56
|
<component
|
|
40
57
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.afterBreadcrumbs || []"
|
|
41
58
|
:is="getCustomComponent(c)"
|
|
42
|
-
:meta="c.meta"
|
|
59
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
43
60
|
:record="coreStore.record"
|
|
44
61
|
:resource="coreStore.resource"
|
|
45
62
|
:adminUser="coreStore.adminUser"
|
|
@@ -51,7 +68,7 @@
|
|
|
51
68
|
<ResourceForm
|
|
52
69
|
v-else
|
|
53
70
|
:record="record"
|
|
54
|
-
:resource="coreStore.resource"
|
|
71
|
+
:resource="coreStore.resource!"
|
|
55
72
|
@update:record="onUpdateRecord"
|
|
56
73
|
@update:isValid="isValid = $event"
|
|
57
74
|
:validating="validating"
|
|
@@ -63,7 +80,7 @@
|
|
|
63
80
|
<component
|
|
64
81
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.bottom || []"
|
|
65
82
|
:is="getCustomComponent(c)"
|
|
66
|
-
:meta="c.meta"
|
|
83
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
67
84
|
:record="coreStore.record"
|
|
68
85
|
:resource="coreStore.resource"
|
|
69
86
|
:adminUser="coreStore.adminUser"
|
|
@@ -88,6 +105,7 @@ import { showErrorTost } from '@/composables/useFrontendApi';
|
|
|
88
105
|
import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
|
|
89
106
|
import adminforth from '@/adminforth';
|
|
90
107
|
import { useI18n } from 'vue-i18n';
|
|
108
|
+
import { type AdminForthComponentDeclarationFull } from '@/types/Common.js';
|
|
91
109
|
|
|
92
110
|
const isValid = ref(false);
|
|
93
111
|
const validating = ref(false);
|
|
@@ -104,41 +122,62 @@ const coreStore = useCoreStore();
|
|
|
104
122
|
|
|
105
123
|
const { t } = useI18n();
|
|
106
124
|
|
|
125
|
+
const createSaveButtonInjection = computed<AdminForthComponentDeclarationFull | null>(() => {
|
|
126
|
+
const raw: any = coreStore.resourceOptions?.pageInjections?.create?.saveButton as any;
|
|
127
|
+
if (!raw) return null;
|
|
128
|
+
const item = Array.isArray(raw) ? raw[0] : raw;
|
|
129
|
+
return item as AdminForthComponentDeclarationFull;
|
|
130
|
+
});
|
|
131
|
+
|
|
107
132
|
const initialValues = ref({});
|
|
108
133
|
|
|
109
134
|
const readonlyColumns = ref([]);
|
|
110
135
|
|
|
111
136
|
|
|
112
|
-
async function onUpdateRecord(newRecord) {
|
|
113
|
-
console.log('newRecord', newRecord);
|
|
137
|
+
async function onUpdateRecord(newRecord: any) {
|
|
114
138
|
record.value = newRecord;
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
onMounted(async () => {
|
|
118
142
|
loading.value = true;
|
|
119
143
|
await coreStore.fetchResourceFull({
|
|
120
|
-
resourceId: route.params.resourceId
|
|
144
|
+
resourceId: route.params.resourceId as string
|
|
121
145
|
});
|
|
122
|
-
initialValues.value = (coreStore.resource?.columns || []).reduce((acc, column) => {
|
|
146
|
+
initialValues.value = (coreStore.resource?.columns || []).reduce<Record<string, unknown>>((acc, column) => {
|
|
123
147
|
if (column.suggestOnCreate !== undefined) {
|
|
124
148
|
acc[column.name] = column.suggestOnCreate;
|
|
125
149
|
}
|
|
126
150
|
return acc;
|
|
127
151
|
}, {});
|
|
152
|
+
let userUseMultipleEncoding = true; //TODO remove this in future versions
|
|
128
153
|
if (route.query.values) {
|
|
129
|
-
|
|
154
|
+
try {
|
|
155
|
+
JSON.parse(decodeURIComponent(route.query.values as string));
|
|
156
|
+
console.warn('You are using an outdated format for the query vales. Please update your links and don`t use multiple URL encoding.');
|
|
157
|
+
} catch (e) {
|
|
158
|
+
userUseMultipleEncoding = false;
|
|
159
|
+
console.warn('You are using an outdated format for the query vales. Please update your links and don`t use multiple URL encoding.');
|
|
160
|
+
}
|
|
161
|
+
if (userUseMultipleEncoding) {
|
|
162
|
+
initialValues.value = { ...initialValues.value, ...JSON.parse(decodeURIComponent((route.query.values as string))) };
|
|
163
|
+
} else {
|
|
164
|
+
initialValues.value = { ...initialValues.value, ...JSON.parse(atob(route.query.values as string)) };
|
|
165
|
+
}
|
|
130
166
|
}
|
|
131
167
|
if (route.query.readonlyColumns) {
|
|
132
|
-
|
|
168
|
+
if (userUseMultipleEncoding) {
|
|
169
|
+
readonlyColumns.value = JSON.parse(decodeURIComponent((route.query.readonlyColumns as string)));
|
|
170
|
+
} else {
|
|
171
|
+
readonlyColumns.value = JSON.parse(atob(route.query.readonlyColumns as string));
|
|
172
|
+
}
|
|
133
173
|
}
|
|
134
174
|
record.value = initialValues.value;
|
|
135
175
|
loading.value = false;
|
|
136
|
-
checkAcessByAllowedActions(coreStore.resourceOptions
|
|
176
|
+
checkAcessByAllowedActions(coreStore.resourceOptions!.allowedActions,'create');
|
|
137
177
|
initThreeDotsDropdown();
|
|
138
178
|
});
|
|
139
179
|
|
|
140
|
-
async function saveRecord() {
|
|
141
|
-
console.log('saveRecord isValid', isValid.value);
|
|
180
|
+
async function saveRecord(opts?: { confirmationResult?: any }) {
|
|
142
181
|
if (!isValid.value) {
|
|
143
182
|
validating.value = true;
|
|
144
183
|
return;
|
|
@@ -152,14 +191,17 @@ async function saveRecord() {
|
|
|
152
191
|
body: {
|
|
153
192
|
resourceId: route.params.resourceId,
|
|
154
193
|
record: record.value,
|
|
194
|
+
meta: {
|
|
195
|
+
...(opts?.confirmationResult ? { confirmationResult: opts.confirmationResult } : {}),
|
|
196
|
+
},
|
|
155
197
|
},
|
|
156
198
|
});
|
|
157
|
-
if (response?.error) {
|
|
199
|
+
if (response?.error && response?.error !== 'Operation aborted by hook') {
|
|
158
200
|
showErrorTost(response.error);
|
|
159
201
|
}
|
|
160
202
|
saving.value = false;
|
|
161
203
|
if (route.query.returnTo) {
|
|
162
|
-
router.push(route.query.returnTo);
|
|
204
|
+
router.push(<string>route.query.returnTo);
|
|
163
205
|
} else {
|
|
164
206
|
router.push({
|
|
165
207
|
name: 'resource-show',
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<component
|
|
4
4
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.beforeBreadcrumbs || []"
|
|
5
5
|
:is="getCustomComponent(c)"
|
|
6
|
-
:meta="c.meta"
|
|
6
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
7
7
|
:record="editableRecord"
|
|
8
8
|
:resource="coreStore.resource"
|
|
9
9
|
:adminUser="coreStore.adminUser"
|
|
@@ -12,14 +12,31 @@
|
|
|
12
12
|
<BreadcrumbsWithButtons>
|
|
13
13
|
<!-- save and cancle -->
|
|
14
14
|
<button @click="$router.back()"
|
|
15
|
-
class="flex items-center py-1 px-3 me-2 text-sm font-medium text-
|
|
15
|
+
class="flex items-center py-1 px-3 me-2 text-sm font-medium text-lightEditViewButtonText rounded-default focus:outline-none bg-lightEditViewButtonBackground rounded border border-lightEditViewButtonBorder hover:bg-lightEditViewButtonBackgroundHover hover:text-lightEditViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightEditViewButtonFocusRing dark:focus:ring-darkEditViewButtonFocusRing dark:bg-darkEditViewButtonBackground dark:text-darkEditViewButtonText dark:border-darkEditViewButtonBorder dark:hover:text-darkEditViewButtonTextHover dark:hover:bg-darkEditViewButtonBackgroundHover"
|
|
16
16
|
>
|
|
17
17
|
{{ $t('Cancel') }}
|
|
18
18
|
</button>
|
|
19
19
|
|
|
20
|
+
<!-- Custom Save Button injection -->
|
|
21
|
+
<component
|
|
22
|
+
v-if="editSaveButtonInjection"
|
|
23
|
+
:is="getCustomComponent(editSaveButtonInjection)"
|
|
24
|
+
:meta="editSaveButtonInjection.meta"
|
|
25
|
+
:record="editableRecord"
|
|
26
|
+
:resource="coreStore.resource"
|
|
27
|
+
:adminUser="coreStore.adminUser"
|
|
28
|
+
:saving="saving"
|
|
29
|
+
:validating="validating"
|
|
30
|
+
:isValid="isValid"
|
|
31
|
+
:disabled="saving || (validating && !isValid)"
|
|
32
|
+
:saveRecord="saveRecord"
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
<!-- Default Save Button fallback -->
|
|
20
36
|
<button
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
v-else
|
|
38
|
+
@click="() => saveRecord()"
|
|
39
|
+
class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-lightEditViewSaveButtonText focus:outline-none bg-lightEditViewButtonBackground rounded border border-lightEditViewButtonBorder hover:bg-lightEditViewButtonBackgroundHover hover:text-lightEditViewSaveButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightEditViewButtonFocusRing dark:focus:ring-darkEditViewButtonFocusRing dark:bg-darkEditViewButtonBackground dark:text-darkEditViewSaveButtonText dark:border-darkEditViewButtonBorder dark:hover:text-darkEditViewSaveButtonTextHover dark:hover:bg-darkEditViewButtonBackgroundHover disabled:opacity-50 gap-1"
|
|
23
40
|
:disabled="saving || (validating && !isValid)"
|
|
24
41
|
>
|
|
25
42
|
<IconFloppyDiskSolid class="w-4 h-4" />
|
|
@@ -27,7 +44,7 @@
|
|
|
27
44
|
</button>
|
|
28
45
|
|
|
29
46
|
<ThreeDotsMenu
|
|
30
|
-
:threeDotsDropdownItems="coreStore.resourceOptions?.pageInjections?.edit?.threeDotsDropdownItems"
|
|
47
|
+
:threeDotsDropdownItems="(coreStore.resourceOptions?.pageInjections?.edit?.threeDotsDropdownItems as [])"
|
|
31
48
|
></ThreeDotsMenu>
|
|
32
49
|
|
|
33
50
|
</BreadcrumbsWithButtons>
|
|
@@ -35,16 +52,16 @@
|
|
|
35
52
|
<component
|
|
36
53
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.afterBreadcrumbs || []"
|
|
37
54
|
:is="getCustomComponent(c)"
|
|
38
|
-
:meta="c.meta"
|
|
55
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
39
56
|
:record="coreStore.record"
|
|
40
57
|
:resource="coreStore.resource"
|
|
41
58
|
:adminUser="coreStore.adminUser"
|
|
42
59
|
/>
|
|
43
60
|
|
|
44
61
|
<SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
|
|
45
|
-
|
|
62
|
+
|
|
46
63
|
<ResourceForm
|
|
47
|
-
v-else
|
|
64
|
+
v-else-if="coreStore.resource"
|
|
48
65
|
:record="editableRecord"
|
|
49
66
|
:resource="coreStore.resource"
|
|
50
67
|
:adminUser="coreStore.adminUser"
|
|
@@ -58,7 +75,7 @@
|
|
|
58
75
|
<component
|
|
59
76
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.bottom || []"
|
|
60
77
|
:is="getCustomComponent(c)"
|
|
61
|
-
:meta="c.meta"
|
|
78
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
62
79
|
:record="coreStore.record"
|
|
63
80
|
:resource="coreStore.resource"
|
|
64
81
|
:adminUser="coreStore.adminUser"
|
|
@@ -76,12 +93,13 @@ import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
|
|
|
76
93
|
import { useCoreStore } from '@/stores/core';
|
|
77
94
|
import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions, initThreeDotsDropdown } from '@/utils';
|
|
78
95
|
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
|
|
79
|
-
import { computed, onMounted, ref } from 'vue';
|
|
96
|
+
import { computed, onMounted, ref, type Ref } from 'vue';
|
|
80
97
|
import { useRoute, useRouter } from 'vue-router';
|
|
81
98
|
import { showErrorTost } from '@/composables/useFrontendApi';
|
|
82
99
|
import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
|
|
83
100
|
import adminforth from '@/adminforth';
|
|
84
101
|
import { useI18n } from 'vue-i18n';
|
|
102
|
+
import { type AdminForthComponentDeclarationFull } from '@/types/Common.js';
|
|
85
103
|
|
|
86
104
|
const { t } = useI18n();
|
|
87
105
|
const coreStore = useCoreStore();
|
|
@@ -96,9 +114,16 @@ const loading = ref(true);
|
|
|
96
114
|
|
|
97
115
|
const saving = ref(false);
|
|
98
116
|
|
|
99
|
-
const record = ref({});
|
|
117
|
+
const record: Ref<Record<string, any>> = ref({});
|
|
118
|
+
|
|
119
|
+
const editSaveButtonInjection = computed<AdminForthComponentDeclarationFull | null>(() => {
|
|
120
|
+
const raw: any = coreStore.resourceOptions?.pageInjections?.edit?.saveButton as any;
|
|
121
|
+
if (!raw) return null;
|
|
122
|
+
const item = Array.isArray(raw) ? raw[0] : raw;
|
|
123
|
+
return item as AdminForthComponentDeclarationFull;
|
|
124
|
+
});
|
|
100
125
|
|
|
101
|
-
async function onUpdateRecord(newRecord) {
|
|
126
|
+
async function onUpdateRecord(newRecord: Record<string, any>) {
|
|
102
127
|
record.value = newRecord;
|
|
103
128
|
}
|
|
104
129
|
|
|
@@ -110,7 +135,7 @@ const editableRecord = computed(() => {
|
|
|
110
135
|
coreStore.resource.columns.forEach(column => {
|
|
111
136
|
if (column.foreignResource) {
|
|
112
137
|
if (column.isArray?.enabled) {
|
|
113
|
-
newRecord[column.name] = newRecord[column.name]?.map(fr => fr.pk);
|
|
138
|
+
newRecord[column.name] = newRecord[column.name]?.map((fr: { pk: any }) => fr.pk);
|
|
114
139
|
} else {
|
|
115
140
|
newRecord[column.name] = newRecord[column.name]?.pk;
|
|
116
141
|
}
|
|
@@ -123,20 +148,24 @@ onMounted(async () => {
|
|
|
123
148
|
loading.value = true;
|
|
124
149
|
|
|
125
150
|
await coreStore.fetchResourceFull({
|
|
126
|
-
resourceId: route.params.resourceId
|
|
151
|
+
resourceId: route.params.resourceId as string
|
|
127
152
|
});
|
|
128
153
|
initThreeDotsDropdown();
|
|
129
154
|
|
|
130
155
|
await coreStore.fetchRecord({
|
|
131
|
-
resourceId: route.params.resourceId,
|
|
132
|
-
primaryKey: route.params.primaryKey,
|
|
156
|
+
resourceId: route.params.resourceId as string,
|
|
157
|
+
primaryKey: route.params.primaryKey as string,
|
|
133
158
|
source: 'edit',
|
|
134
159
|
});
|
|
135
|
-
|
|
160
|
+
|
|
161
|
+
if (coreStore.resourceOptions) {
|
|
162
|
+
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'edit');
|
|
163
|
+
}
|
|
164
|
+
|
|
136
165
|
loading.value = false;
|
|
137
166
|
});
|
|
138
167
|
|
|
139
|
-
async function saveRecord() {
|
|
168
|
+
async function saveRecord(opts?: { confirmationResult?: any }) {
|
|
140
169
|
if (!isValid.value) {
|
|
141
170
|
validating.value = true;
|
|
142
171
|
return;
|
|
@@ -145,7 +174,7 @@ async function saveRecord() {
|
|
|
145
174
|
}
|
|
146
175
|
|
|
147
176
|
saving.value = true;
|
|
148
|
-
const updates = {};
|
|
177
|
+
const updates: Record<string, any> = {};
|
|
149
178
|
for (const key in record.value) {
|
|
150
179
|
let columnIsUpdated = false;
|
|
151
180
|
|
|
@@ -157,7 +186,8 @@ async function saveRecord() {
|
|
|
157
186
|
columnIsUpdated = record.value[key] !== coreStore.record[key];
|
|
158
187
|
}
|
|
159
188
|
|
|
160
|
-
|
|
189
|
+
if (!coreStore.resource) return;
|
|
190
|
+
const column = coreStore.resource.columns.find((c) => c.name === key);
|
|
161
191
|
|
|
162
192
|
if (column?.foreignResource) {
|
|
163
193
|
columnIsUpdated = record.value[key] !== coreStore.record[key]?.pk;
|
|
@@ -175,9 +205,12 @@ async function saveRecord() {
|
|
|
175
205
|
resourceId: route.params.resourceId,
|
|
176
206
|
recordId: route.params.primaryKey,
|
|
177
207
|
record: updates,
|
|
208
|
+
meta: {
|
|
209
|
+
...(opts?.confirmationResult ? { confirmationResult: opts.confirmationResult } : {}),
|
|
210
|
+
},
|
|
178
211
|
},
|
|
179
212
|
});
|
|
180
|
-
if (resp.error) {
|
|
213
|
+
if (resp.error && resp.error !== 'Operation aborted by hook') {
|
|
181
214
|
showErrorTost(resp.error);
|
|
182
215
|
} else {
|
|
183
216
|
adminforth.alert({
|
|
@@ -185,9 +218,9 @@ async function saveRecord() {
|
|
|
185
218
|
variant: 'success',
|
|
186
219
|
timeout: 400000
|
|
187
220
|
});
|
|
221
|
+
router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: resp.recordId } });
|
|
188
222
|
}
|
|
189
223
|
saving.value = false;
|
|
190
|
-
router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: resp.recordId } });
|
|
191
224
|
}
|
|
192
225
|
|
|
193
226
|
</script>
|