@engine9/schemas 1.9.0
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/.eslintignore +1 -0
- package/.prettierrc +7 -0
- package/AGENTS.md +10 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/channels/email/README.md +83 -0
- package/channels/email/index.js +22 -0
- package/channels/email/search.js +86 -0
- package/channels/email/segments.js +81 -0
- package/eslint.config.js +21 -0
- package/event/README.md +79 -0
- package/event/index.js +17 -0
- package/event/schema.js +111 -0
- package/event/search.js +51 -0
- package/message/index.js +8 -0
- package/message/schema.js +130 -0
- package/message/ui.console.json5 +233 -0
- package/package.json +26 -0
- package/person/index.js +100 -0
- package/person/metrics.js +17 -0
- package/person/schema.js +47 -0
- package/person/transforms/inbound/normalize_field_names.js +16 -0
- package/person/transforms/inbound/upsert_tables.js +21 -0
- package/person/transforms/outbound/appendName.js +32 -0
- package/person/transforms/simpleMap.js +34 -0
- package/person/ui.console.json5 +165 -0
- package/person/upsert.test.js +72 -0
- package/person_address/index.js +30 -0
- package/person_address/normalize.js +232 -0
- package/person_address/normalize.test.js +69 -0
- package/person_address/schema.js +49 -0
- package/person_address/transforms/inbound/normalize.js +23 -0
- package/person_address/transforms/inbound/upsert_tables.js +51 -0
- package/person_address/transforms/outbound/appendAddress.js +87 -0
- package/person_address/ui.console.json5 +31 -0
- package/person_custom/index.js +24 -0
- package/person_custom/transforms/appendRemoteId.js +31 -0
- package/person_custom/transforms/inbound/upsert_tables.js +31 -0
- package/person_email/README.md +82 -0
- package/person_email/index.js +35 -0
- package/person_email/schema.js +49 -0
- package/person_email/search.js +61 -0
- package/person_email/segments.js +16 -0
- package/person_email/transforms/inbound/extract_identifiers.js +33 -0
- package/person_email/transforms/inbound/upsert_tables.js +142 -0
- package/person_email/transforms/outbound/appendEmail.js +32 -0
- package/person_email/transforms/outbound/appendEmailHash.js +20 -0
- package/person_email/transforms/outbound/tables.js +14 -0
- package/person_email/ui.console.json5 +58 -0
- package/person_email/upsert.test.js +126 -0
- package/person_hash/README.md +70 -0
- package/person_hash/hash.js +103 -0
- package/person_hash/hash.test.js +165 -0
- package/person_hash/index.js +37 -0
- package/person_hash/schema.js +54 -0
- package/person_hash/search.js +86 -0
- package/person_hash/transforms/inbound/extract_identifiers.js +70 -0
- package/person_hash/transforms/inbound/upsert_tables.js +105 -0
- package/person_hash/transforms/outbound/appendEmailHash.js +42 -0
- package/person_hash/transforms/outbound/appendPhoneHash.js +42 -0
- package/person_hash/ui.console.json5 +80 -0
- package/person_phone/README.md +79 -0
- package/person_phone/index.js +33 -0
- package/person_phone/schema.js +58 -0
- package/person_phone/search.js +79 -0
- package/person_phone/segments.js +26 -0
- package/person_phone/transforms/inbound/extract_identifiers.js +59 -0
- package/person_phone/transforms/inbound/upsert_tables.js +119 -0
- package/person_phone/transforms/outbound/appendPhoneHash.js +37 -0
- package/person_phone/ui.console.json5 +31 -0
- package/person_phone/upsert.test.js +50 -0
- package/person_remote/index.js +58 -0
- package/person_remote/metrics.js +17 -0
- package/person_remote/schema.js +21 -0
- package/person_remote/transforms/inbound/extract_identifiers.js +34 -0
- package/person_remote/transforms/inbound/upsert_tables.js +92 -0
- package/person_remote/transforms/outbound/appendRemotePersonId.js +59 -0
- package/plugin/index.js +13 -0
- package/plugin/schema.js +70 -0
- package/plugin/settings.js +19 -0
- package/plugin/ui.console.json5 +79 -0
- package/report/index.js +7 -0
- package/report/ui.console.json5 +21 -0
- package/segment/index.js +21 -0
- package/segment/schema.js +81 -0
- package/segment/search.js +64 -0
- package/segment/transforms/inbound/upsert.js +44 -0
- package/segment/ui.console.json5 +142 -0
- package/segment_stats/index.js +16 -0
- package/segment_stats/schema.js +30 -0
- package/source_code/index.js +16 -0
- package/source_code/metrics.js +28 -0
- package/source_code/schema.js +29 -0
- package/source_code/ui.console.json5 +31 -0
- package/stacks/limited-pii/index.js +8 -0
- package/stacks/limited-pii/stack.json +22 -0
- package/stacks/stacks.test.js +27 -0
- package/stacks/standard/index.js +7 -0
- package/stacks/standard/stack.json +20 -0
- package/tag/index.js +13 -0
- package/tag/schema.js +23 -0
- package/task/index.js +13 -0
- package/task/schema.js +54 -0
- package/task/ui.console.json5 +60 -0
- package/timeline/index.js +18 -0
- package/timeline/schema.js +18 -0
- package/timeline/transforms/inbound/upsert_tables.js +22 -0
- package/timeline/ui.console.json5 +31 -0
- package/transaction/contact_details/index.js +11 -0
- package/transaction/contact_details/schema.js +22 -0
- package/transaction/core/README.md +79 -0
- package/transaction/core/attribute.test.js +231 -0
- package/transaction/core/index.js +31 -0
- package/transaction/core/metrics.js +20 -0
- package/transaction/core/schema.js +45 -0
- package/transaction/core/search.js +87 -0
- package/transaction/core/segments.js +14 -0
- package/transaction/core/transforms/appendTransactionSummary.js +101 -0
- package/transaction/core/transforms/attribute.js +327 -0
- package/transaction/core/transforms/inbound/upsert_tables.js +57 -0
- package/utilities/limited-pii/index.js +14 -0
- package/utilities/limited-pii/settings.js +12 -0
package/plugin/schema.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const tables = [
|
|
2
|
+
{
|
|
3
|
+
name: 'plugin',
|
|
4
|
+
columns: {
|
|
5
|
+
id: 'id_uuid',
|
|
6
|
+
path: 'string',
|
|
7
|
+
name: 'string',
|
|
8
|
+
nickname: 'string',
|
|
9
|
+
table_prefix: 'string',
|
|
10
|
+
remote_plugin_id: 'string',
|
|
11
|
+
schema: 'json', // Not all plugins need to support file based schemas, like per-account custom fields
|
|
12
|
+
transforms: 'json', // Not all plugins need to support file based transforms, like per-account custom fields
|
|
13
|
+
created_at: 'created_at',
|
|
14
|
+
modified_at: 'modified_at'
|
|
15
|
+
},
|
|
16
|
+
indexes: [
|
|
17
|
+
{ columns: 'id', primary: true },
|
|
18
|
+
{ columns: 'remote_plugin_id', unique: true }
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'plugin_history',
|
|
23
|
+
columns: {
|
|
24
|
+
id: 'id_uuid',
|
|
25
|
+
plugin_id: 'id_uuid', // can't be null, must have a value
|
|
26
|
+
path: 'string',
|
|
27
|
+
created_at: 'created_at',
|
|
28
|
+
modified_at: 'modified_at'
|
|
29
|
+
},
|
|
30
|
+
indexes: [{ columns: 'id', primary: true }]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'setting',
|
|
34
|
+
columns: {
|
|
35
|
+
id: 'id_uuid',
|
|
36
|
+
plugin_id: 'foreign_uuid',
|
|
37
|
+
name: 'string',
|
|
38
|
+
value: 'string',
|
|
39
|
+
created_at: 'created_at',
|
|
40
|
+
modified_at: 'modified_at'
|
|
41
|
+
},
|
|
42
|
+
indexes: [
|
|
43
|
+
{ columns: 'id', primary: true },
|
|
44
|
+
{ columns: 'plugin_id,name', unique: true }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'input',
|
|
49
|
+
columns: {
|
|
50
|
+
id: 'id_uuid',
|
|
51
|
+
plugin_id: 'id_uuid', // can't be null, must have a value
|
|
52
|
+
remote_input_id: 'string', // The remote id for this input, unique across the plugin
|
|
53
|
+
remote_input_name: 'string', // The remote name -- a human name for this input -- e.g. Form Name, message name
|
|
54
|
+
input_type: 'string', // Type of input, e.g. message, remote_person, petition, signup_form, advocacy_action, etc
|
|
55
|
+
min_timeline_ts: 'datetime',
|
|
56
|
+
max_timeline_ts: 'datetime',
|
|
57
|
+
records: 'bigint', // total timeline records across idv1.parquet files in the input store
|
|
58
|
+
data_path: 'string', // where the source data lives for this input, a directory or a packet
|
|
59
|
+
created_at: 'created_at',
|
|
60
|
+
modified_at: 'modified_at'
|
|
61
|
+
},
|
|
62
|
+
indexes: [
|
|
63
|
+
{ columns: 'id', primary: true },
|
|
64
|
+
{ columns: 'plugin_id,remote_input_id', unique: true }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
export default {
|
|
69
|
+
tables
|
|
70
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const settings = [
|
|
2
|
+
{
|
|
3
|
+
name: 'table_prefix_counter',
|
|
4
|
+
type: 'int',
|
|
5
|
+
default: 2729,
|
|
6
|
+
hidden: true,
|
|
7
|
+
description: 'Hex table-prefix allocator. Incremented by PluginWorker.getNextTablePrefixCounter.'
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: 'default_stack',
|
|
11
|
+
type: 'string',
|
|
12
|
+
default: '',
|
|
13
|
+
description:
|
|
14
|
+
'Stack (or plugin) path for installDefaultPlugins when no path is passed — e.g. @engine9/schemas/stacks/standard or @engine9/schemas/stacks/limited-pii. Empty installs the core person schema plugins only. Ignored when @engine9/schemas/utilities/limited-pii has exclude_pii true (forced limited-pii stack).'
|
|
15
|
+
}
|
|
16
|
+
];
|
|
17
|
+
export default {
|
|
18
|
+
settings
|
|
19
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
menu: {
|
|
3
|
+
settings: {
|
|
4
|
+
children: {
|
|
5
|
+
queries: {
|
|
6
|
+
title: 'Plugins',
|
|
7
|
+
icon: 'plugins',
|
|
8
|
+
url: '/plugins'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
routes: {
|
|
14
|
+
plugins: {
|
|
15
|
+
layout: 'full_width',
|
|
16
|
+
components: {
|
|
17
|
+
header: ['Plugins'],
|
|
18
|
+
main: [
|
|
19
|
+
{
|
|
20
|
+
component: 'RecordTable',
|
|
21
|
+
properties: {
|
|
22
|
+
table: 'plugin',
|
|
23
|
+
columns: [
|
|
24
|
+
{
|
|
25
|
+
title: 'Id',
|
|
26
|
+
dataIndex: 'id',
|
|
27
|
+
sorter: true,
|
|
28
|
+
width: '20%'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Name',
|
|
32
|
+
dataIndex: 'name',
|
|
33
|
+
sorter: true,
|
|
34
|
+
template: '{{name}}',
|
|
35
|
+
width: '40%'
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
onRecord: {
|
|
39
|
+
onClick: {
|
|
40
|
+
action: 'navigate',
|
|
41
|
+
url: '/plugins/{{record.id}}'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
'plugins/:id/*': {
|
|
50
|
+
layout: 'full_width',
|
|
51
|
+
components: {
|
|
52
|
+
main: [
|
|
53
|
+
{
|
|
54
|
+
component: 'RecordForm',
|
|
55
|
+
properties: {
|
|
56
|
+
table: 'job',
|
|
57
|
+
title: '{{#if record.id}}Edit Plugin{{else}}Create Job{{/if}}',
|
|
58
|
+
form: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
required: [],
|
|
61
|
+
properties: {
|
|
62
|
+
status: { type: 'string', title: 'Status', default: 'pending' },
|
|
63
|
+
options: { type: 'string', title: 'Options', default: '{}' }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
uiSchema: {
|
|
67
|
+
options: { 'ui:widget': 'textarea' }
|
|
68
|
+
},
|
|
69
|
+
onSave: {
|
|
70
|
+
action: 'navigate',
|
|
71
|
+
url: '/plugins/{{record.id}}'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
package/report/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
menu: {
|
|
3
|
+
'data-menu': {
|
|
4
|
+
children: {
|
|
5
|
+
report: {
|
|
6
|
+
title: 'Reports',
|
|
7
|
+
icon: 'report',
|
|
8
|
+
url: '/report'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
routes: {
|
|
14
|
+
'/report': {
|
|
15
|
+
layout: 'full_width',
|
|
16
|
+
components: {
|
|
17
|
+
main: ['<h1>Reports</h1>']
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
package/segment/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import schema from './schema.js';
|
|
2
|
+
import search from './search.js';
|
|
3
|
+
import upsert from './transforms/inbound/upsert.js';
|
|
4
|
+
const metadata = {
|
|
5
|
+
name: '@engine9/schemas/segment',
|
|
6
|
+
dependencies: {
|
|
7
|
+
'@engine9/schemas/person': '>=1.9.0'
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const transforms = {
|
|
11
|
+
upsert
|
|
12
|
+
};
|
|
13
|
+
export { metadata };
|
|
14
|
+
export { schema };
|
|
15
|
+
export { search };
|
|
16
|
+
export default {
|
|
17
|
+
metadata,
|
|
18
|
+
schema,
|
|
19
|
+
search,
|
|
20
|
+
transforms
|
|
21
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const tables = [
|
|
2
|
+
{
|
|
3
|
+
name: 'segment_folder',
|
|
4
|
+
columns: {
|
|
5
|
+
id: 'id_uuid',
|
|
6
|
+
name: 'string',
|
|
7
|
+
description: 'text',
|
|
8
|
+
created_at: 'created_at',
|
|
9
|
+
modified_at: 'modified_at'
|
|
10
|
+
},
|
|
11
|
+
indexes: [{ columns: 'id', primary: true }]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'segment',
|
|
15
|
+
columns: {
|
|
16
|
+
id: 'id_uuid',
|
|
17
|
+
plugin_id: 'id_uuid', // can't be null, must have a value
|
|
18
|
+
submodule: 'string',
|
|
19
|
+
segment_folder_id: 'foreign_uuid',
|
|
20
|
+
remote_segment_id: 'string',
|
|
21
|
+
legacy_id: 'int',
|
|
22
|
+
name: 'string',
|
|
23
|
+
category: 'string', // A arbitrary type, user facing, not to be used for logic
|
|
24
|
+
definition_path: 'string', // a definition file path, will be used for configuring
|
|
25
|
+
stars: 'int', //number of stars, good for UI organizing
|
|
26
|
+
search: 'json',
|
|
27
|
+
build_type: {
|
|
28
|
+
type: 'enum',
|
|
29
|
+
nullable: false,
|
|
30
|
+
default_value: 'list',
|
|
31
|
+
values: [
|
|
32
|
+
'list', //static list of people
|
|
33
|
+
'search', // built by the defined search
|
|
34
|
+
'scheduled_search', // built on a schedule by the search
|
|
35
|
+
'remote_count', // no person records, just counts, pulled from remote site
|
|
36
|
+
'remote', // pulled from remote plugin site
|
|
37
|
+
'manual' // created outside normal processing
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
build_schedule: 'string',
|
|
41
|
+
build_status: 'string',
|
|
42
|
+
build_status_modified_at: 'modified_at',
|
|
43
|
+
build_table: 'string',
|
|
44
|
+
last_built: 'datetime',
|
|
45
|
+
// Membership policy. null = only a request with `admin` scope.
|
|
46
|
+
// join_min_level: lowest Identity Level at which a person may add
|
|
47
|
+
// themselves (0 = a public form, no login)
|
|
48
|
+
// leave_min_level: lowest Identity Level at which a person may remove
|
|
49
|
+
// themselves (never 0)
|
|
50
|
+
// manager_role_id: role segment whose members may add and remove
|
|
51
|
+
// other people in this segment
|
|
52
|
+
// Enforced by @engine9/core (docs/segments.md), not by the database.
|
|
53
|
+
join_min_level: { type: 'int', nullable: true },
|
|
54
|
+
leave_min_level: { type: 'int', nullable: true },
|
|
55
|
+
manager_role_id: 'foreign_uuid',
|
|
56
|
+
people: 'int', // engine9 count
|
|
57
|
+
reported_people: 'int', // reported by outside parties
|
|
58
|
+
created_at: 'created_at',
|
|
59
|
+
modified_at: 'modified_at'
|
|
60
|
+
},
|
|
61
|
+
indexes: [
|
|
62
|
+
{ columns: 'id', primary: true },
|
|
63
|
+
// if there is a remote_segment_id, it should be unique for the plugin
|
|
64
|
+
{ columns: ['plugin_id', 'remote_segment_id'], unique: true }
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
// Used for some smaller segments, and a cache of segments
|
|
68
|
+
{
|
|
69
|
+
name: 'person_segment',
|
|
70
|
+
columns: {
|
|
71
|
+
id: 'id',
|
|
72
|
+
person_id: 'person_id',
|
|
73
|
+
segment_id: 'foreign_uuid',
|
|
74
|
+
modified_at: 'modified_at'
|
|
75
|
+
},
|
|
76
|
+
indexes: [{ columns: 'segment_id,person_id', unique: true }, { columns: 'person_id' }]
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
export default {
|
|
80
|
+
tables
|
|
81
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const segment = {
|
|
2
|
+
title: 'Segment',
|
|
3
|
+
form: {
|
|
4
|
+
title: 'Segment',
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
segmentId: {
|
|
8
|
+
title: 'Segment',
|
|
9
|
+
description: '',
|
|
10
|
+
type: 'string'
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
required: []
|
|
14
|
+
},
|
|
15
|
+
optionsToEQLContext: function ({ segmentId }) {
|
|
16
|
+
return {
|
|
17
|
+
segments: {
|
|
18
|
+
table: 'segment',
|
|
19
|
+
columns: ['id', 'name'],
|
|
20
|
+
conditions: [
|
|
21
|
+
{
|
|
22
|
+
type: 'EQUALS',
|
|
23
|
+
values: [
|
|
24
|
+
{
|
|
25
|
+
ref: { column: 'id' }
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: { value: segmentId }
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
/* map from provided user data into an EQL structure */
|
|
37
|
+
optionsToEQL(options, { segments } = {}) {
|
|
38
|
+
const { segmentId } = options;
|
|
39
|
+
const segment = segments.find(({ id }) => id == segmentId);
|
|
40
|
+
if (!segment) throw new Error('Could not find segment ' + segmentId + ' in ' + segments.length + ' segments');
|
|
41
|
+
let text = 'In ' + segment.name || segmentId;
|
|
42
|
+
const conditions = [
|
|
43
|
+
{
|
|
44
|
+
type: 'EQUALS',
|
|
45
|
+
values: [
|
|
46
|
+
{
|
|
47
|
+
ref: { column: 'segment_id' }
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
value: { value: segmentId }
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
const eql = {
|
|
56
|
+
table: 'person_segment',
|
|
57
|
+
conditions
|
|
58
|
+
};
|
|
59
|
+
return { text, eql };
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
export default {
|
|
63
|
+
segment
|
|
64
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { mergeIntoQueue } from '@engine9/input-tools';
|
|
2
|
+
|
|
3
|
+
export const bindings = {
|
|
4
|
+
tablesToUpsert: { path: 'sql.tables.upsert' },
|
|
5
|
+
uuidIsValid: { path: '@engine9/input-tools:uuidIsValid' }
|
|
6
|
+
};
|
|
7
|
+
export async function transform({ batch, tablesToUpsert, uuidIsValid, options }) {
|
|
8
|
+
const { segmentIds } = options;
|
|
9
|
+
const globalSegments = String(segmentIds || '')
|
|
10
|
+
.split(',')
|
|
11
|
+
.map((d) => d.trim())
|
|
12
|
+
.filter(Boolean);
|
|
13
|
+
batch.forEach((o) => {
|
|
14
|
+
const localSegmentIds = String(o.segment_ids || '')
|
|
15
|
+
.split(',')
|
|
16
|
+
.map((d) => d.trim())
|
|
17
|
+
.filter(Boolean);
|
|
18
|
+
const allSegmentIds = [].concat(globalSegments).concat(localSegmentIds);
|
|
19
|
+
if (allSegmentIds.length === 0) return;
|
|
20
|
+
const invalid = allSegmentIds.filter((uuid) => !uuidIsValid(uuid));
|
|
21
|
+
if (invalid.length > 0) throw new Error(`There are some invalid segment_ids:${invalid.join(',')}`);
|
|
22
|
+
tablesToUpsert.person_segment = tablesToUpsert.person_segment || [];
|
|
23
|
+
allSegmentIds.forEach((sid) =>
|
|
24
|
+
mergeIntoQueue(
|
|
25
|
+
tablesToUpsert.person_segment,
|
|
26
|
+
{
|
|
27
|
+
id: null,
|
|
28
|
+
person_id: o.person_id,
|
|
29
|
+
segment_id: sid
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
keyFields: ['segment_id', 'person_id'],
|
|
33
|
+
merge: (existing) => existing,
|
|
34
|
+
label: 'person_segment'
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
return batch;
|
|
40
|
+
}
|
|
41
|
+
export default {
|
|
42
|
+
bindings,
|
|
43
|
+
transform
|
|
44
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
menu: {
|
|
3
|
+
people: {
|
|
4
|
+
children: {
|
|
5
|
+
segments: {
|
|
6
|
+
title: 'Segments',
|
|
7
|
+
icon: 'people',
|
|
8
|
+
url: '/segments'
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
routes: {
|
|
14
|
+
'/segments': {
|
|
15
|
+
layout: 'full_width',
|
|
16
|
+
components: {
|
|
17
|
+
header: [
|
|
18
|
+
'Segments',
|
|
19
|
+
{
|
|
20
|
+
component: 'Button',
|
|
21
|
+
properties: {
|
|
22
|
+
icon: 'plus',
|
|
23
|
+
content: 'Add Segment',
|
|
24
|
+
onClick: {
|
|
25
|
+
action: 'navigate',
|
|
26
|
+
url: '/segments/create'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
main: [
|
|
32
|
+
{
|
|
33
|
+
component: 'RecordTable',
|
|
34
|
+
properties: {
|
|
35
|
+
table: 'segment',
|
|
36
|
+
columns: [
|
|
37
|
+
{
|
|
38
|
+
title: 'Id',
|
|
39
|
+
dataIndex: 'id',
|
|
40
|
+
sorter: true,
|
|
41
|
+
width: '20%'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
title: 'Type',
|
|
45
|
+
dataIndex: 'type',
|
|
46
|
+
sorter: true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
title: 'Name',
|
|
50
|
+
dataIndex: 'label',
|
|
51
|
+
sorter: true,
|
|
52
|
+
template: '{{label}}',
|
|
53
|
+
width: '40%'
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
onRecord: {
|
|
57
|
+
onClick: {
|
|
58
|
+
action: 'navigate',
|
|
59
|
+
url: '/segments/{{record.id}}'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
'/segments/:id/*': {
|
|
68
|
+
layout: 'full_width',
|
|
69
|
+
components: {
|
|
70
|
+
main: [
|
|
71
|
+
{
|
|
72
|
+
component: 'RecordForm',
|
|
73
|
+
properties: {
|
|
74
|
+
table: 'job',
|
|
75
|
+
title: '{{#if record.id}}Edit Segment{{else}}Create Segment{{/if}}',
|
|
76
|
+
form: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
required: [],
|
|
79
|
+
properties: {
|
|
80
|
+
type: { type: 'string', title: 'Type' },
|
|
81
|
+
name: { type: 'string', title: 'Name' },
|
|
82
|
+
plugin_id: { type: 'string', title: 'Source Plugin ID' },
|
|
83
|
+
remote_segment_id: { type: 'string', title: 'Remote Segment ID' },
|
|
84
|
+
build_mechanism: { type: 'string', title: 'Mechanism', default: 'static' },
|
|
85
|
+
build_schedule: { type: 'string', title: 'Build Schedule' },
|
|
86
|
+
build_status: { type: 'string', title: 'Build Status' },
|
|
87
|
+
build_status_modified_at: { type: 'modified_at', title: 'Build Status Modified At' }
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
uiSchema: {},
|
|
91
|
+
onSave: {
|
|
92
|
+
action: 'navigate',
|
|
93
|
+
url: '/segments/{{record.id}}'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
component: 'RecordTable',
|
|
99
|
+
properties: {
|
|
100
|
+
table: 'person_segment',
|
|
101
|
+
includes: [{ alias: 'people', table: 'person' }],
|
|
102
|
+
conditions: [{ eql: 'segment_id={{parameters.segment_id}}' }],
|
|
103
|
+
columns: [
|
|
104
|
+
{
|
|
105
|
+
template: '{{person_id}}'
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
'/person/:id/*': {
|
|
114
|
+
components: {
|
|
115
|
+
sidebar: {
|
|
116
|
+
items2: [
|
|
117
|
+
{
|
|
118
|
+
component: 'Link',
|
|
119
|
+
properties: {
|
|
120
|
+
label: 'Segments',
|
|
121
|
+
to: 'segments'
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
main: [
|
|
127
|
+
{
|
|
128
|
+
path: 'segments',
|
|
129
|
+
label: 'Segments',
|
|
130
|
+
component: 'RecordTable',
|
|
131
|
+
properties: {
|
|
132
|
+
table: 'person_segment',
|
|
133
|
+
includes: [{ alias: 'segments', table: 'segment' }],
|
|
134
|
+
conditions: [{ eql: 'person_id={{parameters.person_id}}' }],
|
|
135
|
+
rows: ['{{segment}}']
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import schema from './schema.js';
|
|
2
|
+
|
|
3
|
+
const metadata = {
|
|
4
|
+
name: '@engine9/schemas/segment_stats',
|
|
5
|
+
schemas: ['schema.js'],
|
|
6
|
+
dependencies: {
|
|
7
|
+
'@engine9/schemas/segment': '>=1.9.0'
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { metadata };
|
|
12
|
+
export { schema };
|
|
13
|
+
export default {
|
|
14
|
+
metadata,
|
|
15
|
+
schema
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const tables = [
|
|
2
|
+
{
|
|
3
|
+
name: 'segment_stats',
|
|
4
|
+
columns: {
|
|
5
|
+
id: 'id',
|
|
6
|
+
segment_id: 'foreign_id',
|
|
7
|
+
transactions: 'int',
|
|
8
|
+
revenue: 'currency',
|
|
9
|
+
created_at: 'created_at',
|
|
10
|
+
modified_at: 'modified_at'
|
|
11
|
+
},
|
|
12
|
+
indexes: [{ columns: ['segment_id'] }]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'segment_stats_by_date',
|
|
16
|
+
columns: {
|
|
17
|
+
id: 'id',
|
|
18
|
+
segment_id: 'foreign_id',
|
|
19
|
+
date: 'date',
|
|
20
|
+
transactions: 'int',
|
|
21
|
+
revenue: 'currency',
|
|
22
|
+
created_at: 'created_at',
|
|
23
|
+
modified_at: 'modified_at'
|
|
24
|
+
},
|
|
25
|
+
indexes: [{ columns: ['segment_id', 'date'], unique: true }]
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
export default {
|
|
29
|
+
tables
|
|
30
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import schema from './schema.js';
|
|
2
|
+
import metrics from './metrics.js';
|
|
3
|
+
const metadata = {
|
|
4
|
+
name: '@engine9/schemas/source_code',
|
|
5
|
+
dependencies: {
|
|
6
|
+
'@engine9/schemas/person': '>=1.9.0'
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
export { metadata };
|
|
10
|
+
export { schema };
|
|
11
|
+
export { metrics };
|
|
12
|
+
export default {
|
|
13
|
+
metadata,
|
|
14
|
+
schema,
|
|
15
|
+
metrics
|
|
16
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const parsing = {
|
|
2
|
+
label: 'Overall Parsing',
|
|
3
|
+
description: '',
|
|
4
|
+
eql: {
|
|
5
|
+
table: 'source_code_summary',
|
|
6
|
+
columns: [
|
|
7
|
+
{ eql: 'count(*)', name: 'records' },
|
|
8
|
+
{ eql: 'sum(case when length(format)>0 then 1 else 0 end)', name: 'parsed' }
|
|
9
|
+
],
|
|
10
|
+
conditions: []
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const recent_parsing = {
|
|
14
|
+
label: 'Parsing last 30 days',
|
|
15
|
+
description: '',
|
|
16
|
+
eql: {
|
|
17
|
+
table: 'source_code_summary',
|
|
18
|
+
columns: [
|
|
19
|
+
{ eql: 'count(*)', name: 'records' },
|
|
20
|
+
{ eql: 'sum(case when length(format)>0 then 1 else 0 end)', name: 'parsed' }
|
|
21
|
+
],
|
|
22
|
+
conditions: [{ eql: 'date_sub(now(), interval 30 day)' }]
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export default {
|
|
26
|
+
parsing,
|
|
27
|
+
recent_parsing
|
|
28
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const tables = [
|
|
2
|
+
{
|
|
3
|
+
name: 'source_code_dictionary',
|
|
4
|
+
columns: {
|
|
5
|
+
source_code_id: 'id',
|
|
6
|
+
source_code: {
|
|
7
|
+
type: 'string',
|
|
8
|
+
length: 180,
|
|
9
|
+
nullable: false,
|
|
10
|
+
default_value: ''
|
|
11
|
+
},
|
|
12
|
+
format: 'string',
|
|
13
|
+
format_regex: 'string',
|
|
14
|
+
source_code_channel: 'string',
|
|
15
|
+
source_code_last_used: 'created_at', //by default, when this record is created it needs a last used.
|
|
16
|
+
parsing: 'json',
|
|
17
|
+
created_at: 'created_at',
|
|
18
|
+
modified_at: 'modified_at'
|
|
19
|
+
},
|
|
20
|
+
indexes: [
|
|
21
|
+
{ columns: 'source_code_id', primary: true },
|
|
22
|
+
{ columns: 'source_code', unique: true },
|
|
23
|
+
{ columns: 'source_code_last_used' }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
export default {
|
|
28
|
+
tables
|
|
29
|
+
};
|