adminforth 1.1.70 → 1.1.72

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.
Files changed (47) hide show
  1. package/auth.ts +2 -1
  2. package/dist/auth.js +2 -1
  3. package/dist/spa/index.html +4 -4
  4. package/dist/spa/package-lock.json +206 -5
  5. package/dist/spa/package.json +8 -2
  6. package/dist/spa/public/assets/favicon.png +0 -0
  7. package/dist/spa/spa/src/views/LoginView.vue +2 -0
  8. package/dist/spa/src/App.vue +171 -72
  9. package/dist/spa/src/assets/logo.svg +19 -1
  10. package/dist/spa/src/components/AcceptModal.vue +3 -10
  11. package/dist/spa/src/components/BreadcrumbsWithButtons.vue +1 -1
  12. package/dist/spa/src/components/CustomDatePicker.vue +19 -6
  13. package/dist/spa/src/components/CustomDateRangePicker.vue +14 -5
  14. package/dist/spa/src/components/CustomRangePicker.vue +148 -0
  15. package/dist/spa/src/components/Dropdown.vue +19 -5
  16. package/dist/spa/src/components/Filters.vue +91 -37
  17. package/dist/spa/src/components/MenuLink.vue +2 -2
  18. package/dist/spa/src/components/ResourceForm.vue +163 -103
  19. package/dist/spa/src/components/ResourceListTable.vue +419 -0
  20. package/dist/spa/src/components/Toast.vue +66 -0
  21. package/dist/spa/src/components/ValueRenderer.vue +22 -6
  22. package/dist/spa/src/composables/useFrontendApi.ts +26 -0
  23. package/dist/spa/src/composables/useStores.ts +113 -0
  24. package/dist/spa/src/main.ts +1 -1
  25. package/dist/spa/src/router/index.ts +30 -19
  26. package/dist/spa/src/spa_types/core.ts +51 -0
  27. package/dist/spa/src/stores/core.ts +65 -59
  28. package/dist/spa/src/stores/filters.ts +22 -0
  29. package/dist/spa/src/stores/modal.ts +13 -3
  30. package/dist/spa/src/stores/toast.ts +15 -0
  31. package/dist/spa/src/stores/user.ts +54 -0
  32. package/dist/spa/src/utils.ts +65 -8
  33. package/dist/spa/src/views/CreateView.vue +76 -16
  34. package/dist/spa/src/views/EditView.vue +76 -14
  35. package/dist/spa/src/views/ListView.vue +88 -360
  36. package/dist/spa/src/views/LoginView.vue +17 -5
  37. package/dist/spa/src/views/ResourceParent.vue +1 -1
  38. package/dist/spa/src/views/ShowView.vue +114 -19
  39. package/dist/spa/tailwind.config.js +5 -2
  40. package/dist/spa/vite.config.ts +6 -0
  41. package/package.json +1 -1
  42. package/spa/src/views/LoginView.vue +2 -0
  43. package/dist/spa/public/favicon.ico +0 -0
  44. package/dist/spa/spa/public/favicon.ico +0 -0
  45. package/dist/spa/spa/src/views/HomeView.vue +0 -8
  46. package/dist/spa/src/views/HomeView.vue +0 -8
  47. package/dist/types.js +0 -30
@@ -1,16 +1,25 @@
1
1
  <template>
2
2
  <div class="relative">
3
3
 
4
+ <component
5
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.beforeBreadcrumbs || []"
6
+ :is="getCustomComponent(c)"
7
+ :meta="c.meta"
8
+ :record="coreStore.record"
9
+ :resource="coreStore.resource"
10
+ :adminUser="coreStore.adminUser"
11
+ />
12
+
4
13
  <BreadcrumbsWithButtons>
5
14
  <!-- save and cancle -->
6
15
  <button @click="$router.back()"
7
- class="flex items-center py-1 px-3 me-2 mb-2 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"
16
+ class="flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default 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"
8
17
  >
9
18
  Cancel
10
19
  </button>
11
20
 
12
21
  <button @click="saveRecord"
13
- class="flex items-center py-1 px-3 mb-2 text-sm font-medium text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
22
+ class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 disabled:opacity-50"
14
23
  :disabled="saving || (validating && !isValid)"
15
24
  >
16
25
  <svg v-if="saving" x
@@ -22,32 +31,55 @@
22
31
 
23
32
  </BreadcrumbsWithButtons>
24
33
 
34
+ <component
35
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.afterBreadcrumbs || []"
36
+ :is="getCustomComponent(c)"
37
+ :meta="c.meta"
38
+ :record="coreStore.record"
39
+ :resource="coreStore.resource"
40
+ :adminUser="coreStore.adminUser"
41
+ />
42
+
25
43
  <SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
44
+
26
45
 
27
46
  <ResourceForm
28
47
  v-else
29
- :record="{}"
30
- :resourceColumns="coreStore.resourceColumns"
48
+ :record="record"
49
+ :resource="coreStore.resource"
31
50
  @update:record="onUpdateRecord"
32
51
  @update:isValid="isValid = $event"
33
52
  :validating="validating"
53
+ :customComponentsPerColumn="createComponentsPerColumn"
34
54
  >
35
55
  </ResourceForm>
36
56
 
57
+ <component
58
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.create?.bottom || []"
59
+ :is="getCustomComponent(c)"
60
+ :meta="c.meta"
61
+ :record="coreStore.record"
62
+ :resource="coreStore.resource"
63
+ :adminUser="coreStore.adminUser"
64
+ />
65
+
37
66
  </div>
38
67
  </template>
39
68
 
40
69
 
41
70
  <script setup>
42
71
 
43
- import { ref, computed, onMounted } from 'vue';
44
- import { useRoute, useRouter } from 'vue-router';
45
- import { useCoreStore } from '@/stores/core';
46
- import { callAdminForthApi } from '@/utils';
47
- import ResourceForm from '@/components/ResourceForm.vue';
48
72
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
49
- import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
73
+ import ResourceForm from '@/components/ResourceForm.vue';
50
74
  import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
75
+ import { useCoreStore } from '@/stores/core';
76
+ import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions } from '@/utils';
77
+ import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
78
+ import { onMounted, ref, watch } from 'vue';
79
+ import { useRoute, useRouter } from 'vue-router';
80
+ import { computed } from 'vue';
81
+ import { showErrorTost } from '@/composables/useFrontendApi';
82
+
51
83
 
52
84
  const isValid = ref(false);
53
85
  const validating = ref(false);
@@ -59,9 +91,19 @@ const route = useRoute();
59
91
  const router = useRouter();
60
92
 
61
93
  const record = ref({});
94
+ let createComponentsPerColumn = {};
62
95
 
63
96
  const coreStore = useCoreStore();
64
97
 
98
+ const initalValues = computed(() => {
99
+ if (!route.query.values) {
100
+ return {};
101
+ }
102
+ return JSON.parse(decodeURIComponent(route.query.values));
103
+ });
104
+
105
+
106
+
65
107
  async function onUpdateRecord(newRecord) {
66
108
  console.log('newRecord', newRecord);
67
109
  record.value = newRecord;
@@ -69,10 +111,18 @@ async function onUpdateRecord(newRecord) {
69
111
 
70
112
  onMounted(async () => {
71
113
  loading.value = true;
72
- coreStore.fetchColumns({
114
+ record.value = initalValues.value;
115
+ await coreStore.fetchResourceFull({
73
116
  resourceId: route.params.resourceId
74
117
  });
118
+ createComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
119
+ if (column.components?.create) {
120
+ acc[column.name] = getCustomComponent(column.components.create);
121
+ }
122
+ return acc;
123
+ }, {});
75
124
  loading.value = false;
125
+ checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'create');
76
126
  });
77
127
 
78
128
  async function saveRecord() {
@@ -91,12 +141,22 @@ async function saveRecord() {
91
141
  record: record.value,
92
142
  },
93
143
  });
144
+ if (response.error) {
145
+ showErrorTost(response.error);
146
+
147
+ }
94
148
  saving.value = false;
95
- router.push({ name: 'resource-show', params: {
96
- resourceId: route.params.resourceId,
97
- primaryKey: response.newRecordId
98
-
99
- } });
149
+ if (route.query.returnTo) {
150
+ router.push(route.query.returnTo);
151
+ } else {
152
+ router.push({
153
+ name: 'resource-show',
154
+ params: {
155
+ resourceId: route.params.resourceId,
156
+ primaryKey: response.newRecordId
157
+ }
158
+ });
159
+ }
100
160
  }
101
161
 
102
162
 
@@ -1,16 +1,24 @@
1
1
  <template>
2
2
  <div class="relative">
3
+ <component
4
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.beforeBreadcrumbs || []"
5
+ :is="getCustomComponent(c)"
6
+ :meta="c.meta"
7
+ :record="editableRecord"
8
+ :resource="coreStore.resource"
9
+ :adminUser="coreStore.adminUser"
10
+ />
3
11
 
4
12
  <BreadcrumbsWithButtons>
5
13
  <!-- save and cancle -->
6
14
  <button @click="$router.back()"
7
- class="flex items-center py-1 px-3 me-2 mb-2 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"
15
+ class="flex items-center py-1 px-3 me-2 text-sm font-medium text-gray-900 rounded-default 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"
8
16
  >
9
17
  Cancel
10
18
  </button>
11
19
 
12
20
  <button @click="saveRecord"
13
- class="flex items-center py-1 px-3 mb-2 text-sm font-medium text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
21
+ class="flex items-center py-1 px-3 text-sm font-medium rounded-default text-red-600 focus:outline-none bg-white rounded border border-gray-300 hover:bg-gray-100 hover:text-red-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-red-500 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
14
22
  :disabled="saving || (validating && !isValid)"
15
23
  >
16
24
  <IconFloppyDiskSolid class="w-4 h-4" />
@@ -19,31 +27,53 @@
19
27
 
20
28
  </BreadcrumbsWithButtons>
21
29
 
30
+ <component
31
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.afterBreadcrumbs || []"
32
+ :is="getCustomComponent(c)"
33
+ :meta="c.meta"
34
+ :record="coreStore.record"
35
+ :resource="coreStore.resource"
36
+ :adminUser="coreStore.adminUser"
37
+ />
38
+
22
39
  <SingleSkeletLoader v-if="loading"></SingleSkeletLoader>
23
40
 
24
41
  <ResourceForm
25
42
  v-else
26
- :record="coreStore.record"
27
- :resourceColumns="coreStore.resourceColumns"
43
+ :record="editableRecord"
44
+ :resource="coreStore.resource"
45
+ :adminUser="coreStore.adminUser"
28
46
  @update:record="onUpdateRecord"
29
47
  @update:isValid="isValid = $event"
30
48
  :validating="validating"
49
+ :customComponentsPerColumn="editComponentsPerColumn"
31
50
  >
32
51
  </ResourceForm>
52
+
53
+ <component
54
+ v-for="c in coreStore?.resourceOptions?.pageInjections?.edit?.bottom || []"
55
+ :is="getCustomComponent(c)"
56
+ :meta="c.meta"
57
+ :record="coreStore.record"
58
+ :resource="coreStore.resource"
59
+ :adminUser="coreStore.adminUser"
60
+ />
61
+
33
62
  </div>
34
63
  </template>
35
64
 
36
65
 
37
66
  <script setup>
38
67
 
39
- import { ref, computed, onMounted } from 'vue';
40
- import { useRoute, useRouter } from 'vue-router';
41
- import { useCoreStore } from '@/stores/core';
42
- import ResourceForm from '@/components/ResourceForm.vue';
43
68
  import BreadcrumbsWithButtons from '@/components/BreadcrumbsWithButtons.vue';
44
- import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
69
+ import ResourceForm from '@/components/ResourceForm.vue';
45
70
  import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
46
- import { callAdminForthApi } from '@/utils';
71
+ import { useCoreStore } from '@/stores/core';
72
+ import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions } from '@/utils';
73
+ import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
74
+ import { computed, onMounted, ref } from 'vue';
75
+ import { useRoute, useRouter } from 'vue-router';
76
+ import { showErrorTost } from '@/composables/useFrontendApi';
47
77
 
48
78
  const coreStore = useCoreStore();
49
79
 
@@ -58,23 +88,44 @@ const loading = ref(false);
58
88
  const saving = ref(false);
59
89
 
60
90
  const record = ref({});
91
+ let editComponentsPerColumn = {};
61
92
 
62
93
  async function onUpdateRecord(newRecord) {
63
94
  record.value = newRecord;
64
95
  }
65
96
 
97
+ const editableRecord = computed(() => {
98
+ const newRecord = { ...coreStore.record };
99
+ if (!coreStore.resource) {
100
+ return {};
101
+ }
102
+ coreStore.resource.columns.forEach(column => {
103
+ if (column.foreignResource) {
104
+ newRecord[column.name] = newRecord[column.name]?.pk
105
+ }
106
+ });
107
+ return newRecord;
108
+ })
66
109
 
67
110
  onMounted(async () => {
111
+
68
112
  loading.value = true;
69
113
 
70
- await coreStore.fetchColumns({
114
+ await coreStore.fetchResourceFull({
71
115
  resourceId: route.params.resourceId
72
116
  });
73
117
  await coreStore.fetchRecord({
74
118
  resourceId: route.params.resourceId,
75
119
  primaryKey: route.params.primaryKey,
76
120
  });
77
-
121
+ checkAcessByAllowedActions(coreStore.resourceOptions.allowedActions,'edit');
122
+
123
+ editComponentsPerColumn = coreStore.resource.columns.reduce((acc, column) => {
124
+ if (column.components?.edit) {
125
+ acc[column.name] = getCustomComponent(column.components.edit);
126
+ }
127
+ return acc;
128
+ }, {});
78
129
  loading.value = false;
79
130
  });
80
131
 
@@ -87,15 +138,26 @@ async function saveRecord() {
87
138
  }
88
139
 
89
140
  saving.value = true;
90
- await callAdminForthApi({
141
+
142
+ const updates = {};
143
+ for (const key in record.value) {
144
+ if (record.value[key] !== coreStore.record[key]) {
145
+ updates[key] = record.value[key];
146
+ }
147
+ }
148
+
149
+ const resp = await callAdminForthApi({
91
150
  method: 'POST',
92
151
  path: `/update_record`,
93
152
  body: {
94
153
  resourceId: route.params.resourceId,
95
154
  recordId: route.params.primaryKey,
96
- record: record.value,
155
+ record: updates,
97
156
  },
98
157
  });
158
+ if (resp.error) {
159
+ showErrorTost(resp.error);
160
+ }
99
161
  saving.value = false;
100
162
  router.push({ name: 'resource-show', params: { resourceId: route.params.resourceId, primaryKey: coreStore.record[coreStore.primaryKey] } });
101
163
  }