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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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) =>
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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) =>
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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"
|
|
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"
|
|
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
|
|
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
|
-
|
|
35
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
@@ -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"
|
|
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"
|
|
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
|
|
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
|
-
|
|
35
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
|