datajunction-ui 0.0.1-a81 → 0.0.1-a83
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/package.json +3 -3
- package/src/app/components/ListGroupItem.jsx +1 -1
- package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +2 -2
- package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +8 -8
- package/src/app/pages/NamespacePage/index.jsx +0 -6
- package/src/app/pages/NodePage/NodeDependenciesTab.jsx +1 -1
- package/src/app/pages/NodePage/NodeHistory.jsx +7 -3
- package/src/app/pages/NodePage/NodeInfoTab.jsx +25 -22
- package/src/app/pages/NodePage/NodeValidateTab.jsx +2 -2
- package/src/app/pages/NodePage/RevisionDiff.jsx +8 -1
- package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +4 -4
- package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +3 -2
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +25 -10
- package/src/app/pages/NodePage/index.jsx +7 -7
- package/src/app/services/DJService.js +39 -0
- package/src/app/services/__tests__/DJService.test.jsx +41 -0
- package/src/mocks/mockNodes.jsx +20 -295
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datajunction-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1a83",
|
|
4
4
|
"description": "DataJunction Metrics Platform UI",
|
|
5
5
|
"module": "src/index.tsx",
|
|
6
6
|
"repository": {
|
|
@@ -166,9 +166,9 @@
|
|
|
166
166
|
"coverageThreshold": {
|
|
167
167
|
"global": {
|
|
168
168
|
"statements": 87,
|
|
169
|
-
"branches":
|
|
169
|
+
"branches": 70,
|
|
170
170
|
"lines": 80,
|
|
171
|
-
"functions":
|
|
171
|
+
"functions": 83
|
|
172
172
|
}
|
|
173
173
|
},
|
|
174
174
|
"moduleNameMapper": {
|
|
@@ -37,7 +37,7 @@ export const DimensionsSelect = ({ cube }) => {
|
|
|
37
37
|
value: cubeDim.node_name + '.' + cubeDim.name,
|
|
38
38
|
label:
|
|
39
39
|
labelize(cubeDim.name) +
|
|
40
|
-
(cubeDim.
|
|
40
|
+
(cubeDim.properties?.includes('primary_key') ? ' (PK)' : ''),
|
|
41
41
|
};
|
|
42
42
|
});
|
|
43
43
|
setDefaultDimensions(cubeDimensions);
|
|
@@ -118,7 +118,7 @@ export const DimensionsSelect = ({ cube }) => {
|
|
|
118
118
|
value: dim.name,
|
|
119
119
|
label:
|
|
120
120
|
labelize(dim.name.split('.').slice(-1)[0]) +
|
|
121
|
-
(dim.
|
|
121
|
+
(dim.properties?.includes('primary_key') ? ' (PK)' : ''),
|
|
122
122
|
};
|
|
123
123
|
});
|
|
124
124
|
//
|
|
@@ -106,7 +106,7 @@ const mockCommonDimensions = [
|
|
|
106
106
|
type: 'timestamp',
|
|
107
107
|
node_name: 'default.date_dim',
|
|
108
108
|
node_display_name: 'Date',
|
|
109
|
-
|
|
109
|
+
properties: [],
|
|
110
110
|
path: [
|
|
111
111
|
'default.repair_order_details.repair_order_id',
|
|
112
112
|
'default.repair_order.hard_hat_id',
|
|
@@ -118,7 +118,7 @@ const mockCommonDimensions = [
|
|
|
118
118
|
type: 'timestamp',
|
|
119
119
|
node_name: 'default.date_dim',
|
|
120
120
|
node_display_name: 'Date',
|
|
121
|
-
|
|
121
|
+
properties: [],
|
|
122
122
|
path: [
|
|
123
123
|
'default.repair_order_details.repair_order_id',
|
|
124
124
|
'default.repair_order.hard_hat_id',
|
|
@@ -130,7 +130,7 @@ const mockCommonDimensions = [
|
|
|
130
130
|
type: 'int',
|
|
131
131
|
node_name: 'default.date_dim',
|
|
132
132
|
node_display_name: 'Date',
|
|
133
|
-
|
|
133
|
+
properties: [],
|
|
134
134
|
path: [
|
|
135
135
|
'default.repair_order_details.repair_order_id',
|
|
136
136
|
'default.repair_order.hard_hat_id',
|
|
@@ -142,7 +142,7 @@ const mockCommonDimensions = [
|
|
|
142
142
|
type: 'int',
|
|
143
143
|
node_name: 'default.date_dim',
|
|
144
144
|
node_display_name: 'Date',
|
|
145
|
-
|
|
145
|
+
properties: [],
|
|
146
146
|
path: [
|
|
147
147
|
'default.repair_order_details.repair_order_id',
|
|
148
148
|
'default.repair_order.hard_hat_id',
|
|
@@ -154,7 +154,7 @@ const mockCommonDimensions = [
|
|
|
154
154
|
type: 'int',
|
|
155
155
|
node_name: 'default.date_dim',
|
|
156
156
|
node_display_name: 'Date',
|
|
157
|
-
|
|
157
|
+
properties: [],
|
|
158
158
|
path: [
|
|
159
159
|
'default.repair_order_details.repair_order_id',
|
|
160
160
|
'default.repair_order.hard_hat_id',
|
|
@@ -166,7 +166,7 @@ const mockCommonDimensions = [
|
|
|
166
166
|
type: 'int',
|
|
167
167
|
node_name: 'default.date_dim',
|
|
168
168
|
node_display_name: 'Date',
|
|
169
|
-
|
|
169
|
+
properties: [],
|
|
170
170
|
path: [
|
|
171
171
|
'default.repair_order_details.repair_order_id',
|
|
172
172
|
'default.repair_order.hard_hat_id',
|
|
@@ -178,7 +178,7 @@ const mockCommonDimensions = [
|
|
|
178
178
|
type: 'int',
|
|
179
179
|
node_name: 'default.date_dim',
|
|
180
180
|
node_display_name: 'Date',
|
|
181
|
-
|
|
181
|
+
properties: [],
|
|
182
182
|
path: [
|
|
183
183
|
'default.repair_order_details.repair_order_id',
|
|
184
184
|
'default.repair_order.hard_hat_id',
|
|
@@ -190,7 +190,7 @@ const mockCommonDimensions = [
|
|
|
190
190
|
type: 'int',
|
|
191
191
|
node_name: 'default.date_dim',
|
|
192
192
|
node_display_name: 'Date',
|
|
193
|
-
|
|
193
|
+
properties: [],
|
|
194
194
|
path: [
|
|
195
195
|
'default.repair_order_details.repair_order_id',
|
|
196
196
|
'default.repair_order.hard_hat_id',
|
|
@@ -133,7 +133,6 @@ export function NamespacePage() {
|
|
|
133
133
|
useEffect(() => {
|
|
134
134
|
const fetchData = async () => {
|
|
135
135
|
setRetrieved(false);
|
|
136
|
-
console.log('cursor', before, filters.edited_by);
|
|
137
136
|
const nodes = await djClient.listNodesForLanding(
|
|
138
137
|
namespace,
|
|
139
138
|
filters.node_type ? [filters.node_type.toUpperCase()] : [],
|
|
@@ -143,7 +142,6 @@ export function NamespacePage() {
|
|
|
143
142
|
after,
|
|
144
143
|
50,
|
|
145
144
|
);
|
|
146
|
-
console.log('nodes', nodes);
|
|
147
145
|
|
|
148
146
|
setState({
|
|
149
147
|
namespace: namespace,
|
|
@@ -158,10 +156,6 @@ export function NamespacePage() {
|
|
|
158
156
|
setNextCursor(
|
|
159
157
|
nodes.data ? nodes.data.findNodesPaginated.pageInfo.endCursor : '',
|
|
160
158
|
);
|
|
161
|
-
console.log(
|
|
162
|
-
'setting hasPrevPage, ',
|
|
163
|
-
nodes.data.findNodesPaginated.pageInfo.hasPrevPage,
|
|
164
|
-
);
|
|
165
159
|
setHasPrevPage(
|
|
166
160
|
nodes.data
|
|
167
161
|
? nodes.data.findNodesPaginated.pageInfo.hasPrevPage
|
|
@@ -98,7 +98,7 @@ export function NodeDimensionsList({ rawDimensions }) {
|
|
|
98
98
|
value: dim.name,
|
|
99
99
|
label:
|
|
100
100
|
labelize(dim.name.split('.').slice(-1)[0]) +
|
|
101
|
-
(dim.
|
|
101
|
+
(dim.properties.includes('primary_key') ? ' (PK)' : ''),
|
|
102
102
|
};
|
|
103
103
|
});
|
|
104
104
|
return (
|
|
@@ -57,7 +57,10 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
57
57
|
</div>
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
|
-
if (
|
|
60
|
+
if (
|
|
61
|
+
['create', 'update', 'delete'].includes(event.activity_type) &&
|
|
62
|
+
event.entity_type === 'link'
|
|
63
|
+
) {
|
|
61
64
|
return (
|
|
62
65
|
<div className="history-left">
|
|
63
66
|
<b style={{ textTransform: 'capitalize' }}>{event.activity_type}</b>{' '}
|
|
@@ -180,8 +183,9 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
180
183
|
if (event.activity_type === 'create' && event.entity_type === 'backfill') {
|
|
181
184
|
return (
|
|
182
185
|
<div className="history-left">
|
|
183
|
-
<b>Backfill</b> created for materialization
|
|
184
|
-
|
|
186
|
+
<b>Backfill</b> created for materialization{' '}
|
|
187
|
+
{event.details.materialization} for partition{' '}
|
|
188
|
+
{event.details.partition[0].column_name} from{' '}
|
|
185
189
|
{event.details.partition[0].range[0]} to{' '}
|
|
186
190
|
{event.details.partition[0].range[1]}
|
|
187
191
|
</div>
|
|
@@ -7,9 +7,6 @@ import ListGroupItem from '../../components/ListGroupItem';
|
|
|
7
7
|
import ToggleSwitch from '../../components/ToggleSwitch';
|
|
8
8
|
import DJClientContext from '../../providers/djclient';
|
|
9
9
|
import { labelize } from '../../../utils/form';
|
|
10
|
-
import { AlertMessage } from '../AddEditNodePage/AlertMessage';
|
|
11
|
-
import AlertIcon from '../../icons/AlertIcon';
|
|
12
|
-
import InvalidIcon from '../../icons/InvalidIcon';
|
|
13
10
|
|
|
14
11
|
SyntaxHighlighter.registerLanguage('sql', sql);
|
|
15
12
|
foundation.hljs['padding'] = '2rem';
|
|
@@ -71,24 +68,30 @@ export default function NodeInfoTab({ node }) {
|
|
|
71
68
|
) : (
|
|
72
69
|
''
|
|
73
70
|
);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
71
|
+
|
|
72
|
+
const metricQueryDiv =
|
|
73
|
+
node.type === 'metric' ? (
|
|
74
|
+
<div className="list-group-item d-flex">
|
|
75
|
+
<div className="gap-2 w-100 justify-content-between py-3">
|
|
76
|
+
<div style={{ marginBottom: '30px' }}>
|
|
77
|
+
<h6 className="mb-0 w-100">Upstream Node</h6>
|
|
78
|
+
<p>
|
|
79
|
+
<a href={`/nodes/${node?.upstream_node}`}>
|
|
80
|
+
{node?.upstream_node}
|
|
81
|
+
</a>
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
<div>
|
|
85
|
+
<h6 className="mb-0 w-100">Aggregate Expression</h6>
|
|
86
|
+
<SyntaxHighlighter language="sql" style={foundation}>
|
|
87
|
+
{node?.expression}
|
|
88
|
+
</SyntaxHighlighter>
|
|
89
|
+
</div>
|
|
88
90
|
</div>
|
|
89
91
|
</div>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
) : (
|
|
93
|
+
''
|
|
94
|
+
);
|
|
92
95
|
const queryDiv = node?.query ? (
|
|
93
96
|
<div className="list-group-item d-flex">
|
|
94
97
|
<div className="d-flex gap-2 w-100 justify-content-between py-3">
|
|
@@ -158,7 +161,7 @@ export default function NodeInfoTab({ node }) {
|
|
|
158
161
|
aria-label="MetricDirection"
|
|
159
162
|
>
|
|
160
163
|
{node?.metric_metadata?.direction
|
|
161
|
-
? labelize(node?.metric_metadata?.direction)
|
|
164
|
+
? labelize(node?.metric_metadata?.direction?.toLowerCase())
|
|
162
165
|
: 'None'}
|
|
163
166
|
</p>
|
|
164
167
|
</div>
|
|
@@ -170,8 +173,8 @@ export default function NodeInfoTab({ node }) {
|
|
|
170
173
|
aria-hidden="false"
|
|
171
174
|
aria-label="MetricUnit"
|
|
172
175
|
>
|
|
173
|
-
{node?.metric_metadata?.unit
|
|
174
|
-
? labelize(node?.metric_metadata?.unit?.
|
|
176
|
+
{node?.metric_metadata?.unit?.name
|
|
177
|
+
? labelize(node?.metric_metadata?.unit?.name?.toLowerCase())
|
|
175
178
|
: 'None'}
|
|
176
179
|
</p>
|
|
177
180
|
</div>
|
|
@@ -73,7 +73,7 @@ export default function NodeValidateTab({ node, djClient }) {
|
|
|
73
73
|
const dimensionsList = dimensions.flatMap(grouping => {
|
|
74
74
|
const dimensionsInGroup = grouping[1];
|
|
75
75
|
return dimensionsInGroup
|
|
76
|
-
.filter(dim => dim.
|
|
76
|
+
.filter(dim => dim.properties.includes('primary_key') === true)
|
|
77
77
|
.map(dim => {
|
|
78
78
|
return {
|
|
79
79
|
value: dim.name,
|
|
@@ -167,7 +167,7 @@ export default function NodeValidateTab({ node, djClient }) {
|
|
|
167
167
|
const filters = dimensions.map(grouping => {
|
|
168
168
|
const dimensionsInGroup = grouping[1];
|
|
169
169
|
const dimensionGroupOptions = dimensionsInGroup
|
|
170
|
-
.filter(dim => dim.
|
|
170
|
+
.filter(dim => dim.properties.includes('primary_key') === true)
|
|
171
171
|
.map(dim => {
|
|
172
172
|
return {
|
|
173
173
|
value: dim.name,
|
|
@@ -183,7 +183,14 @@ export default function RevisionDiff() {
|
|
|
183
183
|
</SyntaxHighlighter>
|
|
184
184
|
</>
|
|
185
185
|
) : field === 'columns' ? (
|
|
186
|
-
<div>
|
|
186
|
+
<div>
|
|
187
|
+
{prevRevision[0][field].map(col => (
|
|
188
|
+
<>
|
|
189
|
+
{col.name}
|
|
190
|
+
<br />
|
|
191
|
+
</>
|
|
192
|
+
))}
|
|
193
|
+
</div>
|
|
187
194
|
) : (
|
|
188
195
|
prevRevision[0][field].toString()
|
|
189
196
|
)
|
|
@@ -95,7 +95,7 @@ describe('<NodeDependenciesTab />', () => {
|
|
|
95
95
|
|
|
96
96
|
const mockDimensions = [
|
|
97
97
|
{
|
|
98
|
-
|
|
98
|
+
properties: [],
|
|
99
99
|
name: 'default.dispatcher.company_name',
|
|
100
100
|
node_display_name: 'Default: Dispatcher',
|
|
101
101
|
node_name: 'default.dispatcher',
|
|
@@ -103,7 +103,7 @@ describe('<NodeDependenciesTab />', () => {
|
|
|
103
103
|
type: 'string',
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
|
-
|
|
106
|
+
properties: ['primary_key'],
|
|
107
107
|
name: 'default.dispatcher.dispatcher_id',
|
|
108
108
|
node_display_name: 'Default: Dispatcher',
|
|
109
109
|
node_name: 'default.dispatcher',
|
|
@@ -111,7 +111,7 @@ describe('<NodeDependenciesTab />', () => {
|
|
|
111
111
|
type: 'int',
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
|
|
114
|
+
properties: [],
|
|
115
115
|
name: 'default.hard_hat.city',
|
|
116
116
|
node_display_name: 'Default: Hard Hat',
|
|
117
117
|
node_name: 'default.hard_hat',
|
|
@@ -119,7 +119,7 @@ describe('<NodeDependenciesTab />', () => {
|
|
|
119
119
|
type: 'string',
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
|
-
|
|
122
|
+
properties: ['primary_key'],
|
|
123
123
|
name: 'default.hard_hat.hard_hat_id',
|
|
124
124
|
node_display_name: 'Default: Hard Hat',
|
|
125
125
|
node_name: 'default.hard_hat',
|
|
@@ -34,7 +34,8 @@ describe('<NodeColumnLineage />', () => {
|
|
|
34
34
|
|
|
35
35
|
it('renders and calls node_lineage with the correct node name', async () => {
|
|
36
36
|
const djClient = mockDJClient();
|
|
37
|
-
djClient.DataJunctionAPI.
|
|
37
|
+
djClient.DataJunctionAPI.node = name => mocks.mockMetricNode;
|
|
38
|
+
djClient.DataJunctionAPI.getMetric = name => mocks.mockMetricNodeJson;
|
|
38
39
|
const { container } = render(
|
|
39
40
|
<DJClientContext.Provider value={djClient}>
|
|
40
41
|
<NodeColumnLineage {...defaultProps} />
|
|
@@ -43,7 +44,7 @@ describe('<NodeColumnLineage />', () => {
|
|
|
43
44
|
|
|
44
45
|
await waitFor(() => {
|
|
45
46
|
expect(djClient.DataJunctionAPI.node_lineage).toHaveBeenCalledWith(
|
|
46
|
-
|
|
47
|
+
mocks.mockMetricNode.name,
|
|
47
48
|
);
|
|
48
49
|
|
|
49
50
|
// The origin node should be displayed
|
|
@@ -23,6 +23,7 @@ describe('<NodePage />', () => {
|
|
|
23
23
|
DataJunctionAPI: {
|
|
24
24
|
node: jest.fn(),
|
|
25
25
|
metric: jest.fn(),
|
|
26
|
+
getMetric: jest.fn(),
|
|
26
27
|
revalidate: jest.fn().mockReturnValue({ status: 'valid' }),
|
|
27
28
|
node_dag: jest.fn().mockReturnValue(mocks.mockNodeDAG),
|
|
28
29
|
clientCode: jest.fn().mockReturnValue('dj_client = DJClient()'),
|
|
@@ -279,7 +280,9 @@ describe('<NodePage />', () => {
|
|
|
279
280
|
it('renders the NodeInfo tab correctly for a metric node', async () => {
|
|
280
281
|
const djClient = mockDJClient();
|
|
281
282
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
282
|
-
djClient.DataJunctionAPI.
|
|
283
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
284
|
+
mocks.mockMetricNodeJson,
|
|
285
|
+
);
|
|
283
286
|
const element = (
|
|
284
287
|
<DJClientContext.Provider value={djClient}>
|
|
285
288
|
<NodePage {...defaultProps} />
|
|
@@ -399,7 +402,9 @@ describe('<NodePage />', () => {
|
|
|
399
402
|
it('renders the NodeColumns tab correctly', async () => {
|
|
400
403
|
const djClient = mockDJClient();
|
|
401
404
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
402
|
-
djClient.DataJunctionAPI.
|
|
405
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
406
|
+
mocks.mockMetricNodeJson,
|
|
407
|
+
);
|
|
403
408
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
404
409
|
djClient.DataJunctionAPI.attributes.mockReturnValue(mocks.attributes);
|
|
405
410
|
djClient.DataJunctionAPI.dimensions.mockReturnValue(mocks.dimensions);
|
|
@@ -476,7 +481,9 @@ describe('<NodePage />', () => {
|
|
|
476
481
|
it('renders the NodeHistory tab correctly', async () => {
|
|
477
482
|
const djClient = mockDJClient();
|
|
478
483
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
479
|
-
djClient.DataJunctionAPI.
|
|
484
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
485
|
+
mocks.mockMetricNodeJson,
|
|
486
|
+
);
|
|
480
487
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
481
488
|
djClient.DataJunctionAPI.history.mockReturnValue(mocks.metricNodeHistory);
|
|
482
489
|
djClient.DataJunctionAPI.revisions.mockReturnValue(
|
|
@@ -576,7 +583,9 @@ describe('<NodePage />', () => {
|
|
|
576
583
|
it('renders an empty NodeMaterialization tab correctly', async () => {
|
|
577
584
|
const djClient = mockDJClient();
|
|
578
585
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
579
|
-
djClient.DataJunctionAPI.
|
|
586
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
587
|
+
mocks.mockMetricNodeJson,
|
|
588
|
+
);
|
|
580
589
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
581
590
|
djClient.DataJunctionAPI.materializations.mockReturnValue([]);
|
|
582
591
|
|
|
@@ -609,7 +618,9 @@ describe('<NodePage />', () => {
|
|
|
609
618
|
it('renders the NodeMaterialization tab with materializations correctly', async () => {
|
|
610
619
|
const djClient = mockDJClient();
|
|
611
620
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockTransformNode);
|
|
612
|
-
|
|
621
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
622
|
+
mocks.mockMetricNodeJson,
|
|
623
|
+
);
|
|
613
624
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
614
625
|
djClient.DataJunctionAPI.materializations.mockReturnValue(
|
|
615
626
|
mocks.nodeMaterializations,
|
|
@@ -659,10 +670,10 @@ describe('<NodePage />', () => {
|
|
|
659
670
|
const djClient = mockDJClient();
|
|
660
671
|
window.scrollTo = jest.fn();
|
|
661
672
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
662
|
-
djClient.DataJunctionAPI.nodeDimensions.mockReturnValue(
|
|
663
|
-
|
|
673
|
+
djClient.DataJunctionAPI.nodeDimensions.mockReturnValue([]);
|
|
674
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
675
|
+
mocks.mockMetricNodeJson,
|
|
664
676
|
);
|
|
665
|
-
djClient.DataJunctionAPI.metric.mockReturnValue(mocks.mockMetricNode);
|
|
666
677
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
667
678
|
djClient.DataJunctionAPI.sql.mockReturnValue({
|
|
668
679
|
sql: 'SELECT * FROM testNode',
|
|
@@ -765,7 +776,9 @@ describe('<NodePage />', () => {
|
|
|
765
776
|
it('renders a NodeColumnLineage tab correctly', async () => {
|
|
766
777
|
const djClient = mockDJClient();
|
|
767
778
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
768
|
-
djClient.DataJunctionAPI.
|
|
779
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
780
|
+
mocks.mockMetricNodeJson,
|
|
781
|
+
);
|
|
769
782
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
770
783
|
djClient.DataJunctionAPI.node_lineage.mockReturnValue(
|
|
771
784
|
mocks.mockNodeLineage,
|
|
@@ -796,7 +809,9 @@ describe('<NodePage />', () => {
|
|
|
796
809
|
it('renders a NodeGraph tab correctly', async () => {
|
|
797
810
|
const djClient = mockDJClient();
|
|
798
811
|
djClient.DataJunctionAPI.node.mockReturnValue(mocks.mockMetricNode);
|
|
799
|
-
djClient.DataJunctionAPI.
|
|
812
|
+
djClient.DataJunctionAPI.getMetric.mockReturnValue(
|
|
813
|
+
mocks.mockMetricNodeJson,
|
|
814
|
+
);
|
|
800
815
|
djClient.DataJunctionAPI.columns.mockReturnValue(mocks.metricNodeColumns);
|
|
801
816
|
|
|
802
817
|
const element = (
|
|
@@ -53,13 +53,13 @@ export function NodePage() {
|
|
|
53
53
|
const data = await djClient.node(name);
|
|
54
54
|
data.createNodeClientCode = await djClient.clientCode(name);
|
|
55
55
|
if (data.type === 'metric') {
|
|
56
|
-
const metric = await djClient.
|
|
57
|
-
data.
|
|
58
|
-
data.
|
|
59
|
-
data.
|
|
60
|
-
data.
|
|
61
|
-
data.
|
|
62
|
-
|
|
56
|
+
const metric = await djClient.getMetric(name);
|
|
57
|
+
data.metric_metadata = metric.current.metricMetadata;
|
|
58
|
+
data.required_dimensions = metric.current.requiredDimensions;
|
|
59
|
+
data.upstream_node = metric.current.parents[0].name;
|
|
60
|
+
data.expression = metric.current.metricMetadata.expression;
|
|
61
|
+
data.incompatible_druid_functions =
|
|
62
|
+
metric.current.metricMetadata.incompatibleDruidFunctions;
|
|
63
63
|
}
|
|
64
64
|
if (data.type === 'cube') {
|
|
65
65
|
const cube = await djClient.cube(name);
|
|
@@ -128,6 +128,45 @@ export const DataJunctionAPI = {
|
|
|
128
128
|
return data;
|
|
129
129
|
},
|
|
130
130
|
|
|
131
|
+
getMetric: async function (name) {
|
|
132
|
+
const query = `
|
|
133
|
+
query GetMetric($name: String!) {
|
|
134
|
+
findNodes (names: [$name]) {
|
|
135
|
+
name
|
|
136
|
+
current {
|
|
137
|
+
parents { name }
|
|
138
|
+
metricMetadata {
|
|
139
|
+
direction
|
|
140
|
+
unit { name }
|
|
141
|
+
expression
|
|
142
|
+
incompatibleDruidFunctions
|
|
143
|
+
}
|
|
144
|
+
requiredDimensions {
|
|
145
|
+
name
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
const results = await (
|
|
153
|
+
await fetch(DJ_GQL, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Content-Type': 'application/json',
|
|
157
|
+
},
|
|
158
|
+
credentials: 'include',
|
|
159
|
+
body: JSON.stringify({
|
|
160
|
+
query,
|
|
161
|
+
variables: {
|
|
162
|
+
name: name,
|
|
163
|
+
},
|
|
164
|
+
}),
|
|
165
|
+
})
|
|
166
|
+
).json();
|
|
167
|
+
return results.data.findNodes[0];
|
|
168
|
+
},
|
|
169
|
+
|
|
131
170
|
nodes: async function (prefix) {
|
|
132
171
|
const queryParams = prefix ? `?prefix=${prefix}` : '';
|
|
133
172
|
return await (
|
|
@@ -1096,4 +1096,45 @@ describe('DataJunctionAPI', () => {
|
|
|
1096
1096
|
}),
|
|
1097
1097
|
);
|
|
1098
1098
|
});
|
|
1099
|
+
|
|
1100
|
+
it('calls getMetric correctly', async () => {
|
|
1101
|
+
fetch.mockResponseOnce(
|
|
1102
|
+
JSON.stringify({
|
|
1103
|
+
data: { findNodes: [{ name: 'default.num_repair_orders' }] },
|
|
1104
|
+
}),
|
|
1105
|
+
);
|
|
1106
|
+
await DataJunctionAPI.getMetric('default.num_repair_orders');
|
|
1107
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
1108
|
+
`${DJ_URL}/graphql`,
|
|
1109
|
+
expect.objectContaining({
|
|
1110
|
+
method: 'POST',
|
|
1111
|
+
credentials: 'include',
|
|
1112
|
+
headers: {
|
|
1113
|
+
'Content-Type': 'application/json',
|
|
1114
|
+
},
|
|
1115
|
+
}),
|
|
1116
|
+
);
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
it('calls notebookExportCube correctly', async () => {
|
|
1120
|
+
fetch.mockResponseOnce(JSON.stringify({}));
|
|
1121
|
+
await DataJunctionAPI.notebookExportCube('default.repairs_cube');
|
|
1122
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
1123
|
+
`${DJ_URL}/datajunction-clients/python/notebook/?cube=default.repairs_cube`,
|
|
1124
|
+
{
|
|
1125
|
+
credentials: 'include',
|
|
1126
|
+
},
|
|
1127
|
+
);
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
it('calls notebookExportNamespace correctly', async () => {
|
|
1131
|
+
fetch.mockResponseOnce(JSON.stringify({}));
|
|
1132
|
+
await DataJunctionAPI.notebookExportNamespace('default');
|
|
1133
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
1134
|
+
`${DJ_URL}/datajunction-clients/python/notebook/?namespace=default`,
|
|
1135
|
+
{
|
|
1136
|
+
credentials: 'include',
|
|
1137
|
+
},
|
|
1138
|
+
);
|
|
1139
|
+
});
|
|
1099
1140
|
});
|
package/src/mocks/mockNodes.jsx
CHANGED
|
@@ -422,11 +422,13 @@ export const mocks = {
|
|
|
422
422
|
post: { status: 'invalid' },
|
|
423
423
|
details: {
|
|
424
424
|
materialization: 'druid_metrics_cube__incremental_time__xyz',
|
|
425
|
-
partition: [
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
425
|
+
partition: [
|
|
426
|
+
{
|
|
427
|
+
column_name: 'xyz.abc',
|
|
428
|
+
values: null,
|
|
429
|
+
range: ['20240201', '20240301'],
|
|
430
|
+
},
|
|
431
|
+
],
|
|
430
432
|
},
|
|
431
433
|
created_at: '2023-08-21T16:48:56.950482+00:00',
|
|
432
434
|
},
|
|
@@ -915,297 +917,20 @@ export const mocks = {
|
|
|
915
917
|
},
|
|
916
918
|
],
|
|
917
919
|
mockMetricNodeJson: {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
created_at: '2023-08-21T16:48:51.146121+00:00',
|
|
931
|
-
updated_at: '2023-08-21T16:48:51.146122+00:00',
|
|
932
|
-
extra_params: {},
|
|
933
|
-
name: 'warehouse',
|
|
934
|
-
},
|
|
935
|
-
schema_: null,
|
|
936
|
-
table: null,
|
|
937
|
-
description: 'Average repair price',
|
|
938
|
-
query:
|
|
939
|
-
'SELECT avg(price) default_DOT_avg_repair_price \n FROM default.repair_order_details\n\n',
|
|
940
|
-
availability: null,
|
|
941
|
-
columns: [
|
|
942
|
-
{
|
|
943
|
-
name: 'default_DOT_avg_repair_price',
|
|
944
|
-
type: 'double',
|
|
945
|
-
display_name: 'Default DOT avg repair price',
|
|
946
|
-
attributes: [],
|
|
947
|
-
dimension: null,
|
|
948
|
-
},
|
|
949
|
-
],
|
|
950
|
-
updated_at: '2023-08-21T16:48:56.932231+00:00',
|
|
951
|
-
materializations: [],
|
|
952
|
-
parents: [
|
|
953
|
-
{
|
|
954
|
-
name: 'default.repair_order_details',
|
|
955
|
-
},
|
|
956
|
-
],
|
|
957
|
-
created_at: '2023-08-21T16:48:56.932162+00:00',
|
|
958
|
-
tags: [],
|
|
959
|
-
primary_key: [],
|
|
960
|
-
createNodeClientCode:
|
|
961
|
-
'dj = DJBuilder(DJ_URL)\n\navg_repair_price = dj.create_metric(\n description="Average repair price",\n display_name="Default: Avg Repair Price",\n name="default.avg_repair_price",\n primary_key=[],\n query="""SELECT avg(price) default_DOT_avg_repair_price \n FROM default.repair_order_details\n\n"""\n)',
|
|
962
|
-
dimensions: [
|
|
963
|
-
{
|
|
964
|
-
name: 'default.date_dim.dateint',
|
|
965
|
-
node_name: 'default.date_dim',
|
|
966
|
-
node_display_name: 'Date Dim',
|
|
967
|
-
is_primary_key: true,
|
|
968
|
-
type: 'timestamp',
|
|
969
|
-
path: [
|
|
970
|
-
'default.repair_order_details.repair_order_id',
|
|
971
|
-
'default.repair_order.hard_hat_id',
|
|
972
|
-
'default.hard_hat.birth_date',
|
|
973
|
-
],
|
|
974
|
-
},
|
|
975
|
-
{
|
|
976
|
-
name: 'default.date_dim.dateint',
|
|
977
|
-
node_name: 'default.date_dim',
|
|
978
|
-
node_display_name: 'Date Dim',
|
|
979
|
-
is_primary_key: true,
|
|
980
|
-
type: 'timestamp',
|
|
981
|
-
path: [
|
|
982
|
-
'default.repair_order_details.repair_order_id',
|
|
983
|
-
'default.repair_order.hard_hat_id',
|
|
984
|
-
'default.hard_hat.hire_date',
|
|
985
|
-
],
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
name: 'default.date_dim.day',
|
|
989
|
-
node_name: 'default.date_dim',
|
|
990
|
-
node_display_name: 'Date Dim',
|
|
991
|
-
is_primary_key: false,
|
|
992
|
-
type: 'int',
|
|
993
|
-
path: [
|
|
994
|
-
'default.repair_order_details.repair_order_id',
|
|
995
|
-
'default.repair_order.hard_hat_id',
|
|
996
|
-
'default.hard_hat.birth_date',
|
|
997
|
-
],
|
|
998
|
-
},
|
|
999
|
-
{
|
|
1000
|
-
name: 'default.date_dim.day',
|
|
1001
|
-
node_name: 'default.date_dim',
|
|
1002
|
-
node_display_name: 'Date Dim',
|
|
1003
|
-
is_primary_key: false,
|
|
1004
|
-
type: 'int',
|
|
1005
|
-
path: [
|
|
1006
|
-
'default.repair_order_details.repair_order_id',
|
|
1007
|
-
'default.repair_order.hard_hat_id',
|
|
1008
|
-
'default.hard_hat.hire_date',
|
|
1009
|
-
],
|
|
1010
|
-
},
|
|
1011
|
-
{
|
|
1012
|
-
name: 'default.date_dim.month',
|
|
1013
|
-
node_name: 'default.date_dim',
|
|
1014
|
-
node_display_name: 'Date Dim',
|
|
1015
|
-
is_primary_key: false,
|
|
1016
|
-
type: 'int',
|
|
1017
|
-
path: [
|
|
1018
|
-
'default.repair_order_details.repair_order_id',
|
|
1019
|
-
'default.repair_order.hard_hat_id',
|
|
1020
|
-
'default.hard_hat.birth_date',
|
|
1021
|
-
],
|
|
1022
|
-
},
|
|
1023
|
-
{
|
|
1024
|
-
name: 'default.date_dim.month',
|
|
1025
|
-
node_name: 'default.date_dim',
|
|
1026
|
-
node_display_name: 'Date Dim',
|
|
1027
|
-
is_primary_key: false,
|
|
1028
|
-
type: 'int',
|
|
1029
|
-
path: [
|
|
1030
|
-
'default.repair_order_details.repair_order_id',
|
|
1031
|
-
'default.repair_order.hard_hat_id',
|
|
1032
|
-
'default.hard_hat.hire_date',
|
|
1033
|
-
],
|
|
1034
|
-
},
|
|
1035
|
-
{
|
|
1036
|
-
name: 'default.date_dim.year',
|
|
1037
|
-
node_name: 'default.date_dim',
|
|
1038
|
-
node_display_name: 'Date Dim',
|
|
1039
|
-
is_primary_key: false,
|
|
1040
|
-
type: 'int',
|
|
1041
|
-
path: [
|
|
1042
|
-
'default.repair_order_details.repair_order_id',
|
|
1043
|
-
'default.repair_order.hard_hat_id',
|
|
1044
|
-
'default.hard_hat.birth_date',
|
|
1045
|
-
],
|
|
1046
|
-
},
|
|
1047
|
-
{
|
|
1048
|
-
name: 'default.date_dim.year',
|
|
1049
|
-
node_name: 'default.date_dim',
|
|
1050
|
-
node_display_name: 'Date Dim',
|
|
1051
|
-
is_primary_key: false,
|
|
1052
|
-
type: 'int',
|
|
1053
|
-
path: [
|
|
1054
|
-
'default.repair_order_details.repair_order_id',
|
|
1055
|
-
'default.repair_order.hard_hat_id',
|
|
1056
|
-
'default.hard_hat.hire_date',
|
|
1057
|
-
],
|
|
1058
|
-
},
|
|
1059
|
-
{
|
|
1060
|
-
name: 'default.hard_hat.address',
|
|
1061
|
-
node_name: 'default.hard_hat',
|
|
1062
|
-
node_display_name: 'Hard hat',
|
|
1063
|
-
is_primary_key: false,
|
|
1064
|
-
type: 'string',
|
|
1065
|
-
path: [
|
|
1066
|
-
'default.repair_order_details.repair_order_id',
|
|
1067
|
-
'default.repair_order.hard_hat_id',
|
|
1068
|
-
],
|
|
1069
|
-
},
|
|
1070
|
-
{
|
|
1071
|
-
name: 'default.hard_hat.birth_date',
|
|
1072
|
-
node_name: 'default.hard_hat',
|
|
1073
|
-
node_display_name: 'Hard hat',
|
|
1074
|
-
is_primary_key: false,
|
|
1075
|
-
type: 'date',
|
|
1076
|
-
path: [
|
|
1077
|
-
'default.repair_order_details.repair_order_id',
|
|
1078
|
-
'default.repair_order.hard_hat_id',
|
|
1079
|
-
],
|
|
1080
|
-
},
|
|
1081
|
-
{
|
|
1082
|
-
name: 'default.hard_hat.city',
|
|
1083
|
-
node_name: 'default.hard_hat',
|
|
1084
|
-
node_display_name: 'Hard hat',
|
|
1085
|
-
is_primary_key: false,
|
|
1086
|
-
type: 'string',
|
|
1087
|
-
path: [
|
|
1088
|
-
'default.repair_order_details.repair_order_id',
|
|
1089
|
-
'default.repair_order.hard_hat_id',
|
|
1090
|
-
],
|
|
1091
|
-
},
|
|
1092
|
-
{
|
|
1093
|
-
name: 'default.hard_hat.contractor_id',
|
|
1094
|
-
node_name: 'default.hard_hat',
|
|
1095
|
-
node_display_name: 'Hard hat',
|
|
1096
|
-
is_primary_key: false,
|
|
1097
|
-
type: 'int',
|
|
1098
|
-
path: [
|
|
1099
|
-
'default.repair_order_details.repair_order_id',
|
|
1100
|
-
'default.repair_order.hard_hat_id',
|
|
1101
|
-
],
|
|
1102
|
-
},
|
|
1103
|
-
{
|
|
1104
|
-
name: 'default.hard_hat.country',
|
|
1105
|
-
node_name: 'default.hard_hat',
|
|
1106
|
-
node_display_name: 'Hard hat',
|
|
1107
|
-
is_primary_key: false,
|
|
1108
|
-
type: 'string',
|
|
1109
|
-
path: [
|
|
1110
|
-
'default.repair_order_details.repair_order_id',
|
|
1111
|
-
'default.repair_order.hard_hat_id',
|
|
1112
|
-
],
|
|
1113
|
-
},
|
|
1114
|
-
{
|
|
1115
|
-
name: 'default.hard_hat.first_name',
|
|
1116
|
-
node_name: 'default.hard_hat',
|
|
1117
|
-
node_display_name: 'Hard hat',
|
|
1118
|
-
is_primary_key: false,
|
|
1119
|
-
type: 'string',
|
|
1120
|
-
path: [
|
|
1121
|
-
'default.repair_order_details.repair_order_id',
|
|
1122
|
-
'default.repair_order.hard_hat_id',
|
|
1123
|
-
],
|
|
1124
|
-
},
|
|
1125
|
-
{
|
|
1126
|
-
name: 'default.hard_hat.hard_hat_id',
|
|
1127
|
-
node_name: 'default.hard_hat',
|
|
1128
|
-
node_display_name: 'Hard hat',
|
|
1129
|
-
is_primary_key: true,
|
|
1130
|
-
type: 'int',
|
|
1131
|
-
path: [
|
|
1132
|
-
'default.repair_order_details.repair_order_id',
|
|
1133
|
-
'default.repair_order.hard_hat_id',
|
|
1134
|
-
],
|
|
1135
|
-
},
|
|
1136
|
-
{
|
|
1137
|
-
name: 'default.hard_hat.hire_date',
|
|
1138
|
-
node_name: 'default.hard_hat',
|
|
1139
|
-
node_display_name: 'Hard hat',
|
|
1140
|
-
is_primary_key: false,
|
|
1141
|
-
type: 'date',
|
|
1142
|
-
path: [
|
|
1143
|
-
'default.repair_order_details.repair_order_id',
|
|
1144
|
-
'default.repair_order.hard_hat_id',
|
|
1145
|
-
],
|
|
1146
|
-
},
|
|
1147
|
-
{
|
|
1148
|
-
name: 'default.hard_hat.last_name',
|
|
1149
|
-
node_name: 'default.hard_hat',
|
|
1150
|
-
node_display_name: 'Hard hat',
|
|
1151
|
-
is_primary_key: false,
|
|
1152
|
-
type: 'string',
|
|
1153
|
-
path: [
|
|
1154
|
-
'default.repair_order_details.repair_order_id',
|
|
1155
|
-
'default.repair_order.hard_hat_id',
|
|
1156
|
-
],
|
|
1157
|
-
},
|
|
1158
|
-
{
|
|
1159
|
-
name: 'default.hard_hat.manager',
|
|
1160
|
-
node_name: 'default.hard_hat',
|
|
1161
|
-
node_display_name: 'Hard hat',
|
|
1162
|
-
is_primary_key: false,
|
|
1163
|
-
type: 'int',
|
|
1164
|
-
path: [
|
|
1165
|
-
'default.repair_order_details.repair_order_id',
|
|
1166
|
-
'default.repair_order.hard_hat_id',
|
|
1167
|
-
],
|
|
1168
|
-
},
|
|
1169
|
-
{
|
|
1170
|
-
name: 'default.hard_hat.postal_code',
|
|
1171
|
-
node_name: 'default.hard_hat',
|
|
1172
|
-
node_display_name: 'Hard hat',
|
|
1173
|
-
is_primary_key: false,
|
|
1174
|
-
type: 'string',
|
|
1175
|
-
path: [
|
|
1176
|
-
'default.repair_order_details.repair_order_id',
|
|
1177
|
-
'default.repair_order.hard_hat_id',
|
|
1178
|
-
],
|
|
1179
|
-
},
|
|
1180
|
-
{
|
|
1181
|
-
name: 'default.hard_hat.state',
|
|
1182
|
-
node_name: 'default.hard_hat',
|
|
1183
|
-
node_display_name: 'Hard hat',
|
|
1184
|
-
is_primary_key: false,
|
|
1185
|
-
type: 'string',
|
|
1186
|
-
path: [
|
|
1187
|
-
'default.repair_order_details.repair_order_id',
|
|
1188
|
-
'default.repair_order.hard_hat_id',
|
|
1189
|
-
],
|
|
1190
|
-
},
|
|
1191
|
-
{
|
|
1192
|
-
name: 'default.hard_hat.title',
|
|
1193
|
-
node_name: 'default.hard_hat',
|
|
1194
|
-
node_display_name: 'Hard hat',
|
|
1195
|
-
is_primary_key: false,
|
|
1196
|
-
type: 'string',
|
|
1197
|
-
path: [
|
|
1198
|
-
'default.repair_order_details.repair_order_id',
|
|
1199
|
-
'default.repair_order.hard_hat_id',
|
|
1200
|
-
],
|
|
1201
|
-
},
|
|
1202
|
-
],
|
|
1203
|
-
metric_metadata: {
|
|
1204
|
-
unit: {
|
|
1205
|
-
name: 'unitless',
|
|
1206
|
-
label: 'Unitless',
|
|
920
|
+
name: 'default.num_repair_orders',
|
|
921
|
+
current: {
|
|
922
|
+
parents: [
|
|
923
|
+
{
|
|
924
|
+
name: 'default.repair_orders',
|
|
925
|
+
},
|
|
926
|
+
],
|
|
927
|
+
metricMetadata: {
|
|
928
|
+
direction: null,
|
|
929
|
+
unit: null,
|
|
930
|
+
expression: 'count(repair_order_id)',
|
|
931
|
+
incompatibleDruidFunctions: [],
|
|
1207
932
|
},
|
|
1208
|
-
|
|
933
|
+
requiredDimensions: [],
|
|
1209
934
|
},
|
|
1210
935
|
},
|
|
1211
936
|
mockNodeDAG: [
|