@opengis/bi 1.2.32 → 1.2.34
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/README.md +92 -92
- package/dist/bi.js +1 -1
- package/dist/bi.umd.cjs +68 -68
- package/dist/{import-file-D-ISqB7l.js → import-file-BwxPX622.js} +1132 -1079
- package/dist/style.css +1 -1
- package/dist/{vs-funnel-bar-aoZzvriV.js → vs-funnel-bar-BV18EA4K.js} +3 -3
- package/dist/{vs-list-CBkyJSBj.js → vs-list-WrrWQ5KF.js} +32 -53
- package/dist/{vs-map-C3C11qmT.js → vs-map-CYd9vdrd.js} +3 -3
- package/dist/{vs-map-cluster-BsPmHIMx.js → vs-map-cluster-5TnGPuBH.js} +3 -3
- package/dist/{vs-number-d58ftpH5.js → vs-number-DUeRr7uz.js} +3 -3
- package/dist/{vs-table-BHa5Velm.js → vs-table-CZJnXfUv.js} +6 -6
- package/dist/{vs-text-Bq87gMTx.js → vs-text-D3nCPkgk.js} +4 -4
- package/package.json +77 -77
- package/plugin.js +21 -21
- package/server/helpers/mdToHTML.js +17 -17
- package/server/migrations/bi.dataset.sql +46 -46
- package/server/migrations/bi.sql +114 -114
- package/server/plugins/docs.js +48 -48
- package/server/plugins/hook.js +89 -89
- package/server/routes/dashboard/controllers/dashboard.import.js +103 -103
- package/server/routes/dashboard/controllers/dashboard.js +158 -158
- package/server/routes/dashboard/controllers/dashboard.list.js +60 -60
- package/server/routes/dashboard/controllers/utils/yaml.js +11 -11
- package/server/routes/dashboard/index.mjs +26 -26
- package/server/routes/data/controllers/data.js +230 -230
- package/server/routes/data/controllers/util/chartSQL.js +49 -49
- package/server/routes/data/controllers/util/normalizeData.js +65 -65
- package/server/routes/data/index.mjs +38 -38
- package/server/routes/dataset/controllers/bi.dataset.list.js +29 -29
- package/server/routes/dataset/controllers/bi.db.list.js +19 -19
- package/server/routes/dataset/controllers/comment.js +55 -55
- package/server/routes/dataset/controllers/createDatasetPost.js +134 -134
- package/server/routes/dataset/controllers/data.js +149 -149
- package/server/routes/dataset/controllers/dbTablePreview.js +58 -58
- package/server/routes/dataset/controllers/dbTables.js +34 -34
- package/server/routes/dataset/controllers/delete.js +40 -40
- package/server/routes/dataset/controllers/deleteDataset.js +52 -52
- package/server/routes/dataset/controllers/editDataset.js +90 -90
- package/server/routes/dataset/controllers/export.js +214 -214
- package/server/routes/dataset/controllers/form.js +99 -99
- package/server/routes/dataset/controllers/format.js +46 -46
- package/server/routes/dataset/controllers/insert.js +47 -47
- package/server/routes/dataset/controllers/table.js +68 -68
- package/server/routes/dataset/controllers/update.js +43 -43
- package/server/routes/dataset/index.mjs +132 -132
- package/server/routes/dataset/utils/convertJSONToCSV.js +17 -17
- package/server/routes/dataset/utils/convertJSONToXls.js +47 -47
- package/server/routes/dataset/utils/createTableQuery.js +59 -59
- package/server/routes/dataset/utils/datasetForms.js +1 -1
- package/server/routes/dataset/utils/descriptionList.js +45 -45
- package/server/routes/dataset/utils/downloadRemoteFile.js +58 -58
- package/server/routes/dataset/utils/executeQuery.js +46 -46
- package/server/routes/dataset/utils/getLayersData.js +106 -106
- package/server/routes/dataset/utils/getTableData.js +46 -46
- package/server/routes/dataset/utils/insertDataQuery.js +12 -12
- package/server/routes/dataset/utils/metaFormat.js +24 -24
- package/server/routes/edit/controllers/dashboard.add.js +36 -36
- package/server/routes/edit/controllers/dashboard.delete.js +39 -39
- package/server/routes/edit/controllers/dashboard.edit.js +61 -61
- package/server/routes/edit/controllers/widget.add.js +78 -78
- package/server/routes/edit/controllers/widget.del.js +58 -58
- package/server/routes/edit/controllers/widget.edit.js +115 -115
- package/server/routes/edit/index.mjs +33 -33
- package/server/routes/map/controllers/cluster.js +125 -125
- package/server/routes/map/controllers/clusterVtile.js +166 -166
- package/server/routes/map/controllers/geojson.js +127 -127
- package/server/routes/map/controllers/heatmap.js +118 -118
- package/server/routes/map/controllers/map.js +69 -69
- package/server/routes/map/controllers/utils/downloadClusterData.js +44 -44
- package/server/routes/map/controllers/vtile.js +183 -183
- package/server/routes/map/index.mjs +32 -32
- package/server/templates/page/login.html +58 -58
- package/server/utils/getWidget.js +118 -118
- package/utils.js +12 -12
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
export default async function convertJSONToCSV({
|
|
5
|
-
filepathJSON, send = () => { }, delimiter = ';',
|
|
6
|
-
}) {
|
|
7
|
-
if (!filepathJSON) return null;
|
|
8
|
-
const rows = JSON.parse(await readFile(filepathJSON) || '{}');
|
|
9
|
-
const values = rows.map((row) => Object.values(row).map((el) => `${el};`));
|
|
10
|
-
values.unshift(Object.keys(rows[0]).map((el) => `${el};`));
|
|
11
|
-
|
|
12
|
-
send('Конвертація успішно завершена. Формування файлу...');
|
|
13
|
-
await mkdir(path.dirname(filepathJSON), { recursive: true });
|
|
14
|
-
await writeFile(filepathJSON.replace('.json', '.csv'), `\ufeff${values.join('\n').replace(/;,/g, delimiter)}`, 'utf8');
|
|
15
|
-
send('Файл успішно сформовано. Оновіть сторінку або натисніть кнопку ще раз для завантаження. ', 1);
|
|
16
|
-
return { message: 'Файл успішно сформовано. Натистіть кнопку ще раз для завантаження даних', status: 200 };
|
|
17
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
export default async function convertJSONToCSV({
|
|
5
|
+
filepathJSON, send = () => { }, delimiter = ';',
|
|
6
|
+
}) {
|
|
7
|
+
if (!filepathJSON) return null;
|
|
8
|
+
const rows = JSON.parse(await readFile(filepathJSON) || '{}');
|
|
9
|
+
const values = rows.map((row) => Object.values(row).map((el) => `${el};`));
|
|
10
|
+
values.unshift(Object.keys(rows[0]).map((el) => `${el};`));
|
|
11
|
+
|
|
12
|
+
send('Конвертація успішно завершена. Формування файлу...');
|
|
13
|
+
await mkdir(path.dirname(filepathJSON), { recursive: true });
|
|
14
|
+
await writeFile(filepathJSON.replace('.json', '.csv'), `\ufeff${values.join('\n').replace(/;,/g, delimiter)}`, 'utf8');
|
|
15
|
+
send('Файл успішно сформовано. Оновіть сторінку або натисніть кнопку ще раз для завантаження. ', 1);
|
|
16
|
+
return { message: 'Файл успішно сформовано. Натистіть кнопку ще раз для завантаження даних', status: 200 };
|
|
17
|
+
}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import {
|
|
3
|
-
mkdir, readFile, writeFile,
|
|
4
|
-
} from 'fs/promises';
|
|
5
|
-
|
|
6
|
-
import { logger, grpc } from '@opengis/fastify-table/utils.js';
|
|
7
|
-
|
|
8
|
-
const { jsonToXls } = grpc();
|
|
9
|
-
|
|
10
|
-
export default async function convertJSONToXls({
|
|
11
|
-
filepathJSON, colmodel, domain, source, send = () => { },
|
|
12
|
-
}) {
|
|
13
|
-
if (!filepathJSON) return null;
|
|
14
|
-
|
|
15
|
-
const rows = JSON.parse(await readFile(filepathJSON) || '{}');
|
|
16
|
-
|
|
17
|
-
if (!rows?.length) {
|
|
18
|
-
return { message: 'empty rows', status: 400 };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
send('Конвертація файлу...');
|
|
22
|
-
try {
|
|
23
|
-
const { result } = await jsonToXls({
|
|
24
|
-
json: JSON.stringify(rows),
|
|
25
|
-
header: source,
|
|
26
|
-
subheader: `Завантажено з порталу ${domain} - ${new Date().toLocaleDateString()}. Всього: ${rows.length}`,
|
|
27
|
-
colmodel: JSON.stringify(colmodel),
|
|
28
|
-
});
|
|
29
|
-
send('Конвертація успішно завершена. Формування файлу...');
|
|
30
|
-
await mkdir(path.dirname(filepathJSON), { recursive: true });
|
|
31
|
-
await writeFile(filepathJSON.replace('.json', '.xlsx'), result, 'base64');
|
|
32
|
-
send('Файл успішно сформовано. Оновіть сторінку або натисніть кнопку ще раз для завантаження. ', 1);
|
|
33
|
-
return { message: 'Файл успішно сформовано. Натистіть кнопку ще раз для завантаження даних', status: 200 };
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
send(`jsonToXLS err: ${err.toString()}`, 1);
|
|
37
|
-
logger.error({
|
|
38
|
-
name: 'export/table',
|
|
39
|
-
filepathJSON,
|
|
40
|
-
colmodel,
|
|
41
|
-
domain,
|
|
42
|
-
rows: rows.length,
|
|
43
|
-
error: err.toString(),
|
|
44
|
-
});
|
|
45
|
-
return { error: err.toString(), status: 500 };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import {
|
|
3
|
+
mkdir, readFile, writeFile,
|
|
4
|
+
} from 'fs/promises';
|
|
5
|
+
|
|
6
|
+
import { logger, grpc } from '@opengis/fastify-table/utils.js';
|
|
7
|
+
|
|
8
|
+
const { jsonToXls } = grpc();
|
|
9
|
+
|
|
10
|
+
export default async function convertJSONToXls({
|
|
11
|
+
filepathJSON, colmodel, domain, source, send = () => { },
|
|
12
|
+
}) {
|
|
13
|
+
if (!filepathJSON) return null;
|
|
14
|
+
|
|
15
|
+
const rows = JSON.parse(await readFile(filepathJSON) || '{}');
|
|
16
|
+
|
|
17
|
+
if (!rows?.length) {
|
|
18
|
+
return { message: 'empty rows', status: 400 };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
send('Конвертація файлу...');
|
|
22
|
+
try {
|
|
23
|
+
const { result } = await jsonToXls({
|
|
24
|
+
json: JSON.stringify(rows),
|
|
25
|
+
header: source,
|
|
26
|
+
subheader: `Завантажено з порталу ${domain} - ${new Date().toLocaleDateString()}. Всього: ${rows.length}`,
|
|
27
|
+
colmodel: JSON.stringify(colmodel),
|
|
28
|
+
});
|
|
29
|
+
send('Конвертація успішно завершена. Формування файлу...');
|
|
30
|
+
await mkdir(path.dirname(filepathJSON), { recursive: true });
|
|
31
|
+
await writeFile(filepathJSON.replace('.json', '.xlsx'), result, 'base64');
|
|
32
|
+
send('Файл успішно сформовано. Оновіть сторінку або натисніть кнопку ще раз для завантаження. ', 1);
|
|
33
|
+
return { message: 'Файл успішно сформовано. Натистіть кнопку ще раз для завантаження даних', status: 200 };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
send(`jsonToXLS err: ${err.toString()}`, 1);
|
|
37
|
+
logger.error({
|
|
38
|
+
name: 'export/table',
|
|
39
|
+
filepathJSON,
|
|
40
|
+
colmodel,
|
|
41
|
+
domain,
|
|
42
|
+
rows: rows.length,
|
|
43
|
+
error: err.toString(),
|
|
44
|
+
});
|
|
45
|
+
return { error: err.toString(), status: 500 };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import { randomBytes, createHash } from 'node:crypto';
|
|
2
|
-
|
|
3
|
-
const schema = 'data_user';
|
|
4
|
-
|
|
5
|
-
const columnType = {
|
|
6
|
-
text: 'text',
|
|
7
|
-
select: 'text',
|
|
8
|
-
date: 'date',
|
|
9
|
-
'yes/no': 'boolean',
|
|
10
|
-
badge: 'text',
|
|
11
|
-
number: 'numeric',
|
|
12
|
-
tags: 'text[]',
|
|
13
|
-
geom: 'geom',
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default function createTable(columns, name) {
|
|
17
|
-
const tableName = randomBytes(64).toString('hex').substring(0, 24).replace(/^\d+/, '');
|
|
18
|
-
const table = `${schema}.${tableName}`;
|
|
19
|
-
const pkey = tableName.concat('_id');
|
|
20
|
-
|
|
21
|
-
columns?.forEach?.((el, i) => Object.assign(el, {
|
|
22
|
-
name: `col_${i}`, // el.name
|
|
23
|
-
type: columnType[el.format || 'text'] || 'text',
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
const clsQuery = columns
|
|
27
|
-
?.filter?.(col => col?.format === 'select' && col.data?.length)
|
|
28
|
-
?.map(col => {
|
|
29
|
-
const data = JSON.stringify(col.data).replace(/'/g, "''");
|
|
30
|
-
Object.assign(col, { data: createHash('md5').update([tableName, col.name].join()).digest('hex') });
|
|
31
|
-
return `insert into admin.cls(clsid,name,type,module) values('${col.data}','${col.data}','json', '${table}');
|
|
32
|
-
insert into admin.cls(code,name,parent,icon,data,module)
|
|
33
|
-
select value->>'id',value->>'text','${col.data}',value->>'icon',value->>'data', '${table}'
|
|
34
|
-
from json_array_elements('${data}'::json)`;
|
|
35
|
-
})
|
|
36
|
-
?.join(';');
|
|
37
|
-
|
|
38
|
-
const createQuery = `create table if not exists ${table} (
|
|
39
|
-
${pkey} text not null default encode(public.gen_random_bytes(6), 'hex'),
|
|
40
|
-
geom public.geometry, ${columns ? `
|
|
41
|
-
${columns?.map?.((el) => `${el.name} ${el.type}`).join(', ')},` : ''}
|
|
42
|
-
cdate timestamp without time zone not null default now(),
|
|
43
|
-
editor_date timestamp without time zone,
|
|
44
|
-
uid text,
|
|
45
|
-
editor_id text,
|
|
46
|
-
files json,
|
|
47
|
-
constraint ${table.replace(/\./g, '_')}_constraint_pkey PRIMARY KEY (${pkey}) )`;
|
|
48
|
-
|
|
49
|
-
const commentQuery = columns
|
|
50
|
-
?.filter?.((el) => el.title)
|
|
51
|
-
?.map((el) => `comment on column ${table}.${el.name} is '${el.title}'`)
|
|
52
|
-
?.join(';');
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
table,
|
|
56
|
-
pkey,
|
|
57
|
-
sql: [createQuery, commentQuery, (name ? `comment on table ${table} is '${name}'` : undefined), clsQuery].filter((el) => el).join(';'),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
1
|
+
import { randomBytes, createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
const schema = 'data_user';
|
|
4
|
+
|
|
5
|
+
const columnType = {
|
|
6
|
+
text: 'text',
|
|
7
|
+
select: 'text',
|
|
8
|
+
date: 'date',
|
|
9
|
+
'yes/no': 'boolean',
|
|
10
|
+
badge: 'text',
|
|
11
|
+
number: 'numeric',
|
|
12
|
+
tags: 'text[]',
|
|
13
|
+
geom: 'geom',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function createTable(columns, name) {
|
|
17
|
+
const tableName = randomBytes(64).toString('hex').substring(0, 24).replace(/^\d+/, '');
|
|
18
|
+
const table = `${schema}.${tableName}`;
|
|
19
|
+
const pkey = tableName.concat('_id');
|
|
20
|
+
|
|
21
|
+
columns?.forEach?.((el, i) => Object.assign(el, {
|
|
22
|
+
name: `col_${i}`, // el.name
|
|
23
|
+
type: columnType[el.format || 'text'] || 'text',
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const clsQuery = columns
|
|
27
|
+
?.filter?.(col => col?.format === 'select' && col.data?.length)
|
|
28
|
+
?.map(col => {
|
|
29
|
+
const data = JSON.stringify(col.data).replace(/'/g, "''");
|
|
30
|
+
Object.assign(col, { data: createHash('md5').update([tableName, col.name].join()).digest('hex') });
|
|
31
|
+
return `insert into admin.cls(clsid,name,type,module) values('${col.data}','${col.data}','json', '${table}');
|
|
32
|
+
insert into admin.cls(code,name,parent,icon,data,module)
|
|
33
|
+
select value->>'id',value->>'text','${col.data}',value->>'icon',value->>'data', '${table}'
|
|
34
|
+
from json_array_elements('${data}'::json)`;
|
|
35
|
+
})
|
|
36
|
+
?.join(';');
|
|
37
|
+
|
|
38
|
+
const createQuery = `create table if not exists ${table} (
|
|
39
|
+
${pkey} text not null default encode(public.gen_random_bytes(6), 'hex'),
|
|
40
|
+
geom public.geometry, ${columns ? `
|
|
41
|
+
${columns?.map?.((el) => `${el.name} ${el.type}`).join(', ')},` : ''}
|
|
42
|
+
cdate timestamp without time zone not null default now(),
|
|
43
|
+
editor_date timestamp without time zone,
|
|
44
|
+
uid text,
|
|
45
|
+
editor_id text,
|
|
46
|
+
files json,
|
|
47
|
+
constraint ${table.replace(/\./g, '_')}_constraint_pkey PRIMARY KEY (${pkey}) )`;
|
|
48
|
+
|
|
49
|
+
const commentQuery = columns
|
|
50
|
+
?.filter?.((el) => el.title)
|
|
51
|
+
?.map((el) => `comment on column ${table}.${el.name} is '${el.title}'`)
|
|
52
|
+
?.join(';');
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
table,
|
|
56
|
+
pkey,
|
|
57
|
+
sql: [createQuery, commentQuery, (name ? `comment on table ${table} is '${name}'` : undefined), clsQuery].filter((el) => el).join(';'),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default {};
|
|
1
|
+
export default {};
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { handlebarsSync, handlebars } from '@opengis/fastify-table/utils.js'
|
|
2
|
-
|
|
3
|
-
function format(d, key, data) {
|
|
4
|
-
if (!key?.includes) return '';
|
|
5
|
-
if (d === true) return 'так';
|
|
6
|
-
if (d === false) return 'ні'
|
|
7
|
-
|
|
8
|
-
if (key.includes('{{')) {
|
|
9
|
-
return handlebarsSync.compile(key)(data);
|
|
10
|
-
}
|
|
11
|
-
if (!d) return '-';
|
|
12
|
-
return d;
|
|
13
|
-
}
|
|
14
|
-
export default async function descriptionList(data, opt) {
|
|
15
|
-
const { hash } = opt;
|
|
16
|
-
|
|
17
|
-
// no data
|
|
18
|
-
if (hash.nodata && !data) {
|
|
19
|
-
const noDataText = typeof hash.nodata == 'string' ? hash.nodata : 'no data';
|
|
20
|
-
return noDataText
|
|
21
|
-
}
|
|
22
|
-
if (!data) return 'empty data'
|
|
23
|
-
if (!hash.columns.split) return 'columns empty' + JSON.stringify(hash.columns)
|
|
24
|
-
const keys = hash.columns.split(hash.divider || '|').map(el => hash.comma ? el.trim().replace(new RegExp(hash.comma || '#', 'g'), ',') : el.trim());
|
|
25
|
-
|
|
26
|
-
const result = [];
|
|
27
|
-
|
|
28
|
-
for (let i = 0; i < keys.length; i += 2) {
|
|
29
|
-
const name = keys[i];
|
|
30
|
-
const nameHBS = name.includes('{{') ? handlebarsSync.compile(name)({ ...data, hash }) : false
|
|
31
|
-
|
|
32
|
-
if (!nameHBS && name.includes('{{')) continue;
|
|
33
|
-
|
|
34
|
-
const key = keys[i + 1];
|
|
35
|
-
const d1 = ['{{format', '{{select', '{{badge', '{{ifCond'].filter(el => key?.includes?.(el)).length ? await handlebars.compile(key)(data) || '-' : null
|
|
36
|
-
if (d1 || data[key]) {
|
|
37
|
-
result.push(`<div class="flex py-[16px] text-[14px] border-b border-[#E5E7EB">
|
|
38
|
-
<div class="text-[#6B7280] dark:text-white font-[600] w-[50%]">${nameHBS || name}</div>
|
|
39
|
-
<div class="font-[400] text-black dark:text-[#bdbdbd] w-[50%]">${d1 || format(data[key], key, data)}</div>
|
|
40
|
-
</div>
|
|
41
|
-
`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
return '<div class="w-full">' + result.join('') + '</div>';
|
|
1
|
+
import { handlebarsSync, handlebars } from '@opengis/fastify-table/utils.js'
|
|
2
|
+
|
|
3
|
+
function format(d, key, data) {
|
|
4
|
+
if (!key?.includes) return '';
|
|
5
|
+
if (d === true) return 'так';
|
|
6
|
+
if (d === false) return 'ні'
|
|
7
|
+
|
|
8
|
+
if (key.includes('{{')) {
|
|
9
|
+
return handlebarsSync.compile(key)(data);
|
|
10
|
+
}
|
|
11
|
+
if (!d) return '-';
|
|
12
|
+
return d;
|
|
13
|
+
}
|
|
14
|
+
export default async function descriptionList(data, opt) {
|
|
15
|
+
const { hash } = opt;
|
|
16
|
+
|
|
17
|
+
// no data
|
|
18
|
+
if (hash.nodata && !data) {
|
|
19
|
+
const noDataText = typeof hash.nodata == 'string' ? hash.nodata : 'no data';
|
|
20
|
+
return noDataText
|
|
21
|
+
}
|
|
22
|
+
if (!data) return 'empty data'
|
|
23
|
+
if (!hash.columns.split) return 'columns empty' + JSON.stringify(hash.columns)
|
|
24
|
+
const keys = hash.columns.split(hash.divider || '|').map(el => hash.comma ? el.trim().replace(new RegExp(hash.comma || '#', 'g'), ',') : el.trim());
|
|
25
|
+
|
|
26
|
+
const result = [];
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < keys.length; i += 2) {
|
|
29
|
+
const name = keys[i];
|
|
30
|
+
const nameHBS = name.includes('{{') ? handlebarsSync.compile(name)({ ...data, hash }) : false
|
|
31
|
+
|
|
32
|
+
if (!nameHBS && name.includes('{{')) continue;
|
|
33
|
+
|
|
34
|
+
const key = keys[i + 1];
|
|
35
|
+
const d1 = ['{{format', '{{select', '{{badge', '{{ifCond'].filter(el => key?.includes?.(el)).length ? await handlebars.compile(key)(data) || '-' : null
|
|
36
|
+
if (d1 || data[key]) {
|
|
37
|
+
result.push(`<div class="flex py-[16px] text-[14px] border-b border-[#E5E7EB">
|
|
38
|
+
<div class="text-[#6B7280] dark:text-white font-[600] w-[50%]">${nameHBS || name}</div>
|
|
39
|
+
<div class="font-[400] text-black dark:text-[#bdbdbd] w-[50%]">${d1 || format(data[key], key, data)}</div>
|
|
40
|
+
</div>
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
return '<div class="w-full">' + result.join('') + '</div>';
|
|
46
46
|
}
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { rm, mkdir, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { createHash } from 'node:crypto';
|
|
5
|
-
|
|
6
|
-
import { config, logger } from '@opengis/fastify-table/utils.js';
|
|
7
|
-
|
|
8
|
-
export default async function downloadRemoteFile({
|
|
9
|
-
rootDir, url, table,
|
|
10
|
-
}) {
|
|
11
|
-
if (!rootDir) {
|
|
12
|
-
return { error: 'param rootDir is required', status: 400 };
|
|
13
|
-
}
|
|
14
|
-
if (!url) {
|
|
15
|
-
return { error: 'param url is required', status: 400 };
|
|
16
|
-
}
|
|
17
|
-
if (!table) {
|
|
18
|
-
return { error: 'param table is required', status: 400 };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const response = await fetch(url);
|
|
23
|
-
|
|
24
|
-
if (response?.status !== 200) {
|
|
25
|
-
return { message: 'file not found', status: response?.status };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
29
|
-
const buffer = Buffer.from(arrayBuffer);
|
|
30
|
-
|
|
31
|
-
const contentType = response.headers.get('Content-Type');
|
|
32
|
-
|
|
33
|
-
// eslint-disable-next-line newline-per-chained-call
|
|
34
|
-
const extName = contentType === 'text/plain' ? path.extname(url) : `.${response.headers.get('Content-Type')?.split(';')?.shift()?.split('/')?.pop()?.replace(/\+|\-|\./g, '')}`; // path.extname(url)
|
|
35
|
-
|
|
36
|
-
const filePath = `/files/tmp/${createHash('md5').update([url, table].join()).digest('hex')}${extName}`;
|
|
37
|
-
const fullPath = path.join(rootDir, filePath);
|
|
38
|
-
|
|
39
|
-
if (config?.local) {
|
|
40
|
-
console.log(url, fullPath, existsSync(fullPath));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
await mkdir(path.dirname(fullPath), { recursive: true });
|
|
44
|
-
|
|
45
|
-
if (existsSync(fullPath) && config?.local) {
|
|
46
|
-
await rm(fullPath);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (!existsSync(fullPath)) {
|
|
50
|
-
await writeFile(fullPath, buffer);
|
|
51
|
-
}
|
|
52
|
-
return { filePath };
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
logger.file('dataset/create/error', { url, error: err.toString() });
|
|
56
|
-
return { error: err.toString(), status: 500 };
|
|
57
|
-
}
|
|
58
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { rm, mkdir, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
|
|
6
|
+
import { config, logger } from '@opengis/fastify-table/utils.js';
|
|
7
|
+
|
|
8
|
+
export default async function downloadRemoteFile({
|
|
9
|
+
rootDir, url, table,
|
|
10
|
+
}) {
|
|
11
|
+
if (!rootDir) {
|
|
12
|
+
return { error: 'param rootDir is required', status: 400 };
|
|
13
|
+
}
|
|
14
|
+
if (!url) {
|
|
15
|
+
return { error: 'param url is required', status: 400 };
|
|
16
|
+
}
|
|
17
|
+
if (!table) {
|
|
18
|
+
return { error: 'param table is required', status: 400 };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(url);
|
|
23
|
+
|
|
24
|
+
if (response?.status !== 200) {
|
|
25
|
+
return { message: 'file not found', status: response?.status };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
29
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
30
|
+
|
|
31
|
+
const contentType = response.headers.get('Content-Type');
|
|
32
|
+
|
|
33
|
+
// eslint-disable-next-line newline-per-chained-call
|
|
34
|
+
const extName = contentType === 'text/plain' ? path.extname(url) : `.${response.headers.get('Content-Type')?.split(';')?.shift()?.split('/')?.pop()?.replace(/\+|\-|\./g, '')}`; // path.extname(url)
|
|
35
|
+
|
|
36
|
+
const filePath = `/files/tmp/${createHash('md5').update([url, table].join()).digest('hex')}${extName}`;
|
|
37
|
+
const fullPath = path.join(rootDir, filePath);
|
|
38
|
+
|
|
39
|
+
if (config?.local) {
|
|
40
|
+
console.log(url, fullPath, existsSync(fullPath));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await mkdir(path.dirname(fullPath), { recursive: true });
|
|
44
|
+
|
|
45
|
+
if (existsSync(fullPath) && config?.local) {
|
|
46
|
+
await rm(fullPath);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!existsSync(fullPath)) {
|
|
50
|
+
await writeFile(fullPath, buffer);
|
|
51
|
+
}
|
|
52
|
+
return { filePath };
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
logger.file('dataset/create/error', { url, error: err.toString() });
|
|
56
|
+
return { error: err.toString(), status: 500 };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
import insertDataQuery from './insertDataQuery.js';
|
|
4
|
-
|
|
5
|
-
const insertDataset = `insert into bi.dataset
|
|
6
|
-
(name, table_name, dataset_file_path, column_list, pk, data_source, uid)
|
|
7
|
-
values($1,$2,$3,$4,$5,$6,$7) returning dataset_id`;
|
|
8
|
-
|
|
9
|
-
const updateAppeal = 'update datasets_appeal.appeal set dataset_id=$1, data_key=$2 where ap_id=$3';
|
|
10
|
-
|
|
11
|
-
export default async function executeQuery({
|
|
12
|
-
pg = pgClients.client, sql, data, name, id, table, relPath, columns, pkey, source, user, url, dataKey,
|
|
13
|
-
}) {
|
|
14
|
-
const client = await pg.connect();
|
|
15
|
-
try {
|
|
16
|
-
await client.query('BEGIN');
|
|
17
|
-
|
|
18
|
-
// create table
|
|
19
|
-
await client.query(sql);
|
|
20
|
-
|
|
21
|
-
// insert data
|
|
22
|
-
if (data) {
|
|
23
|
-
const insertData = insertDataQuery(columns, data, table);
|
|
24
|
-
await client.query(insertData);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// create dataset
|
|
28
|
-
const args = [name || id, table, relPath, columns ? JSON.stringify(columns) : null, pkey, JSON.stringify({ type: source, appeal: id, url }), user?.uid];
|
|
29
|
-
const datasetId = await client.query(insertDataset, args).then(el => el.rows?.[0]?.dataset_id);
|
|
30
|
-
|
|
31
|
-
if (id) {
|
|
32
|
-
// update appeal for public only, admin w/o appeal
|
|
33
|
-
await client.query(updateAppeal, [datasetId, dataKey, id]);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
await client.query('COMMIT');
|
|
37
|
-
return { datasetId };
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
await client.query('ROLLBACK');
|
|
41
|
-
return { error: err.toString(), status: 500 };
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
client.release();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
import { pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import insertDataQuery from './insertDataQuery.js';
|
|
4
|
+
|
|
5
|
+
const insertDataset = `insert into bi.dataset
|
|
6
|
+
(name, table_name, dataset_file_path, column_list, pk, data_source, uid)
|
|
7
|
+
values($1,$2,$3,$4,$5,$6,$7) returning dataset_id`;
|
|
8
|
+
|
|
9
|
+
const updateAppeal = 'update datasets_appeal.appeal set dataset_id=$1, data_key=$2 where ap_id=$3';
|
|
10
|
+
|
|
11
|
+
export default async function executeQuery({
|
|
12
|
+
pg = pgClients.client, sql, data, name, id, table, relPath, columns, pkey, source, user, url, dataKey,
|
|
13
|
+
}) {
|
|
14
|
+
const client = await pg.connect();
|
|
15
|
+
try {
|
|
16
|
+
await client.query('BEGIN');
|
|
17
|
+
|
|
18
|
+
// create table
|
|
19
|
+
await client.query(sql);
|
|
20
|
+
|
|
21
|
+
// insert data
|
|
22
|
+
if (data) {
|
|
23
|
+
const insertData = insertDataQuery(columns, data, table);
|
|
24
|
+
await client.query(insertData);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// create dataset
|
|
28
|
+
const args = [name || id, table, relPath, columns ? JSON.stringify(columns) : null, pkey, JSON.stringify({ type: source, appeal: id, url }), user?.uid];
|
|
29
|
+
const datasetId = await client.query(insertDataset, args).then(el => el.rows?.[0]?.dataset_id);
|
|
30
|
+
|
|
31
|
+
if (id) {
|
|
32
|
+
// update appeal for public only, admin w/o appeal
|
|
33
|
+
await client.query(updateAppeal, [datasetId, dataKey, id]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await client.query('COMMIT');
|
|
37
|
+
return { datasetId };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
await client.query('ROLLBACK');
|
|
41
|
+
return { error: err.toString(), status: 500 };
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
client.release();
|
|
45
|
+
}
|
|
46
|
+
}
|