datajunction-ui 0.0.1-rc.19 → 0.0.1-rc.20
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 +6 -5
- package/src/__tests__/reportWebVitals.test.jsx +44 -0
- package/src/app/components/DeleteNode.jsx +79 -0
- package/src/app/components/ListGroupItem.jsx +8 -1
- package/src/app/components/QueryInfo.jsx +4 -4
- package/src/app/components/Tab.jsx +9 -1
- package/src/app/components/ToggleSwitch.jsx +3 -0
- package/src/app/components/__tests__/QueryInfo.test.jsx +55 -0
- package/src/app/components/__tests__/Tab.test.jsx +27 -0
- package/src/app/components/__tests__/ToggleSwitch.test.jsx +43 -0
- package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +3 -0
- package/src/app/components/djgraph/DJNodeColumns.jsx +4 -1
- package/src/app/components/djgraph/DJNodeDimensions.jsx +9 -2
- package/src/app/components/djgraph/__tests__/Collapse.test.jsx +51 -0
- package/src/app/components/djgraph/__tests__/DJNodeColumns.test.jsx +83 -0
- package/src/app/components/djgraph/__tests__/DJNodeDimensions.test.jsx +118 -0
- package/src/app/index.tsx +6 -0
- package/src/app/pages/AddEditNodePage/FormikSelect.jsx +15 -2
- package/src/app/pages/AddEditNodePage/FullNameField.jsx +2 -1
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +77 -0
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +93 -0
- package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +34 -3
- package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +4 -2
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +53 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +53 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +0 -81
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +82 -257
- package/src/app/pages/AddEditNodePage/index.jsx +13 -5
- package/src/app/pages/LoginPage/__tests__/index.test.jsx +70 -0
- package/src/app/pages/NamespacePage/__tests__/index.test.jsx +95 -0
- package/src/app/pages/NamespacePage/index.jsx +8 -5
- package/src/app/pages/NodePage/ClientCodePopover.jsx +3 -1
- package/src/app/pages/NodePage/EditColumnPopover.jsx +102 -0
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +135 -0
- package/src/app/pages/NodePage/NodeColumnTab.jsx +80 -17
- package/src/app/pages/NodePage/NodeHistory.jsx +63 -30
- package/src/app/pages/NodePage/NodeInfoTab.jsx +52 -7
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +50 -27
- package/src/app/pages/NodePage/NodeSQLTab.jsx +0 -10
- package/src/app/pages/NodePage/NodesWithDimension.jsx +4 -2
- package/src/app/pages/NodePage/__tests__/ClientCodePopover.test.jsx +49 -0
- package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +148 -0
- package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +165 -0
- package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +591 -0
- package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +57 -0
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +725 -0
- package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
- package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +402 -0
- package/src/app/pages/NodePage/index.jsx +22 -6
- package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
- package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
- package/src/app/pages/RegisterTablePage/index.jsx +163 -0
- package/src/app/pages/Root/__tests__/index.test.jsx +77 -0
- package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
- package/src/app/pages/SQLBuilderPage/index.jsx +61 -43
- package/src/app/services/DJService.js +125 -54
- package/src/app/services/__tests__/DJService.test.jsx +609 -0
- package/src/mocks/mockNodes.jsx +1397 -0
- package/src/setupTests.ts +30 -0
- package/src/styles/index.css +43 -0
- package/src/styles/node-creation.scss +7 -0
- package/src/utils/form.jsx +23 -0
- package/.github/pull_request_template.md +0 -11
- package/.github/workflows/ci.yml +0 -33
- package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -118
- package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useContext, useState } from 'react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import DJClientContext from '../../providers/djclient';
|
|
4
|
+
import { Form, Formik } from 'formik';
|
|
5
|
+
import { FormikSelect } from '../AddEditNodePage/FormikSelect';
|
|
6
|
+
import EditIcon from '../../icons/EditIcon';
|
|
7
|
+
import { displayMessageAfterSubmit, labelize } from '../../../utils/form';
|
|
8
|
+
|
|
9
|
+
export default function EditColumnPopover({ column, node, options, onSubmit }) {
|
|
10
|
+
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
11
|
+
const [popoverAnchor, setPopoverAnchor] = useState(false);
|
|
12
|
+
|
|
13
|
+
const saveAttributes = async (
|
|
14
|
+
{ node, column, attributes },
|
|
15
|
+
{ setSubmitting, setStatus },
|
|
16
|
+
) => {
|
|
17
|
+
setSubmitting(false);
|
|
18
|
+
const response = await djClient.setAttributes(node, column, attributes);
|
|
19
|
+
if (response.status === 200 || response.status === 201) {
|
|
20
|
+
setStatus({ success: 'Saved!' });
|
|
21
|
+
} else {
|
|
22
|
+
setStatus({
|
|
23
|
+
failure: `${response.json.message}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
onSubmit();
|
|
27
|
+
// window.location.reload();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<button
|
|
33
|
+
className="edit_button"
|
|
34
|
+
aria-label="EditColumn"
|
|
35
|
+
tabIndex="0"
|
|
36
|
+
onClick={() => {
|
|
37
|
+
setPopoverAnchor(!popoverAnchor);
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<EditIcon />
|
|
41
|
+
</button>
|
|
42
|
+
<div
|
|
43
|
+
className="popover"
|
|
44
|
+
role="dialog"
|
|
45
|
+
aria-label="client-code"
|
|
46
|
+
style={{ display: popoverAnchor === false ? 'none' : 'block' }}
|
|
47
|
+
>
|
|
48
|
+
<Formik
|
|
49
|
+
initialValues={{
|
|
50
|
+
column: column.name,
|
|
51
|
+
node: node.name,
|
|
52
|
+
attributes: [],
|
|
53
|
+
}}
|
|
54
|
+
onSubmit={saveAttributes}
|
|
55
|
+
>
|
|
56
|
+
{function Render({ isSubmitting, status, setFieldValue }) {
|
|
57
|
+
return (
|
|
58
|
+
<Form>
|
|
59
|
+
{displayMessageAfterSubmit(status)}
|
|
60
|
+
<span data-testid="edit-attributes">
|
|
61
|
+
<FormikSelect
|
|
62
|
+
selectOptions={options}
|
|
63
|
+
formikFieldName="attributes"
|
|
64
|
+
placeholder="Select column attributes"
|
|
65
|
+
className=""
|
|
66
|
+
defaultValue={column.attributes.map(attr => {
|
|
67
|
+
return {
|
|
68
|
+
value: attr.attribute_type.name,
|
|
69
|
+
label: labelize(attr.attribute_type.name),
|
|
70
|
+
};
|
|
71
|
+
})}
|
|
72
|
+
isMulti={true}
|
|
73
|
+
/>
|
|
74
|
+
</span>
|
|
75
|
+
<input
|
|
76
|
+
hidden={true}
|
|
77
|
+
name="column"
|
|
78
|
+
value={column.name}
|
|
79
|
+
readOnly={true}
|
|
80
|
+
/>
|
|
81
|
+
<input
|
|
82
|
+
hidden={true}
|
|
83
|
+
name="node"
|
|
84
|
+
value={node.name}
|
|
85
|
+
readOnly={true}
|
|
86
|
+
/>
|
|
87
|
+
<button
|
|
88
|
+
className="add_node"
|
|
89
|
+
type="submit"
|
|
90
|
+
aria-label="SaveEditColumn"
|
|
91
|
+
aria-hidden="false"
|
|
92
|
+
>
|
|
93
|
+
Save
|
|
94
|
+
</button>
|
|
95
|
+
</Form>
|
|
96
|
+
);
|
|
97
|
+
}}
|
|
98
|
+
</Formik>
|
|
99
|
+
</div>
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useContext, useState } from 'react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import DJClientContext from '../../providers/djclient';
|
|
4
|
+
import { Form, Formik } from 'formik';
|
|
5
|
+
import { FormikSelect } from '../AddEditNodePage/FormikSelect';
|
|
6
|
+
import EditIcon from '../../icons/EditIcon';
|
|
7
|
+
import { displayMessageAfterSubmit } from '../../../utils/form';
|
|
8
|
+
|
|
9
|
+
export default function LinkDimensionPopover({
|
|
10
|
+
column,
|
|
11
|
+
node,
|
|
12
|
+
options,
|
|
13
|
+
onSubmit,
|
|
14
|
+
}) {
|
|
15
|
+
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
16
|
+
const [popoverAnchor, setPopoverAnchor] = useState(false);
|
|
17
|
+
const columnDimension = column.dimension;
|
|
18
|
+
|
|
19
|
+
const handleSubmit = async (
|
|
20
|
+
{ node, column, dimension },
|
|
21
|
+
{ setSubmitting, setStatus },
|
|
22
|
+
) => {
|
|
23
|
+
setSubmitting(false);
|
|
24
|
+
console.log('dimension', dimension, 'columnDimension', columnDimension);
|
|
25
|
+
if (columnDimension?.name && dimension === 'Remove') {
|
|
26
|
+
await unlinkDimension(node, column, columnDimension?.name, setStatus);
|
|
27
|
+
} else {
|
|
28
|
+
await linkDimension(node, column, dimension, setStatus);
|
|
29
|
+
}
|
|
30
|
+
onSubmit();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const linkDimension = async (node, column, dimension, setStatus) => {
|
|
34
|
+
const response = await djClient.linkDimension(node, column, dimension);
|
|
35
|
+
if (response.status === 200 || response.status === 201) {
|
|
36
|
+
setStatus({ success: 'Saved!' });
|
|
37
|
+
} else {
|
|
38
|
+
setStatus({
|
|
39
|
+
failure: `${response.json.message}`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const unlinkDimension = async (node, column, currentDimension, setStatus) => {
|
|
45
|
+
const response = await djClient.unlinkDimension(
|
|
46
|
+
node,
|
|
47
|
+
column,
|
|
48
|
+
currentDimension,
|
|
49
|
+
);
|
|
50
|
+
if (response.status === 200 || response.status === 201) {
|
|
51
|
+
setStatus({ success: 'Removed dimension link!' });
|
|
52
|
+
} else {
|
|
53
|
+
setStatus({
|
|
54
|
+
failure: `${response.json.message}`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<button
|
|
62
|
+
className="edit_button"
|
|
63
|
+
aria-label="LinkDimension"
|
|
64
|
+
tabIndex="0"
|
|
65
|
+
onClick={() => {
|
|
66
|
+
setPopoverAnchor(!popoverAnchor);
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<EditIcon />
|
|
70
|
+
</button>
|
|
71
|
+
<div
|
|
72
|
+
className="popover"
|
|
73
|
+
role="dialog"
|
|
74
|
+
aria-label="client-code"
|
|
75
|
+
style={{ display: popoverAnchor === false ? 'none' : 'block' }}
|
|
76
|
+
>
|
|
77
|
+
<Formik
|
|
78
|
+
initialValues={{
|
|
79
|
+
column: column.name,
|
|
80
|
+
node: node.name,
|
|
81
|
+
dimension: '',
|
|
82
|
+
currentDimension: column.dimension?.name,
|
|
83
|
+
}}
|
|
84
|
+
onSubmit={handleSubmit}
|
|
85
|
+
>
|
|
86
|
+
{function Render({ isSubmitting, status, setFieldValue }) {
|
|
87
|
+
return (
|
|
88
|
+
<Form>
|
|
89
|
+
{displayMessageAfterSubmit(status)}
|
|
90
|
+
<span data-testid="link-dimension">
|
|
91
|
+
<FormikSelect
|
|
92
|
+
selectOptions={[
|
|
93
|
+
{ value: 'Remove', label: '[Remove Dimension]' },
|
|
94
|
+
].concat(options)}
|
|
95
|
+
formikFieldName="dimension"
|
|
96
|
+
placeholder="Select dimension to link"
|
|
97
|
+
className=""
|
|
98
|
+
defaultValue={
|
|
99
|
+
column.dimension
|
|
100
|
+
? {
|
|
101
|
+
value: column.dimension.name,
|
|
102
|
+
label: column.dimension.name,
|
|
103
|
+
}
|
|
104
|
+
: ''
|
|
105
|
+
}
|
|
106
|
+
/>
|
|
107
|
+
</span>
|
|
108
|
+
<input
|
|
109
|
+
hidden={true}
|
|
110
|
+
name="column"
|
|
111
|
+
value={column.name}
|
|
112
|
+
readOnly={true}
|
|
113
|
+
/>
|
|
114
|
+
<input
|
|
115
|
+
hidden={true}
|
|
116
|
+
name="node"
|
|
117
|
+
value={node.name}
|
|
118
|
+
readOnly={true}
|
|
119
|
+
/>
|
|
120
|
+
<button
|
|
121
|
+
className="add_node"
|
|
122
|
+
type="submit"
|
|
123
|
+
aria-label="SaveLinkDimension"
|
|
124
|
+
aria-hidden="false"
|
|
125
|
+
>
|
|
126
|
+
Save
|
|
127
|
+
</button>
|
|
128
|
+
</Form>
|
|
129
|
+
);
|
|
130
|
+
}}
|
|
131
|
+
</Formik>
|
|
132
|
+
</div>
|
|
133
|
+
</>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
import ClientCodePopover from './ClientCodePopover';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import EditColumnPopover from './EditColumnPopover';
|
|
5
|
+
import LinkDimensionPopover from './LinkDimensionPopover';
|
|
6
|
+
import { labelize } from '../../../utils/form';
|
|
3
7
|
|
|
4
8
|
export default function NodeColumnTab({ node, djClient }) {
|
|
9
|
+
const [attributes, setAttributes] = useState([]);
|
|
10
|
+
const [dimensions, setDimensions] = useState([]);
|
|
5
11
|
const [columns, setColumns] = useState([]);
|
|
6
12
|
useEffect(() => {
|
|
7
13
|
const fetchData = async () => {
|
|
@@ -10,12 +16,57 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
10
16
|
fetchData().catch(console.error);
|
|
11
17
|
}, [djClient, node]);
|
|
12
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const fetchData = async () => {
|
|
21
|
+
const attributes = await djClient.attributes();
|
|
22
|
+
const options = attributes.map(attr => {
|
|
23
|
+
return { value: attr.name, label: labelize(attr.name) };
|
|
24
|
+
});
|
|
25
|
+
setAttributes(options);
|
|
26
|
+
};
|
|
27
|
+
fetchData().catch(console.error);
|
|
28
|
+
}, [djClient]);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const fetchData = async () => {
|
|
32
|
+
const dimensions = await djClient.dimensions();
|
|
33
|
+
const options = dimensions.map(name => {
|
|
34
|
+
return { value: name, label: name };
|
|
35
|
+
});
|
|
36
|
+
setDimensions(options);
|
|
37
|
+
};
|
|
38
|
+
fetchData().catch(console.error);
|
|
39
|
+
}, [djClient]);
|
|
40
|
+
|
|
41
|
+
const showColumnAttributes = col => {
|
|
42
|
+
return col.attributes.map((attr, idx) => (
|
|
43
|
+
<span
|
|
44
|
+
className="node_type__dimension badge node_type"
|
|
45
|
+
key={`col-attr-${col.name}-${idx}`}
|
|
46
|
+
>
|
|
47
|
+
{attr.attribute_type.name.replace(/_/, ' ')}
|
|
48
|
+
</span>
|
|
49
|
+
));
|
|
50
|
+
};
|
|
51
|
+
|
|
13
52
|
const columnList = columns => {
|
|
14
53
|
return columns.map(col => (
|
|
15
|
-
<tr>
|
|
16
|
-
<td
|
|
54
|
+
<tr key={col.name}>
|
|
55
|
+
<td
|
|
56
|
+
className="text-start"
|
|
57
|
+
role="columnheader"
|
|
58
|
+
aria-label="ColumnName"
|
|
59
|
+
aria-hidden="false"
|
|
60
|
+
>
|
|
61
|
+
{col.name}
|
|
62
|
+
</td>
|
|
17
63
|
<td>
|
|
18
|
-
<span
|
|
64
|
+
<span
|
|
65
|
+
className="node_type__transform badge node_type"
|
|
66
|
+
role="columnheader"
|
|
67
|
+
aria-label="ColumnType"
|
|
68
|
+
aria-hidden="false"
|
|
69
|
+
>
|
|
19
70
|
{col.type}
|
|
20
71
|
</span>
|
|
21
72
|
</td>
|
|
@@ -28,17 +79,27 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
28
79
|
) : (
|
|
29
80
|
''
|
|
30
81
|
)}{' '}
|
|
82
|
+
<LinkDimensionPopover
|
|
83
|
+
column={col}
|
|
84
|
+
node={node}
|
|
85
|
+
options={dimensions}
|
|
86
|
+
onSubmit={async () => {
|
|
87
|
+
const res = await djClient.node(node.name);
|
|
88
|
+
setColumns(res.columns);
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
31
91
|
</td>
|
|
32
92
|
<td>
|
|
33
|
-
{col
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
93
|
+
{showColumnAttributes(col)}
|
|
94
|
+
<EditColumnPopover
|
|
95
|
+
column={col}
|
|
96
|
+
node={node}
|
|
97
|
+
options={attributes}
|
|
98
|
+
onSubmit={async () => {
|
|
99
|
+
const res = await djClient.node(node.name);
|
|
100
|
+
setColumns(res.columns);
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
42
103
|
</td>
|
|
43
104
|
</tr>
|
|
44
105
|
));
|
|
@@ -48,12 +109,14 @@ export default function NodeColumnTab({ node, djClient }) {
|
|
|
48
109
|
<div className="table-responsive">
|
|
49
110
|
<table className="card-inner-table table">
|
|
50
111
|
<thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
112
|
+
<tr>
|
|
113
|
+
<th className="text-start">Column</th>
|
|
114
|
+
<th>Type</th>
|
|
115
|
+
<th>Linked Dimension</th>
|
|
116
|
+
<th>Attributes</th>
|
|
117
|
+
</tr>
|
|
55
118
|
</thead>
|
|
56
|
-
{columnList(columns)}
|
|
119
|
+
<tbody>{columnList(columns)}</tbody>
|
|
57
120
|
</table>
|
|
58
121
|
</div>
|
|
59
122
|
);
|
|
@@ -6,10 +6,12 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
6
6
|
|
|
7
7
|
useEffect(() => {
|
|
8
8
|
const fetchData = async () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
if (node) {
|
|
10
|
+
const data = await djClient.history('node', node.name);
|
|
11
|
+
setHistory(data);
|
|
12
|
+
const revisions = await djClient.revisions(node.name);
|
|
13
|
+
setRevisions(revisions);
|
|
14
|
+
}
|
|
13
15
|
};
|
|
14
16
|
fetchData().catch(console.error);
|
|
15
17
|
}, [djClient, node]);
|
|
@@ -21,20 +23,32 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
21
23
|
) {
|
|
22
24
|
return event.details.attributes
|
|
23
25
|
.map(attr => (
|
|
24
|
-
<div
|
|
26
|
+
<div
|
|
27
|
+
key={event.id}
|
|
28
|
+
role="cell"
|
|
29
|
+
aria-label="HistoryAttribute"
|
|
30
|
+
aria-hidden="false"
|
|
31
|
+
>
|
|
25
32
|
Set{' '}
|
|
26
|
-
<span className={`badge partition_value`}>
|
|
33
|
+
<span className={`badge partition_value`}>
|
|
34
|
+
{event.details.column}
|
|
35
|
+
</span>{' '}
|
|
27
36
|
as{' '}
|
|
28
37
|
<span className={`badge partition_value_highlight`}>
|
|
29
|
-
{attr.
|
|
38
|
+
{attr.name}
|
|
30
39
|
</span>
|
|
31
40
|
</div>
|
|
32
41
|
))
|
|
33
|
-
.reduce((prev, curr) => [prev, <br />, curr]);
|
|
42
|
+
.reduce((prev, curr) => [prev, <br />, curr], []);
|
|
34
43
|
}
|
|
35
44
|
if (event.activity_type === 'create' && event.entity_type === 'link') {
|
|
36
45
|
return (
|
|
37
|
-
<div
|
|
46
|
+
<div
|
|
47
|
+
key={event.id}
|
|
48
|
+
role="cell"
|
|
49
|
+
aria-label="HistoryCreateLink"
|
|
50
|
+
aria-hidden="false"
|
|
51
|
+
>
|
|
38
52
|
Linked{' '}
|
|
39
53
|
<span className={`badge partition_value`}>
|
|
40
54
|
{event.details.column}
|
|
@@ -55,7 +69,12 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
55
69
|
event.entity_type === 'materialization'
|
|
56
70
|
) {
|
|
57
71
|
return (
|
|
58
|
-
<div
|
|
72
|
+
<div
|
|
73
|
+
key={event.id}
|
|
74
|
+
role="cell"
|
|
75
|
+
aria-label="HistoryCreateMaterialization"
|
|
76
|
+
aria-hidden="false"
|
|
77
|
+
>
|
|
59
78
|
Initialized materialization{' '}
|
|
60
79
|
<span className={`badge partition_value`}>
|
|
61
80
|
{event.details.materialization}
|
|
@@ -68,7 +87,12 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
68
87
|
event.entity_type === 'availability'
|
|
69
88
|
) {
|
|
70
89
|
return (
|
|
71
|
-
<div
|
|
90
|
+
<div
|
|
91
|
+
key={event.id}
|
|
92
|
+
role="cell"
|
|
93
|
+
aria-label="HistoryCreateAvailability"
|
|
94
|
+
aria-hidden="false"
|
|
95
|
+
>
|
|
72
96
|
Materialized at{' '}
|
|
73
97
|
<span className={`badge partition_value_highlight`}>
|
|
74
98
|
{event.post.catalog}.{event.post.schema_}.{event.post.table}
|
|
@@ -97,7 +121,12 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
97
121
|
</div>
|
|
98
122
|
);
|
|
99
123
|
return (
|
|
100
|
-
<div
|
|
124
|
+
<div
|
|
125
|
+
key={event.id}
|
|
126
|
+
role="cell"
|
|
127
|
+
aria-label="HistoryNodeStatusChange"
|
|
128
|
+
aria-hidden="false"
|
|
129
|
+
>
|
|
101
130
|
Status changed from{' '}
|
|
102
131
|
<span className={`status__${event.pre['status']}`}>
|
|
103
132
|
{event.pre['status']}
|
|
@@ -111,7 +140,7 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
111
140
|
);
|
|
112
141
|
}
|
|
113
142
|
return (
|
|
114
|
-
<div>
|
|
143
|
+
<div key={event.id}>
|
|
115
144
|
{JSON.stringify(event.details) === '{}'
|
|
116
145
|
? ''
|
|
117
146
|
: JSON.stringify(event.details)}
|
|
@@ -121,7 +150,7 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
121
150
|
|
|
122
151
|
const tableData = history => {
|
|
123
152
|
return history.map(event => (
|
|
124
|
-
<tr>
|
|
153
|
+
<tr key={`history-row-${event.id}`}>
|
|
125
154
|
<td className="text-start">
|
|
126
155
|
<span
|
|
127
156
|
className={`history_type__${event.activity_type} badge node_type`}
|
|
@@ -140,7 +169,7 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
140
169
|
|
|
141
170
|
const revisionsTable = revisions => {
|
|
142
171
|
return revisions.map(revision => (
|
|
143
|
-
<tr>
|
|
172
|
+
<tr key={revision.version}>
|
|
144
173
|
<td className="text-start">
|
|
145
174
|
<span className={`badge node_type__source`}>{revision.version}</span>
|
|
146
175
|
</td>
|
|
@@ -153,26 +182,30 @@ export default function NodeHistory({ node, djClient }) {
|
|
|
153
182
|
};
|
|
154
183
|
return (
|
|
155
184
|
<div className="table-vertical">
|
|
156
|
-
<table className="card-inner-table table">
|
|
185
|
+
<table className="card-inner-table table" aria-label="Revisions">
|
|
157
186
|
<thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
187
|
+
<tr>
|
|
188
|
+
<th className="text-start">Version</th>
|
|
189
|
+
<th>Display Name</th>
|
|
190
|
+
<th>Description</th>
|
|
191
|
+
<th>Query</th>
|
|
192
|
+
<th>Tags</th>
|
|
193
|
+
</tr>
|
|
163
194
|
</thead>
|
|
164
|
-
{revisionsTable(revisions)}
|
|
195
|
+
<tbody>{revisionsTable(revisions)}</tbody>
|
|
165
196
|
</table>
|
|
166
|
-
<table className="card-inner-table table">
|
|
197
|
+
<table className="card-inner-table table" aria-label="Activity">
|
|
167
198
|
<thead className="fs-7 fw-bold text-gray-400 border-bottom-0">
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
199
|
+
<tr>
|
|
200
|
+
<th className="text-start">Activity</th>
|
|
201
|
+
<th>Type</th>
|
|
202
|
+
<th>Name</th>
|
|
203
|
+
<th>User</th>
|
|
204
|
+
<th>Timestamp</th>
|
|
205
|
+
<th>Details</th>
|
|
206
|
+
</tr>
|
|
174
207
|
</thead>
|
|
175
|
-
{tableData(history)}
|
|
208
|
+
<tbody>{tableData(history)}</tbody>
|
|
176
209
|
</table>
|
|
177
210
|
</div>
|
|
178
211
|
);
|
|
@@ -73,7 +73,13 @@ export default function NodeInfoTab({ node }) {
|
|
|
73
73
|
<h6 className="mb-0 w-100">Cube Elements</h6>
|
|
74
74
|
<div className={`list-group-item`}>
|
|
75
75
|
{node.cube_elements.map(cubeElem => (
|
|
76
|
-
<div
|
|
76
|
+
<div
|
|
77
|
+
className="button-3 cube-element"
|
|
78
|
+
key={cubeElem.name}
|
|
79
|
+
role="cell"
|
|
80
|
+
aria-label="CubeElement"
|
|
81
|
+
aria-hidden="false"
|
|
82
|
+
>
|
|
77
83
|
<a href={`/nodes/${cubeElem.node_name}`}>
|
|
78
84
|
{cubeElem.type === 'metric'
|
|
79
85
|
? cubeElem.node_name
|
|
@@ -107,6 +113,9 @@ export default function NodeInfoTab({ node }) {
|
|
|
107
113
|
<span
|
|
108
114
|
className="rounded-pill badge bg-secondary-soft"
|
|
109
115
|
style={{ marginLeft: '0.5rem', fontSize: '100%' }}
|
|
116
|
+
role="dialog"
|
|
117
|
+
aria-hidden="false"
|
|
118
|
+
aria-label="Version"
|
|
110
119
|
>
|
|
111
120
|
{node?.version}
|
|
112
121
|
</span>
|
|
@@ -115,7 +124,12 @@ export default function NodeInfoTab({ node }) {
|
|
|
115
124
|
{node.type === 'source' ? (
|
|
116
125
|
<div>
|
|
117
126
|
<h6 className="mb-0 w-100">Table</h6>
|
|
118
|
-
<p
|
|
127
|
+
<p
|
|
128
|
+
className="mb-0 opacity-75"
|
|
129
|
+
role="dialog"
|
|
130
|
+
aria-hidden="false"
|
|
131
|
+
aria-label="Table"
|
|
132
|
+
>
|
|
119
133
|
{node?.catalog.name}.{node?.schema_}.{node?.table}
|
|
120
134
|
</p>
|
|
121
135
|
</div>
|
|
@@ -124,27 +138,58 @@ export default function NodeInfoTab({ node }) {
|
|
|
124
138
|
)}
|
|
125
139
|
<div>
|
|
126
140
|
<h6 className="mb-0 w-100">Status</h6>
|
|
127
|
-
<p
|
|
141
|
+
<p
|
|
142
|
+
className="mb-0 opacity-75"
|
|
143
|
+
role="dialog"
|
|
144
|
+
aria-hidden="false"
|
|
145
|
+
aria-label="NodeStatus"
|
|
146
|
+
>
|
|
128
147
|
<NodeStatus node={node} />
|
|
129
148
|
</p>
|
|
130
149
|
</div>
|
|
131
150
|
<div>
|
|
132
151
|
<h6 className="mb-0 w-100">Mode</h6>
|
|
133
152
|
<p className="mb-0 opacity-75">
|
|
134
|
-
<span
|
|
153
|
+
<span
|
|
154
|
+
className="status"
|
|
155
|
+
role="dialog"
|
|
156
|
+
aria-hidden="false"
|
|
157
|
+
aria-label="Mode"
|
|
158
|
+
>
|
|
159
|
+
{node?.mode}
|
|
160
|
+
</span>
|
|
135
161
|
</p>
|
|
136
162
|
</div>
|
|
137
163
|
<div>
|
|
138
164
|
<h6 className="mb-0 w-100">Tags</h6>
|
|
139
|
-
<p
|
|
165
|
+
<p
|
|
166
|
+
className="mb-0 opacity-75"
|
|
167
|
+
role="dialog"
|
|
168
|
+
aria-hidden="false"
|
|
169
|
+
aria-label="Tags"
|
|
170
|
+
>
|
|
171
|
+
{nodeTags}
|
|
172
|
+
</p>
|
|
140
173
|
</div>
|
|
141
174
|
<div>
|
|
142
175
|
<h6 className="mb-0 w-100">Primary Key</h6>
|
|
143
|
-
<p
|
|
176
|
+
<p
|
|
177
|
+
className="mb-0 opacity-75"
|
|
178
|
+
role="dialog"
|
|
179
|
+
aria-hidden="false"
|
|
180
|
+
aria-label="PrimaryKey"
|
|
181
|
+
>
|
|
182
|
+
{node?.primary_key?.join(', ')}
|
|
183
|
+
</p>
|
|
144
184
|
</div>
|
|
145
185
|
<div>
|
|
146
186
|
<h6 className="mb-0 w-100">Last Updated</h6>
|
|
147
|
-
<p
|
|
187
|
+
<p
|
|
188
|
+
className="mb-0 opacity-75"
|
|
189
|
+
role="dialog"
|
|
190
|
+
aria-hidden="false"
|
|
191
|
+
aria-label="UpdatedAt"
|
|
192
|
+
>
|
|
148
193
|
{new Date(node?.updated_at).toDateString()}
|
|
149
194
|
</p>
|
|
150
195
|
</div>
|