adminforth 1.2.29 → 1.2.31

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.
@@ -61,10 +61,9 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
61
61
  field.type = AdminForthDataTypes.STRING;
62
62
  } else if (baseType.startsWith('Decimal')) {
63
63
  field.type = AdminForthDataTypes.DECIMAL;
64
- // const [precision, scale] = baseType.match(/\d+/g);
65
- // TODO
66
- // field.precision = parseInt(precision);
67
- // field.scale = parseInt(scale);
64
+ const [precision, scale] = baseType.match(/\d+/g);
65
+ field.precision = parseInt(precision);
66
+ field.scale = parseInt(scale);
68
67
  } else if (baseType.startsWith('Float')) {
69
68
  field.type = AdminForthDataTypes.FLOAT;
70
69
  } else if (baseType == 'DateTime64' || baseType == 'DateTime') {
@@ -216,7 +215,6 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
216
215
  limit,
217
216
  offset,
218
217
  };
219
- console.log('🪲 Clickhouse Query', q, 'params:', d);
220
218
 
221
219
  const stmt = await this.client.query({
222
220
  query: q,
@@ -224,9 +222,6 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
224
222
  query_params: d,
225
223
  });
226
224
 
227
- if (process.env.HEAVY_DEBUG) {
228
- console.log('🪲 Clickhouse Query', q, 'params:', d);
229
- }
230
225
  const rows = await stmt.json();
231
226
 
232
227
  let total = 0;
@@ -237,7 +232,6 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
237
232
  query_params: d,
238
233
  });
239
234
  const countResp = await countQ.json()
240
- console.log('🪲 Clickhouse Query count', countResp);
241
235
  total = countResp[0]['COUNT()'];
242
236
  }
243
237
 
@@ -257,53 +251,42 @@ class ClickhouseConnector extends AdminForthBaseConnector implements IAdminForth
257
251
  const tableName = resource.table;
258
252
  const result = {};
259
253
  await Promise.all(columns.map(async (col) => {
260
- // const stmt = await this.db.prepare(`SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`);
261
- // const { min, max } = stmt.get();
262
- // result[col.name] = {
263
- // min, max,
264
- // };
254
+ const stmt = await this.client.query({
255
+ query: `SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`,
256
+ format: 'JSONEachRow',
257
+ });
258
+ const rows = await stmt.json();
259
+ result[col.name] = {
260
+ min: rows[0].min,
261
+ max: rows[0].max,
262
+ };
263
+
265
264
  }))
266
265
  return result;
267
266
  }
268
267
  async createRecordOriginalValues({ resource, record }: { resource: AdminForthResource, record: any }) {
269
268
  const tableName = resource.table;
270
269
  const columns = Object.keys(record);
271
-
272
- // const q = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${columns.map((colName) => {
273
- // const colType = resource.dataSourceColumns.find((col) => col.name == colName)._underlineType;
274
- // if (colType.startsWith('Int') || colType.startsWith('UInt') || colType.startsWith('Float')) {
275
- // return record[colName];
276
- // } else {
277
- // return "'"+record[colName]+"'"
278
- // }
279
- // }).join(', ') })`;
280
- // console.log('🪲 Clickhouse Query', q) ;
281
- // await this.client.command({
282
- // query: q,
283
-
284
- // });
285
-
286
- console.log('🪲 Clickhouse Insert', record);
287
-
288
270
  await this.client.insert({
289
271
  database: this.dbName,
290
272
  table: tableName,
291
273
  columns: columns,
292
274
  values: [Object.values(record)],
293
275
  });
294
-
295
- console.log('🪲 Clickhouse Query done');
296
-
297
276
  }
298
277
 
299
278
  async updateRecord({ resource, recordId, newValues }: { resource: AdminForthResource, recordId: any, newValues: any }) {
300
- const columnsWithPlaceholders = Object.keys(newValues).map((col) => `${col} = ?`);
279
+ const columnsWithPlaceholders = Object.keys(newValues).map((col) => {
280
+ return `${col} = {${col}:${resource.dataSourceColumns.find((c) => c.name == col)._underlineType}}`
281
+ });
301
282
  const values = [...Object.values(newValues), recordId];
302
283
 
303
- // const q = this.db.prepare(
304
- // `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`
305
- // )
306
- // await q.run(values);
284
+ await this.client.command(
285
+ {
286
+ query: `ALTER TABLE ${this.dbName}.${resource.table} UPDATE ${columnsWithPlaceholders.join(', ')} WHERE ${this.getPrimaryKey(resource)} = {recordId:${resource.dataSourceColumns.find((c) => c.primaryKey)._underlineType}}`,
287
+ query_params: { ...newValues, recordId },
288
+ }
289
+ );
307
290
  }
308
291
 
309
292
  async deleteRecord({ resource, recordId }: { resource: AdminForthResource, recordId: any }) {
@@ -77,10 +77,9 @@ class ClickhouseConnector extends AdminForthBaseConnector {
77
77
  }
78
78
  else if (baseType.startsWith('Decimal')) {
79
79
  field.type = AdminForthDataTypes.DECIMAL;
80
- // const [precision, scale] = baseType.match(/\d+/g);
81
- // TODO
82
- // field.precision = parseInt(precision);
83
- // field.scale = parseInt(scale);
80
+ const [precision, scale] = baseType.match(/\d+/g);
81
+ field.precision = parseInt(precision);
82
+ field.scale = parseInt(scale);
84
83
  }
85
84
  else if (baseType.startsWith('Float')) {
86
85
  field.type = AdminForthDataTypes.FLOAT;
@@ -210,15 +209,11 @@ class ClickhouseConnector extends AdminForthBaseConnector {
210
209
  const q = `SELECT ${columns} FROM ${tableName} ${where} ${orderBy} LIMIT {limit:Int} OFFSET {offset:Int}`;
211
210
  const d = Object.assign(Object.assign({}, params), { limit,
212
211
  offset });
213
- console.log('🪲 Clickhouse Query', q, 'params:', d);
214
212
  const stmt = yield this.client.query({
215
213
  query: q,
216
214
  format: 'JSONEachRow',
217
215
  query_params: d,
218
216
  });
219
- if (process.env.HEAVY_DEBUG) {
220
- console.log('🪲 Clickhouse Query', q, 'params:', d);
221
- }
222
217
  const rows = yield stmt.json();
223
218
  let total = 0;
224
219
  if (getTotals) {
@@ -228,7 +223,6 @@ class ClickhouseConnector extends AdminForthBaseConnector {
228
223
  query_params: d,
229
224
  });
230
225
  const countResp = yield countQ.json();
231
- console.log('🪲 Clickhouse Query count', countResp);
232
226
  total = countResp[0]['COUNT()'];
233
227
  }
234
228
  return {
@@ -248,11 +242,15 @@ class ClickhouseConnector extends AdminForthBaseConnector {
248
242
  const tableName = resource.table;
249
243
  const result = {};
250
244
  yield Promise.all(columns.map((col) => __awaiter(this, void 0, void 0, function* () {
251
- // const stmt = await this.db.prepare(`SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`);
252
- // const { min, max } = stmt.get();
253
- // result[col.name] = {
254
- // min, max,
255
- // };
245
+ const stmt = yield this.client.query({
246
+ query: `SELECT MIN(${col.name}) as min, MAX(${col.name}) as max FROM ${tableName}`,
247
+ format: 'JSONEachRow',
248
+ });
249
+ const rows = yield stmt.json();
250
+ result[col.name] = {
251
+ min: rows[0].min,
252
+ max: rows[0].max,
253
+ };
256
254
  })));
257
255
  return result;
258
256
  });
@@ -261,36 +259,24 @@ class ClickhouseConnector extends AdminForthBaseConnector {
261
259
  return __awaiter(this, arguments, void 0, function* ({ resource, record }) {
262
260
  const tableName = resource.table;
263
261
  const columns = Object.keys(record);
264
- // const q = `INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (${columns.map((colName) => {
265
- // const colType = resource.dataSourceColumns.find((col) => col.name == colName)._underlineType;
266
- // if (colType.startsWith('Int') || colType.startsWith('UInt') || colType.startsWith('Float')) {
267
- // return record[colName];
268
- // } else {
269
- // return "'"+record[colName]+"'"
270
- // }
271
- // }).join(', ') })`;
272
- // console.log('🪲 Clickhouse Query', q) ;
273
- // await this.client.command({
274
- // query: q,
275
- // });
276
- console.log('🪲 Clickhouse Insert', record);
277
262
  yield this.client.insert({
278
263
  database: this.dbName,
279
264
  table: tableName,
280
265
  columns: columns,
281
266
  values: [Object.values(record)],
282
267
  });
283
- console.log('🪲 Clickhouse Query done');
284
268
  });
285
269
  }
286
270
  updateRecord(_a) {
287
271
  return __awaiter(this, arguments, void 0, function* ({ resource, recordId, newValues }) {
288
- const columnsWithPlaceholders = Object.keys(newValues).map((col) => `${col} = ?`);
272
+ const columnsWithPlaceholders = Object.keys(newValues).map((col) => {
273
+ return `${col} = {${col}:${resource.dataSourceColumns.find((c) => c.name == col)._underlineType}}`;
274
+ });
289
275
  const values = [...Object.values(newValues), recordId];
290
- // const q = this.db.prepare(
291
- // `UPDATE ${resource.table} SET ${columnsWithPlaceholders} WHERE ${this.getPrimaryKey(resource)} = ?`
292
- // )
293
- // await q.run(values);
276
+ yield this.client.command({
277
+ query: `ALTER TABLE ${this.dbName}.${resource.table} UPDATE ${columnsWithPlaceholders.join(', ')} WHERE ${this.getPrimaryKey(resource)} = {recordId:${resource.dataSourceColumns.find((c) => c.primaryKey)._underlineType}}`,
278
+ query_params: Object.assign(Object.assign({}, newValues), { recordId }),
279
+ });
294
280
  });
295
281
  }
296
282
  deleteRecord(_a) {
@@ -22,17 +22,23 @@
22
22
  </div>
23
23
  <!-- Modal body -->
24
24
  <div class="p-4 md:p-5">
25
- <form class="space-y-4" @submit.prevent>
25
+ <form class="space-y-4" @submit.prevent>
26
26
  <div>
27
27
  <label for="username" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your {{ coreStore.config?.usernameFieldName?.toLowerCase() }}</label>
28
- <input type="username" name="username" id="username" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
28
+ <input type="username" name="username" id="username"
29
+ ref="usernameInput"
30
+ @keydown.enter="passwordInput.focus()"
31
+ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
29
32
  </div>
30
33
  <div class="relative">
31
34
  <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your password</label>
32
- <input :type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
35
+ <input
36
+ ref="passwordInput"
37
+ @keydown.enter="login"
38
+ :type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
33
39
  <button type="button" @click="showPw = !showPw" class="absolute top-12 right-3 -translate-y-1/2 text-gray-400 dark:text-gray-300">
34
- <IconEyeSolid class="w-5 h-5" v-if="!showPw" />
35
- <IconEyeSlashSolid class="w-5 h-5" v-else />
40
+ <IconEyeSolid class="w-5 h-5" v-if="!showPw" />
41
+ <IconEyeSlashSolid class="w-5 h-5" v-else />
36
42
  </button>
37
43
  </div>
38
44
  <!-- <div class="flex justify-between">
@@ -86,6 +92,8 @@ import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbi
86
92
  import { callAdminForthApi, loadFile } from '@/utils';
87
93
  import { useRouter } from 'vue-router';
88
94
 
95
+ const passwordInput = ref(null);
96
+ const usernameInput = ref(null);
89
97
 
90
98
  const router = useRouter();
91
99
  const inProgress = ref(false);
@@ -99,31 +107,36 @@ const showPw = ref(false);
99
107
  const error = ref(null);
100
108
 
101
109
  onMounted(() => {
102
- coreStore.getPublicConfig()
110
+ coreStore.getPublicConfig();
111
+ usernameInput.value.focus();
103
112
  });
104
113
 
105
114
 
106
-
107
115
  async function login() {
108
- inProgress.value = true;
109
- const resp = await callAdminForthApi({
110
- path: '/login',
111
- method: 'POST',
112
- body: {
113
- username: document.getElementById('username').value,
114
- password: document.getElementById('password').value,
115
- }
116
- });
117
- inProgress.value = false;
118
- if (resp.error) {
119
- error.value = resp.error;
120
- } else if (resp.redirectTo) {
121
- router.push(resp.redirectTo);
122
- } else {
123
- error.value = null;
124
- await user.finishLogin();
116
+ const username = usernameInput.value.value;
117
+ const password = passwordInput.value.value;
118
+
119
+ if (!username || !password) {
120
+ return;
121
+ }
122
+ inProgress.value = true;
123
+ const resp = await callAdminForthApi({
124
+ path: '/login',
125
+ method: 'POST',
126
+ body: {
127
+ username,
128
+ password,
125
129
  }
126
-
130
+ });
131
+ inProgress.value = false;
132
+ if (resp.error) {
133
+ error.value = resp.error;
134
+ } else if (resp.redirectTo) {
135
+ router.push(resp.redirectTo);
136
+ } else {
137
+ error.value = null;
138
+ await user.finishLogin();
139
+ }
127
140
  }
128
141
 
129
142
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adminforth",
3
- "version": "1.2.29",
3
+ "version": "1.2.31",
4
4
  "description": "OpenSource Vue3 powered forth-generation admin panel",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,17 +22,23 @@
22
22
  </div>
23
23
  <!-- Modal body -->
24
24
  <div class="p-4 md:p-5">
25
- <form class="space-y-4" @submit.prevent>
25
+ <form class="space-y-4" @submit.prevent>
26
26
  <div>
27
27
  <label for="username" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your {{ coreStore.config?.usernameFieldName?.toLowerCase() }}</label>
28
- <input type="username" name="username" id="username" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
28
+ <input type="username" name="username" id="username"
29
+ ref="usernameInput"
30
+ @keydown.enter="passwordInput.focus()"
31
+ class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" placeholder="name@company.com" required />
29
32
  </div>
30
33
  <div class="relative">
31
34
  <label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your password</label>
32
- <input :type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
35
+ <input
36
+ ref="passwordInput"
37
+ @keydown.enter="login"
38
+ :type="!showPw ? 'password': 'text'" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" required />
33
39
  <button type="button" @click="showPw = !showPw" class="absolute top-12 right-3 -translate-y-1/2 text-gray-400 dark:text-gray-300">
34
- <IconEyeSolid class="w-5 h-5" v-if="!showPw" />
35
- <IconEyeSlashSolid class="w-5 h-5" v-else />
40
+ <IconEyeSolid class="w-5 h-5" v-if="!showPw" />
41
+ <IconEyeSlashSolid class="w-5 h-5" v-else />
36
42
  </button>
37
43
  </div>
38
44
  <!-- <div class="flex justify-between">
@@ -86,6 +92,8 @@ import { IconEyeSolid, IconEyeSlashSolid } from '@iconify-prerendered/vue-flowbi
86
92
  import { callAdminForthApi, loadFile } from '@/utils';
87
93
  import { useRouter } from 'vue-router';
88
94
 
95
+ const passwordInput = ref(null);
96
+ const usernameInput = ref(null);
89
97
 
90
98
  const router = useRouter();
91
99
  const inProgress = ref(false);
@@ -99,31 +107,36 @@ const showPw = ref(false);
99
107
  const error = ref(null);
100
108
 
101
109
  onMounted(() => {
102
- coreStore.getPublicConfig()
110
+ coreStore.getPublicConfig();
111
+ usernameInput.value.focus();
103
112
  });
104
113
 
105
114
 
106
-
107
115
  async function login() {
108
- inProgress.value = true;
109
- const resp = await callAdminForthApi({
110
- path: '/login',
111
- method: 'POST',
112
- body: {
113
- username: document.getElementById('username').value,
114
- password: document.getElementById('password').value,
115
- }
116
- });
117
- inProgress.value = false;
118
- if (resp.error) {
119
- error.value = resp.error;
120
- } else if (resp.redirectTo) {
121
- router.push(resp.redirectTo);
122
- } else {
123
- error.value = null;
124
- await user.finishLogin();
116
+ const username = usernameInput.value.value;
117
+ const password = passwordInput.value.value;
118
+
119
+ if (!username || !password) {
120
+ return;
121
+ }
122
+ inProgress.value = true;
123
+ const resp = await callAdminForthApi({
124
+ path: '/login',
125
+ method: 'POST',
126
+ body: {
127
+ username,
128
+ password,
125
129
  }
126
-
130
+ });
131
+ inProgress.value = false;
132
+ if (resp.error) {
133
+ error.value = resp.error;
134
+ } else if (resp.redirectTo) {
135
+ router.push(resp.redirectTo);
136
+ } else {
137
+ error.value = null;
138
+ await user.finishLogin();
139
+ }
127
140
  }
128
141
 
129
142