datajunction-ui 0.0.1-rc.18 → 0.0.1-rc.19
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/dj-logo.svg +10 -0
- package/package.json +19 -3
- package/src/app/icons/AlertIcon.jsx +32 -0
- package/src/app/icons/DJLogo.jsx +36 -0
- package/src/app/icons/DeleteIcon.jsx +21 -0
- package/src/app/icons/EditIcon.jsx +18 -0
- package/src/app/index.tsx +18 -0
- package/src/app/pages/AddEditNodePage/FormikSelect.jsx +33 -0
- package/src/app/pages/AddEditNodePage/FullNameField.jsx +36 -0
- package/src/app/pages/AddEditNodePage/Loadable.jsx +16 -0
- package/src/app/pages/AddEditNodePage/NodeQueryField.jsx +89 -0
- package/src/app/pages/AddEditNodePage/__tests__/FormikSelect.test.jsx +44 -0
- package/src/app/pages/AddEditNodePage/__tests__/FullNameField.test.jsx +29 -0
- package/src/app/pages/AddEditNodePage/__tests__/NodeQueryField.test.jsx +30 -0
- package/src/app/pages/AddEditNodePage/__tests__/__snapshots__/index.test.jsx.snap +84 -0
- package/src/app/pages/AddEditNodePage/__tests__/index.test.jsx +353 -0
- package/src/app/pages/AddEditNodePage/index.jsx +349 -0
- package/src/app/pages/NamespacePage/__tests__/__snapshots__/index.test.tsx.snap +51 -0
- package/src/app/pages/NamespacePage/index.jsx +36 -0
- package/src/app/pages/NodePage/NodeHistory.jsx +0 -1
- package/src/app/pages/NodePage/index.jsx +43 -26
- package/src/app/pages/Root/index.tsx +3 -3
- package/src/app/services/DJService.js +72 -1
- package/src/setupTests.ts +1 -1
- package/src/styles/index.css +82 -5
- package/src/styles/node-creation.scss +190 -0
- package/src/styles/styles.scss.d.ts +9 -0
|
@@ -13,6 +13,54 @@ exports[`<NamespacePage /> should render and match the snapshot 1`] = `
|
|
|
13
13
|
<h2>
|
|
14
14
|
Explore
|
|
15
15
|
</h2>
|
|
16
|
+
<span
|
|
17
|
+
className="menu-link"
|
|
18
|
+
>
|
|
19
|
+
<span
|
|
20
|
+
className="menu-title"
|
|
21
|
+
>
|
|
22
|
+
<div
|
|
23
|
+
className="dropdown"
|
|
24
|
+
>
|
|
25
|
+
<span
|
|
26
|
+
className="add_node"
|
|
27
|
+
>
|
|
28
|
+
+ Add Node
|
|
29
|
+
</span>
|
|
30
|
+
<div
|
|
31
|
+
className="dropdown-content"
|
|
32
|
+
>
|
|
33
|
+
<a
|
|
34
|
+
href="/create/transform/undefined"
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
className="node_type__transform node_type_creation_heading"
|
|
38
|
+
>
|
|
39
|
+
Transform
|
|
40
|
+
</div>
|
|
41
|
+
</a>
|
|
42
|
+
<a
|
|
43
|
+
href="/create/metric/undefined"
|
|
44
|
+
>
|
|
45
|
+
<div
|
|
46
|
+
className="node_type__metric node_type_creation_heading"
|
|
47
|
+
>
|
|
48
|
+
Metric
|
|
49
|
+
</div>
|
|
50
|
+
</a>
|
|
51
|
+
<a
|
|
52
|
+
href="/create/dimension/undefined"
|
|
53
|
+
>
|
|
54
|
+
<div
|
|
55
|
+
className="node_type__dimension node_type_creation_heading"
|
|
56
|
+
>
|
|
57
|
+
Dimension
|
|
58
|
+
</div>
|
|
59
|
+
</a>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</span>
|
|
63
|
+
</span>
|
|
16
64
|
<div
|
|
17
65
|
className="table-responsive"
|
|
18
66
|
>
|
|
@@ -56,6 +104,9 @@ exports[`<NamespacePage /> should render and match the snapshot 1`] = `
|
|
|
56
104
|
<th>
|
|
57
105
|
Last Updated
|
|
58
106
|
</th>
|
|
107
|
+
<th>
|
|
108
|
+
Actions
|
|
109
|
+
</th>
|
|
59
110
|
</tr>
|
|
60
111
|
</thead>
|
|
61
112
|
<tbody />
|
|
@@ -4,6 +4,8 @@ import { useContext, useEffect, useState } from 'react';
|
|
|
4
4
|
import NodeStatus from '../NodePage/NodeStatus';
|
|
5
5
|
import DJClientContext from '../../providers/djclient';
|
|
6
6
|
import Explorer from '../NamespacePage/Explorer';
|
|
7
|
+
import EditIcon from '../../icons/EditIcon';
|
|
8
|
+
import DeleteIcon from '../../icons/DeleteIcon';
|
|
7
9
|
|
|
8
10
|
export function NamespacePage() {
|
|
9
11
|
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
@@ -102,6 +104,14 @@ export function NamespacePage() {
|
|
|
102
104
|
{new Date(node.updated_at).toLocaleString('en-us')}
|
|
103
105
|
</span>
|
|
104
106
|
</td>
|
|
107
|
+
<td>
|
|
108
|
+
<a href={`/nodes/${node?.name}/edit`} style={{ marginLeft: '0.5rem' }}>
|
|
109
|
+
<EditIcon />
|
|
110
|
+
</a>
|
|
111
|
+
<a href="#" style={{ marginLeft: '0.5rem' }}>
|
|
112
|
+
<DeleteIcon />
|
|
113
|
+
</a>
|
|
114
|
+
</td>
|
|
105
115
|
</tr>
|
|
106
116
|
));
|
|
107
117
|
|
|
@@ -110,6 +120,31 @@ export function NamespacePage() {
|
|
|
110
120
|
<div className="card">
|
|
111
121
|
<div className="card-header">
|
|
112
122
|
<h2>Explore</h2>
|
|
123
|
+
|
|
124
|
+
<span className="menu-link">
|
|
125
|
+
<span className="menu-title">
|
|
126
|
+
<div className="dropdown">
|
|
127
|
+
<span className="add_node">+ Add Node</span>
|
|
128
|
+
<div className="dropdown-content">
|
|
129
|
+
<a href={`/create/transform/${namespace}`}>
|
|
130
|
+
<div className="node_type__transform node_type_creation_heading">
|
|
131
|
+
Transform
|
|
132
|
+
</div>
|
|
133
|
+
</a>
|
|
134
|
+
<a href={`/create/metric/${namespace}`}>
|
|
135
|
+
<div className="node_type__metric node_type_creation_heading">
|
|
136
|
+
Metric
|
|
137
|
+
</div>
|
|
138
|
+
</a>
|
|
139
|
+
<a href={`/create/dimension/${namespace}`}>
|
|
140
|
+
<div className="node_type__dimension node_type_creation_heading">
|
|
141
|
+
Dimension
|
|
142
|
+
</div>
|
|
143
|
+
</a>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</span>
|
|
147
|
+
</span>
|
|
113
148
|
<div className="table-responsive">
|
|
114
149
|
<div className={`sidebar`}>
|
|
115
150
|
<span
|
|
@@ -142,6 +177,7 @@ export function NamespacePage() {
|
|
|
142
177
|
<th>Status</th>
|
|
143
178
|
<th>Mode</th>
|
|
144
179
|
<th>Last Updated</th>
|
|
180
|
+
<th>Actions</th>
|
|
145
181
|
</tr>
|
|
146
182
|
</thead>
|
|
147
183
|
<tbody>{nodesList}</tbody>
|
|
@@ -13,6 +13,8 @@ import NodeMaterializationTab from './NodeMaterializationTab';
|
|
|
13
13
|
import ClientCodePopover from './ClientCodePopover';
|
|
14
14
|
import NodesWithDimension from './NodesWithDimension';
|
|
15
15
|
import NodeColumnLineage from './NodeLineageTab';
|
|
16
|
+
import EditIcon from '../../icons/EditIcon';
|
|
17
|
+
import AlertIcon from '../../icons/AlertIcon';
|
|
16
18
|
|
|
17
19
|
export function NodePage() {
|
|
18
20
|
const djClient = useContext(DJClientContext).DataJunctionAPI;
|
|
@@ -109,7 +111,8 @@ export function NodePage() {
|
|
|
109
111
|
let tabToDisplay = null;
|
|
110
112
|
switch (state.selectedTab) {
|
|
111
113
|
case 0:
|
|
112
|
-
tabToDisplay =
|
|
114
|
+
tabToDisplay =
|
|
115
|
+
node && node.message === undefined ? <NodeInfoTab node={node} /> : '';
|
|
113
116
|
break;
|
|
114
117
|
case 1:
|
|
115
118
|
tabToDisplay = <NodeColumnTab node={node} djClient={djClient} />;
|
|
@@ -136,41 +139,55 @@ export function NodePage() {
|
|
|
136
139
|
default:
|
|
137
140
|
tabToDisplay = <NodeInfoTab node={node} />;
|
|
138
141
|
}
|
|
139
|
-
|
|
140
142
|
// @ts-ignore
|
|
141
143
|
return (
|
|
142
144
|
<div className="node__header">
|
|
143
145
|
<NamespaceHeader namespace={name.split('.').slice(0, -1).join('.')} />
|
|
144
146
|
<div className="card">
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
{node !== undefined && node.message === undefined ? (
|
|
148
|
+
<div className="card-header">
|
|
149
|
+
<h3
|
|
150
|
+
className="card-title align-items-start flex-column"
|
|
151
|
+
style={{ display: 'inline-block' }}
|
|
152
|
+
>
|
|
153
|
+
<span className="card-label fw-bold text-gray-800">
|
|
154
|
+
{node?.display_name}{' '}
|
|
155
|
+
<span
|
|
156
|
+
className={'node_type__' + node?.type + ' badge node_type'}
|
|
157
|
+
>
|
|
158
|
+
{node?.type}
|
|
159
|
+
</span>
|
|
154
160
|
</span>
|
|
155
|
-
</
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
<div>
|
|
159
|
-
<a href={'/nodes/' + node?.name} className="link-table">
|
|
160
|
-
{node?.name}
|
|
161
|
-
</a>
|
|
162
|
-
<span
|
|
163
|
-
className="rounded-pill badge bg-secondary-soft"
|
|
161
|
+
</h3>
|
|
162
|
+
<a
|
|
163
|
+
href={`/nodes/${node?.name}/edit`}
|
|
164
164
|
style={{ marginLeft: '0.5rem' }}
|
|
165
165
|
>
|
|
166
|
-
|
|
167
|
-
</
|
|
166
|
+
<EditIcon />
|
|
167
|
+
</a>
|
|
168
|
+
<ClientCodePopover code={node?.createNodeClientCode} />
|
|
169
|
+
<div>
|
|
170
|
+
<a href={'/nodes/' + node?.name} className="link-table">
|
|
171
|
+
{node?.name}
|
|
172
|
+
</a>
|
|
173
|
+
<span
|
|
174
|
+
className="rounded-pill badge bg-secondary-soft"
|
|
175
|
+
style={{ marginLeft: '0.5rem' }}
|
|
176
|
+
>
|
|
177
|
+
{node?.version}
|
|
178
|
+
</span>
|
|
179
|
+
</div>
|
|
180
|
+
<div className="align-items-center row">
|
|
181
|
+
{tabsList(node).map(buildTabs)}
|
|
182
|
+
</div>
|
|
183
|
+
{tabToDisplay}
|
|
168
184
|
</div>
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
) : (
|
|
186
|
+
<div className="message alert" style={{ margin: '20px' }}>
|
|
187
|
+
<AlertIcon />
|
|
188
|
+
Node `{name}` does not exist!
|
|
171
189
|
</div>
|
|
172
|
-
|
|
173
|
-
</div>
|
|
190
|
+
)}
|
|
174
191
|
</div>
|
|
175
192
|
</div>
|
|
176
193
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useContext } from 'react';
|
|
2
2
|
import { Outlet } from 'react-router-dom';
|
|
3
|
-
import
|
|
3
|
+
import DJLogo from '../../icons/DJLogo';
|
|
4
4
|
import { Helmet } from 'react-helmet-async';
|
|
5
5
|
import DJClientContext from '../../providers/djclient';
|
|
6
6
|
|
|
@@ -24,8 +24,8 @@ export function Root() {
|
|
|
24
24
|
<div className="header">
|
|
25
25
|
<div className="logo">
|
|
26
26
|
<h2>
|
|
27
|
-
<
|
|
28
|
-
|
|
27
|
+
<DJLogo />
|
|
28
|
+
Data<b>Junction</b>
|
|
29
29
|
</h2>
|
|
30
30
|
</div>
|
|
31
31
|
<div className="menu">
|
|
@@ -25,6 +25,9 @@ export const DataJunctionAPI = {
|
|
|
25
25
|
credentials: 'include',
|
|
26
26
|
})
|
|
27
27
|
).json();
|
|
28
|
+
if (data.message !== undefined) {
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
28
31
|
data.primary_key = data.columns
|
|
29
32
|
.filter(col =>
|
|
30
33
|
col.attributes.some(attr => attr.attribute_type.name === 'primary_key'),
|
|
@@ -33,6 +36,72 @@ export const DataJunctionAPI = {
|
|
|
33
36
|
return data;
|
|
34
37
|
},
|
|
35
38
|
|
|
39
|
+
nodes: async function (prefix) {
|
|
40
|
+
return await (
|
|
41
|
+
await fetch(`${DJ_URL}/nodes/?prefix=${prefix}`, {
|
|
42
|
+
credentials: 'include',
|
|
43
|
+
})
|
|
44
|
+
).json();
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
createNode: async function (
|
|
48
|
+
nodeType,
|
|
49
|
+
name,
|
|
50
|
+
display_name,
|
|
51
|
+
description,
|
|
52
|
+
query,
|
|
53
|
+
mode,
|
|
54
|
+
namespace,
|
|
55
|
+
primary_key,
|
|
56
|
+
) {
|
|
57
|
+
const response = await fetch(`${DJ_URL}/nodes/${nodeType}`, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
name: name,
|
|
64
|
+
display_name: display_name,
|
|
65
|
+
description: description,
|
|
66
|
+
query: query,
|
|
67
|
+
mode: mode,
|
|
68
|
+
namespace: namespace,
|
|
69
|
+
primary_key: primary_key,
|
|
70
|
+
}),
|
|
71
|
+
credentials: 'include',
|
|
72
|
+
});
|
|
73
|
+
return { status: response.status, json: await response.json() };
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
patchNode: async function (
|
|
77
|
+
name,
|
|
78
|
+
display_name,
|
|
79
|
+
description,
|
|
80
|
+
query,
|
|
81
|
+
mode,
|
|
82
|
+
primary_key,
|
|
83
|
+
) {
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(`${DJ_URL}/nodes/${name}`, {
|
|
86
|
+
method: 'PATCH',
|
|
87
|
+
headers: {
|
|
88
|
+
'Content-Type': 'application/json',
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify({
|
|
91
|
+
display_name: display_name,
|
|
92
|
+
description: description,
|
|
93
|
+
query: query,
|
|
94
|
+
mode: mode,
|
|
95
|
+
primary_key: primary_key,
|
|
96
|
+
}),
|
|
97
|
+
credentials: 'include',
|
|
98
|
+
});
|
|
99
|
+
return { status: response.status, json: await response.json() };
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return { status: 500, json: { message: 'Update failed' } };
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
36
105
|
upstreams: async function (name) {
|
|
37
106
|
const data = await (
|
|
38
107
|
await fetch(`${DJ_URL}/nodes/${name}/upstream/`, {
|
|
@@ -131,7 +200,9 @@ export const DataJunctionAPI = {
|
|
|
131
200
|
|
|
132
201
|
revisions: async function (name) {
|
|
133
202
|
const data = await (
|
|
134
|
-
await fetch(`${DJ_URL}/nodes/` + name + '/revisions/'
|
|
203
|
+
await fetch(`${DJ_URL}/nodes/` + name + '/revisions/', {
|
|
204
|
+
credentials: 'include',
|
|
205
|
+
})
|
|
135
206
|
).json();
|
|
136
207
|
return data;
|
|
137
208
|
},
|
package/src/setupTests.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// react-testing-library renders your components to document.body,
|
|
2
2
|
// this adds jest-dom's custom assertions
|
|
3
|
-
import '@testing-library/jest-dom
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
4
|
|
|
5
5
|
import 'react-app-polyfill/ie11';
|
|
6
6
|
import 'react-app-polyfill/stable';
|
package/src/styles/index.css
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css?family=Jost');
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@300;600&display=swap');
|
|
3
|
+
@import url('https://fonts.googleapis.com/css?family=Lato');
|
|
4
|
+
|
|
1
5
|
body {
|
|
2
6
|
margin: 0;
|
|
3
|
-
font-family: system-ui, -apple-system,
|
|
4
|
-
|
|
5
|
-
'
|
|
7
|
+
font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell,
|
|
8
|
+
Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
|
|
9
|
+
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
|
6
10
|
-webkit-font-smoothing: antialiased;
|
|
7
11
|
-moz-osx-font-smoothing: grayscale;
|
|
8
12
|
}
|
|
@@ -14,6 +18,13 @@ body {
|
|
|
14
18
|
div {
|
|
15
19
|
display: block;
|
|
16
20
|
}
|
|
21
|
+
h2 {
|
|
22
|
+
font-family: 'Raleway', system-ui;
|
|
23
|
+
font-weight: 300;
|
|
24
|
+
}
|
|
25
|
+
h2 b {
|
|
26
|
+
font-weight: 600;
|
|
27
|
+
}
|
|
17
28
|
p {
|
|
18
29
|
display: block;
|
|
19
30
|
margin-block-start: 1em;
|
|
@@ -26,7 +37,7 @@ a,
|
|
|
26
37
|
a:hover {
|
|
27
38
|
text-decoration: none;
|
|
28
39
|
color: #005c72;
|
|
29
|
-
font-family: '
|
|
40
|
+
font-family: 'Montserrat', sans-serif;
|
|
30
41
|
}
|
|
31
42
|
a:hover {
|
|
32
43
|
text-decoration: underline;
|
|
@@ -153,6 +164,7 @@ ul {
|
|
|
153
164
|
.h6,
|
|
154
165
|
h6 {
|
|
155
166
|
margin: 0;
|
|
167
|
+
font-family: 'Jost';
|
|
156
168
|
text-transform: uppercase;
|
|
157
169
|
font-size: 0.8125rem;
|
|
158
170
|
font-weight: 600;
|
|
@@ -251,6 +263,7 @@ tr {
|
|
|
251
263
|
background-clip: border-box;
|
|
252
264
|
border-radius: 1rem;
|
|
253
265
|
margin: 2rem;
|
|
266
|
+
padding-bottom: 2rem;
|
|
254
267
|
}
|
|
255
268
|
|
|
256
269
|
.card-light-shadow {
|
|
@@ -313,6 +326,7 @@ tr {
|
|
|
313
326
|
font-weight: 600;
|
|
314
327
|
letter-spacing: 0.08em;
|
|
315
328
|
color: #95aac9;
|
|
329
|
+
font-family: 'Jost';
|
|
316
330
|
}
|
|
317
331
|
|
|
318
332
|
.card-table thead th {
|
|
@@ -325,7 +339,7 @@ tr {
|
|
|
325
339
|
td,
|
|
326
340
|
tbody th {
|
|
327
341
|
vertical-align: middle;
|
|
328
|
-
text-align:
|
|
342
|
+
text-align: left;
|
|
329
343
|
}
|
|
330
344
|
.table [data-sort],
|
|
331
345
|
.table-nowrap td,
|
|
@@ -369,6 +383,10 @@ tbody th {
|
|
|
369
383
|
border-bottom-width: 1px;
|
|
370
384
|
box-shadow: inset 0 0 0 9999px transparent;
|
|
371
385
|
}
|
|
386
|
+
.node_type_creation_heading {
|
|
387
|
+
text-transform: capitalize;
|
|
388
|
+
padding: 5px;
|
|
389
|
+
}
|
|
372
390
|
|
|
373
391
|
/* Nodes */
|
|
374
392
|
.node_type {
|
|
@@ -384,6 +402,7 @@ tbody th {
|
|
|
384
402
|
|
|
385
403
|
/* Nodes */
|
|
386
404
|
.node_type__source {
|
|
405
|
+
font-family: 'Jost';
|
|
387
406
|
background-color: #ccf7e5 !important;
|
|
388
407
|
color: #00b368;
|
|
389
408
|
}
|
|
@@ -393,15 +412,21 @@ tbody th {
|
|
|
393
412
|
}
|
|
394
413
|
|
|
395
414
|
.node_type__transform {
|
|
415
|
+
font-family: 'Jost';
|
|
396
416
|
background-color: #ccefff !important;
|
|
397
417
|
color: #0063b4;
|
|
398
418
|
}
|
|
419
|
+
|
|
420
|
+
.node_type__transform:hover {
|
|
421
|
+
background-color: #ccefff !important;
|
|
422
|
+
}
|
|
399
423
|
.react-flow__node .node_type__transform {
|
|
400
424
|
background-color: #6daaa750 !important;
|
|
401
425
|
color: #6daaa7;
|
|
402
426
|
}
|
|
403
427
|
|
|
404
428
|
.node_type__metric {
|
|
429
|
+
font-family: 'Jost';
|
|
405
430
|
background-color: #fad7dd !important;
|
|
406
431
|
color: #a2283e;
|
|
407
432
|
}
|
|
@@ -411,6 +436,7 @@ tbody th {
|
|
|
411
436
|
}
|
|
412
437
|
|
|
413
438
|
.node_type__dimension {
|
|
439
|
+
font-family: 'Jost';
|
|
414
440
|
background-color: #ffefd0 !important;
|
|
415
441
|
color: #a96621;
|
|
416
442
|
}
|
|
@@ -420,6 +446,7 @@ tbody th {
|
|
|
420
446
|
}
|
|
421
447
|
|
|
422
448
|
.node_type__cube {
|
|
449
|
+
font-family: 'Jost';
|
|
423
450
|
background-color: #dbafff !important;
|
|
424
451
|
color: #580076;
|
|
425
452
|
}
|
|
@@ -710,6 +737,10 @@ pre {
|
|
|
710
737
|
padding: 0 2.25rem 0 2.25rem;
|
|
711
738
|
}
|
|
712
739
|
|
|
740
|
+
.card-header h2 {
|
|
741
|
+
font-family: 'Jost';
|
|
742
|
+
}
|
|
743
|
+
|
|
713
744
|
.text-gray-400 {
|
|
714
745
|
color: #b5b5c3 !important;
|
|
715
746
|
}
|
|
@@ -873,3 +904,49 @@ pre {
|
|
|
873
904
|
.inactive {
|
|
874
905
|
display: none;
|
|
875
906
|
}
|
|
907
|
+
|
|
908
|
+
.dropdown {
|
|
909
|
+
position: relative;
|
|
910
|
+
display: inline-block;
|
|
911
|
+
float: right;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.dropdown-content {
|
|
915
|
+
display: none;
|
|
916
|
+
position: absolute;
|
|
917
|
+
margin-top: 6px;
|
|
918
|
+
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
|
919
|
+
min-width: 115px;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.dropdown:hover .dropdown-content {
|
|
923
|
+
display: block;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.dropdown-content a:hover {
|
|
927
|
+
text-decoration: none;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.dropdown-content a div {
|
|
931
|
+
padding: 12px 16px;
|
|
932
|
+
background-color: #ffffff !important;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
.dropdown-content a div:hover {
|
|
936
|
+
background-color: #f3eeff !important;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.add_node {
|
|
940
|
+
background-color: #5d2f86 !important;
|
|
941
|
+
color: #fff;
|
|
942
|
+
text-transform: none;
|
|
943
|
+
vertical-align: middle;
|
|
944
|
+
padding-right: 1rem;
|
|
945
|
+
padding-left: 1rem;
|
|
946
|
+
padding-top: 0.5rem;
|
|
947
|
+
padding-bottom: 0.5rem;
|
|
948
|
+
font-size: 1rem;
|
|
949
|
+
border-radius: 0.5rem;
|
|
950
|
+
word-wrap: break-word;
|
|
951
|
+
white-space: break-spaces;
|
|
952
|
+
}
|