datajunction-ui 0.0.1-rc.9 → 0.0.2-3.dev1
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/.env +2 -0
- package/.prettierignore +3 -1
- package/Makefile +9 -0
- package/dj-logo.svg +10 -0
- package/package.json +53 -14
- package/public/favicon.ico +0 -0
- package/public/index.html +1 -1
- package/src/__tests__/reportWebVitals.test.jsx +44 -0
- package/src/app/__tests__/__snapshots__/index.test.tsx.snap +5 -109
- package/src/app/components/AddNodeDropdown.jsx +44 -0
- package/src/app/components/ListGroupItem.jsx +9 -1
- package/src/app/components/NamespaceHeader.jsx +4 -13
- package/src/app/components/NodeListActions.jsx +69 -0
- package/src/app/components/NodeMaterializationDelete.jsx +90 -0
- package/src/app/components/NotificationBell.tsx +229 -0
- package/src/app/components/QueryInfo.jsx +172 -0
- package/src/app/components/Search.jsx +94 -0
- package/src/app/components/Tab.jsx +8 -1
- package/src/app/components/ToggleSwitch.jsx +20 -0
- package/src/app/components/UserMenu.tsx +92 -0
- package/src/app/components/__tests__/NodeListActions.test.jsx +94 -0
- package/src/app/components/__tests__/NodeMaterializationDelete.test.jsx +263 -0
- package/src/app/components/__tests__/NotificationBell.test.tsx +313 -0
- package/src/app/components/__tests__/QueryInfo.test.jsx +183 -0
- package/src/app/components/__tests__/Search.test.jsx +307 -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__/UserMenu.test.tsx +248 -0
- package/src/app/components/__tests__/__snapshots__/ListGroupItem.test.tsx.snap +8 -3
- package/src/app/components/__tests__/__snapshots__/NamespaceHeader.test.jsx.snap +2 -18
- package/src/app/components/djgraph/Collapse.jsx +47 -0
- package/src/app/components/djgraph/DJNode.jsx +61 -83
- package/src/app/components/djgraph/DJNodeColumns.jsx +75 -0
- package/src/app/components/djgraph/DJNodeDimensions.jsx +75 -0
- package/src/app/components/djgraph/LayoutFlow.jsx +106 -0
- 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/components/djgraph/__tests__/__snapshots__/DJNode.test.tsx.snap +84 -40
- package/src/app/components/forms/Action.jsx +8 -0
- package/src/app/components/forms/NodeNameField.jsx +64 -0
- package/src/app/components/search.css +17 -0
- package/src/app/constants.js +2 -0
- package/src/app/icons/AddItemIcon.jsx +16 -0
- package/src/app/icons/AlertIcon.jsx +33 -0
- package/src/app/icons/CollapsedIcon.jsx +15 -0
- package/src/app/icons/CommitIcon.jsx +45 -0
- package/src/app/icons/DJLogo.jsx +36 -0
- package/src/app/icons/DeleteIcon.jsx +21 -0
- package/src/app/icons/DiffIcon.jsx +63 -0
- package/src/app/icons/EditIcon.jsx +18 -0
- package/src/app/icons/ExpandedIcon.jsx +15 -0
- package/src/app/icons/EyeIcon.jsx +20 -0
- package/src/app/icons/FilterIcon.jsx +7 -0
- package/src/app/icons/HorizontalHierarchyIcon.jsx +15 -0
- package/src/app/icons/InvalidIcon.jsx +16 -0
- package/src/app/icons/JupyterExportIcon.jsx +25 -0
- package/src/app/icons/LoadingIcon.jsx +14 -0
- package/src/app/icons/NodeIcon.jsx +49 -0
- package/src/app/icons/NotificationIcon.jsx +27 -0
- package/src/app/icons/PythonIcon.jsx +14 -0
- package/src/app/icons/SettingsIcon.jsx +28 -0
- package/src/app/icons/TableIcon.jsx +14 -0
- package/src/app/icons/ValidIcon.jsx +16 -0
- package/src/app/index.tsx +138 -38
- package/src/app/pages/AddEditNodePage/AlertMessage.jsx +10 -0
- package/src/app/pages/AddEditNodePage/ColumnsSelect.jsx +84 -0
- package/src/app/pages/AddEditNodePage/CustomMetadataField.jsx +144 -0
- package/src/app/pages/AddEditNodePage/DescriptionField.jsx +17 -0
- package/src/app/pages/AddEditNodePage/DisplayNameField.jsx +16 -0
- package/src/app/pages/AddEditNodePage/FormikSelect.jsx +64 -0
- package/src/app/pages/AddEditNodePage/FullNameField.jsx +38 -0
- package/src/app/pages/AddEditNodePage/Loadable.jsx +20 -0
- package/src/app/pages/AddEditNodePage/MetricMetadataFields.jsx +75 -0
- package/src/app/pages/AddEditNodePage/MetricQueryField.jsx +71 -0
- package/src/app/pages/AddEditNodePage/NamespaceField.jsx +40 -0
- package/src/app/pages/AddEditNodePage/NodeModeField.jsx +14 -0
- package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +94 -0
- package/src/app/pages/AddEditNodePage/OwnersField.jsx +53 -0
- package/src/app/pages/AddEditNodePage/RequiredDimensionsSelect.jsx +54 -0
- package/src/app/pages/AddEditNodePage/TagsField.jsx +47 -0
- package/src/app/pages/AddEditNodePage/UpstreamNodeField.jsx +49 -0
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormFailed.test.jsx +110 -0
- package/src/app/pages/AddEditNodePage/__tests__/AddEditNodePageFormSuccess.test.jsx +291 -0
- package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +75 -0
- package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +31 -0
- package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormFailed.test.jsx.snap +54 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/AddEditNodePageFormSuccess.test.jsx.snap +3 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +3 -0
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +224 -0
- package/src/app/pages/AddEditNodePage/index.jsx +545 -0
- package/src/app/pages/AddEditTagPage/Loadable.jsx +16 -0
- package/src/app/pages/AddEditTagPage/__tests__/AddEditTagPage.test.jsx +107 -0
- package/src/app/pages/AddEditTagPage/index.jsx +132 -0
- package/src/app/pages/CubeBuilderPage/DimensionsSelect.jsx +152 -0
- package/src/app/pages/CubeBuilderPage/Loadable.jsx +16 -0
- package/src/app/pages/CubeBuilderPage/MetricsSelect.jsx +75 -0
- package/src/app/pages/CubeBuilderPage/__tests__/index.test.jsx +373 -0
- package/src/app/pages/CubeBuilderPage/index.jsx +291 -0
- package/src/app/pages/LoginPage/LoginForm.jsx +124 -0
- package/src/app/pages/LoginPage/SignupForm.jsx +156 -0
- package/src/app/pages/LoginPage/__tests__/index.test.jsx +97 -0
- package/src/app/pages/LoginPage/assets/sign-in-with-github.png +0 -0
- package/src/app/pages/LoginPage/assets/sign-in-with-google.png +0 -0
- package/src/app/pages/LoginPage/index.jsx +17 -0
- package/src/app/pages/NamespacePage/AddNamespacePopover.jsx +85 -0
- package/src/app/pages/NamespacePage/Explorer.jsx +232 -0
- package/src/app/pages/NamespacePage/FieldControl.jsx +21 -0
- package/src/app/pages/NamespacePage/NodeModeSelect.jsx +27 -0
- package/src/app/pages/NamespacePage/NodeTypeSelect.jsx +30 -0
- package/src/app/pages/NamespacePage/TagSelect.jsx +44 -0
- package/src/app/pages/NamespacePage/UserSelect.jsx +47 -0
- package/src/app/pages/NamespacePage/__tests__/AddNamespacePopover.test.jsx +283 -0
- package/src/app/pages/NamespacePage/__tests__/index.test.jsx +331 -0
- package/src/app/pages/NamespacePage/index.jsx +354 -42
- package/src/app/pages/NodePage/AddBackfillPopover.jsx +165 -0
- package/src/app/pages/NodePage/AddComplexDimensionLinkPopover.jsx +367 -0
- package/src/app/pages/NodePage/AddMaterializationPopover.jsx +222 -0
- package/src/app/pages/NodePage/AvailabilityStateBlock.jsx +67 -0
- package/src/app/pages/NodePage/ClientCodePopover.jsx +116 -0
- package/src/app/pages/NodePage/DimensionFilter.jsx +86 -0
- package/src/app/pages/NodePage/EditColumnDescriptionPopover.jsx +116 -0
- package/src/app/pages/NodePage/EditColumnPopover.jsx +116 -0
- package/src/app/pages/NodePage/LinkDimensionPopover.jsx +164 -0
- package/src/app/pages/NodePage/ManageDimensionLinksDialog.jsx +526 -0
- package/src/app/pages/NodePage/MaterializationConfigField.jsx +60 -0
- package/src/app/pages/NodePage/NodeColumnTab.jsx +421 -30
- package/src/app/pages/NodePage/NodeDependenciesTab.jsx +155 -0
- package/src/app/pages/NodePage/NodeGraphTab.jsx +119 -148
- package/src/app/pages/NodePage/NodeHistory.jsx +236 -0
- package/src/app/pages/NodePage/NodeInfoTab.jsx +404 -49
- package/src/app/pages/NodePage/NodeLineageTab.jsx +84 -0
- package/src/app/pages/NodePage/NodeMaterializationTab.jsx +585 -0
- package/src/app/pages/NodePage/NodeRevisionMaterializationTab.jsx +58 -0
- package/src/app/pages/NodePage/NodeStatus.jsx +100 -31
- package/src/app/pages/NodePage/NodeValidateTab.jsx +367 -0
- package/src/app/pages/NodePage/NodesWithDimension.jsx +42 -0
- package/src/app/pages/NodePage/NotebookDownload.jsx +36 -0
- package/src/app/pages/NodePage/PartitionColumnPopover.jsx +151 -0
- package/src/app/pages/NodePage/PartitionValueForm.jsx +60 -0
- package/src/app/pages/NodePage/RevisionDiff.jsx +209 -0
- package/src/app/pages/NodePage/WatchNodeButton.jsx +226 -0
- package/src/app/pages/NodePage/__tests__/AddBackfillPopover.test.jsx +56 -0
- package/src/app/pages/NodePage/__tests__/AddComplexDimensionLinkPopover.test.jsx +459 -0
- package/src/app/pages/NodePage/__tests__/AddMaterializationPopover.test.jsx +87 -0
- package/src/app/pages/NodePage/__tests__/DimensionFilter.test.jsx +74 -0
- package/src/app/pages/NodePage/__tests__/EditColumnDescriptionPopover.test.jsx +149 -0
- package/src/app/pages/NodePage/__tests__/EditColumnPopover.test.jsx +144 -0
- package/src/app/pages/NodePage/__tests__/LinkDimensionPopover.test.jsx +132 -0
- package/src/app/pages/NodePage/__tests__/ManageDimensionLinksDialog.test.jsx +390 -0
- package/src/app/pages/NodePage/__tests__/NodeColumnTab.test.jsx +166 -0
- package/src/app/pages/NodePage/__tests__/NodeDependenciesTab.test.jsx +157 -0
- package/src/app/pages/NodePage/__tests__/NodeGraphTab.test.jsx +595 -0
- package/src/app/pages/NodePage/__tests__/NodeLineageTab.test.jsx +58 -0
- package/src/app/pages/NodePage/__tests__/NodeMaterializationTab.test.jsx +190 -0
- package/src/app/pages/NodePage/__tests__/NodePage.test.jsx +892 -0
- package/src/app/pages/NodePage/__tests__/NodeWithDimension.test.jsx +175 -0
- package/src/app/pages/NodePage/__tests__/RevisionDiff.test.jsx +164 -0
- package/src/app/pages/NodePage/__tests__/__snapshots__/NodePage.test.jsx.snap +19 -0
- package/src/app/pages/NodePage/index.jsx +186 -45
- package/src/app/pages/NotFoundPage/__tests__/index.test.jsx +16 -0
- package/src/app/pages/NotificationsPage/Loadable.jsx +6 -0
- package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +287 -0
- package/src/app/pages/NotificationsPage/index.jsx +136 -0
- package/src/app/pages/OverviewPage/ByStatusPanel.jsx +69 -0
- package/src/app/pages/OverviewPage/DimensionNodeUsagePanel.jsx +48 -0
- package/src/app/pages/OverviewPage/GovernanceWarningsPanel.jsx +107 -0
- package/src/app/pages/OverviewPage/Loadable.jsx +16 -0
- package/src/app/pages/OverviewPage/NodesByTypePanel.jsx +63 -0
- package/src/app/pages/OverviewPage/OverviewPanel.jsx +94 -0
- package/src/app/pages/OverviewPage/TrendsPanel.jsx +66 -0
- package/src/app/pages/OverviewPage/__tests__/ByStatusPanel.test.jsx +36 -0
- package/src/app/pages/OverviewPage/__tests__/DimensionNodeUsagePanel.test.jsx +76 -0
- package/src/app/pages/OverviewPage/__tests__/GovernanceWarningsPanel.test.jsx +77 -0
- package/src/app/pages/OverviewPage/__tests__/NodesByTypePanel.test.jsx +86 -0
- package/src/app/pages/OverviewPage/__tests__/OverviewPanel.test.jsx +78 -0
- package/src/app/pages/OverviewPage/__tests__/TrendsPanel.test.jsx +120 -0
- package/src/app/pages/OverviewPage/__tests__/index.test.jsx +54 -0
- package/src/app/pages/OverviewPage/index.jsx +22 -0
- package/src/app/pages/RegisterTablePage/Loadable.jsx +16 -0
- package/src/app/pages/RegisterTablePage/__tests__/RegisterTablePage.test.jsx +112 -0
- package/src/app/pages/RegisterTablePage/__tests__/__snapshots__/RegisterTablePage.test.jsx.snap +38 -0
- package/src/app/pages/RegisterTablePage/index.jsx +142 -0
- package/src/app/pages/Root/__tests__/index.test.jsx +44 -0
- package/src/app/pages/Root/index.tsx +92 -10
- package/src/app/pages/SQLBuilderPage/Loadable.jsx +16 -0
- package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +173 -0
- package/src/app/pages/SQLBuilderPage/index.jsx +390 -0
- package/src/app/pages/SettingsPage/CreateServiceAccountModal.jsx +152 -0
- package/src/app/pages/SettingsPage/Loadable.jsx +16 -0
- package/src/app/pages/SettingsPage/NotificationSubscriptionsSection.jsx +189 -0
- package/src/app/pages/SettingsPage/ProfileSection.jsx +41 -0
- package/src/app/pages/SettingsPage/ServiceAccountsSection.jsx +95 -0
- package/src/app/pages/SettingsPage/__tests__/CreateServiceAccountModal.test.jsx +318 -0
- package/src/app/pages/SettingsPage/__tests__/NotificationSubscriptionsSection.test.jsx +233 -0
- package/src/app/pages/SettingsPage/__tests__/ProfileSection.test.jsx +65 -0
- package/src/app/pages/SettingsPage/__tests__/ServiceAccountsSection.test.jsx +150 -0
- package/src/app/pages/SettingsPage/__tests__/index.test.jsx +187 -0
- package/src/app/pages/SettingsPage/index.jsx +148 -0
- package/src/app/pages/TagPage/Loadable.jsx +16 -0
- package/src/app/pages/TagPage/__tests__/TagPage.test.jsx +70 -0
- package/src/app/pages/TagPage/index.jsx +79 -0
- package/src/app/providers/UserProvider.tsx +78 -0
- package/src/app/services/DJService.js +1487 -21
- package/src/app/services/__tests__/DJService.test.jsx +2194 -0
- package/src/app/utils/__tests__/date.test.js +198 -0
- package/src/app/utils/date.js +65 -0
- package/src/index.tsx +1 -0
- package/src/mocks/mockNodes.jsx +1477 -0
- package/src/setupTests.ts +31 -1
- package/src/styles/dag.css +117 -5
- package/src/styles/index.css +1028 -31
- package/src/styles/loading.css +34 -0
- package/src/styles/login.css +81 -0
- package/src/styles/nav-bar.css +274 -0
- package/src/styles/node-creation.scss +276 -0
- package/src/styles/node-list.css +4 -0
- package/src/styles/overview.css +72 -0
- package/src/styles/settings.css +787 -0
- package/src/styles/sorted-table.css +15 -0
- package/src/styles/styles.scss +44 -0
- package/src/styles/styles.scss.d.ts +9 -0
- package/src/utils/form.jsx +23 -0
- package/webpack.config.js +20 -7
- package/.babelrc +0 -4
- package/.env.local +0 -4
- package/.env.production +0 -1
- package/.github/pull_request_template.md +0 -11
- package/.github/workflows/ci.yml +0 -33
- package/.vscode/extensions.json +0 -7
- package/.vscode/launch.json +0 -15
- package/.vscode/settings.json +0 -25
- package/Dockerfile +0 -7
- package/src/app/pages/ListNamespacesPage/Loadable.jsx +0 -14
- package/src/app/pages/ListNamespacesPage/index.jsx +0 -62
- package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +0 -45
- package/src/app/pages/NamespacePage/__tests__/index.test.tsx +0 -14
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
2
|
+
import ReactFlow, {
|
|
3
|
+
addEdge,
|
|
4
|
+
MiniMap,
|
|
5
|
+
Controls,
|
|
6
|
+
Background,
|
|
7
|
+
useNodesState,
|
|
8
|
+
useEdgesState,
|
|
9
|
+
} from 'reactflow';
|
|
10
|
+
|
|
11
|
+
import '../../../styles/dag.css';
|
|
12
|
+
import 'reactflow/dist/style.css';
|
|
13
|
+
import DJNode from '../../components/djgraph/DJNode';
|
|
14
|
+
import dagre from 'dagre';
|
|
15
|
+
|
|
16
|
+
const getLayoutedElements = (
|
|
17
|
+
nodes,
|
|
18
|
+
edges,
|
|
19
|
+
direction = 'LR',
|
|
20
|
+
nodeWidth = 600,
|
|
21
|
+
) => {
|
|
22
|
+
const dagreGraph = new dagre.graphlib.Graph();
|
|
23
|
+
dagreGraph.setDefaultEdgeLabel(() => ({}));
|
|
24
|
+
|
|
25
|
+
const isHorizontal = direction === 'TB';
|
|
26
|
+
dagreGraph.setGraph({
|
|
27
|
+
rankdir: direction,
|
|
28
|
+
nodesep: 40,
|
|
29
|
+
ranksep: 10,
|
|
30
|
+
ranker: 'longest-path',
|
|
31
|
+
});
|
|
32
|
+
const nodeHeightTracker = {};
|
|
33
|
+
|
|
34
|
+
nodes.forEach(node => {
|
|
35
|
+
const minColumnsLength = node.data.column_names.filter(
|
|
36
|
+
col => col.order > 0,
|
|
37
|
+
).length;
|
|
38
|
+
nodeHeightTracker[node.id] = Math.min(minColumnsLength, 5) * 40 + 250;
|
|
39
|
+
dagreGraph.setNode(node.id, {
|
|
40
|
+
width: nodeWidth,
|
|
41
|
+
height: nodeHeightTracker[node.id],
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
edges.forEach(edge => {
|
|
46
|
+
dagreGraph.setEdge(edge.source, edge.target);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
dagre.layout(dagreGraph);
|
|
50
|
+
|
|
51
|
+
nodes.forEach(node => {
|
|
52
|
+
const nodeWithPosition = dagreGraph.node(node.id);
|
|
53
|
+
node.targetPosition = isHorizontal ? 'left' : 'top';
|
|
54
|
+
node.sourcePosition = isHorizontal ? 'right' : 'bottom';
|
|
55
|
+
node.position = {
|
|
56
|
+
x: nodeWithPosition.x - nodeWidth / 2,
|
|
57
|
+
y: nodeWithPosition.y - nodeHeightTracker[node.id] / 3,
|
|
58
|
+
};
|
|
59
|
+
node.width = nodeWidth;
|
|
60
|
+
node.height = nodeHeightTracker[node.id];
|
|
61
|
+
return node;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return { nodes: nodes, edges: edges };
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const LayoutFlow = (djNode, saveGraph) => {
|
|
68
|
+
const nodeTypes = useMemo(() => ({ DJNode: DJNode }), []);
|
|
69
|
+
|
|
70
|
+
// These are used internally by ReactFlow (to update the nodes on the ReactFlow pane)
|
|
71
|
+
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
72
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
73
|
+
|
|
74
|
+
const minimapStyle = {
|
|
75
|
+
height: 100,
|
|
76
|
+
width: 150,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
saveGraph(getLayoutedElements, setNodes, setEdges).catch(console.error);
|
|
81
|
+
}, [djNode]);
|
|
82
|
+
|
|
83
|
+
const onConnect = useCallback(
|
|
84
|
+
params => setEdges(eds => addEdge(params, eds)),
|
|
85
|
+
[setEdges],
|
|
86
|
+
);
|
|
87
|
+
return (
|
|
88
|
+
<div style={{ height: '800px' }}>
|
|
89
|
+
<ReactFlow
|
|
90
|
+
nodes={nodes}
|
|
91
|
+
edges={edges}
|
|
92
|
+
nodeTypes={nodeTypes}
|
|
93
|
+
onNodesChange={onNodesChange}
|
|
94
|
+
onEdgesChange={onEdgesChange}
|
|
95
|
+
onConnect={onConnect}
|
|
96
|
+
snapToGrid={true}
|
|
97
|
+
fitView
|
|
98
|
+
>
|
|
99
|
+
<MiniMap style={minimapStyle} zoomable pannable />
|
|
100
|
+
<Controls />
|
|
101
|
+
<Background color="#aaa" gap={16} />
|
|
102
|
+
</ReactFlow>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
export default LayoutFlow;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import Collapse from '../Collapse';
|
|
4
|
+
import { mocks } from '../../../../mocks/mockNodes';
|
|
5
|
+
import { ReactFlowProvider } from 'reactflow';
|
|
6
|
+
|
|
7
|
+
jest.mock('../DJNodeDimensions', () => ({
|
|
8
|
+
DJNodeDimensions: jest.fn(data => <div>DJNodeDimensions content</div>),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe('<Collapse />', () => {
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
collapsed: true,
|
|
14
|
+
text: 'Dimensions',
|
|
15
|
+
data: mocks.mockMetricNode,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it('renders without crashing', () => {
|
|
19
|
+
render(<Collapse {...defaultProps} />);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('renders toggle for metric type', () => {
|
|
23
|
+
const { getByText } = render(
|
|
24
|
+
<Collapse {...defaultProps} data={mocks.mockMetricNode} />,
|
|
25
|
+
);
|
|
26
|
+
const button = screen.getByText('▶ Show Dimensions');
|
|
27
|
+
fireEvent.click(button);
|
|
28
|
+
expect(getByText('▼ Hide Dimensions')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('toggles More/Less button text for non-metric type on click', () => {
|
|
32
|
+
defaultProps.text = 'Columns';
|
|
33
|
+
const { getByText } = render(
|
|
34
|
+
<ReactFlowProvider>
|
|
35
|
+
<Collapse
|
|
36
|
+
{...defaultProps}
|
|
37
|
+
data={{
|
|
38
|
+
type: 'transform',
|
|
39
|
+
column_names: Array(11).fill(idx => {
|
|
40
|
+
return `column-${idx}`;
|
|
41
|
+
}),
|
|
42
|
+
primary_key: [],
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
</ReactFlowProvider>,
|
|
46
|
+
);
|
|
47
|
+
const button = getByText('▶ More Columns');
|
|
48
|
+
fireEvent.click(button);
|
|
49
|
+
expect(getByText('▼ Less Columns')).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { DJNodeColumns } from '../DJNodeColumns';
|
|
4
|
+
import { ReactFlowProvider } from 'reactflow';
|
|
5
|
+
|
|
6
|
+
describe('<DJNodeColumns />', () => {
|
|
7
|
+
const defaultProps = {
|
|
8
|
+
data: {
|
|
9
|
+
name: 'TestName',
|
|
10
|
+
type: 'metric',
|
|
11
|
+
column_names: [
|
|
12
|
+
{ name: 'col1', type: 'int' },
|
|
13
|
+
{ name: 'col2', type: 'string' },
|
|
14
|
+
{ name: 'col3', type: 'float' },
|
|
15
|
+
],
|
|
16
|
+
primary_key: ['col1'],
|
|
17
|
+
},
|
|
18
|
+
limit: 10,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const domTestingLib = require('@testing-library/dom');
|
|
22
|
+
const { queryHelpers } = domTestingLib;
|
|
23
|
+
|
|
24
|
+
const queryByAttribute = attribute =>
|
|
25
|
+
queryHelpers.queryAllByAttribute.bind(null, attribute);
|
|
26
|
+
|
|
27
|
+
function getByAttribute(container, id, attribute, ...rest) {
|
|
28
|
+
const result = queryByAttribute(attribute)(container, id, ...rest);
|
|
29
|
+
return result[0];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function DJNodeColumnsWithProvider(props) {
|
|
33
|
+
return (
|
|
34
|
+
<ReactFlowProvider>
|
|
35
|
+
<DJNodeColumns {...props} />
|
|
36
|
+
</ReactFlowProvider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it('renders without crashing', () => {
|
|
41
|
+
render(<DJNodeColumnsWithProvider {...defaultProps} />);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('renders columns correctly', () => {
|
|
45
|
+
const { container } = render(
|
|
46
|
+
<DJNodeColumnsWithProvider {...defaultProps} />,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// renders column names
|
|
50
|
+
defaultProps.data.column_names.forEach(col => {
|
|
51
|
+
expect(screen.getByText(col.name, { exact: false })).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// appends (PK) to primary key column name
|
|
55
|
+
expect(screen.getByText('col1 (PK)')).toBeInTheDocument();
|
|
56
|
+
|
|
57
|
+
// renders column type badge correctly
|
|
58
|
+
defaultProps.data.column_names.forEach(col => {
|
|
59
|
+
expect(screen.getByText(col.type)).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// renders handles correctly
|
|
63
|
+
defaultProps.data.column_names.forEach(col => {
|
|
64
|
+
expect(
|
|
65
|
+
getByAttribute(
|
|
66
|
+
container,
|
|
67
|
+
defaultProps.data.name + '.' + col.name,
|
|
68
|
+
'data-handleid',
|
|
69
|
+
),
|
|
70
|
+
).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('renders limited columns based on the limit prop', () => {
|
|
75
|
+
const limitedProps = {
|
|
76
|
+
...defaultProps,
|
|
77
|
+
limit: 2,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
render(<DJNodeColumnsWithProvider {...limitedProps} />);
|
|
81
|
+
expect(screen.queryByText('col3')).not.toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import { DJNodeDimensions } from '../DJNodeDimensions';
|
|
4
|
+
import DJClientContext from '../../../providers/djclient';
|
|
5
|
+
|
|
6
|
+
const mockMetric = jest.fn();
|
|
7
|
+
describe('<DJNodeDimensions />', () => {
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
type: 'metric',
|
|
10
|
+
name: 'TestMetric',
|
|
11
|
+
};
|
|
12
|
+
const mockDJClient = () => {
|
|
13
|
+
return {
|
|
14
|
+
DataJunctionAPI: {
|
|
15
|
+
metric: mockMetric,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const DJNodeDimensionsWithContext = (djClient, props) => {
|
|
21
|
+
return (
|
|
22
|
+
<DJClientContext.Provider value={djClient}>
|
|
23
|
+
<DJNodeDimensions {...props} />
|
|
24
|
+
</DJClientContext.Provider>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
// Reset the mock before each test
|
|
30
|
+
mockMetric.mockReset();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('fetches dimensions for metric type', async () => {
|
|
34
|
+
mockMetric.mockResolvedValueOnce({
|
|
35
|
+
dimensions: [{ name: 'test.dimension' }],
|
|
36
|
+
});
|
|
37
|
+
const djClient = mockDJClient();
|
|
38
|
+
|
|
39
|
+
render(
|
|
40
|
+
<DJClientContext.Provider value={djClient}>
|
|
41
|
+
<DJNodeDimensions {...defaultProps} />
|
|
42
|
+
</DJClientContext.Provider>,
|
|
43
|
+
);
|
|
44
|
+
waitFor(() => {
|
|
45
|
+
expect(mockMetric).toHaveBeenCalledWith(defaultProps.name);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('renders dimensions correctly after processing', async () => {
|
|
50
|
+
const testDimensions = [
|
|
51
|
+
{
|
|
52
|
+
name: 'default.us_state.state_name',
|
|
53
|
+
type: 'string',
|
|
54
|
+
path: [
|
|
55
|
+
'default.repair_order_details.repair_order_id',
|
|
56
|
+
'default.repair_order.hard_hat_id',
|
|
57
|
+
'default.hard_hat.state',
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'default.us_state.state_region',
|
|
62
|
+
type: 'int',
|
|
63
|
+
path: [
|
|
64
|
+
'default.repair_order_details.repair_order_id',
|
|
65
|
+
'default.repair_order.hard_hat_id',
|
|
66
|
+
'default.hard_hat.state',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'default.us_state.state_region_description',
|
|
71
|
+
type: 'string',
|
|
72
|
+
path: [
|
|
73
|
+
'default.repair_order_details.repair_order_id',
|
|
74
|
+
'default.repair_order.hard_hat_id',
|
|
75
|
+
'default.hard_hat.state',
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
mockMetric.mockResolvedValueOnce({ dimensions: testDimensions });
|
|
80
|
+
const djClient = mockDJClient();
|
|
81
|
+
|
|
82
|
+
const { findByText } = render(
|
|
83
|
+
<DJClientContext.Provider value={djClient}>
|
|
84
|
+
<DJNodeDimensions {...defaultProps} />
|
|
85
|
+
</DJClientContext.Provider>,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
for (const dim of testDimensions) {
|
|
89
|
+
const [attribute, ...nodeName] = dim.name.split('.').reverse();
|
|
90
|
+
const dimension = nodeName.reverse().join('.');
|
|
91
|
+
expect(await findByText(attribute)).toBeInTheDocument();
|
|
92
|
+
expect(await findByText(dimension)).toBeInTheDocument();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('does not fetch dimensions if type is not metric', () => {
|
|
97
|
+
const djClient = mockDJClient();
|
|
98
|
+
render(
|
|
99
|
+
<DJClientContext.Provider value={djClient}>
|
|
100
|
+
<DJNodeDimensions {...defaultProps} type="transform" />
|
|
101
|
+
</DJClientContext.Provider>,
|
|
102
|
+
);
|
|
103
|
+
expect(mockMetric).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('handles errors gracefully', async () => {
|
|
107
|
+
mockMetric.mockRejectedValueOnce(new Error('API error'));
|
|
108
|
+
|
|
109
|
+
const djClient = mockDJClient();
|
|
110
|
+
render(
|
|
111
|
+
<DJClientContext.Provider value={djClient}>
|
|
112
|
+
<DJNodeDimensions {...defaultProps} />
|
|
113
|
+
</DJClientContext.Provider>,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(await mockMetric).toHaveBeenCalledWith(defaultProps.name);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -2,24 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`<DJNode /> should render and match the snapshot 1`] = `
|
|
4
4
|
<React.Fragment>
|
|
5
|
-
<Memo(Handle)
|
|
6
|
-
position="left"
|
|
7
|
-
style={
|
|
8
|
-
Object {
|
|
9
|
-
"backgroundColor": "#ccc",
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
type="target"
|
|
13
|
-
/>
|
|
14
5
|
<div
|
|
15
|
-
className="dj-node__full"
|
|
6
|
+
className="dj-node__full node_type__source"
|
|
16
7
|
style={
|
|
17
8
|
Object {
|
|
18
|
-
"
|
|
19
|
-
"color": "#7EB461",
|
|
9
|
+
"width": "450px",
|
|
20
10
|
}
|
|
21
11
|
}
|
|
22
12
|
>
|
|
13
|
+
<div
|
|
14
|
+
style={
|
|
15
|
+
Object {
|
|
16
|
+
"display": "flex",
|
|
17
|
+
"flexDirection": "column",
|
|
18
|
+
"height": "100%",
|
|
19
|
+
"justifyContent": "space-between",
|
|
20
|
+
"position": "absolute",
|
|
21
|
+
"top": "50%",
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
>
|
|
25
|
+
<Memo(Handle)
|
|
26
|
+
id="shared.dimensions.accounts"
|
|
27
|
+
position="left"
|
|
28
|
+
style={
|
|
29
|
+
Object {
|
|
30
|
+
"background": "transparent",
|
|
31
|
+
"border": "4px solid transparent",
|
|
32
|
+
"borderRadius": "12px",
|
|
33
|
+
"cursor": "pointer",
|
|
34
|
+
"height": "12px",
|
|
35
|
+
"left": 0,
|
|
36
|
+
"position": "absolute",
|
|
37
|
+
"top": "0px",
|
|
38
|
+
"transform": "translate(-100%, -50%)",
|
|
39
|
+
"width": "12px",
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
type="target"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
23
45
|
<div
|
|
24
46
|
className="dj-node__header"
|
|
25
47
|
>
|
|
@@ -35,39 +57,61 @@ exports[`<DJNode /> should render and match the snapshot 1`] = `
|
|
|
35
57
|
<b>
|
|
36
58
|
Source
|
|
37
59
|
</b>
|
|
38
|
-
|
|
60
|
+
<br />
|
|
39
61
|
|
|
62
|
+
<a
|
|
63
|
+
href="/nodes/shared.dimensions.accounts"
|
|
64
|
+
/>
|
|
40
65
|
<Collapse
|
|
41
66
|
collapsed={true}
|
|
67
|
+
data={
|
|
68
|
+
Object {
|
|
69
|
+
"column_names": Array [
|
|
70
|
+
"a",
|
|
71
|
+
],
|
|
72
|
+
"name": "shared.dimensions.accounts",
|
|
73
|
+
"primary_key": Array [
|
|
74
|
+
"id",
|
|
75
|
+
],
|
|
76
|
+
"type": "source",
|
|
77
|
+
}
|
|
78
|
+
}
|
|
42
79
|
text="columns"
|
|
43
|
-
|
|
44
|
-
<div
|
|
45
|
-
className="dj-node__metadata"
|
|
46
|
-
>
|
|
47
|
-
<tr>
|
|
48
|
-
<td>
|
|
49
|
-
<React.Fragment />
|
|
50
|
-
</td>
|
|
51
|
-
<td
|
|
52
|
-
style={
|
|
53
|
-
Object {
|
|
54
|
-
"textAlign": "right",
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/>
|
|
58
|
-
</tr>
|
|
59
|
-
</div>
|
|
60
|
-
</Collapse>
|
|
80
|
+
/>
|
|
61
81
|
</div>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
<div
|
|
83
|
+
style={
|
|
84
|
+
Object {
|
|
85
|
+
"display": "flex",
|
|
86
|
+
"flexDirection": "column",
|
|
87
|
+
"height": "100%",
|
|
88
|
+
"justifyContent": "space-between",
|
|
89
|
+
"position": "absolute",
|
|
90
|
+
"right": 0,
|
|
91
|
+
"top": "50%",
|
|
92
|
+
}
|
|
68
93
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
94
|
+
>
|
|
95
|
+
<Memo(Handle)
|
|
96
|
+
id="shared.dimensions.accounts"
|
|
97
|
+
position="right"
|
|
98
|
+
style={
|
|
99
|
+
Object {
|
|
100
|
+
"background": "transparent",
|
|
101
|
+
"border": "4px solid transparent",
|
|
102
|
+
"borderRadius": "12px",
|
|
103
|
+
"cursor": "pointer",
|
|
104
|
+
"height": "12px",
|
|
105
|
+
"left": 0,
|
|
106
|
+
"position": "absolute",
|
|
107
|
+
"top": "0px",
|
|
108
|
+
"transform": "translate(-90%, -50%)",
|
|
109
|
+
"width": "12px",
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
type="source"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
72
116
|
</React.Fragment>
|
|
73
117
|
`;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ErrorMessage, Field } from 'formik';
|
|
2
|
+
import { FormikSelect } from '../../pages/AddEditNodePage/FormikSelect';
|
|
3
|
+
import { FullNameField } from '../../pages/AddEditNodePage/FullNameField';
|
|
4
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
5
|
+
import DJClientContext from '../../providers/djclient';
|
|
6
|
+
import { useParams } from 'react-router-dom';
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* This component creates the namespace selector, display name input, and
|
|
10
|
+
* derived name fields in a form. It can be reused any time we need to create
|
|
11
|
+
* a new node.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export default function NodeNameField() {
|
|
15
|
+
const [namespaces, setNamespaces] = useState([]);
|
|
16
|
+
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
17
|
+
let { initialNamespace } = useParams();
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const fetchData = async () => {
|
|
21
|
+
const namespaces = await djClient.namespaces();
|
|
22
|
+
setNamespaces(
|
|
23
|
+
namespaces.map(m => ({
|
|
24
|
+
value: m['namespace'],
|
|
25
|
+
label: m['namespace'],
|
|
26
|
+
})),
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
fetchData().catch(console.error);
|
|
30
|
+
}, [djClient, djClient.metrics]);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<div className="NamespaceInput">
|
|
35
|
+
<ErrorMessage name="namespace" component="span" />
|
|
36
|
+
<label htmlFor="namespace">Namespace *</label>
|
|
37
|
+
<FormikSelect
|
|
38
|
+
selectOptions={namespaces}
|
|
39
|
+
formikFieldName="namespace"
|
|
40
|
+
placeholder="Choose Namespace"
|
|
41
|
+
defaultValue={{
|
|
42
|
+
value: initialNamespace,
|
|
43
|
+
label: initialNamespace,
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="DisplayNameInput NodeCreationInput">
|
|
48
|
+
<ErrorMessage name="display_name" component="span" />
|
|
49
|
+
<label htmlFor="displayName">Display Name *</label>
|
|
50
|
+
<Field
|
|
51
|
+
type="text"
|
|
52
|
+
name="display_name"
|
|
53
|
+
id="displayName"
|
|
54
|
+
placeholder="Human readable display name"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="FullNameInput NodeCreationInput">
|
|
58
|
+
<ErrorMessage name="name" component="span" />
|
|
59
|
+
<label htmlFor="FullName">Full Name</label>
|
|
60
|
+
<FullNameField type="text" name="name" />
|
|
61
|
+
</div>
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.search-box {
|
|
2
|
+
display: flex;
|
|
3
|
+
height: 50%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.search-results {
|
|
7
|
+
position: absolute;
|
|
8
|
+
z-index: 1000;
|
|
9
|
+
width: 75%;
|
|
10
|
+
background-color: rgba(244, 244, 244, 0.8);
|
|
11
|
+
border-radius: 1rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.search-result-item {
|
|
15
|
+
text-decoration: wavy;
|
|
16
|
+
padding: 0.5rem;
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const AddItemIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
enableBackground="new 0 0 512 512"
|
|
4
|
+
height="20px"
|
|
5
|
+
id="Layer_1"
|
|
6
|
+
version="1.1"
|
|
7
|
+
viewBox="0 0 512 512"
|
|
8
|
+
width="20px"
|
|
9
|
+
xmlSpace="preserve"
|
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
12
|
+
>
|
|
13
|
+
<path d="M256,512C114.625,512,0,397.391,0,256C0,114.609,114.625,0,256,0c141.391,0,256,114.609,256,256 C512,397.391,397.391,512,256,512z M256,64C149.969,64,64,149.969,64,256s85.969,192,192,192c106.047,0,192-85.969,192-192 S362.047,64,256,64z M288,384h-64v-96h-96v-64h96v-96h64v96h96v64h-96V384z" />
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
export default AddItemIcon;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const AlertIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
width="2em"
|
|
4
|
+
height="2em"
|
|
5
|
+
viewBox="0 0 24 24"
|
|
6
|
+
version="1.1"
|
|
7
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
+
{...props}
|
|
9
|
+
>
|
|
10
|
+
<title>alert_fill</title>
|
|
11
|
+
<g id="page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
12
|
+
<g
|
|
13
|
+
id="System"
|
|
14
|
+
transform="translate(-48.000000, -48.000000)"
|
|
15
|
+
fillRule="nonzero"
|
|
16
|
+
>
|
|
17
|
+
<g id="alert_fill" transform="translate(48.000000, 48.000000)">
|
|
18
|
+
<path
|
|
19
|
+
d="M24,0 L24,24 L0,24 L0,0 L24,0 Z M12.5934901,23.257841 L12.5819402,23.2595131 L12.5108777,23.2950439 L12.4918791,23.2987469 L12.4918791,23.2987469 L12.4767152,23.2950439 L12.4056548,23.2595131 C12.3958229,23.2563662 12.3870493,23.2590235 12.3821421,23.2649074 L12.3780323,23.275831 L12.360941,23.7031097 L12.3658947,23.7234994 L12.3769048,23.7357139 L12.4804777,23.8096931 L12.4953491,23.8136134 L12.4953491,23.8136134 L12.5071152,23.8096931 L12.6106902,23.7357139 L12.6232938,23.7196733 L12.6232938,23.7196733 L12.6266527,23.7031097 L12.609561,23.275831 C12.6075724,23.2657013 12.6010112,23.2592993 12.5934901,23.257841 L12.5934901,23.257841 Z M12.8583906,23.1452862 L12.8445485,23.1473072 L12.6598443,23.2396597 L12.6498822,23.2499052 L12.6498822,23.2499052 L12.6471943,23.2611114 L12.6650943,23.6906389 L12.6699349,23.7034178 L12.6699349,23.7034178 L12.678386,23.7104931 L12.8793402,23.8032389 C12.8914285,23.8068999 12.9022333,23.8029875 12.9078286,23.7952264 L12.9118235,23.7811639 L12.8776777,23.1665331 C12.8752882,23.1545897 12.8674102,23.1470016 12.8583906,23.1452862 L12.8583906,23.1452862 Z M12.1430473,23.1473072 C12.1332178,23.1423925 12.1221763,23.1452606 12.1156365,23.1525954 L12.1099173,23.1665331 L12.0757714,23.7811639 C12.0751323,23.7926639 12.0828099,23.8018602 12.0926481,23.8045676 L12.108256,23.8032389 L12.3092106,23.7104931 L12.3186497,23.7024347 L12.3186497,23.7024347 L12.3225043,23.6906389 L12.340401,23.2611114 L12.337245,23.2485176 L12.337245,23.2485176 L12.3277531,23.2396597 L12.1430473,23.1473072 Z"
|
|
20
|
+
id="MingCute"
|
|
21
|
+
fillRule="nonzero"
|
|
22
|
+
></path>
|
|
23
|
+
<path
|
|
24
|
+
d="M13.299,3.1477 L21.933,18.1022 C22.5103,19.1022 21.7887,20.3522 20.634,20.3522 L3.36601,20.3522 C2.21131,20.3522 1.48962,19.1022 2.06697,18.1022 L10.7009,3.14771 C11.2783,2.14771 12.7217,2.1477 13.299,3.1477 Z M12,15 C11.4477,15 11,15.4477 11,16 C11,16.5523 11.4477,17 12,17 C12.5523,17 13,16.5523 13,16 C13,15.4477 12.5523,15 12,15 Z M12,8 C11.48715,8 11.0644908,8.38604429 11.0067275,8.88337975 L11,9 L11,13 C11,13.5523 11.4477,14 12,14 C12.51285,14 12.9355092,13.613973 12.9932725,13.1166239 L13,13 L13,9 C13,8.44772 12.5523,8 12,8 Z"
|
|
25
|
+
id="shape"
|
|
26
|
+
fill="#09244B"
|
|
27
|
+
></path>
|
|
28
|
+
</g>
|
|
29
|
+
</g>
|
|
30
|
+
</g>
|
|
31
|
+
</svg>
|
|
32
|
+
);
|
|
33
|
+
export default AlertIcon;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const CollapsedIcon = props => (
|
|
2
|
+
<svg
|
|
3
|
+
stroke="currentColor"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
strokeWidth="0"
|
|
6
|
+
viewBox="0 0 512 512"
|
|
7
|
+
height="1em"
|
|
8
|
+
width="1em"
|
|
9
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
10
|
+
>
|
|
11
|
+
<path d="M48 256c0 114.9 93.1 208 208 208s208-93.1 208-208S370.9 48 256 48 48 141.1 48 256zm244.5 0l-81.9-81.1c-7.5-7.5-7.5-19.8 0-27.3s19.8-7.5 27.3 0l95.4 95.7c7.3 7.3 7.5 19.1.6 26.6l-94 94.3c-3.8 3.8-8.7 5.7-13.7 5.7-4.9 0-9.9-1.9-13.6-5.6-7.5-7.5-7.6-19.7 0-27.3l79.9-81z"></path>
|
|
12
|
+
</svg>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default CollapsedIcon;
|