@cdc/core 4.24.5 → 4.24.9
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/assets/icon-gear-multi.svg +23 -0
- package/components/AdvancedEditor/AdvancedEditor.tsx +93 -0
- package/components/AdvancedEditor/advanced-editor-styles.css +3 -0
- package/components/AdvancedEditor/index.ts +1 -0
- package/components/Alert/components/Alert.styles.css +15 -0
- package/components/Alert/components/Alert.tsx +39 -0
- package/components/Alert/index.tsx +3 -0
- package/components/DataTable/DataTable.tsx +127 -32
- package/components/DataTable/DataTableStandAlone.tsx +4 -25
- package/components/DataTable/components/DataTableEditorPanel.tsx +4 -4
- package/components/DataTable/components/ExpandCollapse.tsx +1 -1
- package/components/DataTable/helpers/chartCellMatrix.tsx +6 -12
- package/components/DataTable/helpers/getChartCellValue.ts +9 -5
- package/components/DataTable/helpers/getDataSeriesColumns.ts +10 -7
- package/components/DataTable/helpers/getRowType.ts +6 -0
- package/components/DataTable/helpers/mapCellMatrix.tsx +3 -3
- package/components/DataTable/types/TableConfig.ts +2 -1
- package/components/EditorPanel/ColumnsEditor.tsx +3 -30
- package/components/EditorPanel/DataTableEditor.tsx +66 -22
- package/components/EditorPanel/FieldSetWrapper.tsx +51 -0
- package/components/EditorPanel/FootnotesEditor.tsx +77 -0
- package/components/EditorPanel/Inputs.tsx +13 -4
- package/components/EditorPanel/VizFilterEditor/NestedDropdownEditor.tsx +268 -0
- package/components/EditorPanel/VizFilterEditor/VizFilterEditor.tsx +306 -0
- package/components/EditorPanel/VizFilterEditor/components/FilterOrder.tsx +40 -0
- package/components/EditorPanel/VizFilterEditor/index.ts +1 -0
- package/components/EditorWrapper/EditorWrapper.tsx +3 -4
- package/components/EditorWrapper/index.ts +1 -0
- package/components/Filters.tsx +520 -0
- package/components/Footnotes/Footnotes.tsx +25 -0
- package/components/Footnotes/FootnotesStandAlone.tsx +45 -0
- package/components/Footnotes/footnotes.css +5 -0
- package/components/Footnotes/index.ts +1 -0
- package/components/Layout/components/Responsive.tsx +14 -4
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +14 -5
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +23 -20
- package/components/Layout/components/Visualization/index.tsx +19 -6
- package/components/Layout/components/Visualization/visualizations.scss +32 -26
- package/components/Layout/styles/editor.scss +0 -8
- package/components/Legend/Legend.Gradient.tsx +133 -0
- package/components/LegendShape.tsx +28 -0
- package/components/MultiSelect/MultiSelect.tsx +41 -11
- package/components/MultiSelect/multiselect.styles.css +0 -3
- package/components/NestedDropdown/NestedDropdown.tsx +47 -52
- package/components/NestedDropdown/nesteddropdown.styles.css +19 -25
- package/components/Table/Table.tsx +8 -5
- package/components/Table/components/Cell.tsx +2 -2
- package/components/Table/components/Row.tsx +25 -7
- package/components/_stories/Footnotes.stories.tsx +17 -0
- package/components/_stories/Layout.Debug.stories.tsx +91 -0
- package/components/_stories/_mocks/bar-chart-suppressed.json +474 -0
- package/components/_stories/styles.scss +14 -1
- package/components/createBarElement.jsx +4 -4
- package/components/inputs/InputSelect.tsx +17 -6
- package/components/ui/Icon.tsx +22 -16
- package/components/ui/Title/Title.scss +0 -8
- package/helpers/DataTransform.ts +2 -2
- package/helpers/addValuesToFilters.ts +135 -0
- package/helpers/cove/accessibility.ts +17 -4
- package/helpers/cove/fontSettings.ts +2 -0
- package/helpers/coveUpdateWorker.ts +30 -9
- package/helpers/filterVizData.ts +49 -0
- package/helpers/formatConfigBeforeSave.ts +95 -0
- package/helpers/gatherQueryParams.ts +14 -7
- package/helpers/getGradientLegendWidth.ts +15 -0
- package/helpers/getTextWidth.ts +18 -0
- package/helpers/lineChartHelpers.js +2 -1
- package/helpers/pivotData.ts +18 -0
- package/helpers/queryStringUtils.ts +29 -0
- package/helpers/scaling.ts +7 -0
- package/helpers/tests/addValuesToFilters.test.ts +55 -0
- package/helpers/tests/filterVizData.test.ts +31 -0
- package/helpers/tests/invertValue.test.ts +35 -0
- package/helpers/tests/updateFieldFactory.test.ts +1 -0
- package/helpers/updateFieldFactory.ts +1 -1
- package/helpers/updatePaletteNames.ts +19 -0
- package/helpers/{useDataVizClasses.js → useDataVizClasses.ts} +3 -2
- package/helpers/ver/4.24.5.ts +3 -3
- package/helpers/ver/4.24.7.ts +123 -0
- package/helpers/ver/4.24.9.ts +63 -0
- package/helpers/ver/tests/4.24.9.test.ts +22 -0
- package/helpers/ver/versionNeedsUpdate.ts +9 -0
- package/package.json +6 -4
- package/styles/_button-section.scss +7 -2
- package/styles/_data-table.scss +0 -1
- package/styles/_global.scss +6 -2
- package/styles/base.scss +4 -0
- package/styles/filters.scss +4 -0
- package/styles/v2/themes/_color-definitions.scss +1 -0
- package/types/Annotation.ts +46 -0
- package/types/Axis.ts +3 -2
- package/types/ConfigureData.ts +1 -1
- package/types/Dimensions.ts +1 -0
- package/types/Footnotes.ts +17 -0
- package/types/General.ts +5 -0
- package/types/Runtime.ts +2 -7
- package/types/Table.ts +6 -0
- package/types/Visualization.ts +31 -9
- package/types/VizFilter.ts +39 -7
- package/LICENSE +0 -201
- package/components/AdvancedEditor.jsx +0 -74
- package/components/EditorPanel/VizFilterEditor.tsx +0 -234
- package/components/Filters.jsx +0 -461
- package/components/LegendCircle.jsx +0 -17
- package/helpers/queryStringUtils.js +0 -26
- package/helpers/updatePaletteNames.js +0 -16
- package/types/BaseVisualizationType.ts +0 -1
- /package/components/{Waiting.jsx → Waiting.tsx} +0 -0
- /package/helpers/ver/{4.23.4.ts → 4.24.4.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import LegendShape from '@cdc/core/components/LegendShape'
|
|
2
2
|
import CellAnchor from '../components/CellAnchor'
|
|
3
3
|
import { DataTableProps } from '../DataTable'
|
|
4
4
|
import { ReactNode } from 'react'
|
|
@@ -7,7 +7,7 @@ type MapRowsProps = DataTableProps & {
|
|
|
7
7
|
rows: string[]
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const mapCellArray = ({ rows, columns, runtimeData, config, applyLegendToRow, displayGeoName, formatLegendLocation, displayDataAsText, navigationHandler, setFilteredCountryCode
|
|
10
|
+
const mapCellArray = ({ rows, columns, runtimeData, config, applyLegendToRow, displayGeoName, formatLegendLocation, displayDataAsText, navigationHandler, setFilteredCountryCode }: MapRowsProps): ReactNode[][] => {
|
|
11
11
|
return rows.map(row =>
|
|
12
12
|
Object.keys(columns)
|
|
13
13
|
.filter(column => columns[column].dataTable === true && columns[column].name)
|
|
@@ -31,7 +31,7 @@ const mapCellArray = ({ rows, columns, runtimeData, config, applyLegendToRow, di
|
|
|
31
31
|
}
|
|
32
32
|
cellValue = (
|
|
33
33
|
<div className='col-12'>
|
|
34
|
-
<
|
|
34
|
+
<LegendShape fill={legendColor[0]} />
|
|
35
35
|
<CellAnchor markup={labelValue} row={rowObj} columns={columns} navigationHandler={navigationHandler} mapZoomHandler={mapZoomHandler} />
|
|
36
36
|
</div>
|
|
37
37
|
)
|
|
@@ -2,7 +2,7 @@ import { Axis } from '../../../types/Axis'
|
|
|
2
2
|
import { Runtime } from '../../../types/Runtime'
|
|
3
3
|
import { Region } from '../../../types/Region'
|
|
4
4
|
import { BoxPlot } from '../../../types/BoxPlot'
|
|
5
|
-
import { PreliminaryDataItem } from '@cdc/chart/src/
|
|
5
|
+
import { type PreliminaryDataItem } from '@cdc/chart/src/types/ChartConfig'
|
|
6
6
|
import { Visualization } from '../../../types/Visualization'
|
|
7
7
|
|
|
8
8
|
export type TableConfig = Visualization & {
|
|
@@ -14,4 +14,5 @@ export type TableConfig = Visualization & {
|
|
|
14
14
|
xAxis?: Axis
|
|
15
15
|
yAxis?: Axis
|
|
16
16
|
preliminaryData: PreliminaryDataItem[]
|
|
17
|
+
brush: { active: boolean }
|
|
17
18
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AccordionItem, AccordionItemButton, AccordionItemHeading, AccordionItemPanel } from 'react-accessible-accordion'
|
|
2
1
|
import Tooltip from '../ui/Tooltip'
|
|
3
2
|
import Icon from '../ui/Icon'
|
|
4
3
|
import { TextField } from './Inputs'
|
|
@@ -7,6 +6,7 @@ import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
|
|
|
7
6
|
import { Column } from '../../types/Column'
|
|
8
7
|
import _ from 'lodash'
|
|
9
8
|
import React, { useState } from 'react'
|
|
9
|
+
import FieldSetWrapper from './FieldSetWrapper'
|
|
10
10
|
|
|
11
11
|
interface ColumnsEditorProps {
|
|
12
12
|
config: Partial<Visualization>
|
|
@@ -18,10 +18,6 @@ type OpenControls = [Record<string, boolean>, Function] // useState type
|
|
|
18
18
|
|
|
19
19
|
const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenControls }> = ({ config, deleteColumn, updateField, colKey, controls }) => {
|
|
20
20
|
const [openControls, setOpenControls] = controls
|
|
21
|
-
const show = openControls[colKey]
|
|
22
|
-
const setShow = (key, value) => {
|
|
23
|
-
setOpenControls({ ...openControls, [key]: value })
|
|
24
|
-
}
|
|
25
21
|
|
|
26
22
|
const editColumn = (key, value) => {
|
|
27
23
|
if (key === 'dataTable' && value === true) {
|
|
@@ -66,31 +62,8 @@ const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenCo
|
|
|
66
62
|
|
|
67
63
|
const colName = config.columns[colKey]?.name
|
|
68
64
|
|
|
69
|
-
if (!show)
|
|
70
|
-
return (
|
|
71
|
-
<div className='mb-1'>
|
|
72
|
-
<button onClick={() => setShow(colKey, true)}>
|
|
73
|
-
<Icon display='caretDown' />
|
|
74
|
-
</button>
|
|
75
|
-
<span> {colName ? `${colName}` : 'New Column'}</span>
|
|
76
|
-
</div>
|
|
77
|
-
)
|
|
78
65
|
return (
|
|
79
|
-
<
|
|
80
|
-
<div className='d-flex justify-content-between'>
|
|
81
|
-
<button onClick={() => setShow(colKey, false)}>
|
|
82
|
-
<Icon display='caretUp' />
|
|
83
|
-
</button>
|
|
84
|
-
<button
|
|
85
|
-
className='btn btn-danger btn-sm'
|
|
86
|
-
onClick={event => {
|
|
87
|
-
event.preventDefault()
|
|
88
|
-
deleteColumn(colKey)
|
|
89
|
-
}}
|
|
90
|
-
>
|
|
91
|
-
Remove
|
|
92
|
-
</button>
|
|
93
|
-
</div>
|
|
66
|
+
<FieldSetWrapper fieldName={colName} fieldKey={colKey} fieldType='Column' controls={controls} deleteField={() => deleteColumn(colKey)}>
|
|
94
67
|
<label>
|
|
95
68
|
<span className='edit-label column-heading'>Column</span>
|
|
96
69
|
<select
|
|
@@ -231,7 +204,7 @@ const FieldSet: React.FC<ColumnsEditorProps & { colKey: string; controls: OpenCo
|
|
|
231
204
|
<span className='edit-label column-heading'>Order</span>
|
|
232
205
|
<input onWheel={e => e.currentTarget.blur()} type='number' min='1' value={config.columns[colKey].order} onChange={e => updateField('columns', colKey, 'order', parseInt(e.target.value))} />
|
|
233
206
|
</label>
|
|
234
|
-
</
|
|
207
|
+
</FieldSetWrapper>
|
|
235
208
|
)
|
|
236
209
|
}
|
|
237
210
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react'
|
|
2
2
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
3
3
|
import Icon from '../ui/Icon'
|
|
4
|
-
import { CheckBox, TextField } from './Inputs'
|
|
4
|
+
import { CheckBox, TextField, Select } from './Inputs'
|
|
5
5
|
import MultiSelect from '../MultiSelect'
|
|
6
6
|
import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
|
|
7
7
|
import { Visualization } from '../../types/Visualization'
|
|
@@ -26,15 +26,13 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
26
26
|
.map(([key]) => key)
|
|
27
27
|
}, [config.columns])
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const groupPivotColumns = useMemo(() => {
|
|
30
30
|
const columns: string[] = config.data.flatMap(Object.keys)
|
|
31
|
-
const configuredColumns = Object.values(config.columns).map(col => col.name)
|
|
32
31
|
const cols = _.uniq(columns).filter(key => {
|
|
33
|
-
if (configuredColumns.includes(key)) return false
|
|
34
32
|
return true
|
|
35
33
|
})
|
|
36
34
|
return cols
|
|
37
|
-
}
|
|
35
|
+
}, [config.data])
|
|
38
36
|
|
|
39
37
|
const changeGroupBy = (value: string) => {
|
|
40
38
|
if (value === PLACEHOLDER) value = undefined
|
|
@@ -123,6 +121,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
123
121
|
}
|
|
124
122
|
/>
|
|
125
123
|
)}
|
|
124
|
+
|
|
126
125
|
{config.type !== 'table' && (
|
|
127
126
|
<TextField
|
|
128
127
|
value={config.table.indexLabel}
|
|
@@ -163,7 +162,7 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
163
162
|
/>
|
|
164
163
|
<CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label=' Limit Table Height' updateField={updateField} />
|
|
165
164
|
{config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min={0} max={500} placeholder='Height(px)' updateField={updateField} />}
|
|
166
|
-
<MultiSelect key={excludedColumns.join('') + 'excluded'} options={dataColumns.map(c => ({ label: c, value: c }))} selected={excludedColumns} fieldName='dataTable' label='Exclude Columns' section='columns' updateField={excludeColumns} />
|
|
165
|
+
{config?.visualizationType !== 'Sankey' && <MultiSelect key={excludedColumns.join('') + 'excluded'} options={dataColumns.map(c => ({ label: c, value: c }))} selected={excludedColumns} fieldName='dataTable' label='Exclude Columns' section='columns' updateField={excludeColumns} />}
|
|
167
166
|
<CheckBox value={config.table.collapsible} fieldName='collapsible' label=' Collapsible' section='table' updateField={updateField} />
|
|
168
167
|
{config.table.collapsible !== false && <CheckBox value={config.table.expanded} fieldName='expanded' label=' Expanded by Default' section='table' updateField={updateField} />}
|
|
169
168
|
{isDashboard && config.type !== 'table' && <CheckBox value={config.table.showDataTableLink} fieldName='showDataTableLink' label='Show Data Table Name & Link' section='table' updateField={updateField} />}
|
|
@@ -173,29 +172,74 @@ const DataTableEditor: React.FC<DataTableProps> = ({ config, updateField, isDash
|
|
|
173
172
|
<span className='edit-label column-heading'>Table Cell Min Width</span>
|
|
174
173
|
<input type='number' value={config.table.cellMinWidth ? config.table.cellMinWidth : 0} onChange={e => updateField('table', null, 'cellMinWidth', e.target.value)} />
|
|
175
174
|
</label>
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
175
|
+
{config?.visualizationType !== 'Sankey' && (
|
|
176
|
+
<label>
|
|
177
|
+
<span className='edit-label column-heading'>
|
|
178
|
+
Group By{' '}
|
|
179
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
180
|
+
<Tooltip.Target>
|
|
181
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
182
|
+
</Tooltip.Target>
|
|
183
|
+
<Tooltip.Content>
|
|
184
|
+
<p>Choose a column to use for grouping data rows. The selected column will not be shown in the data table. You will only be able to choose a column which does not have a column configuration.</p>
|
|
185
|
+
</Tooltip.Content>
|
|
186
|
+
</Tooltip>
|
|
187
|
+
</span>
|
|
188
|
+
|
|
189
|
+
<select
|
|
190
|
+
value={config.table.groupBy}
|
|
191
|
+
onChange={event => {
|
|
192
|
+
changeGroupBy(event.target.value)
|
|
193
|
+
}}
|
|
194
|
+
>
|
|
195
|
+
{[PLACEHOLDER, ...groupPivotColumns.filter(col => col !== config.table.pivot?.columnName && col !== config.table.pivot?.valueColumn)].map(option => (
|
|
196
|
+
<option key={option}>{option}</option>
|
|
197
|
+
))}
|
|
198
|
+
</select>
|
|
199
|
+
</label>
|
|
200
|
+
)}
|
|
201
|
+
<Select
|
|
202
|
+
label='Pivot Column: '
|
|
203
|
+
tooltip={
|
|
179
204
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
180
205
|
<Tooltip.Target>
|
|
181
206
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
182
207
|
</Tooltip.Target>
|
|
183
208
|
<Tooltip.Content>
|
|
184
|
-
<p>
|
|
209
|
+
<p>Select a Column whos data values will be pivoted to Column Values.</p>
|
|
185
210
|
</Tooltip.Content>
|
|
186
211
|
</Tooltip>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
}
|
|
213
|
+
value={config.table.pivot?.columnName}
|
|
214
|
+
options={groupPivotColumns.filter(col => col !== config.table.groupBy && col !== config.table.pivot?.valueColumn)}
|
|
215
|
+
initial='-Select-'
|
|
216
|
+
section='table'
|
|
217
|
+
subsection='pivot'
|
|
218
|
+
fieldName='columnName'
|
|
219
|
+
updateField={updateField}
|
|
220
|
+
/>
|
|
221
|
+
{config.table.pivot?.columnName && (
|
|
222
|
+
<Select
|
|
223
|
+
label='Pivot Value Column: '
|
|
224
|
+
tooltip={
|
|
225
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
226
|
+
<Tooltip.Target>
|
|
227
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
228
|
+
</Tooltip.Target>
|
|
229
|
+
<Tooltip.Content>
|
|
230
|
+
<p>The column whos values will be pivoted under the column selected as the Filter.</p>
|
|
231
|
+
</Tooltip.Content>
|
|
232
|
+
</Tooltip>
|
|
233
|
+
}
|
|
234
|
+
value={config.table.pivot?.valueColumn}
|
|
235
|
+
initial='-Select-'
|
|
236
|
+
section='table'
|
|
237
|
+
options={groupPivotColumns.filter(col => col !== config.table.pivot?.columnName && col !== config.table.groupBy)}
|
|
238
|
+
subsection='pivot'
|
|
239
|
+
fieldName='valueColumn'
|
|
240
|
+
updateField={updateField}
|
|
241
|
+
/>
|
|
242
|
+
)}
|
|
199
243
|
</>
|
|
200
244
|
)
|
|
201
245
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Icon from '../ui/Icon'
|
|
2
|
+
|
|
3
|
+
type OpenControls = [Record<string, boolean>, Function] // useState type
|
|
4
|
+
|
|
5
|
+
type FieldSetProps = {
|
|
6
|
+
fieldName: string
|
|
7
|
+
fieldKey: string | number
|
|
8
|
+
fieldType: string
|
|
9
|
+
controls: OpenControls
|
|
10
|
+
deleteField: Function
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const FieldSet: React.FC<FieldSetProps> = ({ fieldName, fieldKey, fieldType, controls, deleteField, children }) => {
|
|
15
|
+
const [openControls, setOpenControls] = controls
|
|
16
|
+
const show = openControls[fieldKey]
|
|
17
|
+
const setShow = (key, value) => {
|
|
18
|
+
setOpenControls({ ...openControls, [key]: value })
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!show)
|
|
22
|
+
return (
|
|
23
|
+
<div className='mb-1'>
|
|
24
|
+
<button onClick={() => setShow(fieldKey, true)}>
|
|
25
|
+
<Icon display='caretDown' />
|
|
26
|
+
</button>
|
|
27
|
+
<span> {fieldName ? `${fieldName}` : 'New ' + fieldType}</span>
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
return (
|
|
31
|
+
<fieldset className='edit-block mb-1' key={fieldKey}>
|
|
32
|
+
<div className='d-flex justify-content-between'>
|
|
33
|
+
<button onClick={() => setShow(fieldKey, false)}>
|
|
34
|
+
<Icon display='caretUp' />
|
|
35
|
+
</button>
|
|
36
|
+
<button
|
|
37
|
+
className='btn btn-danger btn-sm'
|
|
38
|
+
onClick={event => {
|
|
39
|
+
event.preventDefault()
|
|
40
|
+
deleteField()
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
Remove
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
{children}
|
|
47
|
+
</fieldset>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default FieldSet
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { UpdateFieldFunc } from '../../types/UpdateFieldFunc'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import Footnotes, { Footnote } from '../../types/Footnotes'
|
|
4
|
+
import { footnotesSymbols } from '../../helpers/footnoteSymbols'
|
|
5
|
+
import InputSelect from '../inputs/InputSelect'
|
|
6
|
+
import { TextField } from './Inputs'
|
|
7
|
+
interface FootnotesEditorProps {
|
|
8
|
+
config: Footnotes
|
|
9
|
+
updateField: UpdateFieldFunc<Footnote[]>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const FootnotesEditor: React.FC<FootnotesEditorProps> = ({ config, updateField }) => {
|
|
13
|
+
const addStaticFootnote = () => {
|
|
14
|
+
const newStaticNotes = [...(config.staticFootnotes || []), { text: 'Add Footnote Text' }]
|
|
15
|
+
updateField(null, null, 'staticFootnotes', newStaticNotes)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const updateStaticFootnote = (footnoteIndex, footnoteUpdate: Footnote) => {
|
|
19
|
+
const footnoteCopy = _.cloneDeep(config.staticFootnotes)
|
|
20
|
+
footnoteCopy[footnoteIndex] = footnoteUpdate
|
|
21
|
+
updateField(null, null, 'staticFootnotes', footnoteCopy)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const deleteStaticFootnote = footnoteIndex => {
|
|
25
|
+
const footnoteCopy = _.cloneDeep(config.staticFootnotes)
|
|
26
|
+
footnoteCopy.splice(footnoteIndex, 1)
|
|
27
|
+
updateField(null, null, 'staticFootnotes', footnoteCopy)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const getOptions = (opts: string[]) => {
|
|
31
|
+
return [['', '--Select--']].concat(opts.map(key => [key, key]))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const datasets = config.datasets || {}
|
|
35
|
+
|
|
36
|
+
const dataColumns = config.dataKey ? getOptions(Object.keys(datasets[config.dataKey]?.data?.[0] || {})) : []
|
|
37
|
+
const dataSetOptions = getOptions(Object.keys(datasets))
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<em>Dynamic Footnotes</em>
|
|
41
|
+
<div className='row border p-2'>
|
|
42
|
+
<InputSelect label='Select a Footnote Dataset' value={config.dataKey} options={dataSetOptions} fieldName='dataKey' updateField={updateField} />
|
|
43
|
+
|
|
44
|
+
{config.dataKey && (
|
|
45
|
+
<div className='p-3'>
|
|
46
|
+
<InputSelect label='Footnote Symbol Column' value={config.dynamicFootnotes?.symbolColumn} options={dataColumns} section='dynamicFootnotes' fieldName='symbolColumn' updateField={updateField} />
|
|
47
|
+
<InputSelect label='Footnote Text Column' value={config.dynamicFootnotes?.textColumn} options={dataColumns} section='dynamicFootnotes' fieldName='textColumn' updateField={updateField} />
|
|
48
|
+
<InputSelect label='Footnote Order Column' value={config.dynamicFootnotes?.orderColumn} options={dataColumns} section='dynamicFootnotes' fieldName='orderColumn' updateField={updateField} />
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<hr />
|
|
54
|
+
|
|
55
|
+
<em>Static Footnotes</em>
|
|
56
|
+
|
|
57
|
+
{config.staticFootnotes?.map((note, index) => (
|
|
58
|
+
<div key={index} className='row border p-2'>
|
|
59
|
+
<div className='col-8'>
|
|
60
|
+
<InputSelect label='Symbol' value={note.symbol} options={[['', '--Select--'], ...footnotesSymbols]} fieldName='symbol' updateField={(section, subsection, fieldName, value) => updateStaticFootnote(index, { ...note, symbol: value })} />{' '}
|
|
61
|
+
<TextField label='Text' value={note.text} fieldName='text' updateField={(section, subsection, fieldName, value) => updateStaticFootnote(index, { ...note, text: value })} />
|
|
62
|
+
</div>
|
|
63
|
+
<div className='col-2 ml-4'>
|
|
64
|
+
<button className='btn btn-danger p-1' onClick={() => deleteStaticFootnote(index)}>
|
|
65
|
+
Delete
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
))}
|
|
70
|
+
<button className='btn btn-primary' onClick={addStaticFootnote}>
|
|
71
|
+
Add Static Footnote
|
|
72
|
+
</button>
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default FootnotesEditor
|
|
@@ -9,6 +9,7 @@ export type Input = {
|
|
|
9
9
|
subsection?: any
|
|
10
10
|
updateField?: Function
|
|
11
11
|
fieldName?: string
|
|
12
|
+
display?: boolean
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export type TextFieldProps = {
|
|
@@ -39,7 +40,7 @@ export type SelectProps = {
|
|
|
39
40
|
} & Input
|
|
40
41
|
|
|
41
42
|
const TextField = memo((props: TextFieldProps) => {
|
|
42
|
-
const { label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'text', i = null, min = null, ...attributes } = props
|
|
43
|
+
const { display = true, label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'text', i = null, min = null, ...attributes } = props
|
|
43
44
|
const [value, setValue] = useState(stateValue)
|
|
44
45
|
const [debouncedValue] = useDebounce(value, 500)
|
|
45
46
|
|
|
@@ -76,6 +77,9 @@ const TextField = memo((props: TextFieldProps) => {
|
|
|
76
77
|
if ('date' === type) {
|
|
77
78
|
formElement = <input type='date' name={name} onChange={onChange} {...attributes} value={value} />
|
|
78
79
|
}
|
|
80
|
+
if (!display) {
|
|
81
|
+
return <></>
|
|
82
|
+
}
|
|
79
83
|
|
|
80
84
|
return (
|
|
81
85
|
<label>
|
|
@@ -89,8 +93,10 @@ const TextField = memo((props: TextFieldProps) => {
|
|
|
89
93
|
})
|
|
90
94
|
|
|
91
95
|
const CheckBox = memo((props: CheckboxProps) => {
|
|
92
|
-
const { label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes } = props
|
|
93
|
-
|
|
96
|
+
const { display = true, label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes } = props
|
|
97
|
+
if (!display) {
|
|
98
|
+
return <></>
|
|
99
|
+
}
|
|
94
100
|
return (
|
|
95
101
|
<label className='checkbox column-heading'>
|
|
96
102
|
<input
|
|
@@ -111,7 +117,7 @@ const CheckBox = memo((props: CheckboxProps) => {
|
|
|
111
117
|
})
|
|
112
118
|
|
|
113
119
|
const Select = memo((props: SelectProps) => {
|
|
114
|
-
const { label, value, options, fieldName, section = null, subsection = null, required = false, tooltip, updateField, initial: initialValue, ...attributes } = props
|
|
120
|
+
const { display = true, label, value, options, fieldName, section = null, subsection = null, required = false, tooltip, updateField, initial: initialValue, ...attributes } = props
|
|
115
121
|
let optionsJsx = options.map((optionName, index) => (
|
|
116
122
|
<option value={optionName} key={index}>
|
|
117
123
|
{optionName}
|
|
@@ -125,6 +131,9 @@ const Select = memo((props: SelectProps) => {
|
|
|
125
131
|
</option>
|
|
126
132
|
)
|
|
127
133
|
}
|
|
134
|
+
if (!display) {
|
|
135
|
+
return <></>
|
|
136
|
+
}
|
|
128
137
|
|
|
129
138
|
return (
|
|
130
139
|
<label>
|