@cdc/dashboard 4.22.10-alpha.1 → 4.22.11
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/README.md +36 -36
- package/dist/cdcdashboard.js +6 -6
- package/examples/default-data.json +367 -367
- package/examples/default-filter-control.json +176 -174
- package/examples/default-multi-dataset.json +505 -497
- package/examples/default.json +161 -155
- package/examples/private/chart-issue.json +3462 -3466
- package/examples/private/no-issue.json +3462 -3466
- package/examples/private/totals-two.json +103 -103
- package/examples/private/totals.json +102 -102
- package/examples/temp-example-data.json +1 -1
- package/examples/test-example.json +163 -1
- package/package.json +7 -7
- package/src/CdcDashboard.js +200 -124
- package/src/CdcDashboard.jsx +271 -277
- package/src/ConfigContext.js +3 -3
- package/src/components/Column.jsx +10 -9
- package/src/components/DataTable.tsx +91 -111
- package/src/components/EditorPanel.js +184 -246
- package/src/components/Grid.jsx +8 -4
- package/src/components/Header.jsx +209 -118
- package/src/components/Row.js +30 -29
- package/src/components/Row.jsx +36 -52
- package/src/components/Widget.js +68 -61
- package/src/components/Widget.jsx +85 -62
- package/src/data/initial-state.js +3 -9
- package/src/index.html +24 -26
- package/src/index.js +12 -12
- package/src/scss/editor-panel.scss +494 -489
- package/src/scss/grid.scss +20 -19
- package/src/scss/main.scss +16 -15
- package/src/scss/variables.scss +1 -1
package/src/components/Grid.jsx
CHANGED
|
@@ -11,7 +11,7 @@ const Grid = () => {
|
|
|
11
11
|
...config,
|
|
12
12
|
rows: [
|
|
13
13
|
...rows,
|
|
14
|
-
[
|
|
14
|
+
[{ width: 12 }, { equalHeight: false }, {}, {}]
|
|
15
15
|
//[{width: 12}, {}, {}] ],
|
|
16
16
|
],
|
|
17
17
|
uuid: Date.now()
|
|
@@ -19,9 +19,13 @@ const Grid = () => {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
|
-
<div className=
|
|
23
|
-
{rows.map((row, idx) =>
|
|
24
|
-
|
|
22
|
+
<div className='builder-grid'>
|
|
23
|
+
{rows.map((row, idx) => (
|
|
24
|
+
<Row row={row} idx={idx} uuid={row.uuid} key={idx} />
|
|
25
|
+
))}
|
|
26
|
+
<button className='btn add-row' onClick={addRow}>
|
|
27
|
+
Add Row
|
|
28
|
+
</button>
|
|
25
29
|
</div>
|
|
26
30
|
)
|
|
27
31
|
}
|
|
@@ -5,30 +5,24 @@ import ConfigContext from '../ConfigContext'
|
|
|
5
5
|
import { useGlobalContext } from '@cdc/core/components/GlobalContext'
|
|
6
6
|
import Modal from '@cdc/core/components/ui/Modal'
|
|
7
7
|
|
|
8
|
-
const Header = ({setPreview, tabSelected, setTabSelected, back, subEditor = null}) => {
|
|
9
|
-
|
|
10
|
-
const {
|
|
11
|
-
config,
|
|
12
|
-
updateConfig,
|
|
13
|
-
setParentConfig
|
|
14
|
-
} = useContext(ConfigContext);
|
|
8
|
+
const Header = ({ setPreview, tabSelected, setTabSelected, back, subEditor = null }) => {
|
|
9
|
+
const { config, updateConfig, setParentConfig } = useContext(ConfigContext)
|
|
15
10
|
|
|
16
11
|
const { overlay } = useGlobalContext()
|
|
17
12
|
|
|
18
|
-
const [
|
|
13
|
+
const [columns, setColumns] = useState([])
|
|
19
14
|
|
|
20
15
|
const changeConfigValue = (parentObj, key, value) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
newConfig[parentObj][key] = value;
|
|
16
|
+
let newConfig = { ...config }
|
|
17
|
+
if (!newConfig[parentObj]) newConfig[parentObj] = {}
|
|
18
|
+
newConfig[parentObj][key] = value
|
|
25
19
|
|
|
26
20
|
updateConfig(newConfig)
|
|
27
21
|
}
|
|
28
22
|
|
|
29
|
-
const setTab =
|
|
23
|
+
const setTab = index => {
|
|
30
24
|
setTabSelected(index)
|
|
31
|
-
if(index === 3){
|
|
25
|
+
if (index === 3) {
|
|
32
26
|
setPreview(true)
|
|
33
27
|
} else {
|
|
34
28
|
setPreview(false)
|
|
@@ -36,33 +30,32 @@ const Header = ({setPreview, tabSelected, setTabSelected, back, subEditor = null
|
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
const addNewFilter = () => {
|
|
39
|
-
let dashboardConfig = {...config.dashboard}
|
|
40
|
-
|
|
41
|
-
dashboardConfig.sharedFilters = dashboardConfig.sharedFilters || [];
|
|
33
|
+
let dashboardConfig = { ...config.dashboard }
|
|
42
34
|
|
|
43
|
-
dashboardConfig.sharedFilters
|
|
35
|
+
dashboardConfig.sharedFilters = dashboardConfig.sharedFilters || []
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
dashboardConfig.sharedFilters.push({ key: 'Dashboard Filter ' + (dashboardConfig.sharedFilters.length + 1), values: [] })
|
|
46
38
|
|
|
39
|
+
updateConfig({ ...config, dashboard: dashboardConfig })
|
|
47
40
|
}
|
|
48
41
|
|
|
49
|
-
const removeFilter =
|
|
50
|
-
let dashboardConfig = {...config.dashboard}
|
|
42
|
+
const removeFilter = index => {
|
|
43
|
+
let dashboardConfig = { ...config.dashboard }
|
|
51
44
|
|
|
52
|
-
dashboardConfig.sharedFilters.splice(index, 1)
|
|
45
|
+
dashboardConfig.sharedFilters.splice(index, 1)
|
|
53
46
|
|
|
54
|
-
updateConfig({...config, dashboard: dashboardConfig})
|
|
47
|
+
updateConfig({ ...config, dashboard: dashboardConfig })
|
|
55
48
|
|
|
56
|
-
overlay?.actions.toggleOverlay()
|
|
49
|
+
overlay?.actions.toggleOverlay()
|
|
57
50
|
}
|
|
58
51
|
|
|
59
|
-
const convertStateToConfig = (type =
|
|
52
|
+
const convertStateToConfig = (type = 'JSON') => {
|
|
60
53
|
let strippedState = JSON.parse(JSON.stringify(config))
|
|
61
54
|
delete strippedState.newViz
|
|
62
55
|
delete strippedState.runtime
|
|
63
56
|
|
|
64
|
-
if(type ===
|
|
65
|
-
return JSON.stringify(
|
|
57
|
+
if (type === 'JSON') {
|
|
58
|
+
return JSON.stringify(strippedState)
|
|
66
59
|
}
|
|
67
60
|
|
|
68
61
|
return strippedState
|
|
@@ -72,40 +65,40 @@ const Header = ({setPreview, tabSelected, setTabSelected, back, subEditor = null
|
|
|
72
65
|
const parsedData = convertStateToConfig()
|
|
73
66
|
|
|
74
67
|
// Emit the data in a regular JS event so it can be consumed by anything.
|
|
75
|
-
const event = new CustomEvent('updateVizConfig', { detail: parsedData})
|
|
68
|
+
const event = new CustomEvent('updateVizConfig', { detail: parsedData })
|
|
76
69
|
|
|
77
70
|
window.dispatchEvent(event)
|
|
78
71
|
|
|
79
72
|
// Pass up to Editor if needed
|
|
80
|
-
if(setParentConfig) {
|
|
81
|
-
const newConfig = convertStateToConfig(
|
|
73
|
+
if (setParentConfig) {
|
|
74
|
+
const newConfig = convertStateToConfig('object')
|
|
82
75
|
setParentConfig(newConfig)
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
86
|
-
}, [config])
|
|
79
|
+
}, [config])
|
|
87
80
|
|
|
88
81
|
useEffect(() => {
|
|
89
82
|
const runSetColumns = async () => {
|
|
90
|
-
let columns = {}
|
|
91
|
-
let dataKeys = Object.keys(config.datasets)
|
|
83
|
+
let columns = {}
|
|
84
|
+
let dataKeys = Object.keys(config.datasets)
|
|
92
85
|
|
|
93
|
-
for(let i = 0; i < dataKeys.length; i++){
|
|
94
|
-
if(!config.datasets[dataKeys[i]].data && config.datasets[dataKeys[i]].dataUrl){
|
|
95
|
-
config.datasets[dataKeys[i]].data = await fetchRemoteData(config.datasets[dataKeys[i]].dataUrl)
|
|
96
|
-
if(config.datasets[dataKeys[i]].dataDescription) {
|
|
86
|
+
for (let i = 0; i < dataKeys.length; i++) {
|
|
87
|
+
if (!config.datasets[dataKeys[i]].data && config.datasets[dataKeys[i]].dataUrl) {
|
|
88
|
+
config.datasets[dataKeys[i]].data = await fetchRemoteData(config.datasets[dataKeys[i]].dataUrl)
|
|
89
|
+
if (config.datasets[dataKeys[i]].dataDescription) {
|
|
97
90
|
try {
|
|
98
|
-
config.datasets[dataKeys[i]].data = transform.autoStandardize(config.datasets[dataKeys[i]].data)
|
|
99
|
-
config.datasets[dataKeys[i]].data = transform.developerStandardize(config.datasets[dataKeys[i]].data, config.datasets[dataKey].dataDescription)
|
|
100
|
-
} catch(e) {
|
|
91
|
+
config.datasets[dataKeys[i]].data = transform.autoStandardize(config.datasets[dataKeys[i]].data)
|
|
92
|
+
config.datasets[dataKeys[i]].data = transform.developerStandardize(config.datasets[dataKeys[i]].data, config.datasets[dataKey].dataDescription)
|
|
93
|
+
} catch (e) {
|
|
101
94
|
//Data not able to be standardized, leave as is
|
|
102
95
|
}
|
|
103
96
|
}
|
|
104
97
|
}
|
|
105
98
|
|
|
106
|
-
if(config.datasets[dataKeys[i]].data) {
|
|
99
|
+
if (config.datasets[dataKeys[i]].data) {
|
|
107
100
|
config.datasets[dataKeys[i]].data.map(row => {
|
|
108
|
-
Object.keys(row).forEach(columnName => columns[columnName] = true)
|
|
101
|
+
Object.keys(row).forEach(columnName => (columns[columnName] = true))
|
|
109
102
|
})
|
|
110
103
|
}
|
|
111
104
|
}
|
|
@@ -114,131 +107,229 @@ const Header = ({setPreview, tabSelected, setTabSelected, back, subEditor = null
|
|
|
114
107
|
}
|
|
115
108
|
|
|
116
109
|
runSetColumns()
|
|
117
|
-
}, [config.datasets])
|
|
110
|
+
}, [config.datasets])
|
|
118
111
|
|
|
119
112
|
const filterModal = (filter, index) => {
|
|
120
|
-
|
|
121
113
|
const saveChanges = () => {
|
|
122
|
-
let tempConfig = {...config.dashboard}
|
|
123
|
-
tempConfig.sharedFilters[index] = filter
|
|
114
|
+
let tempConfig = { ...config.dashboard }
|
|
115
|
+
tempConfig.sharedFilters[index] = filter
|
|
116
|
+
|
|
117
|
+
updateConfig({ ...config, dashboard: tempConfig })
|
|
124
118
|
|
|
125
|
-
updateConfig({...config, dashboard: tempConfig});
|
|
126
|
-
|
|
127
119
|
overlay?.actions.toggleOverlay()
|
|
128
120
|
}
|
|
129
121
|
|
|
130
122
|
const updateFilterProp = (name, index, value) => {
|
|
131
|
-
let newFilter = {...filter}
|
|
123
|
+
let newFilter = { ...filter }
|
|
132
124
|
|
|
133
|
-
newFilter[name] = value
|
|
125
|
+
newFilter[name] = value
|
|
134
126
|
|
|
135
127
|
overlay?.actions.openOverlay(filterModal(newFilter, index))
|
|
136
128
|
}
|
|
137
129
|
|
|
138
130
|
const addFilterUsedBy = (filter, index, value) => {
|
|
139
|
-
if(!filter.usedBy) filter.usedBy = []
|
|
140
|
-
filter.usedBy.push(value)
|
|
141
|
-
updateFilterProp('usedBy', index, filter.usedBy)
|
|
131
|
+
if (!filter.usedBy) filter.usedBy = []
|
|
132
|
+
filter.usedBy.push(value)
|
|
133
|
+
updateFilterProp('usedBy', index, filter.usedBy)
|
|
142
134
|
}
|
|
143
|
-
|
|
135
|
+
|
|
144
136
|
const removeFilterUsedBy = (filter, index, value) => {
|
|
145
|
-
let usedByIndex = filter.usedBy.indexOf(value)
|
|
146
|
-
if(usedByIndex !== -1){
|
|
147
|
-
filter.usedBy.splice(usedByIndex, 1)
|
|
148
|
-
updateFilterProp('usedBy', index, filter.usedBy)
|
|
137
|
+
let usedByIndex = filter.usedBy.indexOf(value)
|
|
138
|
+
if (usedByIndex !== -1) {
|
|
139
|
+
filter.usedBy.splice(usedByIndex, 1)
|
|
140
|
+
updateFilterProp('usedBy', index, filter.usedBy)
|
|
149
141
|
}
|
|
150
|
-
|
|
151
142
|
}
|
|
152
|
-
|
|
143
|
+
|
|
153
144
|
return (
|
|
154
145
|
<Modal>
|
|
155
146
|
<Modal.Content>
|
|
156
147
|
<h2>Dashboard Filter Settings</h2>
|
|
157
|
-
<fieldset className=
|
|
158
|
-
<button
|
|
148
|
+
<fieldset className='shared-filter-modal' key={filter.columnName + index}>
|
|
149
|
+
<button
|
|
150
|
+
type='button'
|
|
151
|
+
className='btn btn-primary remove-column'
|
|
152
|
+
onClick={() => {
|
|
153
|
+
removeFilter(index)
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
Remove Filter
|
|
157
|
+
</button>
|
|
159
158
|
<label>
|
|
160
|
-
<span className=
|
|
161
|
-
<select
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
|
|
159
|
+
<span className='edit-label column-heading'>Filter: </span>
|
|
160
|
+
<select
|
|
161
|
+
value={filter.columnName}
|
|
162
|
+
onChange={e => {
|
|
163
|
+
updateFilterProp('columnName', index, e.target.value)
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
<option value=''>- Select Option -</option>
|
|
167
|
+
{columns.map(dataKey => (
|
|
168
|
+
<option value={dataKey} key={`filter-column-select-item-${dataKey}`}>
|
|
169
|
+
{dataKey}
|
|
170
|
+
</option>
|
|
165
171
|
))}
|
|
166
172
|
</select>
|
|
167
173
|
</label>
|
|
168
174
|
<label>
|
|
169
|
-
<span className=
|
|
170
|
-
<input
|
|
175
|
+
<span className='edit-label column-heading'>Label: </span>
|
|
176
|
+
<input
|
|
177
|
+
type='text'
|
|
178
|
+
value={filter.key}
|
|
179
|
+
onChange={e => {
|
|
180
|
+
updateFilterProp('key', index, e.target.value)
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
171
183
|
</label>
|
|
172
184
|
<label>
|
|
173
|
-
<span className=
|
|
174
|
-
<input
|
|
185
|
+
<span className='edit-label column-heading'>Show Dropdown</span>
|
|
186
|
+
<input
|
|
187
|
+
type='checkbox'
|
|
188
|
+
defaultChecked={filter.showDropdown === true}
|
|
189
|
+
onChange={e => {
|
|
190
|
+
updateFilterProp('showDropdown', index, !filter.showDropdown)
|
|
191
|
+
}}
|
|
192
|
+
/>
|
|
175
193
|
</label>
|
|
176
194
|
<label>
|
|
177
|
-
<span className=
|
|
195
|
+
<span className='edit-label column-heading'>Set By: </span>
|
|
178
196
|
<select value={filter.setBy} onChange={e => updateFilterProp('setBy', index, e.target.value)}>
|
|
179
|
-
<option value=
|
|
180
|
-
{Object.keys(config.visualizations).map(
|
|
181
|
-
<option value={vizKey} key={`set-by-select-item-${vizKey}`}>
|
|
197
|
+
<option value=''>- Select Option -</option>
|
|
198
|
+
{Object.keys(config.visualizations).map(vizKey => (
|
|
199
|
+
<option value={vizKey} key={`set-by-select-item-${vizKey}`}>
|
|
200
|
+
{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}
|
|
201
|
+
</option>
|
|
182
202
|
))}
|
|
183
203
|
</select>
|
|
184
204
|
</label>
|
|
185
205
|
<label>
|
|
186
|
-
<span className=
|
|
206
|
+
<span className='edit-label column-heading'>Used By:</span>
|
|
187
207
|
<ul>
|
|
188
|
-
{filter.usedBy &&
|
|
189
|
-
|
|
190
|
-
|
|
208
|
+
{filter.usedBy &&
|
|
209
|
+
filter.usedBy.map(vizKey => (
|
|
210
|
+
<li key={`used-by-list-item-${vizKey}`}>
|
|
211
|
+
<span>{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}</span>{' '}
|
|
212
|
+
<button
|
|
213
|
+
onClick={e => {
|
|
214
|
+
e.preventDefault()
|
|
215
|
+
removeFilterUsedBy(filter, index, vizKey)
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
218
|
+
X
|
|
219
|
+
</button>
|
|
220
|
+
</li>
|
|
221
|
+
))}
|
|
191
222
|
</ul>
|
|
192
223
|
<select onChange={e => addFilterUsedBy(filter, index, e.target.value)}>
|
|
193
|
-
<option value=
|
|
194
|
-
{Object.keys(config.visualizations)
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
<option value=''>- Select Option -</option>
|
|
225
|
+
{Object.keys(config.visualizations)
|
|
226
|
+
.filter(vizKey => filter.setBy !== vizKey && (!filter.usedBy || filter.usedBy.indexOf(vizKey) === -1) && !config.visualizations[vizKey].usesSharedFilter)
|
|
227
|
+
.map(vizKey => (
|
|
228
|
+
<option value={vizKey} key={`used-by-select-item-${vizKey}`}>
|
|
229
|
+
{config.visualizations[vizKey].general && config.visualizations[vizKey].general.title ? config.visualizations[vizKey].general.title : config.visualizations[vizKey].title || vizKey}
|
|
230
|
+
</option>
|
|
231
|
+
))}
|
|
197
232
|
</select>
|
|
198
233
|
</label>
|
|
199
234
|
</fieldset>
|
|
200
|
-
<button type=
|
|
201
|
-
|
|
235
|
+
<button type='button' className='btn btn-primary' style={{ display: 'inline-block', 'margin-right': '1em' }} onClick={overlay?.actions.toggleOverlay}>
|
|
236
|
+
Cancel
|
|
237
|
+
</button>
|
|
238
|
+
<button type='button' className='btn btn-primary' style={{ display: 'inline-block' }} onClick={saveChanges}>
|
|
239
|
+
Save
|
|
240
|
+
</button>
|
|
202
241
|
</Modal.Content>
|
|
203
242
|
</Modal>
|
|
204
243
|
)
|
|
205
244
|
}
|
|
206
245
|
|
|
207
246
|
return (
|
|
208
|
-
<div aria-level=
|
|
209
|
-
{subEditor ?
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
247
|
+
<div aria-level='2' role='heading' className={`editor-heading${subEditor ? ' sub-dashboard-viz' : ''}`}>
|
|
248
|
+
{subEditor ? (
|
|
249
|
+
<div className='heading-1 back-to' onClick={back} style={{ cursor: 'pointer' }}>
|
|
250
|
+
<span>←</span> Back to Dashboard
|
|
251
|
+
</div>
|
|
252
|
+
) : (
|
|
253
|
+
<div className='heading-1'>
|
|
254
|
+
Dashboard Editor
|
|
255
|
+
<br />
|
|
256
|
+
{<input type='text' placeholder='Enter Dashboard Name Here' defaultValue={config.dashboard.title} onChange={e => changeConfigValue('dashboard', 'title', e.target.value)} />}
|
|
257
|
+
</div>
|
|
258
|
+
)}
|
|
259
|
+
{!subEditor && (
|
|
260
|
+
<div>
|
|
261
|
+
<ul className='toggle-bar'>
|
|
262
|
+
<li
|
|
263
|
+
className={tabSelected === 0 ? 'active' : 'inactive'}
|
|
264
|
+
onClick={() => {
|
|
265
|
+
setTab(0)
|
|
266
|
+
}}
|
|
267
|
+
>
|
|
268
|
+
Dashboard Description
|
|
269
|
+
</li>
|
|
270
|
+
<li
|
|
271
|
+
className={tabSelected === 1 ? 'active' : 'inactive'}
|
|
272
|
+
onClick={() => {
|
|
273
|
+
setTab(1)
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
Dashboard Filters
|
|
277
|
+
</li>
|
|
278
|
+
<li
|
|
279
|
+
className={tabSelected === 2 ? 'active' : 'inactive'}
|
|
280
|
+
onClick={() => {
|
|
281
|
+
setTab(2)
|
|
282
|
+
}}
|
|
283
|
+
>
|
|
284
|
+
Data Table Settings
|
|
285
|
+
</li>
|
|
286
|
+
<li
|
|
287
|
+
className={tabSelected === 3 ? 'active' : 'inactive'}
|
|
288
|
+
onClick={() => {
|
|
289
|
+
setTab(3)
|
|
290
|
+
}}
|
|
291
|
+
>
|
|
292
|
+
Dashboard Preview
|
|
293
|
+
</li>
|
|
294
|
+
</ul>
|
|
295
|
+
<div className='heading-body'>
|
|
296
|
+
{tabSelected === 0 && <input type='text' className='description-input' placeholder='Type a dashboard description here.' defaultValue={config.dashboard.description} onChange={e => changeConfigValue('dashboard', 'description', e.target.value)} />}
|
|
297
|
+
{tabSelected === 1 && (
|
|
298
|
+
<>
|
|
299
|
+
{config.dashboard.sharedFilters &&
|
|
300
|
+
config.dashboard.sharedFilters.map((sharedFilter, index) => (
|
|
301
|
+
<span className='shared-filter-button' key={`shared-filter-${sharedFilter.key}`}>
|
|
302
|
+
<a
|
|
303
|
+
href='#'
|
|
304
|
+
onClick={e => {
|
|
305
|
+
e.preventDefault()
|
|
306
|
+
overlay?.actions.openOverlay(filterModal(sharedFilter, index))
|
|
307
|
+
}}
|
|
308
|
+
>
|
|
309
|
+
{sharedFilter.key}
|
|
310
|
+
</a>
|
|
311
|
+
<button onClick={() => removeFilter(index)}>X</button>
|
|
312
|
+
</span>
|
|
313
|
+
))}
|
|
314
|
+
<button onClick={addNewFilter}>Add New Filter</button>
|
|
315
|
+
</>
|
|
316
|
+
)}
|
|
317
|
+
{tabSelected === 2 && (
|
|
318
|
+
<>
|
|
319
|
+
<label>Show Table</label>
|
|
320
|
+
<input type='checkbox' defaultChecked={config.table.show} onChange={e => changeConfigValue('table', 'show', e.target.checked)} />
|
|
321
|
+
<label>Expanded by Default</label>
|
|
322
|
+
<input type='checkbox' defaultChecked={config.table.expanded} onChange={e => changeConfigValue('table', 'expanded', e.target.checked)} />
|
|
323
|
+
<label>Display Download Button</label>
|
|
324
|
+
<input type='checkbox' defaultChecked={config.table.download} onChange={e => changeConfigValue('table', 'download', e.target.checked)} />
|
|
325
|
+
<label>Limit Table Height</label>
|
|
326
|
+
<input type='checkbox' defaultChecked={config.table.limitHeight} onChange={e => changeConfigValue('table', 'limitHeight', e.target.checked)} />
|
|
327
|
+
{config.table.limitHeight && <input class='table-height-input' type='text' placeholder='Height (px)' defaultValue={config.table.height} onChange={e => changeConfigValue('table', 'height', e.target.value)} />}
|
|
328
|
+
</>
|
|
329
|
+
)}
|
|
330
|
+
</div>
|
|
240
331
|
</div>
|
|
241
|
-
|
|
332
|
+
)}
|
|
242
333
|
</div>
|
|
243
334
|
)
|
|
244
335
|
}
|
package/src/components/Row.js
CHANGED
|
@@ -17,7 +17,7 @@ const RowMenu = ({ rowIdx, row }) => {
|
|
|
17
17
|
let res = []
|
|
18
18
|
|
|
19
19
|
for (let i = 0; i < row.length; i++) {
|
|
20
|
-
if(row[i].width) res.push(row[i].width)
|
|
20
|
+
if (row[i].width) res.push(row[i].width)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return res.join('')
|
|
@@ -25,7 +25,7 @@ const RowMenu = ({ rowIdx, row }) => {
|
|
|
25
25
|
|
|
26
26
|
const [curr, setCurr] = useState(getCurr())
|
|
27
27
|
|
|
28
|
-
const setRowLayout =
|
|
28
|
+
const setRowLayout = layout => {
|
|
29
29
|
const newRows = [...rows]
|
|
30
30
|
const r = newRows[rowIdx]
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ const RowMenu = ({ rowIdx, row }) => {
|
|
|
33
33
|
r[i].width = layout[i] ?? null
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
updateConfig({ ...config, rows: newRows})
|
|
36
|
+
updateConfig({ ...config, rows: newRows })
|
|
37
37
|
setCurr(layout.join(''))
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -48,17 +48,17 @@ const RowMenu = ({ rowIdx, row }) => {
|
|
|
48
48
|
rows[newIdx] = row
|
|
49
49
|
rows[rowIdx] = temp
|
|
50
50
|
|
|
51
|
-
rows[newIdx].uuid = Date.now()
|
|
52
|
-
rows[rowIdx].uuid = Date.now()
|
|
51
|
+
rows[newIdx].uuid = Date.now()
|
|
52
|
+
rows[rowIdx].uuid = Date.now()
|
|
53
53
|
|
|
54
|
-
updateConfig({...config, rows})
|
|
54
|
+
updateConfig({ ...config, rows })
|
|
55
55
|
|
|
56
56
|
// TODO: Migrate this animation to a React animation library once one is selected for COVE. This is pretty minor so can stay for now.
|
|
57
57
|
let calcRowMove = dir === 'down' ? 202 : -202
|
|
58
58
|
let calcRowMove2 = dir === 'down' ? -202 : 202
|
|
59
59
|
|
|
60
|
-
let rowEle = document.querySelector(
|
|
61
|
-
let rowNewEle = document.querySelector(
|
|
60
|
+
let rowEle = document.querySelector("[data-row-id='" + rowIdx + "']")
|
|
61
|
+
let rowNewEle = document.querySelector("[data-row-id='" + newIdx + "']")
|
|
62
62
|
|
|
63
63
|
rowEle.style.pointerEvents = 'none'
|
|
64
64
|
rowNewEle.style.pointerEvents = 'none'
|
|
@@ -77,62 +77,63 @@ const RowMenu = ({ rowIdx, row }) => {
|
|
|
77
77
|
rowNewEle.style = null
|
|
78
78
|
}, 500)
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
|
|
81
81
|
const deleteRow = () => {
|
|
82
82
|
rows.splice(rowIdx, 1) // Just delete the row. Don't delete the instantiated widgets for now.
|
|
83
83
|
|
|
84
|
-
updateConfig({...config, rows})
|
|
84
|
+
updateConfig({ ...config, rows })
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const layoutList = [
|
|
88
|
-
<li className={curr === '12' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([
|
|
88
|
+
<li className={curr === '12' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([12])} key='12' title='1 Column'>
|
|
89
89
|
<OneColIcon />
|
|
90
90
|
</li>,
|
|
91
|
-
<li className={curr === '66' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([
|
|
91
|
+
<li className={curr === '66' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([6, 6])} key='66' title='2 Columns'>
|
|
92
92
|
<TwoColIcon />
|
|
93
93
|
</li>,
|
|
94
|
-
<li className={curr === '444' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([
|
|
94
|
+
<li className={curr === '444' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([4, 4, 4])} key='444' title='3 Columns'>
|
|
95
95
|
<ThreeColIcon />
|
|
96
96
|
</li>,
|
|
97
|
-
<li className={curr === '48' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([
|
|
97
|
+
<li className={curr === '48' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([4, 8])} key='48' title='2 Columns'>
|
|
98
98
|
<FourEightColIcon />
|
|
99
99
|
</li>,
|
|
100
|
-
<li className={curr === '84' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([
|
|
100
|
+
<li className={curr === '84' ? `current row-menu__list--item` : `row-menu__list--item`} onClick={() => setRowLayout([8, 4])} key='84' title='2 Columns'>
|
|
101
101
|
<EightFourColIcon />
|
|
102
102
|
</li>
|
|
103
103
|
]
|
|
104
104
|
|
|
105
105
|
return (
|
|
106
|
-
<nav className=
|
|
107
|
-
<div className=
|
|
108
|
-
<ul className=
|
|
109
|
-
{layoutList}
|
|
110
|
-
</ul>
|
|
106
|
+
<nav className='row-menu'>
|
|
107
|
+
<div className='row-menu__btn'>
|
|
108
|
+
<ul className='row-menu__flyout'>{layoutList}</ul>
|
|
111
109
|
</div>
|
|
112
|
-
<div className=
|
|
113
|
-
<button className={rowIdx === 0 ? 'row-menu__btn row-menu__btn-disabled' : 'row-menu__btn'} title=
|
|
110
|
+
<div className='spacer'></div>
|
|
111
|
+
<button className={rowIdx === 0 ? 'row-menu__btn row-menu__btn-disabled' : 'row-menu__btn'} title='Move Row Up' onClick={() => moveRow('up')}>
|
|
114
112
|
<RowUp />
|
|
115
113
|
</button>
|
|
116
|
-
<button className={rowIdx + 1 === rows.length ? 'row-menu__btn row-menu__btn-disabled' : 'row-menu__btn'} title=
|
|
114
|
+
<button className={rowIdx + 1 === rows.length ? 'row-menu__btn row-menu__btn-disabled' : 'row-menu__btn'} title='Move Row Down' onClick={() => moveRow('down')}>
|
|
117
115
|
<RowDown />
|
|
118
116
|
</button>
|
|
119
|
-
<button className={rowIdx === 0 && rows.length === 1 ? 'row-menu__btn row-menu__btn--remove row-menu__btn-disabled' : 'row-menu__btn row-menu__btn--remove'} title=
|
|
117
|
+
<button className={rowIdx === 0 && rows.length === 1 ? 'row-menu__btn row-menu__btn--remove row-menu__btn-disabled' : 'row-menu__btn row-menu__btn--remove'} title='Delete Row' onClick={deleteRow}>
|
|
120
118
|
<CloseIcon />
|
|
121
119
|
</button>
|
|
122
120
|
</nav>
|
|
123
121
|
)
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
const Row = ({ row, idx: rowIdx, uuid}) => {
|
|
124
|
+
const Row = ({ row, idx: rowIdx, uuid }) => {
|
|
127
125
|
return (
|
|
128
|
-
<div className=
|
|
126
|
+
<div className='builder-row' data-row-id={rowIdx}>
|
|
129
127
|
<RowMenu rowIdx={rowIdx} row={row} />
|
|
130
|
-
<div className=
|
|
131
|
-
{row
|
|
128
|
+
<div className='column-container'>
|
|
129
|
+
{row
|
|
130
|
+
.filter(column => column.width)
|
|
131
|
+
.map((column, colIdx) => (
|
|
132
|
+
<Column data={column} key={`row-${uuid}-col-${colIdx}`} rowIdx={rowIdx} colIdx={colIdx} />
|
|
133
|
+
))}
|
|
132
134
|
</div>
|
|
133
135
|
</div>
|
|
134
136
|
)
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
export default Row
|
|
138
|
-
|