@cdc/dashboard 4.26.2 → 4.26.4
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/CONFIG.md +172 -0
- package/README.md +60 -20
- package/dist/cdcdashboard-CY9IcPSi.es.js +6 -0
- package/dist/cdcdashboard-DlpiY3fQ.es.js +4 -0
- package/dist/cdcdashboard.js +56686 -50281
- package/examples/__data__/data-2.json +6 -0
- package/examples/__data__/data-with-metadata.json +18 -0
- package/examples/__data__/data.json +6 -0
- package/examples/default.json +7 -36
- package/examples/legend-issue.json +1 -1
- package/examples/minimal-example.json +34 -0
- package/examples/private/dengue.json +4640 -0
- package/examples/private/inline-markup.json +775 -0
- package/examples/private/link_to_file.json +16662 -0
- package/examples/private/recent-update.json +1456 -0
- package/examples/private/toggle.json +10137 -0
- package/examples/sankey.json +3 -3
- package/examples/test-api-filter-reset.json +4 -4
- package/examples/tp5-test.json +86 -4
- package/package.json +9 -9
- package/src/CdcDashboard.tsx +2 -1
- package/src/CdcDashboardComponent.tsx +48 -28
- package/src/_stories/Dashboard.DataSetup.stories.tsx +6 -1
- package/src/_stories/Dashboard.Pages.smoke.stories.tsx +22 -0
- package/src/_stories/Dashboard.smoke.stories.tsx +33 -0
- package/src/_stories/Dashboard.stories.tsx +4523 -83
- package/src/_stories/_mock/dashboard-data-driven-colors.json +171 -0
- package/src/_stories/_mock/tab-simple-filter.json +153 -0
- package/src/_stories/_mock/tp5-test.json +86 -5
- package/src/components/DashboardEditors.tsx +15 -0
- package/src/components/DashboardFilters/DashboardFilters.test.tsx +129 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +29 -10
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +12 -8
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +6 -4
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/DeleteFilterModal.tsx +59 -58
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.test.tsx +127 -0
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +29 -6
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +10 -9
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
- package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
- package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
- package/src/components/DataDesignerModal.tsx +2 -2
- package/src/components/ExpandCollapseButtons.tsx +6 -4
- package/src/components/Grid.tsx +4 -3
- package/src/components/Header/Header.tsx +27 -5
- package/src/components/Header/index.scss +1 -1
- package/src/components/MultiConfigTabs/MultiConfigTabs.tsx +141 -140
- package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
- package/src/components/Row.tsx +30 -8
- package/src/components/Toggle/toggle-style.css +7 -7
- package/src/components/VisualizationRow.tsx +81 -22
- package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +2 -55
- package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
- package/src/components/Widget/Widget.tsx +7 -6
- package/src/components/Widget/widget.styles.css +48 -17
- package/src/data/initial-state.js +2 -1
- package/src/helpers/addVisualization.ts +73 -0
- package/src/helpers/formatConfigBeforeSave.ts +1 -1
- package/src/helpers/getVizConfig.ts +13 -3
- package/src/helpers/iconHash.tsx +45 -36
- package/src/helpers/processDataLegacy.ts +19 -14
- package/src/helpers/tests/addVisualization.test.ts +52 -0
- package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
- package/src/scss/editor-panel.scss +1 -1
- package/src/scss/grid.scss +38 -8
- package/src/scss/main.scss +237 -40
- package/src/store/dashboard.reducer.ts +2 -1
- package/src/test/CdcDashboard.test.jsx +26 -2
- package/src/test/CdcDashboardComponent.test.tsx +74 -0
- package/src/types/FilterStyles.ts +2 -1
- package/src/types/SharedFilter.ts +1 -0
- package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
- package/vite.config.js +2 -2
- package/dist/cdcdashboard-Cf9_fbQf.es.js +0 -6
- package/examples/DEV-6574.json +0 -2224
- package/examples/api-dashboard-data.json +0 -272
- package/examples/api-dashboard-years.json +0 -11
- package/examples/api-geographies-data.json +0 -11
- package/examples/chart-data.json +0 -5409
- package/examples/custom/css/respiratory.css +0 -236
- package/examples/custom/js/respiratory.js +0 -242
- package/examples/default-data.json +0 -368
- package/examples/default-filter-control.json +0 -209
- package/examples/default-multi-dataset-shared-filter.json +0 -1729
- package/examples/default-multi-dataset.json +0 -506
- package/examples/ed-visits-county-file.json +0 -402
- package/examples/filters/Alabama.json +0 -72
- package/examples/filters/Alaska.json +0 -1737
- package/examples/filters/Arkansas.json +0 -4713
- package/examples/filters/California.json +0 -212
- package/examples/filters/Colorado.json +0 -1500
- package/examples/filters/Connecticut.json +0 -559
- package/examples/filters/Delaware.json +0 -63
- package/examples/filters/DistrictofColumbia.json +0 -63
- package/examples/filters/Florida.json +0 -4217
- package/examples/filters/States.json +0 -146
- package/examples/state-level.json +0 -90136
- package/examples/state-points.json +0 -10474
- package/examples/temp-example-data.json +0 -130
- package/examples/test-dashboard-simple.json +0 -503
- package/examples/test-example.json +0 -752
- package/examples/test-file.json +0 -147
- package/examples/test.json +0 -752
- package/examples/testing.json +0 -94456
- /package/examples/{legend-issue-data.json → __data__/legend-issue-data.json} +0 -0
- /package/examples/api-test/{categories.json → __data__/categories.json} +0 -0
- /package/examples/api-test/{chart-data.json → __data__/chart-data.json} +0 -0
- /package/examples/api-test/{topics.json → __data__/topics.json} +0 -0
- /package/examples/api-test/{years.json → __data__/years.json} +0 -0
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
font-weight: 700;
|
|
5
5
|
}
|
|
6
6
|
.btn {
|
|
7
|
+
align-self: flex-end;
|
|
7
8
|
/* this is the height that is defined for the .form-control class in _forms.scss in bootstrap. */
|
|
8
9
|
height: calc(1.5em + 0.75rem + 2px);
|
|
9
|
-
align-self: flex-end;
|
|
10
10
|
}
|
|
11
11
|
.loading-filter {
|
|
12
12
|
position: relative;
|
|
13
13
|
.spinner-border {
|
|
14
|
+
height: 1.5rem;
|
|
14
15
|
position: absolute;
|
|
15
|
-
top: 55%;
|
|
16
16
|
right: 10%;
|
|
17
|
+
top: 55%;
|
|
17
18
|
width: 1.5rem;
|
|
18
|
-
height: 1.5rem;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
:is(select):disabled {
|
|
@@ -59,8 +59,8 @@ export const DataDesignerModal: React.FC<DataDesignerModalProps> = ({ vizKey, ro
|
|
|
59
59
|
if (dataSetChanged || noCachedData) {
|
|
60
60
|
setLoadingAPIData(true)
|
|
61
61
|
try {
|
|
62
|
-
|
|
63
|
-
newData = transform.autoStandardize(
|
|
62
|
+
const result = await fetchRemoteData(dataUrl)
|
|
63
|
+
newData = transform.autoStandardize(result.data)
|
|
64
64
|
} catch (e) {
|
|
65
65
|
setErrorMessage('There was an issue loading the data source. Please check the datasource URL and try again.')
|
|
66
66
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
2
|
+
|
|
1
3
|
type ExpandCollapseButtonsProps = {
|
|
2
4
|
setAllExpanded: Function
|
|
3
5
|
}
|
|
@@ -6,12 +8,12 @@ const ExpandCollapseButtons: React.FC<ExpandCollapseButtonsProps> = ({ setAllExp
|
|
|
6
8
|
return (
|
|
7
9
|
<div className='d-block '>
|
|
8
10
|
<div className='d-flex flex-row-reverse mb-2'>
|
|
9
|
-
<
|
|
11
|
+
<Button variant='light' onClick={() => setAllExpanded(false)}>
|
|
10
12
|
- Collapse All
|
|
11
|
-
</
|
|
12
|
-
<
|
|
13
|
+
</Button>
|
|
14
|
+
<Button variant='light' className='me-2' onClick={() => setAllExpanded(true)}>
|
|
13
15
|
+ Expand All
|
|
14
|
-
</
|
|
16
|
+
</Button>
|
|
15
17
|
</div>
|
|
16
18
|
</div>
|
|
17
19
|
)
|
package/src/components/Grid.tsx
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
2
|
import Row from './Row'
|
|
3
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
3
4
|
|
|
4
5
|
import { DashboardContext, DashboardDispatchContext } from '../DashboardContext'
|
|
5
6
|
import { ConfigRow } from '../types/ConfigRow'
|
|
6
7
|
|
|
7
8
|
const Grid = () => {
|
|
8
9
|
const { config } = useContext(DashboardContext)
|
|
10
|
+
const dispatch = useContext(DashboardDispatchContext)
|
|
9
11
|
if (!config) return null
|
|
10
12
|
const rows = config.rows
|
|
11
|
-
const dispatch = useContext(DashboardDispatchContext)
|
|
12
13
|
const updateConfig = config => dispatch({ type: 'UPDATE_CONFIG', payload: [config] })
|
|
13
14
|
const addRow = () => {
|
|
14
15
|
const blankRow: Partial<ConfigRow> = { columns: [{ width: 12 }] }
|
|
@@ -24,9 +25,9 @@ const Grid = () => {
|
|
|
24
25
|
{(rows || []).map((row, idx) => (
|
|
25
26
|
<Row row={row} idx={idx} uuid={row.uuid} key={idx} />
|
|
26
27
|
))}
|
|
27
|
-
<
|
|
28
|
+
<Button variant='primary' className='col' onClick={addRow}>
|
|
28
29
|
Add Row
|
|
29
|
-
</
|
|
30
|
+
</Button>
|
|
30
31
|
</div>
|
|
31
32
|
)
|
|
32
33
|
}
|
|
@@ -176,7 +176,6 @@ const Header = (props: HeaderProps) => {
|
|
|
176
176
|
Show Data Table(s)
|
|
177
177
|
</label>
|
|
178
178
|
<br />
|
|
179
|
-
|
|
180
179
|
<label>
|
|
181
180
|
<input
|
|
182
181
|
type='checkbox'
|
|
@@ -185,7 +184,6 @@ const Header = (props: HeaderProps) => {
|
|
|
185
184
|
/>
|
|
186
185
|
Expanded by Default
|
|
187
186
|
</label>
|
|
188
|
-
<br />
|
|
189
187
|
</div>
|
|
190
188
|
|
|
191
189
|
<div className='wrap'>
|
|
@@ -206,9 +204,6 @@ const Header = (props: HeaderProps) => {
|
|
|
206
204
|
onChange={e => changeConfigValue('table', 'height', e.target.value)}
|
|
207
205
|
/>
|
|
208
206
|
)}
|
|
209
|
-
</div>
|
|
210
|
-
|
|
211
|
-
<div className='wrap'>
|
|
212
207
|
<label>
|
|
213
208
|
<input
|
|
214
209
|
type='checkbox'
|
|
@@ -217,6 +212,17 @@ const Header = (props: HeaderProps) => {
|
|
|
217
212
|
/>
|
|
218
213
|
Show Download CSV Link
|
|
219
214
|
</label>
|
|
215
|
+
{config.table.download && (
|
|
216
|
+
<input
|
|
217
|
+
type='text'
|
|
218
|
+
placeholder='Customize label'
|
|
219
|
+
defaultValue={config.table.downloadDataLabel}
|
|
220
|
+
onChange={e => changeConfigValue('table', 'downloadDataLabel', e.target.value)}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div className='wrap'>
|
|
220
226
|
<label>
|
|
221
227
|
<input
|
|
222
228
|
type='checkbox'
|
|
@@ -225,6 +231,22 @@ const Header = (props: HeaderProps) => {
|
|
|
225
231
|
/>
|
|
226
232
|
Show URL to Automatically Updated Data
|
|
227
233
|
</label>
|
|
234
|
+
<label>
|
|
235
|
+
<input
|
|
236
|
+
type='checkbox'
|
|
237
|
+
defaultChecked={config.table.downloadImageButton}
|
|
238
|
+
onChange={e => changeConfigValue('table', 'downloadImageButton', e.target.checked)}
|
|
239
|
+
/>
|
|
240
|
+
Show Download Image Button
|
|
241
|
+
</label>
|
|
242
|
+
{config.table.downloadImageButton && (
|
|
243
|
+
<input
|
|
244
|
+
type='text'
|
|
245
|
+
placeholder='Customize label'
|
|
246
|
+
defaultValue={config.table.downloadImageLabel}
|
|
247
|
+
onChange={e => changeConfigValue('table', 'downloadImageLabel', e.target.value)}
|
|
248
|
+
/>
|
|
249
|
+
)}
|
|
228
250
|
</div>
|
|
229
251
|
</>
|
|
230
252
|
)}
|
|
@@ -1,140 +1,141 @@
|
|
|
1
|
-
import { createRef, useContext, useMemo, useState } from 'react'
|
|
2
|
-
import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
|
|
3
|
-
import Modal from '@cdc/core/components/ui/Modal'
|
|
4
|
-
import { useGlobalContext } from '@cdc/core/components/GlobalContext'
|
|
5
|
-
import '
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
dispatch({ type: '
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
1
|
+
import { createRef, useContext, useMemo, useState } from 'react'
|
|
2
|
+
import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
|
|
3
|
+
import Modal from '@cdc/core/components/ui/Modal'
|
|
4
|
+
import { useGlobalContext } from '@cdc/core/components/GlobalContext'
|
|
5
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
6
|
+
import './multiconfigtabs.styles.css'
|
|
7
|
+
|
|
8
|
+
const AreYouSure = deleteCallback => {
|
|
9
|
+
return (
|
|
10
|
+
<Modal>
|
|
11
|
+
<Modal.Content>
|
|
12
|
+
<p>Are you sure you want to delete this dashboard? </p>
|
|
13
|
+
<Button variant='danger' onClick={deleteCallback}>
|
|
14
|
+
DELETE
|
|
15
|
+
</Button>
|
|
16
|
+
</Modal.Content>
|
|
17
|
+
</Modal>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const Tab = ({ name, handleClick, tabs, index, active }) => {
|
|
22
|
+
const [editing, setEditing] = useState(false)
|
|
23
|
+
const dispatch = useContext(DashboardDispatchContext)
|
|
24
|
+
const { overlay } = useGlobalContext()
|
|
25
|
+
const inputRef = createRef<HTMLInputElement>()
|
|
26
|
+
|
|
27
|
+
const saveName = e => {
|
|
28
|
+
e.stopPropagation()
|
|
29
|
+
const newVal = inputRef.current.value
|
|
30
|
+
const sameName = newVal === name
|
|
31
|
+
const blankName = !newVal
|
|
32
|
+
const duplicateName = tabs.includes(newVal)
|
|
33
|
+
if (!sameName && !blankName && !duplicateName) {
|
|
34
|
+
dispatch({ type: 'RENAME_DASHBOARD_TAB', payload: { current: name, new: newVal } })
|
|
35
|
+
}
|
|
36
|
+
setEditing(false)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const onClick = e => {
|
|
40
|
+
// ignore click on delete button
|
|
41
|
+
if (e.target.className === 'remove') return
|
|
42
|
+
if (active) {
|
|
43
|
+
setEditing(true)
|
|
44
|
+
} else {
|
|
45
|
+
handleClick()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const handleRemove = () => {
|
|
50
|
+
const deleteCallback = () => {
|
|
51
|
+
dispatch({ type: 'REMOVE_MULTIDASHBOARD_AT_INDEX', payload: index })
|
|
52
|
+
overlay?.actions.toggleOverlay(false)
|
|
53
|
+
}
|
|
54
|
+
overlay?.actions.openOverlay(AreYouSure(deleteCallback))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const handleReorder = (index: number, moveTo: -1 | 1) => {
|
|
58
|
+
const newIndex = index + moveTo
|
|
59
|
+
const inbounds = newIndex > -1 && newIndex <= tabs.length - 1
|
|
60
|
+
if (inbounds) {
|
|
61
|
+
dispatch({ type: 'REORDER_MULTIDASHBOARDS', payload: { currentIndex: index, newIndex: index + moveTo } })
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const canMoveLeft = index !== 0
|
|
66
|
+
const canMoveRight = index <= tabs.length - 2
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<li className='nav-item d-flex mt-0'>
|
|
70
|
+
{canMoveLeft && editing && (
|
|
71
|
+
<button className='border-0' onClick={() => handleReorder(index, -1)}>
|
|
72
|
+
{'<'}
|
|
73
|
+
</button>
|
|
74
|
+
)}
|
|
75
|
+
<div
|
|
76
|
+
className={`edit nav-link${active ? ' active' : ''}`}
|
|
77
|
+
aria-current={active ? 'page' : null}
|
|
78
|
+
onClick={onClick}
|
|
79
|
+
>
|
|
80
|
+
{editing ? (
|
|
81
|
+
<div className='d-flex'>
|
|
82
|
+
<input type='text' defaultValue={name} onBlur={saveName} ref={inputRef} />
|
|
83
|
+
<Button variant='link' className='save' onClick={saveName}>
|
|
84
|
+
save
|
|
85
|
+
</Button>
|
|
86
|
+
</div>
|
|
87
|
+
) : (
|
|
88
|
+
<>
|
|
89
|
+
{name}
|
|
90
|
+
<Button variant='danger' className='border-0 ms-1' onClick={handleRemove}>
|
|
91
|
+
X
|
|
92
|
+
</Button>
|
|
93
|
+
</>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
{canMoveRight && editing && (
|
|
97
|
+
<button className='border-0' onClick={() => handleReorder(index, 1)}>
|
|
98
|
+
{'>'}
|
|
99
|
+
</button>
|
|
100
|
+
)}
|
|
101
|
+
</li>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const MultiConfigTabs = () => {
|
|
106
|
+
const { config } = useContext(DashboardContext)
|
|
107
|
+
const dispatch = useContext(DashboardDispatchContext)
|
|
108
|
+
const tabs = useMemo<string[]>(
|
|
109
|
+
() => (config.multiDashboards || []).map(({ label }) => label),
|
|
110
|
+
[config.multiDashboards]
|
|
111
|
+
)
|
|
112
|
+
const activeTab = useMemo<number>(() => config.activeDashboard, [config.activeDashboard])
|
|
113
|
+
|
|
114
|
+
const saveAndLoad = (indexToSwitchTo: number) => {
|
|
115
|
+
dispatch({ type: 'SAVE_CURRENT_CHANGES' })
|
|
116
|
+
dispatch({ type: 'SWITCH_CONFIG', payload: indexToSwitchTo })
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!config.multiDashboards) return null
|
|
120
|
+
return (
|
|
121
|
+
<ul className='nav nav-tabs multi-config-tabs mb-4'>
|
|
122
|
+
{tabs.map((tab, index) => (
|
|
123
|
+
<Tab
|
|
124
|
+
key={tab + index}
|
|
125
|
+
name={tab}
|
|
126
|
+
tabs={tabs}
|
|
127
|
+
index={index}
|
|
128
|
+
handleClick={() => saveAndLoad(index)}
|
|
129
|
+
active={index === activeTab}
|
|
130
|
+
/>
|
|
131
|
+
))}
|
|
132
|
+
<li className='nav-item'>
|
|
133
|
+
<button className='nav-link add' onClick={() => dispatch({ type: 'ADD_NEW_DASHBOARD' })}>
|
|
134
|
+
+
|
|
135
|
+
</button>
|
|
136
|
+
</li>
|
|
137
|
+
</ul>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default MultiConfigTabs
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
.multi-config-tabs {
|
|
2
2
|
.nav-link {
|
|
3
|
+
border-color: var(--lightGray);
|
|
3
4
|
border-radius: 6px 6px 0 0;
|
|
4
|
-
|
|
5
|
+
color: var(--primary);
|
|
5
6
|
display: block;
|
|
7
|
+
font-weight: 400;
|
|
6
8
|
padding: 0.5rem 1rem;
|
|
7
9
|
@media (max-width: 480px) {
|
|
8
10
|
padding: 0.5rem 0.8rem;
|
|
9
11
|
}
|
|
10
|
-
color: var(--primary);
|
|
11
|
-
border-color: var(--lightGray);
|
|
12
12
|
:is(button) {
|
|
13
|
-
display: none;
|
|
14
13
|
background: none;
|
|
14
|
+
display: none;
|
|
15
15
|
}
|
|
16
16
|
&:hover {
|
|
17
17
|
:is(button) {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
font-weight: bold;
|
|
32
32
|
}
|
|
33
33
|
.btn-danger {
|
|
34
|
-
text-decoration: none;
|
|
35
|
-
padding: 0px 5px;
|
|
36
34
|
font-size: inherit;
|
|
35
|
+
padding: 0px 5px;
|
|
36
|
+
text-decoration: none;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
.add {
|
package/src/components/Row.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import ToggleIcon from '../images/icon-toggle.svg'
|
|
|
15
15
|
import { ConfigRow } from '../types/ConfigRow'
|
|
16
16
|
import { DataDesignerModal } from './DataDesignerModal'
|
|
17
17
|
import { useGlobalContext } from '@cdc/core/components/GlobalContext'
|
|
18
|
+
import Button from '@cdc/core/components/elements/Button'
|
|
18
19
|
import { iconHash } from '../helpers/iconHash'
|
|
19
20
|
import _ from 'lodash'
|
|
20
21
|
import { Visualization } from '@cdc/core/types/Visualization'
|
|
@@ -70,6 +71,12 @@ const RowMenu: React.FC<RowMenuProps> = ({ rowIdx }) => {
|
|
|
70
71
|
updateConfig({ ...config, rows: newRows })
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
const toggleEqualHeight = () => {
|
|
75
|
+
const newRows = _.cloneDeep(rows)
|
|
76
|
+
newRows[rowIdx].equalHeight = !newRows[rowIdx].equalHeight
|
|
77
|
+
updateConfig({ ...config, rows: newRows })
|
|
78
|
+
}
|
|
79
|
+
|
|
73
80
|
const moveRow = (dir = 'down') => {
|
|
74
81
|
if (rowIdx === rows.length - 1 && dir === 'down') return
|
|
75
82
|
|
|
@@ -179,34 +186,49 @@ const RowMenu: React.FC<RowMenuProps> = ({ rowIdx }) => {
|
|
|
179
186
|
</li>
|
|
180
187
|
]
|
|
181
188
|
|
|
189
|
+
const isMultiColumn = curr !== '12' && curr !== 'toggle'
|
|
190
|
+
|
|
182
191
|
return (
|
|
183
192
|
<nav className='row-menu'>
|
|
184
193
|
<ul className='row-menu__flyout'>{layoutList}</ul>
|
|
194
|
+
{isMultiColumn && (
|
|
195
|
+
<Button
|
|
196
|
+
className={`btn row-menu__btn border-0${row.equalHeight ? ' btn-primary' : ''}`}
|
|
197
|
+
title={row.equalHeight ? 'Disable Equal Height Rows' : 'Enable Equal Height Rows'}
|
|
198
|
+
onClick={toggleEqualHeight}
|
|
199
|
+
>
|
|
200
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='25' height='20' fill='#fff'>
|
|
201
|
+
<rect x='1' y='2' width='9' height='14' rx='1' />
|
|
202
|
+
<rect x='14' y='2' width='9' height='14' rx='1' />
|
|
203
|
+
<line x1='0' y1='19' x2='24' y2='19' stroke='#fff' strokeWidth='2' strokeDasharray='3 2' />
|
|
204
|
+
</svg>
|
|
205
|
+
</Button>
|
|
206
|
+
)}
|
|
185
207
|
<div className='spacer'></div>
|
|
186
|
-
<
|
|
208
|
+
<Button
|
|
187
209
|
className={`btn btn-primary row-menu__btn border-0`}
|
|
188
210
|
title='Move Row Up'
|
|
189
211
|
onClick={() => moveRow('up')}
|
|
190
212
|
disabled={rowIdx === 0}
|
|
191
213
|
>
|
|
192
214
|
<Icon display='caretUp' color='#fff' size={25} />
|
|
193
|
-
</
|
|
194
|
-
<
|
|
215
|
+
</Button>
|
|
216
|
+
<Button
|
|
195
217
|
className={'btn btn-primary row-menu__btn border-0'}
|
|
196
218
|
title='Move Row Down'
|
|
197
219
|
onClick={() => moveRow('down')}
|
|
198
220
|
disabled={rowIdx + 1 === rows.length}
|
|
199
221
|
>
|
|
200
222
|
<Icon display='caretDown' color='#fff' size={25} />
|
|
201
|
-
</
|
|
202
|
-
<
|
|
223
|
+
</Button>
|
|
224
|
+
<Button
|
|
203
225
|
className={'btn btn-danger row-menu__btn row-menu__btn--remove border-0'}
|
|
204
226
|
title='Delete Row'
|
|
205
227
|
onClick={deleteRow}
|
|
206
228
|
disabled={rowIdx === 0 && rows.length === 1}
|
|
207
229
|
>
|
|
208
230
|
<Icon display='close' color='#fff' size={25} />
|
|
209
|
-
</
|
|
231
|
+
</Button>
|
|
210
232
|
</nav>
|
|
211
233
|
)
|
|
212
234
|
}
|
|
@@ -220,7 +242,7 @@ const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
|
|
|
220
242
|
<div className='builder-row' data-row-id={rowIdx}>
|
|
221
243
|
<RowMenu rowIdx={rowIdx} />
|
|
222
244
|
<span className='ms-2 mt-n3'>Row - {rowIdx + 1}</span>
|
|
223
|
-
<
|
|
245
|
+
<Button
|
|
224
246
|
title='Configure Data'
|
|
225
247
|
className='btn btn-configure-row'
|
|
226
248
|
onClick={() => {
|
|
@@ -228,7 +250,7 @@ const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
|
|
|
228
250
|
}}
|
|
229
251
|
>
|
|
230
252
|
{iconHash['gearMulti']}
|
|
231
|
-
</
|
|
253
|
+
</Button>
|
|
232
254
|
<div className='column-container'>
|
|
233
255
|
{row.columns
|
|
234
256
|
.filter(column => column.width)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
.
|
|
1
|
+
.cove-visualization {
|
|
2
2
|
--border: 1px solid var(--lightGray);
|
|
3
3
|
.toggle-component {
|
|
4
4
|
display: flex;
|
|
5
5
|
justify-content: right;
|
|
6
|
-
width: 100%;
|
|
7
6
|
margin-bottom: 15px;
|
|
7
|
+
width: 100%;
|
|
8
8
|
:first-child:is(div) {
|
|
9
9
|
border: var(--border);
|
|
10
10
|
border-radius: 5px 0 0 5px;
|
|
@@ -14,18 +14,18 @@
|
|
|
14
14
|
border-radius: 0 5px 5px 0;
|
|
15
15
|
}
|
|
16
16
|
:is(div) {
|
|
17
|
-
|
|
17
|
+
background-color: var(--white);
|
|
18
18
|
border-bottom: var(--border);
|
|
19
|
-
|
|
19
|
+
border-top: var(--border);
|
|
20
|
+
color: var(--primary);
|
|
21
|
+
cursor: pointer;
|
|
20
22
|
display: inline;
|
|
21
23
|
float: right;
|
|
22
|
-
|
|
24
|
+
padding: 7px 15px;
|
|
23
25
|
&.selected {
|
|
24
26
|
background-color: var(--primary);
|
|
25
27
|
color: white;
|
|
26
28
|
}
|
|
27
|
-
background-color: var(--white);
|
|
28
|
-
color: var(--primary);
|
|
29
29
|
:is(svg) {
|
|
30
30
|
height: 25px;
|
|
31
31
|
}
|