@opengis/bi 1.0.1
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/.eslintrc.cjs +42 -0
- package/.prettierrc.json +9 -0
- package/README.md +22 -0
- package/config.example +21 -0
- package/config.js +12 -0
- package/dashboard/controllers/dashboard.js +22 -0
- package/dashboard/controllers/data.js +108 -0
- package/dashboard/controllers/geojson.js +3 -0
- package/dashboard/controllers/utils/yaml.js +12 -0
- package/dashboard/controllers/vtile.js +3 -0
- package/dashboard/index.mjs +35 -0
- package/helper.js +34 -0
- package/index.js +28 -0
- package/package.json +24 -0
- package/server.js +14 -0
- package/test/config.example +18 -0
- package/test/config.js +19 -0
- package/test/plugins/bi.test.js +76 -0
- package/test/templates/chart/bar.zone.yml +23 -0
- package/test/templates/chart/histogram.yml +14 -0
- package/test/templates/chart/line.yml +16 -0
- package/test/templates/chart/pivot.yml +11 -0
- package/test/templates/chart/table.yml +15 -0
- package/test/templates/chart/test.map.yml +28 -0
- package/test/templates/chart/user.yml +7 -0
- package/test/templates/dashboard/dashboard1.yml +11 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint-env node */
|
|
2
|
+
//require('@rushstack/eslint-patch/modern-module-resolution');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
root: true,
|
|
6
|
+
extends: [
|
|
7
|
+
'plugin:vue/vue3-essential',
|
|
8
|
+
'eslint:recommended',
|
|
9
|
+
'@vue/eslint-config-typescript',
|
|
10
|
+
'@vue/eslint-config-prettier/skip-formatting',
|
|
11
|
+
'airbnb-base',
|
|
12
|
+
],
|
|
13
|
+
parserOptions: {
|
|
14
|
+
ecmaVersion: 2024,
|
|
15
|
+
sourceType: 'module',
|
|
16
|
+
},
|
|
17
|
+
rules: {
|
|
18
|
+
'brace-style': [2, 'stroustrup', { allowSingleLine: true }],
|
|
19
|
+
'vue/max-attributes-per-line': 0,
|
|
20
|
+
'vue/valid-v-for': 0,
|
|
21
|
+
|
|
22
|
+
// allow async-await
|
|
23
|
+
'generator-star-spacing': 'off',
|
|
24
|
+
|
|
25
|
+
// allow paren-less arrow functions
|
|
26
|
+
'arrow-parens': 0,
|
|
27
|
+
'one-var': 0,
|
|
28
|
+
'max-len': 0,
|
|
29
|
+
'import/first': 0,
|
|
30
|
+
'import/named': 2,
|
|
31
|
+
'import/namespace': 2,
|
|
32
|
+
'import/default': 2,
|
|
33
|
+
'import/export': 2,
|
|
34
|
+
'import/extensions': 0,
|
|
35
|
+
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
|
36
|
+
'import/no-unresolved': 0,
|
|
37
|
+
'import/no-extraneous-dependencies': 0,
|
|
38
|
+
'linebreak-style': ['error', 'unix'],
|
|
39
|
+
// allow debugger during development
|
|
40
|
+
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
|
41
|
+
},
|
|
42
|
+
};
|
package/.prettierrc.json
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# bi
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@opengis/fastify-table)
|
|
4
|
+
[](http://standardjs.com/)
|
|
5
|
+
|
|
6
|
+
It standardizes the entire form bi visualization process:
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i @opengis/bi
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
fastify.register(import('@opengis/bi'), config);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Documenation
|
|
21
|
+
|
|
22
|
+
For a detailed understanding fastify-table, its features, and how to use them, refer to our [Documentation](https://apidocs.softpro.ua/bi/api/).
|
package/config.example
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"folder": "M:/work/geo/storage",
|
|
3
|
+
"templateDir": "test/templates",
|
|
4
|
+
"pg": {
|
|
5
|
+
"host": "192.168.3.160",
|
|
6
|
+
"port": 5432,
|
|
7
|
+
"database": "geo_green_poltava",
|
|
8
|
+
"user": "postgres",
|
|
9
|
+
"password": "postgres"
|
|
10
|
+
},
|
|
11
|
+
"redis": {
|
|
12
|
+
"host": "192.168.3.160",
|
|
13
|
+
"port": 6379,
|
|
14
|
+
"family": 4
|
|
15
|
+
},
|
|
16
|
+
"prefix": "/api",
|
|
17
|
+
"signServerAddress": "192.168.3.160:4001",
|
|
18
|
+
"mapServerAddress": "192.168.3.160:4002",
|
|
19
|
+
"convertServerAddress": "192.168.3.160:4003",
|
|
20
|
+
"gdalServerAddress": "192.168.3.160:4005"
|
|
21
|
+
}
|
package/config.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
|
|
3
|
+
import { readFile } from 'fs/promises';
|
|
4
|
+
|
|
5
|
+
const fileName = ['/data/local/config.json', 'config.json'].find(el => (fs.existsSync(el) ? el : null));
|
|
6
|
+
const config = fileName ? await readFile(fileName).then(el => JSON.parse(el)) : {};
|
|
7
|
+
|
|
8
|
+
Object.assign(config, {
|
|
9
|
+
allTemplates: config?.allTemplates || {},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export default config;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
//import { existsSync, readFileSync } from 'fs';
|
|
4
|
+
|
|
5
|
+
import yaml from './utils/yaml.js';
|
|
6
|
+
import getTemplate from '@opengis/fastify-table/table/controllers/utils/getTemplate.js';
|
|
7
|
+
|
|
8
|
+
export default async function data({ params, query = {} }) {
|
|
9
|
+
|
|
10
|
+
const { id, } = params;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if (!id) {
|
|
14
|
+
return { message: 'not enough params: dashboard required', status: 400 };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const yml = await getTemplate('dashboard', id);
|
|
18
|
+
if (!yml) return { message: 'not found ' + id, status: 404 };
|
|
19
|
+
const data = yaml.loadSafe(yml);
|
|
20
|
+
return data
|
|
21
|
+
|
|
22
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import getTemplate from '@opengis/fastify-table/table/controllers/utils/getTemplate.js';
|
|
3
|
+
import autoIndex from '@opengis/fastify-table/pg/funcs/autoIndex.js';
|
|
4
|
+
import pgClients from '@opengis/fastify-table/pg/pgClients.js';
|
|
5
|
+
|
|
6
|
+
//import { existsSync, readFileSync } from 'fs';
|
|
7
|
+
|
|
8
|
+
import yaml from './utils/yaml.js';
|
|
9
|
+
|
|
10
|
+
export default async function data({ pg = pgClients.client, funcs, query = {} }) {
|
|
11
|
+
const time = Date.now();
|
|
12
|
+
const {
|
|
13
|
+
dashboard, chart, filter,
|
|
14
|
+
} = query;
|
|
15
|
+
|
|
16
|
+
if (!chart && !dashboard) {
|
|
17
|
+
return { message: 'not enough params: chart or dashboard required', status: 400 };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const yml = await getTemplate('chart', chart);
|
|
21
|
+
if (!yml) return { message: 'not found ' + chart, status: 404 };
|
|
22
|
+
const { data, options, controls } = yaml.loadSafe(yml);
|
|
23
|
+
|
|
24
|
+
if (!data?.source) {
|
|
25
|
+
return { error: json.error || `invalid ${chart ? 'chart' : 'dashboard'}`, status: 500 };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const granularity = query.granularity || data.granularity || 'month';
|
|
30
|
+
|
|
31
|
+
const dimension = (data?.time ? `date_trunc('${granularity}',${data?.time})::date` : null) || data.dimension?.[0]?.name || data.dimension;
|
|
32
|
+
const metric = data.metrics?.map(el => `${el.operator || 'sum'}(${el.name}) as "${el.title || el.name}"`) || 'count(*)';
|
|
33
|
+
const groupby = query.groupby || data.groupby?.[0] || data.groupby;
|
|
34
|
+
|
|
35
|
+
// filter rows
|
|
36
|
+
const fData = filter ? await funcs.getFilterSQL({
|
|
37
|
+
filter, table: json.data.source, json: 1,
|
|
38
|
+
}) : {};
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
if (data.columns) {
|
|
42
|
+
const sql = `select ${data.columns.map(el => el.name || el)}::text from ${data.source} where ${data.query || '1=1'} limit 20 `;
|
|
43
|
+
const { rows } = await pg.query(sql); // test with limit
|
|
44
|
+
return { count: rows.length, rows, options }
|
|
45
|
+
}
|
|
46
|
+
// auto Index
|
|
47
|
+
autoIndex({ table: data.source, columns: [data?.time].concat([dimension]).concat([groupby]).filter(el => el) })
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const groupSQL = `select ${groupby}::text as x,count(*) from ${data.source} where ${groupby} is not null group by ${groupby} order by count(*) desc limit 10 `;
|
|
54
|
+
const { rows: groups } = groupby ? await pg.query(groupSQL) : {}; // test with limit
|
|
55
|
+
const groupMetric = data.metrics?.map(el => `${el.operator || 'sum'}(${el.name || el})`)?.[0] || 'count(*)';
|
|
56
|
+
|
|
57
|
+
// scratch, rewrite 2015, 2016 as separate columns
|
|
58
|
+
// const { rows: granularityDimensions } = await pg.query('select json_array_elements_text($1)', [granularities]);
|
|
59
|
+
|
|
60
|
+
const sql = `select ${dimension}::text as ${(data.time ? granularity : null) || dimension || 'x'} , ${metric}
|
|
61
|
+
${groups?.length ? ',' : ''} ${groups?.map(el => `${groupMetric} filter(where ${groupby} = '${el.x}') as "${el.x}"`).join(',') || ''}
|
|
62
|
+
from ${data.source}
|
|
63
|
+
where ${data.query || '1=1'}
|
|
64
|
+
group by ${dimension}`;
|
|
65
|
+
|
|
66
|
+
if (query.sql) return sql;
|
|
67
|
+
|
|
68
|
+
const { rows, fields } = await pg.query(sql); // test with limit
|
|
69
|
+
const dimensions = fields.map(el => el.name)
|
|
70
|
+
// return result
|
|
71
|
+
const res = {
|
|
72
|
+
time: Date.now() - time,
|
|
73
|
+
dimensions,
|
|
74
|
+
source: rows,
|
|
75
|
+
|
|
76
|
+
options,
|
|
77
|
+
controls,
|
|
78
|
+
};
|
|
79
|
+
/*
|
|
80
|
+
source: [
|
|
81
|
+
{
|
|
82
|
+
product: 'Matcha Latte',
|
|
83
|
+
2015: 43.3,
|
|
84
|
+
2016: 85.8,
|
|
85
|
+
2017: 93.7,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
product: 'Milk Tea',
|
|
89
|
+
2015: 83.1,
|
|
90
|
+
2016: 73.4,
|
|
91
|
+
2017: 55.1,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
product: 'Cheese Cocoa',
|
|
95
|
+
2015: 86.4,
|
|
96
|
+
2016: 65.2,
|
|
97
|
+
2017: 82.5,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
product: 'Walnut Brownie',
|
|
101
|
+
2015: 72.4,
|
|
102
|
+
2016: 53.9,
|
|
103
|
+
2017: 39.1,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
*/
|
|
107
|
+
return res;
|
|
108
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const schemaInfo = {};
|
|
2
|
+
|
|
3
|
+
import config from '../config.js';
|
|
4
|
+
|
|
5
|
+
import data from './controllers/data.js';
|
|
6
|
+
import dashboard from './controllers/dashboard.js';
|
|
7
|
+
import geojson from './controllers/geojson.js';
|
|
8
|
+
import vtile from './controllers/vtile.js';
|
|
9
|
+
|
|
10
|
+
export default async function route(fastify, opts) {
|
|
11
|
+
const prefix = opts?.prefix || config.prefix || '/api';
|
|
12
|
+
fastify.route({
|
|
13
|
+
method: 'GET',
|
|
14
|
+
url: `${prefix}/bi-data`,
|
|
15
|
+
schema: schemaInfo,
|
|
16
|
+
handler: data,
|
|
17
|
+
});
|
|
18
|
+
fastify.route({
|
|
19
|
+
method: 'GET',
|
|
20
|
+
url: `${prefix}/bi-dashboard/:id`,
|
|
21
|
+
handler: dashboard,
|
|
22
|
+
});
|
|
23
|
+
fastify.route({
|
|
24
|
+
method: 'GET',
|
|
25
|
+
url: `${prefix}/bi-geojson`,
|
|
26
|
+
schema: schemaInfo,
|
|
27
|
+
handler: geojson,
|
|
28
|
+
});
|
|
29
|
+
fastify.route({
|
|
30
|
+
method: 'GET',
|
|
31
|
+
url: `${prefix}/bi-vtile`,
|
|
32
|
+
schema: schemaInfo,
|
|
33
|
+
handler: vtile,
|
|
34
|
+
});
|
|
35
|
+
}
|
package/helper.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// This file contains code that we reuse
|
|
2
|
+
// between our tests.
|
|
3
|
+
import Fastify from 'fastify';
|
|
4
|
+
import rclient from '@opengis/fastify-table/redis/client.js';
|
|
5
|
+
import pgClients from '@opengis/fastify-table/pg/pgClients.js';
|
|
6
|
+
|
|
7
|
+
import config from './test/config.js';
|
|
8
|
+
import appService from './index.js';
|
|
9
|
+
|
|
10
|
+
// automatically build and tear down our instance
|
|
11
|
+
async function build(t) {
|
|
12
|
+
await pgClients.client.init()
|
|
13
|
+
// you can set all the options supported by the fastify CLI command
|
|
14
|
+
// const argv = [AppPath]
|
|
15
|
+
process.env.NODE_ENV = 'production';
|
|
16
|
+
const app = Fastify({ logger: false });
|
|
17
|
+
app.register(appService, config);
|
|
18
|
+
|
|
19
|
+
// unit test
|
|
20
|
+
// app.register(import('@opengis/fastify-table'), config);
|
|
21
|
+
// app.register(import('../../../npm/fastify-table/index.js'), config);
|
|
22
|
+
|
|
23
|
+
// close the app after we are done
|
|
24
|
+
t.after(() => {
|
|
25
|
+
// console.log('close app');
|
|
26
|
+
pgClients.client?.end();
|
|
27
|
+
rclient?.quit();
|
|
28
|
+
app.close();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return app;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default build;
|
package/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fp from 'fastify-plugin';
|
|
2
|
+
import config from './config.js';
|
|
3
|
+
|
|
4
|
+
import biPlugin from './dashboard/index.mjs';
|
|
5
|
+
|
|
6
|
+
async function plugin(fastify, opt) {
|
|
7
|
+
config.folder = opt.folder;
|
|
8
|
+
config.root = opt.root;
|
|
9
|
+
|
|
10
|
+
config.funcs = fastify;
|
|
11
|
+
config.pg = opt.pg;
|
|
12
|
+
config.redis = opt.redis;
|
|
13
|
+
config.s3 = opt.s3;
|
|
14
|
+
|
|
15
|
+
// independent npm start / unit test
|
|
16
|
+
if (!fastify.config) {
|
|
17
|
+
fastify.decorate('config', config);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!fastify.funcs) {
|
|
21
|
+
fastify.addHook('onRequest', async (req) => {
|
|
22
|
+
req.funcs = fastify;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
biPlugin(fastify); // { prefix: config.prefix }
|
|
27
|
+
}
|
|
28
|
+
export default fp(plugin);
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opengis/bi",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "BI data visualization module",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
|
9
|
+
"test": "node --test"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "Softpro",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"fastify": "^4.26.1",
|
|
16
|
+
"fastify-plugin": "^4.0.0",
|
|
17
|
+
"@opengis/fastify-table": "^1.0.36",
|
|
18
|
+
"js-yaml": "^4.1.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"eslint": "^8.49.0",
|
|
22
|
+
"eslint-config-airbnb": "^19.0.4"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/server.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// This file contains code that we reuse
|
|
2
|
+
// between our tests.
|
|
3
|
+
import Fastify from 'fastify';
|
|
4
|
+
import config from './test/config.js';
|
|
5
|
+
import appService from './index.js';
|
|
6
|
+
|
|
7
|
+
const app = Fastify({ logger: false });
|
|
8
|
+
app.register(appService, config);
|
|
9
|
+
app.listen({ host: '0.0.0.0', port: process.env.PORT || 3000 }, (err) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
app.log.error(err);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import config from '../config.js';
|
|
2
|
+
|
|
3
|
+
Object.assign(config, {
|
|
4
|
+
templateDir: 'test/templates',
|
|
5
|
+
pg: {
|
|
6
|
+
host: '192.168.3.160',
|
|
7
|
+
port: 5434,
|
|
8
|
+
database: 'mbk_rivne_dma',
|
|
9
|
+
user: 'postgres',
|
|
10
|
+
password: 'postgres',
|
|
11
|
+
},
|
|
12
|
+
redis: {
|
|
13
|
+
host: '192.168.3.160',
|
|
14
|
+
port: 6379,
|
|
15
|
+
family: 4,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
export default config;
|
package/test/config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import config from '../config.js';
|
|
2
|
+
|
|
3
|
+
Object.assign(config, {
|
|
4
|
+
templateDir: 'test/templates',
|
|
5
|
+
pg: config.pg || {
|
|
6
|
+
host: '192.168.3.160',
|
|
7
|
+
port: 5432,
|
|
8
|
+
database: 'geo_green_poltava',
|
|
9
|
+
user: 'postgres',
|
|
10
|
+
password: 'postgres',
|
|
11
|
+
},
|
|
12
|
+
redis: config.redis || {
|
|
13
|
+
host: '192.168.3.160',
|
|
14
|
+
port: 6379,
|
|
15
|
+
family: 4,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default config;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
|
|
4
|
+
import build from '../../helper.js';
|
|
5
|
+
|
|
6
|
+
import config from '../config.js';
|
|
7
|
+
|
|
8
|
+
test('api crud', async (t) => {
|
|
9
|
+
const app = await build(t);
|
|
10
|
+
const prefix = config.prefix || '/api';
|
|
11
|
+
|
|
12
|
+
// 2 metric + dimension
|
|
13
|
+
await t.test('GET /bi-data', async () => {
|
|
14
|
+
const res = await app.inject({
|
|
15
|
+
method: 'GET',
|
|
16
|
+
url: `${prefix}/bi-data`,
|
|
17
|
+
query: { chart: 'bar.zone' }
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const rep = JSON.parse(res?.body);
|
|
21
|
+
assert.ok(rep.source);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// count + time
|
|
25
|
+
await t.test('GET /bi-data', async () => {
|
|
26
|
+
const res = await app.inject({
|
|
27
|
+
method: 'GET',
|
|
28
|
+
url: `${prefix}/bi-data`,
|
|
29
|
+
query: { chart: 'user' }
|
|
30
|
+
});
|
|
31
|
+
const rep = JSON.parse(res?.body);
|
|
32
|
+
assert.ok(rep.source);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// dimension + groupby
|
|
36
|
+
await t.test('GET /bi-data', async () => {
|
|
37
|
+
const res = await app.inject({
|
|
38
|
+
method: 'GET',
|
|
39
|
+
url: `${prefix}/bi-data`,
|
|
40
|
+
query: { chart: 'user' }
|
|
41
|
+
});
|
|
42
|
+
const rep = JSON.parse(res?.body);
|
|
43
|
+
assert.ok(rep.source);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await t.test('GET /bi-data', async () => {
|
|
47
|
+
const res = await app.inject({
|
|
48
|
+
method: 'GET',
|
|
49
|
+
url: `${prefix}/bi-data`,
|
|
50
|
+
query: { chart: 'bar.zone' }
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const rep = JSON.parse(res?.body);
|
|
54
|
+
assert.ok(rep.source);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
await t.test('GET /bi-vtile', async () => {
|
|
58
|
+
const res = await app.inject({
|
|
59
|
+
method: 'GET',
|
|
60
|
+
url: `${prefix}/bi-vtile`,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const rep = JSON.parse(res?.body);
|
|
64
|
+
assert.ok(rep);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
await t.test('GET /bi-geojson', async () => {
|
|
68
|
+
const res = await app.inject({
|
|
69
|
+
method: 'DELETE',
|
|
70
|
+
url: `${prefix}/bi-geojson`,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const rep = JSON.parse(res?.body);
|
|
74
|
+
assert.ok(rep);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
data:
|
|
2
|
+
source: itree.rest_zones # Назва таблиці
|
|
3
|
+
query: 1=1 # Запит
|
|
4
|
+
|
|
5
|
+
dimension: category
|
|
6
|
+
groupby1: [verif]
|
|
7
|
+
metrics: # Групування
|
|
8
|
+
- name: area
|
|
9
|
+
operator: sum
|
|
10
|
+
title: Площа
|
|
11
|
+
- name: area
|
|
12
|
+
operator: count
|
|
13
|
+
title: Кількість
|
|
14
|
+
|
|
15
|
+
controls: [invertAxis, details, switcher]
|
|
16
|
+
filters:
|
|
17
|
+
- name: cdate
|
|
18
|
+
type: date
|
|
19
|
+
default: year
|
|
20
|
+
title: Дата внесення у БД
|
|
21
|
+
- name: katotg
|
|
22
|
+
type: text
|
|
23
|
+
title: КАТОТТГ
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
data:
|
|
2
|
+
source: itree.rest_zones # Назва таблиці
|
|
3
|
+
query: uid is null # Запит
|
|
4
|
+
metrics: # Групування
|
|
5
|
+
- name: ownership
|
|
6
|
+
title: Форма власності
|
|
7
|
+
time: cdate
|
|
8
|
+
granularity: month
|
|
9
|
+
|
|
10
|
+
options:
|
|
11
|
+
formats:
|
|
12
|
+
- name: metric
|
|
13
|
+
type: histogram, background
|
|
14
|
+
color: blue [red,blue]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
data:
|
|
2
|
+
source: itree.rest_zones # Назва таблиці
|
|
3
|
+
query: uid is null # Запит
|
|
4
|
+
|
|
5
|
+
metrics: # Групування
|
|
6
|
+
- name: monetary_valuation
|
|
7
|
+
title: Нормативна грошова оцінка, грн
|
|
8
|
+
dimension:
|
|
9
|
+
- name: balancer
|
|
10
|
+
title: Балансоутримувач об'єкта
|
|
11
|
+
|
|
12
|
+
options:
|
|
13
|
+
formats:
|
|
14
|
+
- name: metric
|
|
15
|
+
type: histogram, background
|
|
16
|
+
color: blue [red,blue]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
data:
|
|
2
|
+
source: data_address.addr_city # Назва таблиці
|
|
3
|
+
query: verified # Запит
|
|
4
|
+
|
|
5
|
+
columns:
|
|
6
|
+
- city_name
|
|
7
|
+
- city_koatuu
|
|
8
|
+
|
|
9
|
+
geom: geom
|
|
10
|
+
|
|
11
|
+
country: ua
|
|
12
|
+
|
|
13
|
+
cluster: # закачати через cdn
|
|
14
|
+
- region
|
|
15
|
+
- community
|
|
16
|
+
|
|
17
|
+
controls: []
|
|
18
|
+
|
|
19
|
+
options:
|
|
20
|
+
style:
|
|
21
|
+
color: red
|
|
22
|
+
size: 5
|
|
23
|
+
colorAttr: status
|
|
24
|
+
|
|
25
|
+
filters:
|
|
26
|
+
- name: cdate
|
|
27
|
+
type: date
|
|
28
|
+
title: Creation year
|