adminforth 2.4.0-next.15 → 2.4.0-next.151
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/cli.js +12 -4
- package/commands/createApp/templates/custom/tsconfig.json.hbs +2 -3
- package/commands/createApp/templates/index.ts.hbs +10 -2
- package/commands/createApp/templates/package.json.hbs +1 -1
- package/commands/createApp/utils.js +27 -2
- package/commands/createCustomComponent/configLoader.js +3 -0
- package/commands/createCustomComponent/main.js +1 -0
- package/commands/createCustomComponent/templates/customCrud/beforeActionButtons.vue.hbs +38 -0
- package/dist/dataConnectors/baseConnector.d.ts.map +1 -1
- package/dist/dataConnectors/baseConnector.js +46 -15
- 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 +44 -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 +11 -0
- 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 +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -9
- package/dist/index.js.map +1 -1
- package/dist/modules/codeInjector.d.ts.map +1 -1
- package/dist/modules/codeInjector.js +22 -5
- package/dist/modules/codeInjector.js.map +1 -1
- package/dist/modules/configValidator.d.ts.map +1 -1
- package/dist/modules/configValidator.js +54 -3
- package/dist/modules/configValidator.js.map +1 -1
- package/dist/modules/restApi.d.ts.map +1 -1
- package/dist/modules/restApi.js +147 -25
- package/dist/modules/restApi.js.map +1 -1
- package/dist/modules/styles.d.ts +457 -13
- package/dist/modules/styles.d.ts.map +1 -1
- package/dist/modules/styles.js +513 -31
- package/dist/modules/styles.js.map +1 -1
- package/dist/modules/utils.d.ts +1 -0
- package/dist/modules/utils.d.ts.map +1 -1
- package/dist/modules/utils.js +9 -0
- package/dist/modules/utils.js.map +1 -1
- package/dist/spa/index.html +1 -1
- package/dist/spa/src/App.vue +33 -15
- package/dist/spa/src/adminforth.ts +30 -10
- package/dist/spa/src/afcl/BarChart.vue +2 -2
- package/dist/spa/src/afcl/Button.vue +6 -6
- 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 +44 -27
- package/dist/spa/src/afcl/Dropzone.vue +12 -12
- package/dist/spa/src/afcl/Input.vue +6 -6
- package/dist/spa/src/afcl/JsonViewer.vue +25 -0
- package/dist/spa/src/afcl/LinkButton.vue +1 -1
- 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 +68 -34
- package/dist/spa/src/afcl/Skeleton.vue +6 -6
- package/dist/spa/src/afcl/Table.vue +199 -71
- 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 +1 -2
- package/dist/spa/src/afcl/VerticalTabs.vue +3 -3
- package/dist/spa/src/afcl/index.ts +4 -3
- package/dist/spa/src/components/AcceptModal.vue +7 -7
- package/dist/spa/src/components/Breadcrumbs.vue +5 -5
- 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 -8
- package/dist/spa/src/components/ErrorMessage.vue +21 -0
- package/dist/spa/src/components/Filters.vue +83 -37
- package/dist/spa/src/components/GroupsTable.vue +9 -8
- package/dist/spa/src/components/MenuLink.vue +3 -3
- package/dist/spa/src/components/ResourceForm.vue +94 -51
- package/dist/spa/src/components/ResourceListTable.vue +78 -80
- package/dist/spa/src/components/ResourceListTableVirtual.vue +70 -72
- package/dist/spa/src/components/ShowTable.vue +17 -12
- 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 +73 -14
- package/dist/spa/src/components/Toast.vue +27 -9
- package/dist/spa/src/components/ValueRenderer.vue +43 -16
- package/dist/spa/src/controls/BoolToggle.vue +34 -0
- package/dist/spa/src/i18n.ts +1 -1
- package/dist/spa/src/shims-vue.d.ts +5 -0
- package/dist/spa/src/spa_types/core.ts +8 -1
- package/dist/spa/src/stores/core.ts +1 -1
- 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 +107 -21
- package/dist/spa/src/types/Common.ts +45 -31
- package/dist/spa/src/types/FrontendAPI.ts +15 -2
- package/dist/spa/src/types/adapters/CompletionAdapter.ts +25 -0
- package/dist/spa/src/types/adapters/EmailAdapter.ts +27 -0
- package/dist/spa/src/types/adapters/ImageGenerationAdapter.ts +50 -0
- package/dist/spa/src/types/adapters/ImageVisionAdapter.ts +30 -0
- package/dist/spa/src/types/adapters/OAuth2Adapter.ts +34 -0
- package/dist/spa/src/types/adapters/StorageAdapter.ts +73 -0
- package/dist/spa/src/types/adapters/index.ts +6 -0
- package/dist/spa/src/utils.ts +217 -7
- package/dist/spa/src/views/CreateView.vue +18 -19
- package/dist/spa/src/views/EditView.vue +25 -19
- package/dist/spa/src/views/ListView.vue +124 -79
- package/dist/spa/src/views/LoginView.vue +36 -44
- package/dist/spa/src/views/ResourceParent.vue +2 -2
- package/dist/spa/src/views/ShowView.vue +59 -39
- 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 +75 -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 +38 -28
- package/dist/types/Common.d.ts.map +1 -1
- package/dist/types/Common.js.map +1 -1
- package/dist/types/FrontendAPI.d.ts +15 -1
- package/dist/types/FrontendAPI.d.ts.map +1 -1
- package/dist/types/FrontendAPI.js.map +1 -1
- package/dist/types/adapters/CompletionAdapter.d.ts +20 -0
- package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -0
- package/dist/types/adapters/CompletionAdapter.js +2 -0
- package/dist/types/adapters/CompletionAdapter.js.map +1 -0
- package/dist/types/adapters/EmailAdapter.d.ts +20 -0
- package/dist/types/adapters/EmailAdapter.d.ts.map +1 -0
- package/dist/types/adapters/EmailAdapter.js +2 -0
- package/dist/types/adapters/EmailAdapter.js.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts +37 -0
- package/dist/types/adapters/ImageGenerationAdapter.d.ts.map +1 -0
- package/dist/types/adapters/ImageGenerationAdapter.js +2 -0
- package/dist/types/adapters/ImageGenerationAdapter.js.map +1 -0
- 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/OAuth2Adapter.d.ts +32 -0
- package/dist/types/adapters/OAuth2Adapter.d.ts.map +1 -0
- package/dist/types/adapters/OAuth2Adapter.js +2 -0
- package/dist/types/adapters/OAuth2Adapter.js.map +1 -0
- package/dist/types/adapters/StorageAdapter.d.ts +63 -0
- package/dist/types/adapters/StorageAdapter.d.ts.map +1 -0
- package/dist/types/adapters/StorageAdapter.js +2 -0
- package/dist/types/adapters/StorageAdapter.js.map +1 -0
- package/dist/types/adapters/index.d.ts +7 -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 +3 -2
- package/dist/spa/src/types/Adapters.ts +0 -213
- package/dist/types/Adapters.d.ts +0 -168
- package/dist/types/Adapters.d.ts.map +0 -1
- package/dist/types/Adapters.js +0 -2
- package/dist/types/Adapters.js.map +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
v-if="!loading"
|
|
5
5
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.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"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
v-for="action in coreStore.resource.options.actions.filter(a => a.showIn?.showButton)"
|
|
16
16
|
:key="action.id"
|
|
17
17
|
@click="startCustomAction(action.id)"
|
|
18
|
-
:disabled="actionLoadingStates[action.id]"
|
|
18
|
+
:disabled="actionLoadingStates[action.id!]"
|
|
19
19
|
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-default border border-gray-300 hover:bg-gray-100 hover:text-lightPrimary focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
20
20
|
>
|
|
21
21
|
<component
|
|
@@ -28,28 +28,28 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
<RouterLink v-if="coreStore.resource?.options?.allowedActions?.create"
|
|
30
30
|
:to="{ name: 'resource-create', params: { resourceId: $route.params.resourceId } }"
|
|
31
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
31
|
+
class="af-add-new-button flex items-center py-1 px-3 text-sm font-medium text-lightShowViewButtonText focus:outline-none bg-lightShowViewButtonBackground rounded border border-lightShowViewButtonBorder hover:bg-lightShowViewButtonBackgroundHover hover:text-lightShowViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightShowViewButtonFocusRing dark:focus:ring-darkShowViewButtonFocusRing dark:bg-darkShowViewButtonBackground dark:text-darkShowViewButtonText dark:border-darkShowViewButtonBorder dark:hover:text-darkShowViewButtonTextHover dark:hover:bg-darkShowViewButtonBackgroundHover rounded-default gap-1"
|
|
32
32
|
>
|
|
33
|
-
<IconPlusOutline class="w-4 h-4
|
|
33
|
+
<IconPlusOutline class="w-4 h-4"/>
|
|
34
34
|
{{ $t('Add new') }}
|
|
35
35
|
</RouterLink>
|
|
36
36
|
|
|
37
37
|
<RouterLink v-if="coreStore?.resourceOptions?.allowedActions?.edit" :to="{ name: 'resource-edit', params: { resourceId: $route.params.resourceId, primaryKey: $route.params.primaryKey } }"
|
|
38
|
-
class="flex items-center py-1 px-3 text-sm font-medium text-
|
|
38
|
+
class="flex items-center af-edit-button py-1 px-3 text-sm font-medium text-lightShowViewButtonText focus:outline-none bg-lightShowViewButtonBackground rounded-default border border-lightShowViewButtonBorder hover:bg-lightShowViewButtonBackgroundHover hover:text-lightShowViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightShowViewButtonFocusRing dark:focus:ring-darkShowViewButtonFocusRing dark:bg-darkShowViewButtonBackground dark:text-darkShowViewButtonText dark:border-darkShowViewButtonBorder dark:hover:text-darkShowViewButtonTextHover dark:hover:bg-darkShowViewButtonBackgroundHover gap-1"
|
|
39
39
|
>
|
|
40
40
|
<IconPenSolid class="w-4 h-4" />
|
|
41
41
|
{{ $t('Edit') }}
|
|
42
42
|
</RouterLink>
|
|
43
43
|
|
|
44
44
|
<button v-if="coreStore?.resourceOptions?.allowedActions?.delete" @click="deleteRecord"
|
|
45
|
-
class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-
|
|
45
|
+
class="flex items-center af-delete-button py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-lightShowViewButtonBackground border border-lightShowViewButtonBorder hover:bg-lightShowViewButtonBackgroundHover hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-lightShowViewButtonFocusRing dark:focus:ring-darkShowViewButtonFocusRing dark:bg-darkShowViewButtonBackground dark:text-red-500 dark:border-darkShowViewButtonBorder dark:hover:text-darkShowViewButtonTextHover dark:hover:bg-darkShowViewButtonBackgroundHover gap-1"
|
|
46
46
|
>
|
|
47
47
|
<IconTrashBinSolid class="w-4 h-4" />
|
|
48
48
|
{{ $t('Delete') }}
|
|
49
49
|
</button>
|
|
50
50
|
|
|
51
51
|
<ThreeDotsMenu
|
|
52
|
-
:threeDotsDropdownItems="coreStore.resourceOptions?.pageInjections?.show?.threeDotsDropdownItems"
|
|
52
|
+
:threeDotsDropdownItems="(coreStore.resourceOptions?.pageInjections?.show?.threeDotsDropdownItems as [])"
|
|
53
53
|
:customActions="customActions"
|
|
54
54
|
></ThreeDotsMenu>
|
|
55
55
|
</BreadcrumbsWithButtons>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
<component
|
|
58
58
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.afterBreadcrumbs || []"
|
|
59
59
|
:is="getCustomComponent(c)"
|
|
60
|
-
:meta="c.meta"
|
|
60
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
61
61
|
:record="coreStore.record"
|
|
62
62
|
:resource="coreStore.resource"
|
|
63
63
|
:adminUser="coreStore.adminUser"
|
|
@@ -76,11 +76,11 @@
|
|
|
76
76
|
v-else-if="coreStore.record"
|
|
77
77
|
class="relative w-full flex flex-col gap-4"
|
|
78
78
|
>
|
|
79
|
-
<div v-if="!groups.length && allColumns
|
|
79
|
+
<div v-if="!groups.length && allColumns?.length">
|
|
80
80
|
<ShowTable
|
|
81
|
-
:columns="allColumns"
|
|
82
81
|
:resource="coreStore.resource"
|
|
83
82
|
:record="coreStore.record"
|
|
83
|
+
:columns="allColumns as Array<{ name: string; label?: string; components?: any }>"
|
|
84
84
|
/>
|
|
85
85
|
</div>
|
|
86
86
|
<template v-else>
|
|
@@ -93,12 +93,12 @@
|
|
|
93
93
|
:record="coreStore.record"
|
|
94
94
|
/>
|
|
95
95
|
</template>
|
|
96
|
-
<template v-if="otherColumns.length > 0">
|
|
96
|
+
<template v-if="otherColumns && otherColumns.length > 0">
|
|
97
97
|
<ShowTable
|
|
98
|
-
:columns="otherColumns"
|
|
99
98
|
groupName="Other Fields"
|
|
100
99
|
:resource="coreStore.resource"
|
|
101
100
|
:record="coreStore.record"
|
|
101
|
+
:columns="otherColumns as Array<{ name: string; label?: string; components?: any }>"
|
|
102
102
|
/>
|
|
103
103
|
</template>
|
|
104
104
|
</template>
|
|
@@ -112,8 +112,7 @@
|
|
|
112
112
|
v-if="!loading"
|
|
113
113
|
v-for="c in coreStore?.resourceOptions?.pageInjections?.show?.bottom || []"
|
|
114
114
|
:is="getCustomComponent(c)"
|
|
115
|
-
:meta="c.meta"
|
|
116
|
-
:column="column"
|
|
115
|
+
:meta="(c as AdminForthComponentDeclarationFull).meta"
|
|
117
116
|
:record="coreStore.record"
|
|
118
117
|
:resource="coreStore.resource"
|
|
119
118
|
:adminUser="coreStore.adminUser"
|
|
@@ -140,6 +139,7 @@ import ShowTable from '@/components/ShowTable.vue';
|
|
|
140
139
|
import adminforth from "@/adminforth";
|
|
141
140
|
import { useI18n } from 'vue-i18n';
|
|
142
141
|
import { getIcon } from '@/utils';
|
|
142
|
+
import { type AdminForthComponentDeclarationFull, type AdminForthResourceColumnCommon, type FieldGroup } from '@/types/Common.js';
|
|
143
143
|
|
|
144
144
|
const route = useRoute();
|
|
145
145
|
const router = useRouter();
|
|
@@ -147,62 +147,65 @@ const loading = ref(true);
|
|
|
147
147
|
const { t } = useI18n();
|
|
148
148
|
const coreStore = useCoreStore();
|
|
149
149
|
|
|
150
|
-
const actionLoadingStates = ref({});
|
|
150
|
+
const actionLoadingStates = ref<Record<string, boolean>>({});
|
|
151
151
|
|
|
152
152
|
const customActions = computed(() => {
|
|
153
|
-
return coreStore.resource?.options?.actions?.filter(a => a.showIn?.showThreeDotsMenu) || [];
|
|
153
|
+
return coreStore.resource?.options?.actions?.filter((a: any) => a.showIn?.showThreeDotsMenu) || [];
|
|
154
154
|
});
|
|
155
155
|
|
|
156
156
|
onMounted(async () => {
|
|
157
157
|
loading.value = true;
|
|
158
158
|
await coreStore.fetchResourceFull({
|
|
159
|
-
resourceId: route.params.resourceId
|
|
159
|
+
resourceId: route.params.resourceId as string,
|
|
160
160
|
});
|
|
161
161
|
initThreeDotsDropdown();
|
|
162
162
|
await coreStore.fetchRecord({
|
|
163
|
-
resourceId: route.params.resourceId,
|
|
164
|
-
primaryKey: route.params.primaryKey,
|
|
163
|
+
resourceId: route.params.resourceId as string,
|
|
164
|
+
primaryKey: route.params.primaryKey as string,
|
|
165
165
|
source: 'show',
|
|
166
166
|
});
|
|
167
|
-
|
|
167
|
+
if(coreStore.resourceOptions){
|
|
168
|
+
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'show');
|
|
169
|
+
}
|
|
168
170
|
loading.value = false;
|
|
169
171
|
});
|
|
170
172
|
|
|
171
173
|
const groups = computed(() => {
|
|
172
174
|
let fieldGroupType;
|
|
173
|
-
if (coreStore.resource
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
175
|
+
if (coreStore.resource) {
|
|
176
|
+
if (coreStore.resource.options?.showFieldGroups) {
|
|
177
|
+
fieldGroupType = coreStore.resource.options.showFieldGroups;
|
|
178
|
+
} else if (coreStore.resource.options?.showFieldGroups === null) {
|
|
179
|
+
fieldGroupType = [];
|
|
180
|
+
} else {
|
|
181
|
+
fieldGroupType = coreStore.resource.options?.fieldGroups;
|
|
182
|
+
}
|
|
179
183
|
}
|
|
184
|
+
const activeGroups: typeof fieldGroupType | [] = fieldGroupType ?? [];
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return activeGroups.map(group => ({
|
|
186
|
+
return activeGroups.map((group: FieldGroup) => ({
|
|
184
187
|
...group,
|
|
185
|
-
columns: coreStore.resource
|
|
186
|
-
col => group.columns.includes(col.name) && col.showIn
|
|
188
|
+
columns: coreStore.resource?.columns.filter(
|
|
189
|
+
col => group.columns.includes(col.name) && col.showIn?.show
|
|
187
190
|
),
|
|
188
191
|
}));
|
|
189
192
|
});
|
|
190
193
|
|
|
191
194
|
const allColumns = computed(() => {
|
|
192
|
-
return coreStore.resource
|
|
195
|
+
return coreStore.resource?.columns.filter(col => col.showIn?.show);
|
|
193
196
|
});
|
|
194
197
|
|
|
195
198
|
const otherColumns = computed(() => {
|
|
196
199
|
const groupedColumnNames = new Set(
|
|
197
|
-
groups.value.flatMap(group => group.columns.map(col => col.name))
|
|
200
|
+
groups.value.flatMap(group => group.columns.map((col: AdminForthResourceColumnCommon) => col.name))
|
|
198
201
|
);
|
|
199
202
|
|
|
200
|
-
return coreStore.resource
|
|
201
|
-
col => !groupedColumnNames.has(col.name) && col.showIn
|
|
203
|
+
return coreStore.resource?.columns.filter(
|
|
204
|
+
col => !groupedColumnNames.has(col.name) && col.showIn?.show
|
|
202
205
|
);
|
|
203
206
|
});
|
|
204
207
|
|
|
205
|
-
async function deleteRecord(
|
|
208
|
+
async function deleteRecord() {
|
|
206
209
|
const data = await adminforth.confirm({
|
|
207
210
|
message: t('Are you sure you want to delete this item?'),
|
|
208
211
|
yes: t('Delete'),
|
|
@@ -231,7 +234,7 @@ async function deleteRecord(row) {
|
|
|
231
234
|
|
|
232
235
|
}
|
|
233
236
|
|
|
234
|
-
async function startCustomAction(actionId) {
|
|
237
|
+
async function startCustomAction(actionId: string) {
|
|
235
238
|
actionLoadingStates.value[actionId] = true;
|
|
236
239
|
|
|
237
240
|
const data = await callAdminForthApi({
|
|
@@ -263,8 +266,8 @@ async function startCustomAction(actionId) {
|
|
|
263
266
|
|
|
264
267
|
if (data?.ok) {
|
|
265
268
|
await coreStore.fetchRecord({
|
|
266
|
-
resourceId: route.params.resourceId,
|
|
267
|
-
primaryKey: route.params.primaryKey,
|
|
269
|
+
resourceId: route.params.resourceId as string,
|
|
270
|
+
primaryKey: route.params.primaryKey as string,
|
|
268
271
|
source: 'show',
|
|
269
272
|
});
|
|
270
273
|
|
|
@@ -281,4 +284,21 @@ async function startCustomAction(actionId) {
|
|
|
281
284
|
}
|
|
282
285
|
}
|
|
283
286
|
|
|
287
|
+
adminforth.show.refresh = () => {
|
|
288
|
+
(async () => {
|
|
289
|
+
try {
|
|
290
|
+
loading.value = true;
|
|
291
|
+
await coreStore.fetchRecord({
|
|
292
|
+
resourceId: String(route.params.resourceId),
|
|
293
|
+
primaryKey: String(route.params.primaryKey),
|
|
294
|
+
source: 'show',
|
|
295
|
+
});
|
|
296
|
+
} catch (e) {
|
|
297
|
+
showErrorTost((e as Error).message);
|
|
298
|
+
} finally {
|
|
299
|
+
loading.value = false;
|
|
300
|
+
}
|
|
301
|
+
})();
|
|
302
|
+
}
|
|
303
|
+
|
|
284
304
|
</script>
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
|
|
2
2
|
const subscriptions: { [topic: string]: ((data: any) => void)[] } = {};
|
|
3
|
+
|
|
4
|
+
interface ExtendedWebSocket extends WebSocket {
|
|
5
|
+
connected?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
3
8
|
const state: {
|
|
4
9
|
status: 'connecting' | 'connected' | 'disconnected';
|
|
5
|
-
ws:
|
|
10
|
+
ws: ExtendedWebSocket | null;
|
|
6
11
|
} = {
|
|
7
12
|
status: 'connecting',
|
|
8
13
|
ws: null
|
package/dist/spa/vite.config.ts
CHANGED
|
@@ -1,18 +1,60 @@
|
|
|
1
1
|
import { fileURLToPath, URL } from 'node:url'
|
|
2
|
-
|
|
3
2
|
import { defineConfig } from 'vite'
|
|
4
3
|
import vue from '@vitejs/plugin-vue'
|
|
5
4
|
import portfinder from 'portfinder';
|
|
5
|
+
import { Plugin } from 'vite';
|
|
6
|
+
import tailwindcss from 'tailwindcss';
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Find the next available port after a specified port.
|
|
9
11
|
* @param {number} startPort - The starting port to check.
|
|
10
12
|
* @returns {Promise<number>} - A promise that resolves with the next available port.
|
|
11
13
|
*/
|
|
12
|
-
async function getNextAvailablePort(startPort) {
|
|
14
|
+
async function getNextAvailablePort(startPort: number | undefined) {
|
|
13
15
|
return await portfinder.getPortPromise({ port: startPort });
|
|
14
16
|
};
|
|
15
17
|
|
|
18
|
+
function ignoreTailwindErrors(): Plugin {
|
|
19
|
+
return {
|
|
20
|
+
name: 'ignore-tailwind-errors',
|
|
21
|
+
configureServer(server) {
|
|
22
|
+
server.middlewares.use((req, res, next) => {
|
|
23
|
+
const originalWrite = res.write;
|
|
24
|
+
res.write = function(chunk) {
|
|
25
|
+
if (typeof chunk === 'string' && chunk.includes('tailwind')) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return originalWrite.call(this, chunk);
|
|
29
|
+
};
|
|
30
|
+
next();
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
config(config, { command }) {
|
|
34
|
+
if (command === 'build') {
|
|
35
|
+
// Override PostCSS config for build
|
|
36
|
+
config.css = config.css || {};
|
|
37
|
+
config.css.postcss = {
|
|
38
|
+
plugins: [
|
|
39
|
+
{
|
|
40
|
+
postcssPlugin: 'ignore-tailwind-errors',
|
|
41
|
+
Once(root, helpers) {
|
|
42
|
+
try {
|
|
43
|
+
return tailwindcss()(root, helpers);
|
|
44
|
+
} catch (error: any) {
|
|
45
|
+
console.warn('TailwindCSS warning ignored:', error.message);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
16
58
|
const appPort = await getNextAvailablePort(5173);
|
|
17
59
|
const hmrPort = await getNextAvailablePort(5273);
|
|
18
60
|
console.log(`SPA port: ${appPort}. HMR port: ${hmrPort}`);
|
|
@@ -27,6 +69,7 @@ export default defineConfig({
|
|
|
27
69
|
},
|
|
28
70
|
},
|
|
29
71
|
plugins: [
|
|
72
|
+
//ignoreTailwindErrors(),
|
|
30
73
|
vue(),
|
|
31
74
|
],
|
|
32
75
|
resolve: {
|
package/dist/types/Back.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
-
import type { Express } from 'express';
|
|
2
|
+
import type { Express, Request } from 'express';
|
|
3
3
|
import type { Writable } from 'stream';
|
|
4
|
-
import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum, type AdminForthComponentDeclaration, type AdminUser, type AllowedActionsResolved, type AdminForthBulkActionCommon, type AdminForthForeignResourceCommon, type AdminForthResourceColumnCommon, AdminForthResourceInputCommon, AdminForthComponentDeclarationFull, AdminForthConfigMenuItem, AnnouncementBadgeResponse, AdminForthResourcePages, AdminForthResourceColumnInputCommon } from './Common.js';
|
|
4
|
+
import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum, type AdminForthComponentDeclaration, type AdminUser, type AllowedActionsResolved, type AdminForthBulkActionCommon, type AdminForthForeignResourceCommon, type AdminForthResourceColumnCommon, type AdminForthResourceInputCommon, type AdminForthComponentDeclarationFull, type AdminForthConfigMenuItem, type AnnouncementBadgeResponse, AdminForthResourcePages, type AdminForthResourceColumnInputCommon } from './Common.js';
|
|
5
5
|
export interface ICodeInjector {
|
|
6
6
|
srcFoldersToSync: Object;
|
|
7
7
|
allComponentNames: Object;
|
|
@@ -62,23 +62,34 @@ export interface IExpressHttpServer extends IHttpServer {
|
|
|
62
62
|
* Adds adminUser to request object if user is authorized. Drops request with 401 status if user is not authorized.
|
|
63
63
|
* @param callable : Function which will be called if user is authorized.
|
|
64
64
|
*
|
|
65
|
-
* Example:
|
|
66
65
|
*
|
|
66
|
+
* @example
|
|
67
67
|
* ```ts
|
|
68
|
-
* expressApp.get('/myApi', authorize((req, res) =>
|
|
68
|
+
* expressApp.get('/myApi', authorize((req, res) => {
|
|
69
69
|
* console.log('User is authorized', req.adminUser);
|
|
70
|
-
* res.json(
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* res.json({ message: 'Hello World' });
|
|
71
|
+
* }));
|
|
72
|
+
* ```
|
|
73
73
|
*
|
|
74
74
|
*/
|
|
75
75
|
authorize(callable: Function): void;
|
|
76
76
|
}
|
|
77
|
+
export interface ITranslateFunction {
|
|
78
|
+
(msg: string, category: string, params: any, pluralizationNumber?: number): Promise<string>;
|
|
79
|
+
}
|
|
80
|
+
export interface IAdminUserExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
81
|
+
adminUser: AdminUser;
|
|
82
|
+
}
|
|
83
|
+
export interface ITranslateExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
|
|
84
|
+
tr: ITranslateFunction;
|
|
85
|
+
}
|
|
77
86
|
export interface IAdminForthSingleFilter {
|
|
78
87
|
field?: string;
|
|
79
88
|
operator?: AdminForthFilterOperators.EQ | AdminForthFilterOperators.NE | AdminForthFilterOperators.GT | AdminForthFilterOperators.LT | AdminForthFilterOperators.GTE | AdminForthFilterOperators.LTE | AdminForthFilterOperators.LIKE | AdminForthFilterOperators.ILIKE | AdminForthFilterOperators.IN | AdminForthFilterOperators.NIN;
|
|
80
89
|
value?: any;
|
|
90
|
+
rightField?: string;
|
|
81
91
|
insecureRawSQL?: string;
|
|
92
|
+
insecureRawNoSQL?: any;
|
|
82
93
|
}
|
|
83
94
|
export interface IAdminForthAndOrFilter {
|
|
84
95
|
operator: AdminForthFilterOperators.AND | AdminForthFilterOperators.OR;
|
|
@@ -315,6 +326,7 @@ export interface IAdminForth {
|
|
|
315
326
|
}): Promise<{
|
|
316
327
|
error?: string;
|
|
317
328
|
createdRecord?: any;
|
|
329
|
+
newRecordId?: any;
|
|
318
330
|
}>;
|
|
319
331
|
updateResourceRecord(params: {
|
|
320
332
|
resource: AdminForthResource;
|
|
@@ -451,6 +463,7 @@ export type BeforeDataSourceRequestFunction = (params: {
|
|
|
451
463
|
}) => Promise<{
|
|
452
464
|
ok: boolean;
|
|
453
465
|
error?: string;
|
|
466
|
+
newRecordId?: string;
|
|
454
467
|
}>;
|
|
455
468
|
/**
|
|
456
469
|
* Modify response to change how data is returned after fetching from database.
|
|
@@ -509,7 +522,7 @@ export type BeforeEditSaveFunction = (params: {
|
|
|
509
522
|
extra?: HttpExtra;
|
|
510
523
|
}) => Promise<{
|
|
511
524
|
ok: boolean;
|
|
512
|
-
error?: string;
|
|
525
|
+
error?: string | null;
|
|
513
526
|
}>;
|
|
514
527
|
export type BeforeCreateSaveFunction = (params: {
|
|
515
528
|
resource: AdminForthResource;
|
|
@@ -519,7 +532,8 @@ export type BeforeCreateSaveFunction = (params: {
|
|
|
519
532
|
extra?: HttpExtra;
|
|
520
533
|
}) => Promise<{
|
|
521
534
|
ok: boolean;
|
|
522
|
-
error?: string;
|
|
535
|
+
error?: string | null;
|
|
536
|
+
newRecordId?: string;
|
|
523
537
|
}>;
|
|
524
538
|
export type AfterCreateSaveFunction = (params: {
|
|
525
539
|
resource: AdminForthResource;
|
|
@@ -602,11 +616,20 @@ interface AdminForthInputConfigCustomization {
|
|
|
602
616
|
* Your app name
|
|
603
617
|
*/
|
|
604
618
|
brandName?: string;
|
|
619
|
+
/**
|
|
620
|
+
* Whether to use single theme for the app
|
|
621
|
+
*/
|
|
622
|
+
singleTheme?: 'light' | 'dark';
|
|
605
623
|
/**
|
|
606
624
|
* Whether to show brand name in sidebar
|
|
607
625
|
* default is true
|
|
608
626
|
*/
|
|
609
627
|
showBrandNameInSidebar?: boolean;
|
|
628
|
+
/**
|
|
629
|
+
* Whether to show brand logo in sidebar
|
|
630
|
+
* default is true
|
|
631
|
+
*/
|
|
632
|
+
showBrandLogoInSidebar?: boolean;
|
|
610
633
|
/**
|
|
611
634
|
* Path to your app logo
|
|
612
635
|
*
|
|
@@ -727,8 +750,17 @@ interface AdminForthInputConfigCustomization {
|
|
|
727
750
|
userMenu?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>;
|
|
728
751
|
header?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>;
|
|
729
752
|
sidebar?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>;
|
|
753
|
+
sidebarTop?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>;
|
|
730
754
|
everyPageBottom?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>;
|
|
731
755
|
};
|
|
756
|
+
/**
|
|
757
|
+
* Allows adding custom elements (e.g., <link>, <script>, <meta>) to the <head> of the HTML document.
|
|
758
|
+
* Each item must include a tag name and a set of attributes.
|
|
759
|
+
*/
|
|
760
|
+
customHeadItems?: {
|
|
761
|
+
tagName: string;
|
|
762
|
+
attributes: Record<string, string | boolean>;
|
|
763
|
+
}[];
|
|
732
764
|
}
|
|
733
765
|
export interface AdminForthActionInput {
|
|
734
766
|
name: string;
|
|
@@ -885,6 +917,12 @@ export interface AdminForthInputConfig {
|
|
|
885
917
|
* Default: '1/2'
|
|
886
918
|
*/
|
|
887
919
|
loginBackgroundPosition?: 'over' | '1/2' | '1/3' | '2/3' | '3/4' | '2/5' | '3/5';
|
|
920
|
+
/**
|
|
921
|
+
* If true, background blend mode will be removed from login background image when position is 'over'
|
|
922
|
+
*
|
|
923
|
+
* Default: false
|
|
924
|
+
*/
|
|
925
|
+
removeBackgroundBlendMode?: boolean;
|
|
888
926
|
/**
|
|
889
927
|
* Function or functions which will be called before user try to login.
|
|
890
928
|
* Each function will resive User object as an argument
|
|
@@ -903,7 +941,7 @@ export interface AdminForthInputConfig {
|
|
|
903
941
|
/**
|
|
904
942
|
* Any prompt to show users on login. Supports HTML.
|
|
905
943
|
*/
|
|
906
|
-
loginPromptHTML?: string;
|
|
944
|
+
loginPromptHTML?: string | (() => string | void | undefined | Promise<string | void | undefined>) | undefined;
|
|
907
945
|
/**
|
|
908
946
|
* Remember me days for "Remember Me" checkbox on login page.
|
|
909
947
|
* If not set or set to null/0/undefined, "Remember Me" checkbox will not be displayed.
|
|
@@ -991,8 +1029,13 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
|
|
|
991
1029
|
userMenu: Array<AdminForthComponentDeclarationFull>;
|
|
992
1030
|
header: Array<AdminForthComponentDeclarationFull>;
|
|
993
1031
|
sidebar: Array<AdminForthComponentDeclarationFull>;
|
|
1032
|
+
sidebarTop: Array<AdminForthComponentDeclarationFull>;
|
|
994
1033
|
everyPageBottom: Array<AdminForthComponentDeclarationFull>;
|
|
995
1034
|
};
|
|
1035
|
+
customHeadItems?: {
|
|
1036
|
+
tagName: string;
|
|
1037
|
+
attributes: Record<string, string | boolean>;
|
|
1038
|
+
}[];
|
|
996
1039
|
}
|
|
997
1040
|
export interface AdminForthConfig extends Omit<AdminForthInputConfig, 'customization' | 'resources'> {
|
|
998
1041
|
baseUrl: string;
|
|
@@ -1011,6 +1054,11 @@ export declare class Filters {
|
|
|
1011
1054
|
static IN(field: string, value: any): IAdminForthSingleFilter;
|
|
1012
1055
|
static NOT_IN(field: string, value: any): IAdminForthSingleFilter;
|
|
1013
1056
|
static LIKE(field: string, value: any): IAdminForthSingleFilter;
|
|
1057
|
+
static ILIKE(field: string, value: any): IAdminForthSingleFilter;
|
|
1058
|
+
static GT_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter;
|
|
1059
|
+
static GTE_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter;
|
|
1060
|
+
static LT_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter;
|
|
1061
|
+
static LTE_FIELD(leftField: string, rightField: string): IAdminForthSingleFilter;
|
|
1014
1062
|
static AND(...args: (IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter>)[]): IAdminForthAndOrFilter;
|
|
1015
1063
|
static OR(...args: (IAdminForthSingleFilter | IAdminForthAndOrFilter | Array<IAdminForthSingleFilter | IAdminForthAndOrFilter>)[]): IAdminForthAndOrFilter;
|
|
1016
1064
|
}
|
|
@@ -1166,9 +1214,13 @@ export interface AdminForthResource extends Omit<AdminForthResourceInput, 'optio
|
|
|
1166
1214
|
};
|
|
1167
1215
|
create?: {
|
|
1168
1216
|
/**
|
|
1217
|
+
* Should return `ok: true` to continue saving pipeline and allow creating record in database, and `ok: false` to interrupt pipeline and prevent record creation.
|
|
1218
|
+
* If you need to show error on UI, set `error: \<error message\>` in response.
|
|
1219
|
+
*
|
|
1169
1220
|
* Typical use-cases:
|
|
1170
|
-
* -
|
|
1171
|
-
* -
|
|
1221
|
+
* - Create record by custom code (return `{ ok: false, newRecordId: <id of created record from custom code> }`)
|
|
1222
|
+
* - Validate record before saving to database and interrupt execution if validation failed (return `{ ok: false, error: <validation error> }`), though `allowedActions.create` should be preferred in most cases
|
|
1223
|
+
* - fill-in adminUser as creator of record (set `record.<some field> = x; return \{ ok: true \}`)
|
|
1172
1224
|
* - Attach additional data to record before saving to database (mostly fillOnCreate should be used instead)
|
|
1173
1225
|
*/
|
|
1174
1226
|
beforeSave?: Array<BeforeCreateSaveFunction>;
|
|
@@ -1306,13 +1358,22 @@ export type ShowInInput = ShowInModernInput | ShowInLegacyInput;
|
|
|
1306
1358
|
export type ShowIn = {
|
|
1307
1359
|
[key in AdminForthResourcePages]: AllowedActionValue;
|
|
1308
1360
|
};
|
|
1309
|
-
export
|
|
1361
|
+
export type BackendOnlyInput = boolean | ((p: {
|
|
1362
|
+
adminUser: AdminUser;
|
|
1363
|
+
resource: AdminForthResource;
|
|
1364
|
+
meta: any;
|
|
1365
|
+
source: ActionCheckSource;
|
|
1366
|
+
adminforth: IAdminForth;
|
|
1367
|
+
}) => boolean | Promise<boolean>);
|
|
1368
|
+
export interface AdminForthResourceColumnInput extends Omit<AdminForthResourceColumnInputCommon, 'showIn' | 'backendOnly'> {
|
|
1310
1369
|
showIn?: ShowInInput;
|
|
1311
1370
|
foreignResource?: AdminForthForeignResource;
|
|
1371
|
+
backendOnly?: BackendOnlyInput;
|
|
1312
1372
|
}
|
|
1313
|
-
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn'> {
|
|
1373
|
+
export interface AdminForthResourceColumn extends Omit<AdminForthResourceColumnCommon, 'showIn' | 'backendOnly'> {
|
|
1314
1374
|
showIn?: ShowIn;
|
|
1315
1375
|
foreignResource?: AdminForthForeignResource;
|
|
1376
|
+
backendOnly?: BackendOnlyInput;
|
|
1316
1377
|
}
|
|
1317
1378
|
export interface IWebSocketClient {
|
|
1318
1379
|
id: string;
|