@cdc/core 4.24.3 → 4.24.5
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-command.svg +3 -0
- package/assets/icon-rotate-left.svg +3 -0
- package/components/AdvancedEditor.jsx +9 -0
- package/components/DataTable/DataTable.tsx +20 -15
- package/components/DataTable/DataTableStandAlone.tsx +51 -4
- package/components/DataTable/components/ChartHeader.tsx +3 -2
- package/components/DataTable/components/DataTableEditorPanel.tsx +20 -3
- package/components/DataTable/components/ExpandCollapse.tsx +22 -16
- package/components/DataTable/helpers/chartCellMatrix.tsx +3 -2
- package/components/DataTable/helpers/getChartCellValue.ts +21 -1
- package/components/DataTable/helpers/getDataSeriesColumns.ts +37 -16
- package/components/DataTable/helpers/getSeriesName.ts +2 -1
- package/components/DataTable/helpers/mapCellMatrix.tsx +2 -2
- package/components/DataTable/helpers/{customColumns.ts → removeNullColumns.ts} +3 -3
- package/components/DataTable/types/TableConfig.ts +11 -21
- package/components/EditorPanel/ColumnsEditor.tsx +304 -260
- package/components/EditorPanel/DataTableEditor.tsx +119 -48
- package/components/EditorPanel/VizFilterEditor.tsx +234 -0
- package/components/EditorWrapper/EditorWrapper.tsx +48 -0
- package/components/EditorWrapper/editor-wrapper.style.css +14 -0
- package/components/Filters.jsx +78 -61
- package/components/Layout/components/Responsive.tsx +184 -0
- package/components/Layout/components/Sidebar/components/Sidebar.tsx +47 -0
- package/components/Layout/components/Sidebar/components/sidebar.styles.scss +902 -0
- package/components/Layout/components/Sidebar/index.tsx +3 -0
- package/components/Layout/components/Visualization/index.tsx +81 -0
- package/components/Layout/components/Visualization/visualizations.scss +33 -0
- package/components/Layout/index.tsx +11 -0
- package/components/Layout/styles/editor-grid-view.scss +156 -0
- package/components/Layout/styles/editor-utils.scss +197 -0
- package/components/Layout/styles/editor.scss +144 -0
- package/components/LegendCircle.jsx +4 -3
- package/components/MediaControls.jsx +1 -1
- package/components/Table/Table.tsx +7 -5
- package/components/Table/components/Row.tsx +6 -2
- package/components/Table/types/RowType.ts +3 -0
- package/components/Waiting.jsx +11 -1
- package/components/_stories/DataTable.stories.tsx +1 -2
- package/components/_stories/EditorPanel.stories.tsx +1 -0
- package/components/createBarElement.jsx +37 -34
- package/components/elements/SkipTo.tsx +37 -5
- package/components/managers/DataDesigner.tsx +18 -18
- package/components/ui/Icon.tsx +5 -1
- package/helpers/DataTransform.ts +9 -32
- package/helpers/coveUpdateWorker.ts +21 -0
- package/helpers/footnoteSymbols.ts +11 -0
- package/helpers/useDataVizClasses.js +1 -5
- package/helpers/ver/4.23.4.ts +27 -0
- package/helpers/ver/4.24.3.ts +56 -0
- package/helpers/ver/4.24.5.ts +32 -0
- package/package.json +2 -2
- package/styles/_data-table.scss +8 -0
- package/styles/_global.scss +7 -4
- package/styles/_reset.scss +7 -6
- package/styles/_variables.scss +3 -0
- package/styles/base.scss +0 -18
- package/styles/v2/base/index.scss +1 -1
- package/styles/v2/components/ui/tooltip.scss +0 -21
- package/types/Axis.ts +4 -0
- package/types/Column.ts +1 -0
- package/types/ConfigureData.ts +8 -0
- package/types/DataDescription.ts +9 -0
- package/types/Legend.ts +1 -0
- package/types/MarkupInclude.ts +26 -0
- package/types/Runtime.ts +1 -0
- package/types/Series.ts +1 -1
- package/types/Table.ts +15 -13
- package/types/Visualization.ts +14 -10
- package/types/VizFilter.ts +13 -0
- package/helpers/coveUpdateWorker.js +0 -19
- package/helpers/ver/4.23.js +0 -10
- package/helpers/ver/4.24.3.js +0 -25
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true" focusable="false" role="img" fill="currentColor">
|
|
2
|
+
<path d="M404.83356,297.97872H354.67715V214.177h50.15641a107.08854,107.08854,0,1,0,0-214.177C345.64284,0,297.51145,47.97571,297.82294,107.01074v50.46778H214.33287V107.01074A107.09452,107.09452,0,0,0,107.32225,0C47.97572,0,0,47.97571,0,107.01074c0,59.3464,48.28721,107.6336,107.32225,107.16629h50.15628v83.80169H107.32225C47.97572,297.97872,0,345.79862,0,404.83352a107.16644,107.16644,0,1,0,214.33287,0V354.83291h83.49007v50.00061a107.08879,107.08879,0,1,0,107.01062-106.8548ZM354.67715,106.85493a50.2348,50.2348,0,1,1,50.0006,50.46791h-50.0006ZM157.47853,404.83352a50.2348,50.2348,0,1,1-50.0006-50.00061h50.0006Zm0-247.51068h-50.0006a50.2348,50.2348,0,1,1,50.0006-50.46791ZM297.97862,297.97872H214.33287V214.33285h83.64575Zm106.69913,157.3227a50.15888,50.15888,0,0,1-50.0006-50.4679V354.83291h50.0006a50.2348,50.2348,0,1,1,0,100.46851Z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true" focusable="false" role="img" fill="currentColor">
|
|
2
|
+
<path d="M480 256c0 123.4-100.5 223.9-223.9 223.9c-48.84 0-95.17-15.58-134.2-44.86c-14.12-10.59-16.97-30.66-6.375-44.81c10.59-14.12 30.62-16.94 44.81-6.375c27.84 20.91 61 31.94 95.88 31.94C344.3 415.8 416 344.1 416 256s-71.69-159.8-159.8-159.8c-37.46 0-73.09 13.49-101.3 36.64l45.12 45.14c17.01 17.02 4.955 46.1-19.1 46.1H35.17C24.58 224.1 16 215.5 16 204.9V59.04c0-24.04 29.07-36.08 46.07-19.07l47.6 47.63C149.9 52.71 201.5 32.11 256.1 32.11C379.5 32.11 480 132.6 480 256z"/>
|
|
3
|
+
</svg>
|
|
@@ -51,6 +51,15 @@ export const AdvancedEditor = ({ loadConfig, state, convertStateToConfig }) => {
|
|
|
51
51
|
<p className='pb-2'>
|
|
52
52
|
This tool displays the actual <acronym title='JavaScript Object Notation'>JSON</acronym> configuration that is generated by this editor and allows you to edit properties directly and apply them.
|
|
53
53
|
</p>
|
|
54
|
+
<button
|
|
55
|
+
className='btn'
|
|
56
|
+
onClick={() => {
|
|
57
|
+
navigator.clipboard.writeText(configTextboxValue)
|
|
58
|
+
alert('Copied!')
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
Copy to Clipboard
|
|
62
|
+
</button>
|
|
54
63
|
<textarea value={configTextboxValue} onChange={event => setConfigTextbox(event.target.value)} />
|
|
55
64
|
<button className='btn full-width' onClick={() => loadConfig(JSON.parse(configTextboxValue))}>
|
|
56
65
|
Apply
|
|
@@ -16,7 +16,7 @@ import Table from '../Table'
|
|
|
16
16
|
import chartCellMatrix from './helpers/chartCellMatrix'
|
|
17
17
|
import regionCellMatrix from './helpers/regionCellMatrix'
|
|
18
18
|
import boxplotCellMatrix from './helpers/boxplotCellMatrix'
|
|
19
|
-
import
|
|
19
|
+
import removeNullColumns from './helpers/removeNullColumns'
|
|
20
20
|
import { TableConfig } from './types/TableConfig'
|
|
21
21
|
import { Column } from '../../types/Column'
|
|
22
22
|
|
|
@@ -44,7 +44,7 @@ export type DataTableProps = {
|
|
|
44
44
|
showDownloadButton?: boolean
|
|
45
45
|
tabbingId: string
|
|
46
46
|
tableTitle: string
|
|
47
|
-
viewport:
|
|
47
|
+
viewport: 'lg' | 'md' | 'sm' | 'xs' | 'xxs'
|
|
48
48
|
vizTitle?: string
|
|
49
49
|
// determines if columns should be wrapped in the table
|
|
50
50
|
wrapColumns?: boolean
|
|
@@ -52,7 +52,8 @@ export type DataTableProps = {
|
|
|
52
52
|
|
|
53
53
|
/* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
|
|
54
54
|
const DataTable = (props: DataTableProps) => {
|
|
55
|
-
const { config, dataConfig, tableTitle, vizTitle, rawData, runtimeData, headerColor, expandDataTable, columns, viewport, formatLegendLocation, tabbingId, wrapColumns } = props
|
|
55
|
+
const { config, dataConfig, tableTitle, vizTitle, rawData, runtimeData: parentRuntimeData, headerColor, expandDataTable, columns, viewport, formatLegendLocation, tabbingId, wrapColumns } = props
|
|
56
|
+
const runtimeData = removeNullColumns(parentRuntimeData)
|
|
56
57
|
const [expanded, setExpanded] = useState(expandDataTable)
|
|
57
58
|
|
|
58
59
|
const [sortBy, setSortBy] = useState<any>({ column: config.type === 'map' ? 'geo' : 'date', asc: false, colIndex: null })
|
|
@@ -98,25 +99,23 @@ const DataTable = (props: DataTableProps) => {
|
|
|
98
99
|
break
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const rawRows = Object.keys(_runtimeData).filter(column => column != 'columns')
|
|
102
|
+
const rawRows = Object.keys(runtimeData).filter(column => column != 'columns')
|
|
104
103
|
const rows = isVertical
|
|
105
104
|
? rawRows.sort((a, b) => {
|
|
106
105
|
let dataA
|
|
107
106
|
let dataB
|
|
108
107
|
if (config.type === 'map' && config.columns) {
|
|
109
108
|
const sortByColName = config.columns[sortBy.column].name
|
|
110
|
-
dataA =
|
|
111
|
-
dataB =
|
|
109
|
+
dataA = runtimeData[a][sortByColName]
|
|
110
|
+
dataB = runtimeData[b][sortByColName]
|
|
112
111
|
}
|
|
113
112
|
if (config.type === 'chart' || config.type === 'dashboard') {
|
|
114
|
-
dataA =
|
|
115
|
-
dataB =
|
|
113
|
+
dataA = runtimeData[a][sortBy.column]
|
|
114
|
+
dataB = runtimeData[b][sortBy.column]
|
|
116
115
|
}
|
|
117
116
|
if (!dataA && !dataB && config.type === 'chart' && config.xAxis && config.xAxis.type === 'date-time') {
|
|
118
|
-
dataA = timeParse(config.runtime.xAxis.dateParseFormat)(
|
|
119
|
-
dataB = timeParse(config.runtime.xAxis.dateParseFormat)(
|
|
117
|
+
dataA = timeParse(config.runtime.xAxis.dateParseFormat)(runtimeData[a][config.xAxis.dataKey])
|
|
118
|
+
dataB = timeParse(config.runtime.xAxis.dateParseFormat)(runtimeData[b][config.xAxis.dataKey])
|
|
120
119
|
}
|
|
121
120
|
return dataA && dataB ? customSort(dataA, dataB, sortBy, config) : 0
|
|
122
121
|
})
|
|
@@ -185,22 +184,25 @@ const DataTable = (props: DataTableProps) => {
|
|
|
185
184
|
</MediaControls.Section>
|
|
186
185
|
<section id={tabbingId.replace('#', '')} className={`data-table-container ${viewport}`} aria-label={accessibilityLabel}>
|
|
187
186
|
<SkipTo skipId={skipId} skipMessage='Skip Data Table' />
|
|
188
|
-
<ExpandCollapse expanded={expanded} setExpanded={setExpanded} tableTitle={tableTitle} />
|
|
187
|
+
{config.table.collapsible !== false && <ExpandCollapse expanded={expanded} setExpanded={setExpanded} fontSize={config.fontSize} tableTitle={tableTitle} viewport={viewport} />}
|
|
189
188
|
<div className='table-container' style={limitHeight}>
|
|
190
189
|
<Table
|
|
190
|
+
viewport={viewport}
|
|
191
191
|
wrapColumns={wrapColumns}
|
|
192
|
-
childrenMatrix={config.type === 'map' ? mapCellMatrix({ rows, wrapColumns, ...props, runtimeData
|
|
192
|
+
childrenMatrix={config.type === 'map' ? mapCellMatrix({ rows, wrapColumns, ...props, runtimeData, viewport }) : chartCellMatrix({ rows, ...props, runtimeData, isVertical, sortBy, hasRowType, viewport })}
|
|
193
193
|
tableName={config.type}
|
|
194
194
|
caption={caption}
|
|
195
195
|
stickyHeader
|
|
196
196
|
hasRowType={hasRowType}
|
|
197
|
-
headContent={config.type === 'map' ? <MapHeader columns={columns} {...props} sortBy={sortBy} setSortBy={setSortBy} /> : <ChartHeader data={
|
|
197
|
+
headContent={config.type === 'map' ? <MapHeader columns={columns} {...props} sortBy={sortBy} setSortBy={setSortBy} /> : <ChartHeader data={runtimeData} {...props} hasRowType={hasRowType} isVertical={isVertical} sortBy={sortBy} setSortBy={setSortBy} />}
|
|
198
198
|
tableOptions={{ className: `${expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'}${isVertical ? '' : ' horizontal'}`, 'aria-live': 'assertive', 'aria-rowcount': config?.data?.length ? config.data.length : -1, hidden: !expanded }}
|
|
199
|
+
fontSize={config.fontSize}
|
|
199
200
|
/>
|
|
200
201
|
|
|
201
202
|
{/* REGION Data Table */}
|
|
202
203
|
{noRelativeRegions && config.regions && config.regions.length > 0 && config.visualizationType !== 'Box Plot' && (
|
|
203
204
|
<Table
|
|
205
|
+
viewport={viewport}
|
|
204
206
|
wrapColumns={wrapColumns}
|
|
205
207
|
childrenMatrix={regionCellMatrix({ config })}
|
|
206
208
|
tableName={config.visualizationType}
|
|
@@ -213,6 +215,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
213
215
|
</tr>
|
|
214
216
|
}
|
|
215
217
|
tableOptions={{ className: 'region-table data-table' }}
|
|
218
|
+
fontSize={config.fontSize}
|
|
216
219
|
/>
|
|
217
220
|
)}
|
|
218
221
|
</div>
|
|
@@ -231,6 +234,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
231
234
|
<ExpandCollapse expanded={expanded} setExpanded={setExpanded} tableTitle={tableTitle} />
|
|
232
235
|
<div className='table-container' style={limitHeight}>
|
|
233
236
|
<Table
|
|
237
|
+
viewport={viewport}
|
|
234
238
|
wrapColumns={wrapColumns}
|
|
235
239
|
childrenMatrix={boxplotCellMatrix({ rows: tableData, config })}
|
|
236
240
|
tableName={config.visualizationType}
|
|
@@ -238,6 +242,7 @@ const DataTable = (props: DataTableProps) => {
|
|
|
238
242
|
stickyHeader
|
|
239
243
|
headContent={<BoxplotHeader categories={config.boxplot.categories} />}
|
|
240
244
|
tableOptions={{ className: `${expanded ? 'data-table' : 'data-table cdcdataviz-sr-only'}`, 'aria-live': 'assertive', 'aria-rowcount': 11, hidden: !expanded }}
|
|
245
|
+
fontSize={config.fontSize}
|
|
241
246
|
/>
|
|
242
247
|
</div>
|
|
243
248
|
</section>
|
|
@@ -1,15 +1,62 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
1
2
|
import { ViewPort } from '../../types/ViewPort'
|
|
2
|
-
import
|
|
3
|
+
import EditorWrapper from '../EditorWrapper/EditorWrapper'
|
|
3
4
|
import DataTable from './DataTable'
|
|
5
|
+
import DataTableEditorPanel from './components/DataTableEditorPanel'
|
|
6
|
+
import Filters from '../Filters'
|
|
7
|
+
import { TableConfig } from './types/TableConfig'
|
|
4
8
|
|
|
5
9
|
type StandAloneProps = {
|
|
6
10
|
visualizationKey: string
|
|
7
|
-
config:
|
|
11
|
+
config: TableConfig
|
|
8
12
|
viewport?: ViewPort
|
|
13
|
+
isEditor?: boolean
|
|
14
|
+
updateConfig?: (Visualization) => void
|
|
9
15
|
}
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
// filterData is copied from ./packages/chart/src/helpers/filterData.ts
|
|
18
|
+
// consider moving this to a shared location
|
|
19
|
+
const filterData = (filters, data) => {
|
|
20
|
+
if (!filters) return data
|
|
21
|
+
const filteredData: any[] = []
|
|
22
|
+
|
|
23
|
+
data.forEach(row => {
|
|
24
|
+
let add = true
|
|
25
|
+
filters
|
|
26
|
+
.filter(filter => filter.type !== 'url')
|
|
27
|
+
.forEach(filter => {
|
|
28
|
+
if (row[filter.columnName] != filter.active) {
|
|
29
|
+
add = false
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
if (add) filteredData.push(row)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return filteredData
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const DataTableStandAlone: React.FC<StandAloneProps> = ({ visualizationKey, config, updateConfig, viewport, isEditor }) => {
|
|
40
|
+
const [filteredData, setFilteredData] = useState<Record<string, any>[]>(filterData(config.filters, config.formattedData))
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
// when using editor changes to filter should update the data
|
|
44
|
+
setFilteredData(filterData(config.filters, config.formattedData))
|
|
45
|
+
}, [config.filters])
|
|
46
|
+
|
|
47
|
+
if (isEditor)
|
|
48
|
+
return (
|
|
49
|
+
<EditorWrapper component={DataTableStandAlone} visualizationKey={visualizationKey} visualizationConfig={config} updateConfig={updateConfig} type={'Table'} viewport={viewport}>
|
|
50
|
+
<DataTableEditorPanel key={visualizationKey} config={config} updateConfig={updateConfig} />
|
|
51
|
+
</EditorWrapper>
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<Filters config={config} setConfig={updateConfig} setFilteredData={setFilteredData} filterData={filterData} filteredData={filteredData} excludedData={config.formattedData} />
|
|
57
|
+
<DataTable expandDataTable={true} config={config} rawData={config.data} runtimeData={filteredData} tabbingId={visualizationKey} tableTitle={config.table.label} viewport={viewport || 'lg'} />
|
|
58
|
+
</>
|
|
59
|
+
)
|
|
13
60
|
}
|
|
14
61
|
|
|
15
62
|
export default DataTableStandAlone
|
|
@@ -4,9 +4,10 @@ import { getDataSeriesColumns } from '../helpers/getDataSeriesColumns'
|
|
|
4
4
|
import { DownIcon, UpIcon } from './Icons'
|
|
5
5
|
import ScreenReaderText from '@cdc/core/components/elements/ScreenReaderText'
|
|
6
6
|
|
|
7
|
-
type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy;
|
|
7
|
+
type ChartHeaderProps = { data; isVertical; config; setSortBy; sortBy; hasRowType? }
|
|
8
8
|
|
|
9
|
-
const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy,
|
|
9
|
+
const ChartHeader = ({ data, isVertical, config, setSortBy, sortBy, hasRowType }: ChartHeaderProps) => {
|
|
10
|
+
const groupBy = config.table?.groupBy
|
|
10
11
|
if (!data) return
|
|
11
12
|
let dataSeriesColumns = getDataSeriesColumns(config, isVertical, data)
|
|
12
13
|
if (groupBy) {
|
|
@@ -4,6 +4,8 @@ import { Visualization } from '@cdc/core/types/Visualization'
|
|
|
4
4
|
import { updateFieldFactory } from '@cdc/core/helpers/updateFieldFactory'
|
|
5
5
|
import { useMemo } from 'react'
|
|
6
6
|
import ColumnsEditor from '../../EditorPanel/ColumnsEditor'
|
|
7
|
+
import VizFilterEditor from '../../EditorPanel/VizFilterEditor'
|
|
8
|
+
import _ from 'lodash'
|
|
7
9
|
|
|
8
10
|
type DataTableEditorProps = {
|
|
9
11
|
config: Visualization
|
|
@@ -13,7 +15,7 @@ type DataTableEditorProps = {
|
|
|
13
15
|
const DataTableEditorPanel: React.FC<DataTableEditorProps> = ({ config, updateConfig }) => {
|
|
14
16
|
const updateField = useMemo(() => updateFieldFactory(config, updateConfig), [JSON.stringify(config)])
|
|
15
17
|
const deleteColumn = columnName => {
|
|
16
|
-
const newColumns = config.columns
|
|
18
|
+
const newColumns = _.cloneDeep(config.columns)
|
|
17
19
|
|
|
18
20
|
delete newColumns[columnName]
|
|
19
21
|
|
|
@@ -23,10 +25,25 @@ const DataTableEditorPanel: React.FC<DataTableEditorProps> = ({ config, updateCo
|
|
|
23
25
|
})
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
const columns = Object.keys(config.
|
|
28
|
+
const columns = Object.keys(config.originalFormattedData[0] || {})
|
|
27
29
|
return (
|
|
28
30
|
<>
|
|
29
|
-
<
|
|
31
|
+
<AccordionItem>
|
|
32
|
+
<AccordionItemHeading>
|
|
33
|
+
<AccordionItemButton>Filters</AccordionItemButton>
|
|
34
|
+
</AccordionItemHeading>
|
|
35
|
+
<AccordionItemPanel>
|
|
36
|
+
<VizFilterEditor config={config} updateField={updateField} rawData={config.originalFormattedData} />
|
|
37
|
+
</AccordionItemPanel>
|
|
38
|
+
</AccordionItem>
|
|
39
|
+
<AccordionItem>
|
|
40
|
+
<AccordionItemHeading>
|
|
41
|
+
<AccordionItemButton>Columns</AccordionItemButton>
|
|
42
|
+
</AccordionItemHeading>
|
|
43
|
+
<AccordionItemPanel>
|
|
44
|
+
<ColumnsEditor config={config} updateField={updateField} deleteColumn={deleteColumn} />
|
|
45
|
+
</AccordionItemPanel>
|
|
46
|
+
</AccordionItem>
|
|
30
47
|
<AccordionItem>
|
|
31
48
|
<AccordionItemHeading>
|
|
32
49
|
<AccordionItemButton>Data Table</AccordionItemButton>
|
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import Icon from '../../ui/Icon'
|
|
2
2
|
|
|
3
|
-
const ExpandCollapse = ({ expanded, setExpanded, tableTitle }) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
const ExpandCollapse = ({ expanded, setExpanded, tableTitle, fontSize, viewport }) => {
|
|
4
|
+
const fontSizes = { small: 16, medium: 18, large: 20 }
|
|
5
|
+
const titleFontSize = ['sm', 'xs', 'xxs'].includes(viewport) ? '13px' : `${fontSizes[fontSize]}px`
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
style={{ fontSize: titleFontSize }}
|
|
9
|
+
role='button'
|
|
10
|
+
className={expanded ? 'data-table-heading' : 'collapsed data-table-heading'}
|
|
11
|
+
onClick={() => {
|
|
12
12
|
setExpanded(!expanded)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
}}
|
|
14
|
+
tabIndex={0}
|
|
15
|
+
onKeyDown={e => {
|
|
16
|
+
if (e.keyCode === 13) {
|
|
17
|
+
setExpanded(!expanded)
|
|
18
|
+
}
|
|
19
|
+
}}
|
|
20
|
+
>
|
|
21
|
+
<Icon display={expanded ? 'minus' : 'plus'} base />
|
|
22
|
+
{tableTitle}
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
20
26
|
|
|
21
27
|
export default ExpandCollapse
|
|
@@ -15,7 +15,8 @@ type ChartRowsProps = DataTableProps & {
|
|
|
15
15
|
hasRowType?: boolean
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const chartCellArray = ({ rows, runtimeData, config, isVertical, sortBy, colorScale,
|
|
18
|
+
const chartCellArray = ({ rows, runtimeData, config, isVertical, sortBy, colorScale, hasRowType, viewport }: ChartRowsProps): CellMatrix | GroupCellMatrix => {
|
|
19
|
+
const groupBy = config.table?.groupBy
|
|
19
20
|
const dataSeriesColumns = getDataSeriesColumns(config, isVertical, runtimeData)
|
|
20
21
|
|
|
21
22
|
const dataSeriesColumnsSorted = () => {
|
|
@@ -79,7 +80,7 @@ const chartCellArray = ({ rows, runtimeData, config, isVertical, sortBy, colorSc
|
|
|
79
80
|
config.visualizationType !== 'Pie'
|
|
80
81
|
? [
|
|
81
82
|
<>
|
|
82
|
-
{colorScale && colorScale(seriesName) && <LegendCircle fill={colorScale(seriesName)} />}
|
|
83
|
+
{colorScale && colorScale(seriesName) && <LegendCircle viewport={viewport} fill={colorScale(seriesName)} />}
|
|
83
84
|
{seriesName}
|
|
84
85
|
</>
|
|
85
86
|
]
|
|
@@ -25,7 +25,7 @@ const isAdditionalColumn = (column, config) => {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const getChartCellValue = (row: string, column: string, config: TableConfig, runtimeData: Object[]) => {
|
|
28
|
-
if (config.
|
|
28
|
+
if (config.visualizationType === 'Sankey' || runtimeData?.[0]?.tableData) return runtimeData[row][column]
|
|
29
29
|
|
|
30
30
|
const rowObj = runtimeData[row]
|
|
31
31
|
let cellValue // placeholder for formatting below
|
|
@@ -54,5 +54,25 @@ export const getChartCellValue = (row: string, column: string, config: TableConf
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
// suppress cell value
|
|
58
|
+
config.preliminaryData?.forEach(pd => {
|
|
59
|
+
// check entered suppression value against cell value
|
|
60
|
+
const isValueMatch = String(pd.value) === String(labelValue)
|
|
61
|
+
// check entered suppression column against table key
|
|
62
|
+
const isColumnMatch = !pd.column || pd.column === column
|
|
63
|
+
if (isValueMatch && isColumnMatch && pd.displayTable && pd.type === 'suppression') {
|
|
64
|
+
switch (config.visualizationType) {
|
|
65
|
+
case 'Combo':
|
|
66
|
+
cellValue = config.runtime.barSeriesKeys.includes(column) ? pd.iconCode : config.runtime.lineSeriesKeys.includes(column) ? pd.lineCode : ''
|
|
67
|
+
break
|
|
68
|
+
case 'Bar':
|
|
69
|
+
cellValue = pd.iconCode
|
|
70
|
+
break
|
|
71
|
+
case 'Line':
|
|
72
|
+
cellValue = pd.lineCode
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
57
77
|
return cellValue
|
|
58
78
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { TableConfig } from '../types/TableConfig'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import { Column } from '../../../types/Column'
|
|
2
4
|
|
|
3
5
|
export const getDataSeriesColumns = (config: TableConfig, isVertical: boolean, runtimeData: Object[]): string[] => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return Object.keys(runtimeData[0]).filter(columnName => !excludeColumns.includes(columnName))
|
|
10
|
-
}
|
|
11
|
-
let tmpSeriesColumns
|
|
6
|
+
const configColumns: Record<string, Column> = _.cloneDeep(config.columns) || {}
|
|
7
|
+
const excludeColumns = Object.values(configColumns)
|
|
8
|
+
.filter(column => column.dataTable === false)
|
|
9
|
+
.map(column => column.name)
|
|
10
|
+
let tmpSeriesColumns: string[] = []
|
|
12
11
|
if (config.visualizationType !== 'Pie') {
|
|
13
12
|
tmpSeriesColumns = isVertical ? [config.xAxis?.dataKey] : [] //, ...config.runtime.seriesLabelsAll
|
|
14
13
|
if (config.series) {
|
|
@@ -23,15 +22,37 @@ export const getDataSeriesColumns = (config: TableConfig, isVertical: boolean, r
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
// then add the additional Columns
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
Object.keys(configColumns).forEach(function (key) {
|
|
26
|
+
var value = configColumns[key]
|
|
27
|
+
// add if not the index AND it is enabled to be added to data table
|
|
28
|
+
const alreadyAdded = tmpSeriesColumns.includes(value.name)
|
|
29
|
+
if (value.name !== config.xAxis?.dataKey && value.dataTable === true && !alreadyAdded) {
|
|
30
|
+
tmpSeriesColumns.push(value.name)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const columnOrderingHash = Object.values(configColumns).reduce((acc, column) => {
|
|
35
|
+
// subtract 1 to switch from cardinal positioning to index
|
|
36
|
+
if (column.order !== undefined) {
|
|
37
|
+
acc[column.name] = column.order - 1
|
|
38
|
+
}
|
|
39
|
+
return acc
|
|
40
|
+
}, {})
|
|
41
|
+
|
|
42
|
+
tmpSeriesColumns = tmpSeriesColumns.filter(columnName => !excludeColumns.includes(columnName))
|
|
43
|
+
|
|
44
|
+
tmpSeriesColumns.forEach((columnName, index) => {
|
|
45
|
+
if (columnOrderingHash[columnName] === undefined) {
|
|
46
|
+
if (Object.values(columnOrderingHash).includes(index)) {
|
|
47
|
+
// add 1 to place unsorted columns behind sorted columns
|
|
48
|
+
columnOrderingHash[columnName] = index + 1
|
|
49
|
+
} else {
|
|
50
|
+
columnOrderingHash[columnName] = index
|
|
32
51
|
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
tmpSeriesColumns.sort((a, b) => columnOrderingHash[a] - columnOrderingHash[b])
|
|
35
56
|
|
|
36
57
|
return tmpSeriesColumns
|
|
37
58
|
}
|
|
@@ -17,5 +17,6 @@ export const getSeriesName = (column: string, config: TableConfig) => {
|
|
|
17
17
|
}
|
|
18
18
|
if (config.runtimeSeriesLabels && config.runtimeSeriesLabels[column]) return config.runtimeSeriesLabels[column]
|
|
19
19
|
const columnIsDataKey = column === config.xAxis?.dataKey
|
|
20
|
-
|
|
20
|
+
const indexLabel = config.table?.indexLabel
|
|
21
|
+
return columnIsDataKey && indexLabel ? indexLabel : getLabel(column, config)
|
|
21
22
|
}
|
|
@@ -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 }: MapRowsProps): ReactNode[][] => {
|
|
10
|
+
const mapCellArray = ({ rows, columns, runtimeData, config, applyLegendToRow, displayGeoName, formatLegendLocation, displayDataAsText, navigationHandler, setFilteredCountryCode, viewport }: 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
|
-
<LegendCircle fill={legendColor[0]} />
|
|
34
|
+
<LegendCircle viewport={viewport} fill={legendColor[0]} />
|
|
35
35
|
<CellAnchor markup={labelValue} row={rowObj} columns={columns} navigationHandler={navigationHandler} mapZoomHandler={mapZoomHandler} />
|
|
36
36
|
</div>
|
|
37
37
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
type RuntimeData = Object[] & Record<string, Object>
|
|
2
2
|
|
|
3
3
|
// removes null and excluded columns
|
|
4
|
-
const
|
|
4
|
+
const removeNullColumns = (runtimeData: Object[] | RuntimeData): RuntimeData => {
|
|
5
5
|
if (!Array.isArray(runtimeData)) {
|
|
6
6
|
// currently we don't support Record types
|
|
7
7
|
return runtimeData
|
|
@@ -10,7 +10,7 @@ const customColumns = (runtimeData: Object[] | RuntimeData, excludeColumns: stri
|
|
|
10
10
|
runtimeData.forEach(row => {
|
|
11
11
|
Object.keys(row).forEach(key => {
|
|
12
12
|
if (runtimeDataMemo[key] === undefined) runtimeDataMemo[key] = null
|
|
13
|
-
if (row[key] !== null
|
|
13
|
+
if (row[key] !== null) runtimeDataMemo[key] = true
|
|
14
14
|
})
|
|
15
15
|
})
|
|
16
16
|
return runtimeData.map(d => {
|
|
@@ -24,4 +24,4 @@ const customColumns = (runtimeData: Object[] | RuntimeData, excludeColumns: stri
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export default
|
|
27
|
+
export default removeNullColumns
|
|
@@ -1,27 +1,17 @@
|
|
|
1
|
-
import { Axis } from '
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Table } from '@cdc/core/types/Table'
|
|
5
|
-
import { Region } from '@cdc/core/types/Region'
|
|
1
|
+
import { Axis } from '../../../types/Axis'
|
|
2
|
+
import { Runtime } from '../../../types/Runtime'
|
|
3
|
+
import { Region } from '../../../types/Region'
|
|
6
4
|
import { BoxPlot } from '../../../types/BoxPlot'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { Legend } from '@cdc/core/types/Legend'
|
|
5
|
+
import { PreliminaryDataItem } from '@cdc/chart/src/components/LineChart/LineChartProps'
|
|
6
|
+
import { Visualization } from '../../../types/Visualization'
|
|
10
7
|
|
|
11
|
-
export type TableConfig = {
|
|
12
|
-
type?: string
|
|
13
|
-
table: Table
|
|
14
|
-
xAxis?: Axis
|
|
15
|
-
yAxis?: Axis
|
|
8
|
+
export type TableConfig = Visualization & {
|
|
16
9
|
boxplot?: BoxPlot
|
|
17
|
-
|
|
18
|
-
general?: General
|
|
19
|
-
columns?: Record<string, Column>
|
|
20
|
-
legend?: Legend
|
|
21
|
-
series?: Series
|
|
10
|
+
fontSize: 'small' | 'medium' | 'large'
|
|
22
11
|
regions?: Region[]
|
|
23
|
-
runtimeSeriesLabels?: Object
|
|
24
|
-
dataFormat?: Object
|
|
25
12
|
runtime?: Runtime
|
|
26
|
-
|
|
13
|
+
runtimeSeriesLabels?: Object
|
|
14
|
+
xAxis?: Axis
|
|
15
|
+
yAxis?: Axis
|
|
16
|
+
preliminaryData: PreliminaryDataItem[]
|
|
27
17
|
}
|