adminforth 1.1.5 → 1.1.6
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/spa/spa/src/components/ResourceForm.vue +3 -3
- package/dist/spa/spa/src/components/ResourceListTable.vue +8 -2
- package/dist/spa/spa/src/composables/useStores.ts +3 -2
- package/dist/spa/spa/src/stores/core.ts +12 -13
- package/dist/spa/spa/src/views/CreateView.vue +17 -8
- package/dist/spa/spa/src/views/EditView.vue +3 -3
- package/dist/spa/spa/src/views/ListView.vue +4 -2
- package/dist/spa/spa/src/views/ShowView.vue +2 -2
- package/package.json +1 -1
- package/plugins/ForeignInlineListPlugin/custom/InlineList.vue +41 -9
- package/spa/src/components/ResourceForm.vue +3 -3
- package/spa/src/components/ResourceListTable.vue +8 -2
- package/spa/src/composables/useStores.ts +3 -2
- package/spa/src/stores/core.ts +12 -13
- package/spa/src/views/CreateView.vue +17 -8
- package/spa/src/views/EditView.vue +3 -3
- package/spa/src/views/ListView.vue +4 -2
- package/spa/src/views/ShowView.vue +2 -2
|
@@ -152,7 +152,7 @@ const router = useRouter();
|
|
|
152
152
|
|
|
153
153
|
const props = defineProps({
|
|
154
154
|
loading: Boolean,
|
|
155
|
-
|
|
155
|
+
resource: Object,
|
|
156
156
|
record: Object,
|
|
157
157
|
validating: Boolean,
|
|
158
158
|
customComponentsPerColumn: Object,
|
|
@@ -228,7 +228,7 @@ onMounted(() => {
|
|
|
228
228
|
|
|
229
229
|
const columnOptions = computedAsync(async () => {
|
|
230
230
|
return (await Promise.all(
|
|
231
|
-
Object.values(props.
|
|
231
|
+
Object.values(props.resource.columns).map(async (column) => {
|
|
232
232
|
if (column.foreignResource) {
|
|
233
233
|
const list = await callAdminForthApi({
|
|
234
234
|
method: 'POST',
|
|
@@ -251,7 +251,7 @@ const coreStore = useCoreStore();
|
|
|
251
251
|
|
|
252
252
|
const editableColumns = computed(() => {
|
|
253
253
|
const mode = props.record ? 'edit' : 'create';
|
|
254
|
-
return props.
|
|
254
|
+
return props.resource?.columns?.filter(column => column.showIn.includes(mode));
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
const isValid = computed(() => {
|
|
@@ -146,7 +146,13 @@
|
|
|
146
146
|
<div class="flex">
|
|
147
147
|
<RouterLink
|
|
148
148
|
v-if="resource.options?.allowedActions.show"
|
|
149
|
-
:to="{
|
|
149
|
+
:to="{
|
|
150
|
+
name: 'resource-show',
|
|
151
|
+
params: {
|
|
152
|
+
resourceId: resource.resourceId,
|
|
153
|
+
primaryKey: row._primaryKeyValue,
|
|
154
|
+
}
|
|
155
|
+
}"
|
|
150
156
|
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
|
151
157
|
:data-tooltip-target="`tooltip-show-${rowI}`"
|
|
152
158
|
>
|
|
@@ -164,7 +170,7 @@
|
|
|
164
170
|
:to="{
|
|
165
171
|
name: 'resource-edit',
|
|
166
172
|
params: {
|
|
167
|
-
resourceId: resource.
|
|
173
|
+
resourceId: resource.resourceId,
|
|
168
174
|
primaryKey: row._primaryKeyValue
|
|
169
175
|
}
|
|
170
176
|
}"
|
|
@@ -4,6 +4,7 @@ import { useModalStore } from '../stores/modal';
|
|
|
4
4
|
import { useCoreStore } from '@/stores/core';
|
|
5
5
|
import { useFiltersStore } from '@/stores/filters';
|
|
6
6
|
import router from '@/router'
|
|
7
|
+
import type { AdminForthResourceColumn } from '@/types/AdminForthConfig';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
|
|
@@ -65,7 +66,7 @@ export class FrontendAPI implements FrontendAPIInterface {
|
|
|
65
66
|
} else {
|
|
66
67
|
if(!this.coreStore) this.coreStore = useCoreStore()
|
|
67
68
|
console.log(this.coreStore.resourceColumnsWithFilters,'core store')
|
|
68
|
-
const filterField = this.coreStore.resourceColumnsWithFilters.find((col) => col.name === filter.field)
|
|
69
|
+
const filterField = this.coreStore.resourceColumnsWithFilters.find((col: AdminForthResourceColumn) => col.name === filter.field)
|
|
69
70
|
if(!filterField){
|
|
70
71
|
throw new Error(`Field ${filter.field} is not available for filtering`)
|
|
71
72
|
}
|
|
@@ -97,7 +98,7 @@ export class FrontendAPI implements FrontendAPIInterface {
|
|
|
97
98
|
updateListFilter(filter: FilterParams): void {
|
|
98
99
|
if(this.listFilterValidation(filter)){
|
|
99
100
|
this.filtersStore = useFiltersStore()
|
|
100
|
-
const index = this.filtersStore.filters.findIndex((f) => f.field === filter.field)
|
|
101
|
+
const index = this.filtersStore.filters.findIndex((f: FilterParams) => f.field === filter.field)
|
|
101
102
|
if(index === -1) {
|
|
102
103
|
this.filtersStore.setFilter(filter)
|
|
103
104
|
} else {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { ref, computed } from 'vue'
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { callAdminForthApi } from '@/utils';
|
|
4
|
+
import type { AdminForthResource, AdminForthResourceColumn } from '@/types/AdminForthConfig';
|
|
5
|
+
import type { Ref } from 'vue'
|
|
4
6
|
|
|
5
7
|
export const useCoreStore = defineStore('core', () => {
|
|
6
|
-
const resourceById = ref(
|
|
8
|
+
const resourceById: Ref<Object> = ref({});
|
|
7
9
|
const menu = ref([]);
|
|
8
10
|
const config = ref({});
|
|
9
11
|
const record = ref({});
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
+
const resource: Ref<AdminForthResource | null> = ref(null);
|
|
13
|
+
|
|
12
14
|
const resourceColumnsWithFilters = computed(() => {
|
|
13
|
-
if (!
|
|
15
|
+
if (!resource.value) {
|
|
14
16
|
return [];
|
|
15
17
|
}
|
|
16
|
-
return
|
|
18
|
+
return resource.value.columns.filter((col: AdminForthResourceColumn) => col.showIn?.includes('filter'));
|
|
17
19
|
})
|
|
18
20
|
|
|
19
21
|
const resourceOptions = ref(null);
|
|
@@ -30,7 +32,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
30
32
|
return
|
|
31
33
|
}
|
|
32
34
|
menu.value = resp.menu;
|
|
33
|
-
resourceById.value = resp.resources.reduce((acc, resource) => {
|
|
35
|
+
resourceById.value = resp.resources.reduce((acc: Object, resource: AdminForthResource) => {
|
|
34
36
|
acc[resource.resourceId] = resource;
|
|
35
37
|
return acc;
|
|
36
38
|
}, {});
|
|
@@ -42,7 +44,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
42
44
|
async function fetchRecord({ resourceId, primaryKey }) {
|
|
43
45
|
record.value = null;
|
|
44
46
|
|
|
45
|
-
if (!
|
|
47
|
+
if (!resource.value) {
|
|
46
48
|
throw new Error('Columns not fetched yet');
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -54,7 +56,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
54
56
|
resourceId: resourceId,
|
|
55
57
|
filters: [
|
|
56
58
|
{
|
|
57
|
-
field:
|
|
59
|
+
field: resource.value.columns.find((col: AdminForthResourceColumn) => col.primaryKey).name,
|
|
58
60
|
operator: 'eq',
|
|
59
61
|
value: primaryKey
|
|
60
62
|
}
|
|
@@ -70,13 +72,12 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
70
72
|
resourceOptions.value = respData.options;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
async function fetchResourceFull({ resourceId }) {
|
|
74
|
-
if (resourceColumnsId.value === resourceId &&
|
|
75
|
+
async function fetchResourceFull({ resourceId }: { resourceId: string }) {
|
|
76
|
+
if (resourceColumnsId.value === resourceId && resource.value) {
|
|
75
77
|
// already fetched
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
resourceColumnsId.value = resourceId;
|
|
79
|
-
resourceColumns.value = null;
|
|
80
81
|
resourceColumnsError.value = '';
|
|
81
82
|
const res = await callAdminForthApi({
|
|
82
83
|
path: '/get_resource',
|
|
@@ -88,7 +89,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
88
89
|
if (res.error) {
|
|
89
90
|
resourceColumnsError.value = res.error;
|
|
90
91
|
} else {
|
|
91
|
-
resourceColumns.value = res.resource.columns;
|
|
92
92
|
resourceById.value[resourceId] = res.resource;
|
|
93
93
|
resource.value = res.resource;
|
|
94
94
|
resourceOptions.value = res.resource.options;
|
|
@@ -131,7 +131,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
131
131
|
fetchMenuAndResource,
|
|
132
132
|
fetchRecord,
|
|
133
133
|
record,
|
|
134
|
-
resourceColumns,
|
|
135
134
|
fetchResourceFull,
|
|
136
135
|
resourceColumnsError,
|
|
137
136
|
resourceOptions,
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<ResourceForm
|
|
47
47
|
v-else
|
|
48
48
|
:record="initalValues"
|
|
49
|
-
:
|
|
49
|
+
:resource="coreStore.resource"
|
|
50
50
|
@update:record="onUpdateRecord"
|
|
51
51
|
@update:isValid="isValid = $event"
|
|
52
52
|
:validating="validating"
|
|
@@ -95,7 +95,10 @@ let createComponentsPerColumn = {};
|
|
|
95
95
|
const coreStore = useCoreStore();
|
|
96
96
|
|
|
97
97
|
const initalValues = computed(() => {
|
|
98
|
-
|
|
98
|
+
if (!route.query.values) {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
return JSON.parse(decodeURIComponent(route.query.values));
|
|
99
102
|
});
|
|
100
103
|
|
|
101
104
|
async function onUpdateRecord(newRecord) {
|
|
@@ -108,7 +111,7 @@ onMounted(async () => {
|
|
|
108
111
|
await coreStore.fetchResourceFull({
|
|
109
112
|
resourceId: route.params.resourceId
|
|
110
113
|
});
|
|
111
|
-
createComponentsPerColumn = coreStore.
|
|
114
|
+
createComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
112
115
|
if (column.components?.create) {
|
|
113
116
|
acc[column.name] = getCustomComponent(column.components.create);
|
|
114
117
|
}
|
|
@@ -135,11 +138,17 @@ async function saveRecord() {
|
|
|
135
138
|
},
|
|
136
139
|
});
|
|
137
140
|
saving.value = false;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
if (route.query.returnTo) {
|
|
142
|
+
router.push(route.query.returnTo);
|
|
143
|
+
} else {
|
|
144
|
+
router.push({
|
|
145
|
+
name: 'resource-show',
|
|
146
|
+
params: {
|
|
147
|
+
resourceId: route.params.resourceId,
|
|
148
|
+
primaryKey: response.newRecordId
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
143
152
|
}
|
|
144
153
|
|
|
145
154
|
|
|
@@ -95,10 +95,10 @@ async function onUpdateRecord(newRecord) {
|
|
|
95
95
|
|
|
96
96
|
const editableRecord = computed(() => {
|
|
97
97
|
const newRecord = { ...coreStore.record };
|
|
98
|
-
if (!coreStore.
|
|
98
|
+
if (!coreStore.resource) {
|
|
99
99
|
return {};
|
|
100
100
|
}
|
|
101
|
-
coreStore.
|
|
101
|
+
coreStore.resource.columns.forEach(column => {
|
|
102
102
|
if (column.foreignResource) {
|
|
103
103
|
newRecord[column.name] = newRecord[column.name]?.pk
|
|
104
104
|
}
|
|
@@ -119,7 +119,7 @@ onMounted(async () => {
|
|
|
119
119
|
});
|
|
120
120
|
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'edit');
|
|
121
121
|
|
|
122
|
-
editComponentsPerColumn = coreStore.
|
|
122
|
+
editComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
123
123
|
if (column.components?.edit) {
|
|
124
124
|
acc[column.name] = getCustomComponent(column.components.edit);
|
|
125
125
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<Teleport to="body">
|
|
4
4
|
<Filters
|
|
5
|
-
:columns="coreStore.
|
|
5
|
+
:columns="coreStore.resource.columns"
|
|
6
6
|
:columnsMinMax="columnsMinMax" :show="filtersShow"
|
|
7
7
|
@hide="filtersShow = false"
|
|
8
8
|
/>
|
|
@@ -159,6 +159,8 @@ watch([page], async () => {
|
|
|
159
159
|
|
|
160
160
|
watch(()=>filtersStore.filters, async () => {
|
|
161
161
|
page.value = 1;
|
|
162
|
+
checkboxes.value = [];
|
|
163
|
+
|
|
162
164
|
await getList();
|
|
163
165
|
}, {deep: true});
|
|
164
166
|
|
|
@@ -183,7 +185,7 @@ async function getList() {
|
|
|
183
185
|
});
|
|
184
186
|
|
|
185
187
|
rows.value = data.data?.map(row => {
|
|
186
|
-
row._primaryKeyValue = row[coreStore.
|
|
188
|
+
row._primaryKeyValue = row[coreStore.resource.columns.find(c => c.primaryKey).name];
|
|
187
189
|
return row;
|
|
188
190
|
});
|
|
189
191
|
totalRows.value = data.total;
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
</tr>
|
|
59
59
|
</thead>
|
|
60
60
|
<tbody>
|
|
61
|
-
<tr v-for="column in coreStore.
|
|
61
|
+
<tr v-for="column in coreStore.resource?.columns.filter(c => c.showIn.includes('show'))" :key="column.name"
|
|
62
62
|
class="bg-form-view-bg odd:dark:bg-gray-900 even:dark:bg-gray-800 border-b dark:border-gray-700"
|
|
63
63
|
>
|
|
64
64
|
<component
|
|
@@ -145,7 +145,7 @@ onMounted(async () => {
|
|
|
145
145
|
});
|
|
146
146
|
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'show');
|
|
147
147
|
|
|
148
|
-
showComponentsPerColumn = coreStore.
|
|
148
|
+
showComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
149
149
|
if (column.components?.show) {
|
|
150
150
|
acc[column.name] = getCustomComponent(column.components.show);
|
|
151
151
|
}
|
package/package.json
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
<!-- todo exclude foreign column-->
|
|
4
4
|
<Filters
|
|
5
5
|
v-if="listResource"
|
|
6
|
-
:columns="listResource.columns"
|
|
6
|
+
:columns="listResource.columns.filter((c) => c.name !== listResourceRefColumn.name)"
|
|
7
7
|
v-model:filters="filters"
|
|
8
8
|
:columnsMinMax="columnsMinMax"
|
|
9
9
|
:show="filtersShow"
|
|
10
10
|
@hide="filtersShow = false"
|
|
11
11
|
/>
|
|
12
|
-
{{ listResource?.columns}}
|
|
13
12
|
</Teleport>
|
|
14
13
|
|
|
15
14
|
<td colspan="2">
|
|
@@ -56,23 +55,24 @@
|
|
|
56
55
|
name: 'resource-create',
|
|
57
56
|
params: { resourceId: listResource.resourceId },
|
|
58
57
|
query: {
|
|
59
|
-
[listResourceRefColumn.name]: props.record[selfPrimaryKeyColumn.name]
|
|
60
|
-
|
|
58
|
+
values: encodeURIComponent(JSON.stringify({[listResourceRefColumn.name]: props.record[selfPrimaryKeyColumn.name]})),
|
|
59
|
+
returnTo: $route.fullPath,
|
|
60
|
+
},
|
|
61
61
|
}"
|
|
62
|
-
class="flex items-center py-1 px-3
|
|
62
|
+
class="flex items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 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 rounded-default"
|
|
63
63
|
>
|
|
64
64
|
<IconPlusOutline class="w-4 h-4 me-2"/>
|
|
65
65
|
Create
|
|
66
66
|
</RouterLink>
|
|
67
67
|
|
|
68
68
|
<button
|
|
69
|
-
class="flex gap-1 items-center py-1 px-3
|
|
69
|
+
class="flex gap-1 items-center py-1 px-3 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-blue-700 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 rounded-default"
|
|
70
70
|
@click="()=>{filtersShow = !filtersShow}"
|
|
71
71
|
>
|
|
72
72
|
<IconFilterOutline class="w-4 h-4 me-2"/>
|
|
73
73
|
Filter
|
|
74
74
|
<span
|
|
75
|
-
class="bg-red-100 text-red-800 text-xs font-medium
|
|
75
|
+
class="bg-red-100 text-red-800 text-xs font-medium px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-red-400 border border-red-400"
|
|
76
76
|
v-if="filters.length">
|
|
77
77
|
{{ filters.length }}
|
|
78
78
|
</span>
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
@update:checkboxes="checkboxes = $event"
|
|
89
89
|
:pageSize="pageSize"
|
|
90
90
|
:totalRows="totalRows"
|
|
91
|
+
:checkboxes="checkboxes"
|
|
91
92
|
/>
|
|
92
93
|
</td>
|
|
93
94
|
</template>
|
|
@@ -96,13 +97,15 @@
|
|
|
96
97
|
import { callAdminForthApi } from '@/utils';
|
|
97
98
|
import { ref, onMounted, watch, computed } from 'vue';
|
|
98
99
|
import ResourceListTable from '@/components/ResourceListTable.vue';
|
|
99
|
-
|
|
100
|
+
import Filters from '@/components/Filters.vue';
|
|
100
101
|
import {
|
|
101
102
|
IconBanOutline,
|
|
102
103
|
IconFilterOutline,
|
|
103
104
|
IconPlusOutline,
|
|
104
105
|
} from '@iconify-prerendered/vue-flowbite';
|
|
105
106
|
|
|
107
|
+
import { getIcon } from '@/utils';
|
|
108
|
+
|
|
106
109
|
const props = defineProps(['column', 'record', 'meta', 'resource', 'adminUser']);
|
|
107
110
|
|
|
108
111
|
const listResource = ref(null);
|
|
@@ -118,6 +121,7 @@ const totalRows = ref(0);
|
|
|
118
121
|
|
|
119
122
|
const filters = ref([]);
|
|
120
123
|
const filtersShow = ref(false);
|
|
124
|
+
const columnsMinMax = ref(null);
|
|
121
125
|
|
|
122
126
|
const listResourceRefColumn = computed(() => {
|
|
123
127
|
if (!listResource.value) {
|
|
@@ -164,6 +168,28 @@ watch([sort], async () => {
|
|
|
164
168
|
await getList();
|
|
165
169
|
}, {deep: true});
|
|
166
170
|
|
|
171
|
+
watch([filters], async () => {
|
|
172
|
+
page.value = 1;
|
|
173
|
+
checkboxes.value = [];
|
|
174
|
+
await getList();
|
|
175
|
+
}, {deep: true});
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
async function startBulkAction(actionId) {
|
|
179
|
+
const data = await callAdminForthApi({
|
|
180
|
+
path: '/start_bulk_action',
|
|
181
|
+
method: 'POST',
|
|
182
|
+
body: {
|
|
183
|
+
resourceId: listResource.value.resourceId,
|
|
184
|
+
actionId: actionId,
|
|
185
|
+
recordIds: checkboxes.value
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
if (data?.status === 'success') {
|
|
189
|
+
checkboxes.value = [];
|
|
190
|
+
}
|
|
191
|
+
await getList();
|
|
192
|
+
}
|
|
167
193
|
|
|
168
194
|
async function getList() {
|
|
169
195
|
rows.value = null;
|
|
@@ -188,7 +214,6 @@ async function getList() {
|
|
|
188
214
|
totalRows.value = data.total;
|
|
189
215
|
}
|
|
190
216
|
|
|
191
|
-
|
|
192
217
|
onMounted( async () => {
|
|
193
218
|
loading.value = true;
|
|
194
219
|
const foreighResourceId = props.meta.foreignResourceId;
|
|
@@ -197,6 +222,13 @@ onMounted( async () => {
|
|
|
197
222
|
method: 'POST',
|
|
198
223
|
body: {},
|
|
199
224
|
})).resource;
|
|
225
|
+
columnsMinMax.value = await callAdminForthApi({
|
|
226
|
+
path: '/get_min_max_for_columns',
|
|
227
|
+
method: 'POST',
|
|
228
|
+
body: {
|
|
229
|
+
resourceId: foreighResourceId,
|
|
230
|
+
}
|
|
231
|
+
});
|
|
200
232
|
loading.value = false;
|
|
201
233
|
await getList();
|
|
202
234
|
});
|
|
@@ -152,7 +152,7 @@ const router = useRouter();
|
|
|
152
152
|
|
|
153
153
|
const props = defineProps({
|
|
154
154
|
loading: Boolean,
|
|
155
|
-
|
|
155
|
+
resource: Object,
|
|
156
156
|
record: Object,
|
|
157
157
|
validating: Boolean,
|
|
158
158
|
customComponentsPerColumn: Object,
|
|
@@ -228,7 +228,7 @@ onMounted(() => {
|
|
|
228
228
|
|
|
229
229
|
const columnOptions = computedAsync(async () => {
|
|
230
230
|
return (await Promise.all(
|
|
231
|
-
Object.values(props.
|
|
231
|
+
Object.values(props.resource.columns).map(async (column) => {
|
|
232
232
|
if (column.foreignResource) {
|
|
233
233
|
const list = await callAdminForthApi({
|
|
234
234
|
method: 'POST',
|
|
@@ -251,7 +251,7 @@ const coreStore = useCoreStore();
|
|
|
251
251
|
|
|
252
252
|
const editableColumns = computed(() => {
|
|
253
253
|
const mode = props.record ? 'edit' : 'create';
|
|
254
|
-
return props.
|
|
254
|
+
return props.resource?.columns?.filter(column => column.showIn.includes(mode));
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
const isValid = computed(() => {
|
|
@@ -146,7 +146,13 @@
|
|
|
146
146
|
<div class="flex">
|
|
147
147
|
<RouterLink
|
|
148
148
|
v-if="resource.options?.allowedActions.show"
|
|
149
|
-
:to="{
|
|
149
|
+
:to="{
|
|
150
|
+
name: 'resource-show',
|
|
151
|
+
params: {
|
|
152
|
+
resourceId: resource.resourceId,
|
|
153
|
+
primaryKey: row._primaryKeyValue,
|
|
154
|
+
}
|
|
155
|
+
}"
|
|
150
156
|
class="font-medium text-blue-600 dark:text-blue-500 hover:underline"
|
|
151
157
|
:data-tooltip-target="`tooltip-show-${rowI}`"
|
|
152
158
|
>
|
|
@@ -164,7 +170,7 @@
|
|
|
164
170
|
:to="{
|
|
165
171
|
name: 'resource-edit',
|
|
166
172
|
params: {
|
|
167
|
-
resourceId: resource.
|
|
173
|
+
resourceId: resource.resourceId,
|
|
168
174
|
primaryKey: row._primaryKeyValue
|
|
169
175
|
}
|
|
170
176
|
}"
|
|
@@ -4,6 +4,7 @@ import { useModalStore } from '../stores/modal';
|
|
|
4
4
|
import { useCoreStore } from '@/stores/core';
|
|
5
5
|
import { useFiltersStore } from '@/stores/filters';
|
|
6
6
|
import router from '@/router'
|
|
7
|
+
import type { AdminForthResourceColumn } from '@/types/AdminForthConfig';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
|
|
@@ -65,7 +66,7 @@ export class FrontendAPI implements FrontendAPIInterface {
|
|
|
65
66
|
} else {
|
|
66
67
|
if(!this.coreStore) this.coreStore = useCoreStore()
|
|
67
68
|
console.log(this.coreStore.resourceColumnsWithFilters,'core store')
|
|
68
|
-
const filterField = this.coreStore.resourceColumnsWithFilters.find((col) => col.name === filter.field)
|
|
69
|
+
const filterField = this.coreStore.resourceColumnsWithFilters.find((col: AdminForthResourceColumn) => col.name === filter.field)
|
|
69
70
|
if(!filterField){
|
|
70
71
|
throw new Error(`Field ${filter.field} is not available for filtering`)
|
|
71
72
|
}
|
|
@@ -97,7 +98,7 @@ export class FrontendAPI implements FrontendAPIInterface {
|
|
|
97
98
|
updateListFilter(filter: FilterParams): void {
|
|
98
99
|
if(this.listFilterValidation(filter)){
|
|
99
100
|
this.filtersStore = useFiltersStore()
|
|
100
|
-
const index = this.filtersStore.filters.findIndex((f) => f.field === filter.field)
|
|
101
|
+
const index = this.filtersStore.filters.findIndex((f: FilterParams) => f.field === filter.field)
|
|
101
102
|
if(index === -1) {
|
|
102
103
|
this.filtersStore.setFilter(filter)
|
|
103
104
|
} else {
|
package/spa/src/stores/core.ts
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { ref, computed } from 'vue'
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { callAdminForthApi } from '@/utils';
|
|
4
|
+
import type { AdminForthResource, AdminForthResourceColumn } from '@/types/AdminForthConfig';
|
|
5
|
+
import type { Ref } from 'vue'
|
|
4
6
|
|
|
5
7
|
export const useCoreStore = defineStore('core', () => {
|
|
6
|
-
const resourceById = ref(
|
|
8
|
+
const resourceById: Ref<Object> = ref({});
|
|
7
9
|
const menu = ref([]);
|
|
8
10
|
const config = ref({});
|
|
9
11
|
const record = ref({});
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
+
const resource: Ref<AdminForthResource | null> = ref(null);
|
|
13
|
+
|
|
12
14
|
const resourceColumnsWithFilters = computed(() => {
|
|
13
|
-
if (!
|
|
15
|
+
if (!resource.value) {
|
|
14
16
|
return [];
|
|
15
17
|
}
|
|
16
|
-
return
|
|
18
|
+
return resource.value.columns.filter((col: AdminForthResourceColumn) => col.showIn?.includes('filter'));
|
|
17
19
|
})
|
|
18
20
|
|
|
19
21
|
const resourceOptions = ref(null);
|
|
@@ -30,7 +32,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
30
32
|
return
|
|
31
33
|
}
|
|
32
34
|
menu.value = resp.menu;
|
|
33
|
-
resourceById.value = resp.resources.reduce((acc, resource) => {
|
|
35
|
+
resourceById.value = resp.resources.reduce((acc: Object, resource: AdminForthResource) => {
|
|
34
36
|
acc[resource.resourceId] = resource;
|
|
35
37
|
return acc;
|
|
36
38
|
}, {});
|
|
@@ -42,7 +44,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
42
44
|
async function fetchRecord({ resourceId, primaryKey }) {
|
|
43
45
|
record.value = null;
|
|
44
46
|
|
|
45
|
-
if (!
|
|
47
|
+
if (!resource.value) {
|
|
46
48
|
throw new Error('Columns not fetched yet');
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -54,7 +56,7 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
54
56
|
resourceId: resourceId,
|
|
55
57
|
filters: [
|
|
56
58
|
{
|
|
57
|
-
field:
|
|
59
|
+
field: resource.value.columns.find((col: AdminForthResourceColumn) => col.primaryKey).name,
|
|
58
60
|
operator: 'eq',
|
|
59
61
|
value: primaryKey
|
|
60
62
|
}
|
|
@@ -70,13 +72,12 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
70
72
|
resourceOptions.value = respData.options;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
async function fetchResourceFull({ resourceId }) {
|
|
74
|
-
if (resourceColumnsId.value === resourceId &&
|
|
75
|
+
async function fetchResourceFull({ resourceId }: { resourceId: string }) {
|
|
76
|
+
if (resourceColumnsId.value === resourceId && resource.value) {
|
|
75
77
|
// already fetched
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
resourceColumnsId.value = resourceId;
|
|
79
|
-
resourceColumns.value = null;
|
|
80
81
|
resourceColumnsError.value = '';
|
|
81
82
|
const res = await callAdminForthApi({
|
|
82
83
|
path: '/get_resource',
|
|
@@ -88,7 +89,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
88
89
|
if (res.error) {
|
|
89
90
|
resourceColumnsError.value = res.error;
|
|
90
91
|
} else {
|
|
91
|
-
resourceColumns.value = res.resource.columns;
|
|
92
92
|
resourceById.value[resourceId] = res.resource;
|
|
93
93
|
resource.value = res.resource;
|
|
94
94
|
resourceOptions.value = res.resource.options;
|
|
@@ -131,7 +131,6 @@ export const useCoreStore = defineStore('core', () => {
|
|
|
131
131
|
fetchMenuAndResource,
|
|
132
132
|
fetchRecord,
|
|
133
133
|
record,
|
|
134
|
-
resourceColumns,
|
|
135
134
|
fetchResourceFull,
|
|
136
135
|
resourceColumnsError,
|
|
137
136
|
resourceOptions,
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<ResourceForm
|
|
47
47
|
v-else
|
|
48
48
|
:record="initalValues"
|
|
49
|
-
:
|
|
49
|
+
:resource="coreStore.resource"
|
|
50
50
|
@update:record="onUpdateRecord"
|
|
51
51
|
@update:isValid="isValid = $event"
|
|
52
52
|
:validating="validating"
|
|
@@ -95,7 +95,10 @@ let createComponentsPerColumn = {};
|
|
|
95
95
|
const coreStore = useCoreStore();
|
|
96
96
|
|
|
97
97
|
const initalValues = computed(() => {
|
|
98
|
-
|
|
98
|
+
if (!route.query.values) {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
return JSON.parse(decodeURIComponent(route.query.values));
|
|
99
102
|
});
|
|
100
103
|
|
|
101
104
|
async function onUpdateRecord(newRecord) {
|
|
@@ -108,7 +111,7 @@ onMounted(async () => {
|
|
|
108
111
|
await coreStore.fetchResourceFull({
|
|
109
112
|
resourceId: route.params.resourceId
|
|
110
113
|
});
|
|
111
|
-
createComponentsPerColumn = coreStore.
|
|
114
|
+
createComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
112
115
|
if (column.components?.create) {
|
|
113
116
|
acc[column.name] = getCustomComponent(column.components.create);
|
|
114
117
|
}
|
|
@@ -135,11 +138,17 @@ async function saveRecord() {
|
|
|
135
138
|
},
|
|
136
139
|
});
|
|
137
140
|
saving.value = false;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
if (route.query.returnTo) {
|
|
142
|
+
router.push(route.query.returnTo);
|
|
143
|
+
} else {
|
|
144
|
+
router.push({
|
|
145
|
+
name: 'resource-show',
|
|
146
|
+
params: {
|
|
147
|
+
resourceId: route.params.resourceId,
|
|
148
|
+
primaryKey: response.newRecordId
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
143
152
|
}
|
|
144
153
|
|
|
145
154
|
|
|
@@ -95,10 +95,10 @@ async function onUpdateRecord(newRecord) {
|
|
|
95
95
|
|
|
96
96
|
const editableRecord = computed(() => {
|
|
97
97
|
const newRecord = { ...coreStore.record };
|
|
98
|
-
if (!coreStore.
|
|
98
|
+
if (!coreStore.resource) {
|
|
99
99
|
return {};
|
|
100
100
|
}
|
|
101
|
-
coreStore.
|
|
101
|
+
coreStore.resource.columns.forEach(column => {
|
|
102
102
|
if (column.foreignResource) {
|
|
103
103
|
newRecord[column.name] = newRecord[column.name]?.pk
|
|
104
104
|
}
|
|
@@ -119,7 +119,7 @@ onMounted(async () => {
|
|
|
119
119
|
});
|
|
120
120
|
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'edit');
|
|
121
121
|
|
|
122
|
-
editComponentsPerColumn = coreStore.
|
|
122
|
+
editComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
123
123
|
if (column.components?.edit) {
|
|
124
124
|
acc[column.name] = getCustomComponent(column.components.edit);
|
|
125
125
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="relative">
|
|
3
3
|
<Teleport to="body">
|
|
4
4
|
<Filters
|
|
5
|
-
:columns="coreStore.
|
|
5
|
+
:columns="coreStore.resource.columns"
|
|
6
6
|
:columnsMinMax="columnsMinMax" :show="filtersShow"
|
|
7
7
|
@hide="filtersShow = false"
|
|
8
8
|
/>
|
|
@@ -159,6 +159,8 @@ watch([page], async () => {
|
|
|
159
159
|
|
|
160
160
|
watch(()=>filtersStore.filters, async () => {
|
|
161
161
|
page.value = 1;
|
|
162
|
+
checkboxes.value = [];
|
|
163
|
+
|
|
162
164
|
await getList();
|
|
163
165
|
}, {deep: true});
|
|
164
166
|
|
|
@@ -183,7 +185,7 @@ async function getList() {
|
|
|
183
185
|
});
|
|
184
186
|
|
|
185
187
|
rows.value = data.data?.map(row => {
|
|
186
|
-
row._primaryKeyValue = row[coreStore.
|
|
188
|
+
row._primaryKeyValue = row[coreStore.resource.columns.find(c => c.primaryKey).name];
|
|
187
189
|
return row;
|
|
188
190
|
});
|
|
189
191
|
totalRows.value = data.total;
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
</tr>
|
|
59
59
|
</thead>
|
|
60
60
|
<tbody>
|
|
61
|
-
<tr v-for="column in coreStore.
|
|
61
|
+
<tr v-for="column in coreStore.resource?.columns.filter(c => c.showIn.includes('show'))" :key="column.name"
|
|
62
62
|
class="bg-form-view-bg odd:dark:bg-gray-900 even:dark:bg-gray-800 border-b dark:border-gray-700"
|
|
63
63
|
>
|
|
64
64
|
<component
|
|
@@ -145,7 +145,7 @@ onMounted(async () => {
|
|
|
145
145
|
});
|
|
146
146
|
checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'show');
|
|
147
147
|
|
|
148
|
-
showComponentsPerColumn = coreStore.
|
|
148
|
+
showComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
|
|
149
149
|
if (column.components?.show) {
|
|
150
150
|
acc[column.name] = getCustomComponent(column.components.show);
|
|
151
151
|
}
|