adminforth 1.3.14 → 1.3.15

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.
@@ -57,6 +57,21 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
57
57
  throw new Error('Method not implemented.');
58
58
  }
59
59
 
60
+ async checkUnique(resource: AdminForthResource, column: AdminForthResourceColumn, value: any) {
61
+ process.env.HEAVY_DEBUG && console.log('☝️🪲🪲🪲🪲 checkUnique|||', column, value);
62
+ const existingRecord = await this.getData({
63
+ resource,
64
+ filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value }],
65
+ limit: 1,
66
+ sort: [],
67
+ offset: 0,
68
+ getTotals: false
69
+ });
70
+ process.env.HEAVY_DEBUG && console.log('☝️🪲🪲🪲🪲 existingRecord|||', existingRecord);
71
+
72
+ return existingRecord.data.length > 0;
73
+ }
74
+
60
75
  async createRecord({ resource, record, adminUser }: {
61
76
  resource: AdminForthResource; record: any; adminUser: any;
62
77
  }): Promise<{ error?: string; ok: boolean; createdRecord?: any; }> {
@@ -76,28 +91,21 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
76
91
  recordWithOriginalValues[col.name] = this.setFieldValue(col, filledRecord[col.name]);
77
92
  }
78
93
 
79
- async function checkUnique(column: AdminForthResourceColumn, value: any) {
80
- const existingRecord = await this.getData({
81
- resource,
82
- filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value }],
83
- limit: 1,
84
- sort: [],
85
- offset: 0,
86
- getTotals: false
87
- });
88
- return existingRecord.data.length > 0;
89
- }
94
+
90
95
  let error: string | null = null;
91
- await Promise.race(
96
+ await Promise.all(
92
97
  resource.dataSourceColumns.map(async (col) => {
98
+
93
99
  if (col.isUnique && !col.virtual && !error) {
94
- const exists = await checkUnique(col, recordWithOriginalValues[col.name]);
100
+
101
+ const exists = await this.checkUnique(resource, col, recordWithOriginalValues[col.name]);
95
102
  if (exists) {
96
103
  error = `Record with ${col.name} ${recordWithOriginalValues[col.name]} already exists`;
97
104
  }
98
105
  }
99
106
  })
100
107
  );
108
+ process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 error', error);
101
109
  if (error) {
102
110
  return { error, ok: false };
103
111
  }
@@ -50,6 +50,21 @@ export default class AdminForthBaseConnector {
50
50
  createRecordOriginalValues({ resource, record }) {
51
51
  throw new Error('Method not implemented.');
52
52
  }
53
+ checkUnique(resource, column, value) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ process.env.HEAVY_DEBUG && console.log('☝️🪲🪲🪲🪲 checkUnique|||', column, value);
56
+ const existingRecord = yield this.getData({
57
+ resource,
58
+ filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value }],
59
+ limit: 1,
60
+ sort: [],
61
+ offset: 0,
62
+ getTotals: false
63
+ });
64
+ process.env.HEAVY_DEBUG && console.log('☝️🪲🪲🪲🪲 existingRecord|||', existingRecord);
65
+ return existingRecord.data.length > 0;
66
+ });
67
+ }
53
68
  createRecord(_a) {
54
69
  return __awaiter(this, arguments, void 0, function* ({ resource, record, adminUser }) {
55
70
  // transform value using setFieldValue and call createRecordOriginalValues
@@ -66,28 +81,16 @@ export default class AdminForthBaseConnector {
66
81
  }
67
82
  recordWithOriginalValues[col.name] = this.setFieldValue(col, filledRecord[col.name]);
68
83
  }
69
- function checkUnique(column, value) {
70
- return __awaiter(this, void 0, void 0, function* () {
71
- const existingRecord = yield this.getData({
72
- resource,
73
- filters: [{ field: column.name, operator: AdminForthFilterOperators.EQ, value }],
74
- limit: 1,
75
- sort: [],
76
- offset: 0,
77
- getTotals: false
78
- });
79
- return existingRecord.data.length > 0;
80
- });
81
- }
82
84
  let error = null;
83
- yield Promise.race(resource.dataSourceColumns.map((col) => __awaiter(this, void 0, void 0, function* () {
85
+ yield Promise.all(resource.dataSourceColumns.map((col) => __awaiter(this, void 0, void 0, function* () {
84
86
  if (col.isUnique && !col.virtual && !error) {
85
- const exists = yield checkUnique(col, recordWithOriginalValues[col.name]);
87
+ const exists = yield this.checkUnique(resource, col, recordWithOriginalValues[col.name]);
86
88
  if (exists) {
87
89
  error = `Record with ${col.name} ${recordWithOriginalValues[col.name]} already exists`;
88
90
  }
89
91
  }
90
92
  })));
93
+ process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 error', error);
91
94
  if (error) {
92
95
  return { error, ok: false };
93
96
  }
package/dist/index.js CHANGED
@@ -185,6 +185,9 @@ class AdminForth {
185
185
  const connector = this.connectors[resource.dataSource];
186
186
  process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 creating record createResourceRecord', record);
187
187
  const { ok, error, createdRecord } = yield connector.createRecord({ resource, record, adminUser });
188
+ if (!ok) {
189
+ return { ok, error };
190
+ }
188
191
  const primaryKey = record[resource.columns.find((col) => col.primaryKey).name];
189
192
  // execute hook if needed
190
193
  for (const hook of listify((_g = (_f = resource.hooks) === null || _f === void 0 ? void 0 : _f.create) === null || _g === void 0 ? void 0 : _g.afterSave)) {
@@ -319,6 +319,7 @@ export default class AdminForthRestAPI {
319
319
  offset,
320
320
  filters,
321
321
  sort,
322
+ getTotals: true,
322
323
  });
323
324
  // for foreign keys, add references
324
325
  yield Promise.all(resource.columns.filter((col) => col.foreignResource).map((col) => __awaiter(this, void 0, void 0, function* () {
package/index.ts CHANGED
@@ -236,7 +236,10 @@ class AdminForth implements IAdminForth {
236
236
  const connector = this.connectors[resource.dataSource];
237
237
  process.env.HEAVY_DEBUG && console.log('🪲🪲🪲🪲 creating record createResourceRecord', record);
238
238
  const { ok, error, createdRecord } = await connector.createRecord({ resource, record, adminUser });
239
-
239
+ if (!ok) {
240
+ return { ok, error };
241
+ }
242
+
240
243
  const primaryKey = record[resource.columns.find((col) => col.primaryKey).name];
241
244
 
242
245
  // execute hook if needed
@@ -261,8 +261,6 @@ export default class AdminForthRestAPI {
261
261
  },
262
262
  });
263
263
 
264
-
265
-
266
264
  function checkAccess(action: AllowedActionsEnum, allowedActions: AllowedActions): { allowed: boolean, error?: string } {
267
265
  const allowed = (allowedActions[action] as boolean | string | undefined);
268
266
  if (allowed !== true) {
@@ -383,6 +381,7 @@ export default class AdminForthRestAPI {
383
381
  offset,
384
382
  filters,
385
383
  sort,
384
+ getTotals: true,
386
385
  });
387
386
  // for foreign keys, add references
388
387
  await Promise.all(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.3.14",
3
+ "version": "1.3.15",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -115,7 +115,7 @@
115
115
  </template>
116
116
 
117
117
  <script setup>
118
- import { watch, computed, ref, onMounted } from 'vue'
118
+ import { watch, computed } from 'vue'
119
119
  import Dropdown from '@/components/Dropdown.vue';
120
120
  import CustomDateRangePicker from '@/components/CustomDateRangePicker.vue';
121
121
  import { callAdminForthApi } from '@/utils';
@@ -130,7 +130,6 @@
130
130
  </button>
131
131
  </template>
132
132
  <div v-if="columnError(column) && validating" class="mt-1 text-xs text-red-500 dark:text-red-400">{{ columnError(column) }}</div>
133
-
134
133
  <div v-if="column.editingNote && column.editingNote[mode]" class="mt-1 text-xs text-gray-400 dark:text-gray-500">{{ column.editingNote[mode] }}</div>
135
134
 
136
135
  </td>
@@ -154,10 +153,10 @@ import { IconExclamationCircleSolid, IconEyeSlashSolid, IconEyeSolid } from '@ic
154
153
  import { computedAsync } from '@vueuse/core';
155
154
  import { initFlowbite } from 'flowbite';
156
155
  import { computed, onMounted, ref, watch } from 'vue';
157
- import { useRouter } from 'vue-router';
156
+ import { useRouter, useRoute } from 'vue-router';
158
157
 
159
158
  const router = useRouter();
160
-
159
+ const route = useRoute();
161
160
  const props = defineProps({
162
161
  loading: Boolean,
163
162
  resource: Object,
@@ -168,7 +167,7 @@ const props = defineProps({
168
167
 
169
168
  const unmasked = ref({});
170
169
 
171
- const mode = computed(() => props.record && Object.keys(props.record).length ? 'edit' : 'create');
170
+ const mode = computed(() => route.name === 'resource-create' ? 'create' : 'edit');
172
171
 
173
172
  const emit = defineEmits(['update:record', 'update:isValid']);
174
173
 
@@ -56,12 +56,4 @@ const router = createRouter({
56
56
  ]
57
57
  })
58
58
 
59
- router.beforeEach((to, from, next) => {
60
- const filterStore = useFiltersStore();
61
- if (to.path.startsWith('/resource/')) {
62
- filterStore.clearFilters();
63
- }
64
- next()
65
- })
66
-
67
59
  export default router
@@ -3,11 +3,12 @@ import { defineStore } from 'pinia';
3
3
 
4
4
  export const useFiltersStore = defineStore('filters', () => {
5
5
  const filters: Ref<any[]> = ref([]);
6
+
6
7
  const setFilter = (filter: any) => {
7
- filters.value = [...filters.value, filter];
8
+ filters.value.push(filter);
8
9
  }
9
10
  const setFilters = (f: any) => {
10
- filters.value = [...f];
11
+ filters.value = f;
11
12
  }
12
13
  const getFilters = () => {
13
14
  return filters.value;
@@ -117,8 +117,6 @@ import { initFlowbite } from 'flowbite';
117
117
  import { computed, onMounted, ref, watch } from 'vue';
118
118
  import { useRoute } from 'vue-router';
119
119
  import { showErrorTost } from '@/composables/useFrontendApi'
120
-
121
- import ValueRenderer from '@/components/ValueRenderer.vue';
122
120
  import { getCustomComponent } from '@/utils';
123
121
 
124
122
 
@@ -151,20 +149,7 @@ const DEFAULT_PAGE_SIZE = 10;
151
149
  const pageSize = computed(() => coreStore.resource?.options?.listPageSize || DEFAULT_PAGE_SIZE);
152
150
 
153
151
 
154
- watch([page], async () => {
155
- await getList();
156
- });
157
-
158
- watch(()=>filtersStore.filters, async () => {
159
- page.value = 1;
160
- checkboxes.value = [];
161
-
162
- await getList();
163
- }, {deep: true});
164
152
 
165
- watch([sort], async () => {
166
- await getList();
167
- }, {deep: true});
168
153
 
169
154
 
170
155
  async function getList() {
@@ -222,6 +207,8 @@ async function init() {
222
207
  resourceId: route.params.resourceId
223
208
  });
224
209
 
210
+ // !!! clear filters should be in same tick with sort assignment so that watch can catch it
211
+ filtersStore.clearFilters();
225
212
  if (coreStore.resource.options?.defaultSort) {
226
213
  sort.value = [{
227
214
  field: coreStore.resource.options.defaultSort.columnName,
@@ -230,8 +217,8 @@ async function init() {
230
217
  } else {
231
218
  sort.value = [];
232
219
  }
233
-
234
- await getList();
220
+ console.log('↘️init fired');
221
+ // await getList();
235
222
  columnsMinMax.value = await callAdminForthApi({
236
223
  path: '/get_min_max_for_columns',
237
224
  method: 'POST',
@@ -241,18 +228,22 @@ async function init() {
241
228
  });
242
229
  }
243
230
 
231
+ watch([page, sort, () => filtersStore.filters], async () => {
232
+ console.log('↘️watch fired getList');
233
+ await getList();
234
+ }, { deep: true });
235
+
236
+ watch(() => filtersStore.filters, async (to, from) => {
237
+ page.value = 1;
238
+ checkboxes.value = [];
239
+ }, {deep: true});
240
+
244
241
  onMounted(async () => {
242
+ console.log('🧱onMounted fired');
245
243
  initFlowbite();
246
-
247
244
  await init();
248
-
249
245
  });
250
246
 
251
- // on route param change
252
- watch(() => route.params.resourceId, async () => {
253
- filtersStore.setFilters([]);
254
- checkboxes.value = [];
255
- await init();
256
- });
247
+
257
248
 
258
249
  </script>