@cdc/dashboard 4.25.5-1 → 4.25.6-1
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/LICENSE +201 -0
- package/dist/cdcdashboard.js +77779 -77245
- package/examples/special-classes.json +54340 -0
- package/package.json +9 -9
- package/src/CdcDashboardComponent.tsx +36 -214
- package/src/_stories/_mock/api-filter-map.json +1 -0
- package/src/components/CollapsibleVisualizationRow.tsx +2 -4
- package/src/components/DashboardEditors.tsx +143 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +205 -205
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +286 -287
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +198 -198
- package/src/components/Header/Header.tsx +7 -9
- package/src/components/Row.tsx +1 -24
- package/src/components/VisualizationRow.tsx +190 -213
- package/src/helpers/getVizConfig.ts +93 -80
- package/src/helpers/getVizRowColumnLocator.ts +0 -1
- package/src/helpers/reloadURLHelpers.ts +10 -13
- package/src/store/dashboard.actions.ts +61 -64
- package/src/store/dashboard.reducer.ts +0 -11
- package/src/types/ConfigRow.ts +0 -1
- package/src/types/Dashboard.ts +1 -1
- package/src/types/DashboardConfig.ts +1 -1
- package/src/types/DataSet.ts +0 -12
|
@@ -1,198 +1,198 @@
|
|
|
1
|
-
import { useContext, useState } from 'react'
|
|
2
|
-
import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
|
|
3
|
-
import Filters from './DashboardFilters'
|
|
4
|
-
import { changeFilterActive } from '../../helpers/changeFilterActive'
|
|
5
|
-
import _ from 'lodash'
|
|
6
|
-
import { FilterBehavior } from '../../helpers/FilterBehavior'
|
|
7
|
-
import { getFilteredData } from '../../helpers/getFilteredData'
|
|
8
|
-
import { DashboardFilters } from '../../types/DashboardFilters'
|
|
9
|
-
import { getQueryParams, updateQueryString } from '@cdc/core/helpers/queryStringUtils'
|
|
10
|
-
import Layout from '@cdc/core/components/Layout'
|
|
11
|
-
import DashboardFiltersEditor from './DashboardFiltersEditor'
|
|
12
|
-
import { ViewPort } from '@cdc/core/types/ViewPort'
|
|
13
|
-
import { hasDashboardApplyBehavior } from '../../helpers/hasDashboardApplyBehavior'
|
|
14
|
-
import * as apiFilterHelpers from '../../helpers/apiFilterHelpers'
|
|
15
|
-
import { applyQueuedActive } from '@cdc/core/components/Filters/helpers/applyQueuedActive'
|
|
16
|
-
import './dashboardfilter.styles.css'
|
|
17
|
-
import { updateChildFilters } from '../../helpers/updateChildFilters'
|
|
18
|
-
|
|
19
|
-
type SubOptions = { subOptions?: Record<'value' | 'text', string>[] }
|
|
20
|
-
|
|
21
|
-
export type DropdownOptions = (Record<'value' | 'text', string> & SubOptions)[]
|
|
22
|
-
|
|
23
|
-
/** the cached dropdown options for each filter */
|
|
24
|
-
export type APIFilterDropdowns = {
|
|
25
|
-
// null means still loading
|
|
26
|
-
[dropdownsKey: string]: null | DropdownOptions
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
type DashboardFiltersProps = {
|
|
30
|
-
apiFilterDropdowns: APIFilterDropdowns
|
|
31
|
-
visualizationConfig: DashboardFilters
|
|
32
|
-
isEditor?: boolean
|
|
33
|
-
setConfig: (config: DashboardFilters) => void
|
|
34
|
-
currentViewport?: ViewPort
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const DashboardFiltersWrapper: React.FC<DashboardFiltersProps> = ({
|
|
38
|
-
apiFilterDropdowns,
|
|
39
|
-
visualizationConfig,
|
|
40
|
-
setConfig: updateConfig,
|
|
41
|
-
currentViewport,
|
|
42
|
-
isEditor = false
|
|
43
|
-
}) => {
|
|
44
|
-
const state = useContext(DashboardContext)
|
|
45
|
-
const { config: dashboardConfig, reloadURLData, loadAPIFilters, setAPIFilterDropdowns, setAPILoading } = state
|
|
46
|
-
const dispatch = useContext(DashboardDispatchContext)
|
|
47
|
-
|
|
48
|
-
const applyFilters = e => {
|
|
49
|
-
e.preventDefault() // prevent form submission
|
|
50
|
-
const dashboardConfig = _.cloneDeep(state.config.dashboard)
|
|
51
|
-
const nonAutoLoadFilterIndexes = Object.values(state.config.visualizations)
|
|
52
|
-
.filter(v => v.type === 'dashboardFilters')
|
|
53
|
-
.reduce((acc, viz: DashboardFilters) => (!viz.autoLoad ? [...acc, viz.sharedFilterIndexes] : acc), [])
|
|
54
|
-
const allRequiredFiltersSelected = !dashboardConfig.sharedFilters.some((filter, filterIndex) => {
|
|
55
|
-
if (nonAutoLoadFilterIndexes.includes(filterIndex)) {
|
|
56
|
-
return !filter.active && !filter.queuedActive
|
|
57
|
-
} else {
|
|
58
|
-
// autoload filters don't need to be selected to apply filters
|
|
59
|
-
return false
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
if (allRequiredFiltersSelected) {
|
|
63
|
-
if (hasDashboardApplyBehavior(state.config.visualizations)) {
|
|
64
|
-
const queryParams = getQueryParams()
|
|
65
|
-
let needsQueryUpdate = false
|
|
66
|
-
dashboardConfig.sharedFilters.forEach(sharedFilter => {
|
|
67
|
-
if (sharedFilter.queuedActive) applyQueuedActive(sharedFilter)
|
|
68
|
-
if (
|
|
69
|
-
sharedFilter.setByQueryParameter &&
|
|
70
|
-
queryParams[sharedFilter.setByQueryParameter] !== sharedFilter.active
|
|
71
|
-
) {
|
|
72
|
-
queryParams[sharedFilter.setByQueryParameter] = Array.isArray(sharedFilter.active)
|
|
73
|
-
? sharedFilter.active.join(',')
|
|
74
|
-
: sharedFilter.active
|
|
75
|
-
needsQueryUpdate = true
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
if (needsQueryUpdate) {
|
|
80
|
-
updateQueryString(queryParams)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
setAPILoading(true)
|
|
84
|
-
dispatch({ type: 'SET_SHARED_FILTERS', payload: dashboardConfig.sharedFilters })
|
|
85
|
-
dispatch({ type: 'SET_FILTERED_DATA', payload: getFilteredData(_.cloneDeep(state)) })
|
|
86
|
-
loadAPIFilters(dashboardConfig.sharedFilters, apiFilterDropdowns)
|
|
87
|
-
.then(newFilters => {
|
|
88
|
-
reloadURLData(newFilters)
|
|
89
|
-
})
|
|
90
|
-
.catch(e => {
|
|
91
|
-
console.error(e)
|
|
92
|
-
})
|
|
93
|
-
} else {
|
|
94
|
-
// TODO noftify of required fields
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const handleOnChange = (index: number, value: string | string[]) => {
|
|
99
|
-
const newConfig = _.cloneDeep(dashboardConfig)
|
|
100
|
-
let [newSharedFilters, changedFilterIndexes] = changeFilterActive(
|
|
101
|
-
index,
|
|
102
|
-
value,
|
|
103
|
-
newConfig.dashboard.sharedFilters,
|
|
104
|
-
visualizationConfig
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
// sets the active filter option that the user just selected.
|
|
108
|
-
dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
|
|
109
|
-
|
|
110
|
-
if (hasDashboardApplyBehavior(dashboardConfig.visualizations)) {
|
|
111
|
-
const isAutoSelectFilter = visualizationConfig.autoLoad
|
|
112
|
-
const missingFilterSelections = newConfig.dashboard.sharedFilters.some(f => !f.active)
|
|
113
|
-
const apiEndpoints = newSharedFilters.filter(f => f.apiFilter).map(f => f.apiFilter.apiEndpoint)
|
|
114
|
-
const loadingFilterMemo = apiFilterHelpers.getLoadingFilterMemo(
|
|
115
|
-
apiEndpoints,
|
|
116
|
-
apiFilterDropdowns,
|
|
117
|
-
changedFilterIndexes
|
|
118
|
-
)
|
|
119
|
-
if (isAutoSelectFilter && !missingFilterSelections) {
|
|
120
|
-
// a dropdown has been selected that doesn't
|
|
121
|
-
// require the Go Button
|
|
122
|
-
setAPIFilterDropdowns(loadingFilterMemo)
|
|
123
|
-
loadAPIFilters(newSharedFilters, loadingFilterMemo).then(filters => {
|
|
124
|
-
reloadURLData(filters)
|
|
125
|
-
})
|
|
126
|
-
} else {
|
|
127
|
-
newSharedFilters[index].queuedActive = value
|
|
128
|
-
// setData to empty object because we no longer have a data state.
|
|
129
|
-
dispatch({ type: 'SET_DATA', payload: {} })
|
|
130
|
-
dispatch({ type: 'SET_FILTERED_DATA', payload: {} })
|
|
131
|
-
setAPIFilterDropdowns(loadingFilterMemo)
|
|
132
|
-
loadAPIFilters(newSharedFilters, loadingFilterMemo)
|
|
133
|
-
}
|
|
134
|
-
} else {
|
|
135
|
-
if (newSharedFilters[index].type === 'urlfilter' && newSharedFilters[index].apiFilter) {
|
|
136
|
-
reloadURLData(newSharedFilters)
|
|
137
|
-
} else {
|
|
138
|
-
const clonedState = _.cloneDeep(state)
|
|
139
|
-
clonedState.config.dashboard.sharedFilters = newSharedFilters
|
|
140
|
-
const newFilteredData = getFilteredData(clonedState)
|
|
141
|
-
dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
|
|
142
|
-
dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const [displayPanel, setDisplayPanel] = useState(true)
|
|
147
|
-
const onBackClick = () => {
|
|
148
|
-
setDisplayPanel(!displayPanel)
|
|
149
|
-
updateConfig({
|
|
150
|
-
...visualizationConfig,
|
|
151
|
-
showEditorPanel: !displayPanel
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// if all of the filters are hidden filters don't display the VisualizationWrapper
|
|
156
|
-
const filters = visualizationConfig?.sharedFilterIndexes
|
|
157
|
-
?.map(Number)
|
|
158
|
-
.map(filterIndex => dashboardConfig.dashboard.sharedFilters[filterIndex])
|
|
159
|
-
|
|
160
|
-
const displayNone = filters.length ? filters.every(filter => filter.showDropdown === false) : false
|
|
161
|
-
if (displayNone && !isEditor) return <></>
|
|
162
|
-
return (
|
|
163
|
-
<Layout.VisualizationWrapper config={visualizationConfig} isEditor={isEditor} currentViewport={currentViewport}>
|
|
164
|
-
{isEditor && (
|
|
165
|
-
<Layout.Sidebar
|
|
166
|
-
displayPanel={displayPanel}
|
|
167
|
-
isDashboard={true}
|
|
168
|
-
title={'Configure Dashboard Filters'}
|
|
169
|
-
onBackClick={onBackClick}
|
|
170
|
-
>
|
|
171
|
-
<DashboardFiltersEditor updateConfig={updateConfig} vizConfig={visualizationConfig} />
|
|
172
|
-
</Layout.Sidebar>
|
|
173
|
-
)}
|
|
174
|
-
|
|
175
|
-
{!displayNone && (
|
|
176
|
-
<Layout.Responsive isEditor={isEditor}>
|
|
177
|
-
<div
|
|
178
|
-
className={`${
|
|
179
|
-
isEditor ? ' is-editor' : ''
|
|
180
|
-
} cove-component__content col-12 cove-dashboard-filters-container`}
|
|
181
|
-
>
|
|
182
|
-
<Filters
|
|
183
|
-
show={visualizationConfig?.sharedFilterIndexes?.map(Number)}
|
|
184
|
-
filters={updateChildFilters(dashboardConfig.dashboard.sharedFilters, state.data) || []}
|
|
185
|
-
apiFilterDropdowns={apiFilterDropdowns}
|
|
186
|
-
handleOnChange={handleOnChange}
|
|
187
|
-
showSubmit={visualizationConfig.filterBehavior === FilterBehavior.Apply && !visualizationConfig.autoLoad}
|
|
188
|
-
applyFilters={applyFilters}
|
|
189
|
-
applyFiltersButtonText={visualizationConfig.applyFiltersButtonText}
|
|
190
|
-
/>
|
|
191
|
-
</div>
|
|
192
|
-
</Layout.Responsive>
|
|
193
|
-
)}
|
|
194
|
-
</Layout.VisualizationWrapper>
|
|
195
|
-
)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export default DashboardFiltersWrapper
|
|
1
|
+
import { useContext, useState } from 'react'
|
|
2
|
+
import { DashboardContext, DashboardDispatchContext } from '../../DashboardContext'
|
|
3
|
+
import Filters from './DashboardFilters'
|
|
4
|
+
import { changeFilterActive } from '../../helpers/changeFilterActive'
|
|
5
|
+
import _ from 'lodash'
|
|
6
|
+
import { FilterBehavior } from '../../helpers/FilterBehavior'
|
|
7
|
+
import { getFilteredData } from '../../helpers/getFilteredData'
|
|
8
|
+
import { DashboardFilters } from '../../types/DashboardFilters'
|
|
9
|
+
import { getQueryParams, updateQueryString } from '@cdc/core/helpers/queryStringUtils'
|
|
10
|
+
import Layout from '@cdc/core/components/Layout'
|
|
11
|
+
import DashboardFiltersEditor from './DashboardFiltersEditor'
|
|
12
|
+
import { ViewPort } from '@cdc/core/types/ViewPort'
|
|
13
|
+
import { hasDashboardApplyBehavior } from '../../helpers/hasDashboardApplyBehavior'
|
|
14
|
+
import * as apiFilterHelpers from '../../helpers/apiFilterHelpers'
|
|
15
|
+
import { applyQueuedActive } from '@cdc/core/components/Filters/helpers/applyQueuedActive'
|
|
16
|
+
import './dashboardfilter.styles.css'
|
|
17
|
+
import { updateChildFilters } from '../../helpers/updateChildFilters'
|
|
18
|
+
|
|
19
|
+
type SubOptions = { subOptions?: Record<'value' | 'text', string>[] }
|
|
20
|
+
|
|
21
|
+
export type DropdownOptions = (Record<'value' | 'text', string> & SubOptions)[]
|
|
22
|
+
|
|
23
|
+
/** the cached dropdown options for each filter */
|
|
24
|
+
export type APIFilterDropdowns = {
|
|
25
|
+
// null means still loading
|
|
26
|
+
[dropdownsKey: string]: null | DropdownOptions
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type DashboardFiltersProps = {
|
|
30
|
+
apiFilterDropdowns: APIFilterDropdowns
|
|
31
|
+
visualizationConfig: DashboardFilters
|
|
32
|
+
isEditor?: boolean
|
|
33
|
+
setConfig: (config: DashboardFilters) => void
|
|
34
|
+
currentViewport?: ViewPort
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DashboardFiltersWrapper: React.FC<DashboardFiltersProps> = ({
|
|
38
|
+
apiFilterDropdowns,
|
|
39
|
+
visualizationConfig,
|
|
40
|
+
setConfig: updateConfig,
|
|
41
|
+
currentViewport,
|
|
42
|
+
isEditor = false
|
|
43
|
+
}) => {
|
|
44
|
+
const state = useContext(DashboardContext)
|
|
45
|
+
const { config: dashboardConfig, reloadURLData, loadAPIFilters, setAPIFilterDropdowns, setAPILoading } = state
|
|
46
|
+
const dispatch = useContext(DashboardDispatchContext)
|
|
47
|
+
|
|
48
|
+
const applyFilters = e => {
|
|
49
|
+
e.preventDefault() // prevent form submission
|
|
50
|
+
const dashboardConfig = _.cloneDeep(state.config.dashboard)
|
|
51
|
+
const nonAutoLoadFilterIndexes = Object.values(state.config.visualizations)
|
|
52
|
+
.filter(v => v.type === 'dashboardFilters')
|
|
53
|
+
.reduce((acc, viz: DashboardFilters) => (!viz.autoLoad ? [...acc, viz.sharedFilterIndexes] : acc), [])
|
|
54
|
+
const allRequiredFiltersSelected = !dashboardConfig.sharedFilters.some((filter, filterIndex) => {
|
|
55
|
+
if (nonAutoLoadFilterIndexes.includes(filterIndex)) {
|
|
56
|
+
return !filter.active && !filter.queuedActive
|
|
57
|
+
} else {
|
|
58
|
+
// autoload filters don't need to be selected to apply filters
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
if (allRequiredFiltersSelected) {
|
|
63
|
+
if (hasDashboardApplyBehavior(state.config.visualizations)) {
|
|
64
|
+
const queryParams = getQueryParams()
|
|
65
|
+
let needsQueryUpdate = false
|
|
66
|
+
dashboardConfig.sharedFilters.forEach(sharedFilter => {
|
|
67
|
+
if (sharedFilter.queuedActive) applyQueuedActive(sharedFilter)
|
|
68
|
+
if (
|
|
69
|
+
sharedFilter.setByQueryParameter &&
|
|
70
|
+
queryParams[sharedFilter.setByQueryParameter] !== sharedFilter.active
|
|
71
|
+
) {
|
|
72
|
+
queryParams[sharedFilter.setByQueryParameter] = Array.isArray(sharedFilter.active)
|
|
73
|
+
? sharedFilter.active.join(',')
|
|
74
|
+
: sharedFilter.active
|
|
75
|
+
needsQueryUpdate = true
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
if (needsQueryUpdate) {
|
|
80
|
+
updateQueryString(queryParams)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
setAPILoading(true)
|
|
84
|
+
dispatch({ type: 'SET_SHARED_FILTERS', payload: dashboardConfig.sharedFilters })
|
|
85
|
+
dispatch({ type: 'SET_FILTERED_DATA', payload: getFilteredData(_.cloneDeep(state)) })
|
|
86
|
+
loadAPIFilters(dashboardConfig.sharedFilters, apiFilterDropdowns)
|
|
87
|
+
.then(newFilters => {
|
|
88
|
+
reloadURLData(newFilters)
|
|
89
|
+
})
|
|
90
|
+
.catch(e => {
|
|
91
|
+
console.error(e)
|
|
92
|
+
})
|
|
93
|
+
} else {
|
|
94
|
+
// TODO noftify of required fields
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const handleOnChange = (index: number, value: string | string[]) => {
|
|
99
|
+
const newConfig = _.cloneDeep(dashboardConfig)
|
|
100
|
+
let [newSharedFilters, changedFilterIndexes] = changeFilterActive(
|
|
101
|
+
index,
|
|
102
|
+
value,
|
|
103
|
+
newConfig.dashboard.sharedFilters,
|
|
104
|
+
visualizationConfig
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
// sets the active filter option that the user just selected.
|
|
108
|
+
dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
|
|
109
|
+
|
|
110
|
+
if (hasDashboardApplyBehavior(dashboardConfig.visualizations)) {
|
|
111
|
+
const isAutoSelectFilter = visualizationConfig.autoLoad
|
|
112
|
+
const missingFilterSelections = newConfig.dashboard.sharedFilters.some(f => !f.active)
|
|
113
|
+
const apiEndpoints = newSharedFilters.filter(f => f.apiFilter).map(f => f.apiFilter.apiEndpoint)
|
|
114
|
+
const loadingFilterMemo = apiFilterHelpers.getLoadingFilterMemo(
|
|
115
|
+
apiEndpoints,
|
|
116
|
+
apiFilterDropdowns,
|
|
117
|
+
changedFilterIndexes
|
|
118
|
+
)
|
|
119
|
+
if (isAutoSelectFilter && !missingFilterSelections) {
|
|
120
|
+
// a dropdown has been selected that doesn't
|
|
121
|
+
// require the Go Button
|
|
122
|
+
setAPIFilterDropdowns(loadingFilterMemo)
|
|
123
|
+
loadAPIFilters(newSharedFilters, loadingFilterMemo).then(filters => {
|
|
124
|
+
reloadURLData(filters)
|
|
125
|
+
})
|
|
126
|
+
} else {
|
|
127
|
+
newSharedFilters[index].queuedActive = value
|
|
128
|
+
// setData to empty object because we no longer have a data state.
|
|
129
|
+
dispatch({ type: 'SET_DATA', payload: {} })
|
|
130
|
+
dispatch({ type: 'SET_FILTERED_DATA', payload: {} })
|
|
131
|
+
setAPIFilterDropdowns(loadingFilterMemo)
|
|
132
|
+
loadAPIFilters(newSharedFilters, loadingFilterMemo)
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
if (newSharedFilters[index].type === 'urlfilter' && newSharedFilters[index].apiFilter) {
|
|
136
|
+
reloadURLData(newSharedFilters)
|
|
137
|
+
} else {
|
|
138
|
+
const clonedState = _.cloneDeep(state)
|
|
139
|
+
clonedState.config.dashboard.sharedFilters = newSharedFilters
|
|
140
|
+
const newFilteredData = getFilteredData(clonedState)
|
|
141
|
+
dispatch({ type: 'SET_FILTERED_DATA', payload: newFilteredData })
|
|
142
|
+
dispatch({ type: 'SET_SHARED_FILTERS', payload: newSharedFilters })
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const [displayPanel, setDisplayPanel] = useState(true)
|
|
147
|
+
const onBackClick = () => {
|
|
148
|
+
setDisplayPanel(!displayPanel)
|
|
149
|
+
updateConfig({
|
|
150
|
+
...visualizationConfig,
|
|
151
|
+
showEditorPanel: !displayPanel
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// if all of the filters are hidden filters don't display the VisualizationWrapper
|
|
156
|
+
const filters = visualizationConfig?.sharedFilterIndexes
|
|
157
|
+
?.map(Number)
|
|
158
|
+
.map(filterIndex => dashboardConfig.dashboard.sharedFilters[filterIndex])
|
|
159
|
+
|
|
160
|
+
const displayNone = filters.length ? filters.every(filter => filter.showDropdown === false) : false
|
|
161
|
+
if (displayNone && !isEditor) return <></>
|
|
162
|
+
return (
|
|
163
|
+
<Layout.VisualizationWrapper config={visualizationConfig} isEditor={isEditor} currentViewport={currentViewport}>
|
|
164
|
+
{isEditor && (
|
|
165
|
+
<Layout.Sidebar
|
|
166
|
+
displayPanel={displayPanel}
|
|
167
|
+
isDashboard={true}
|
|
168
|
+
title={'Configure Dashboard Filters'}
|
|
169
|
+
onBackClick={onBackClick}
|
|
170
|
+
>
|
|
171
|
+
<DashboardFiltersEditor updateConfig={updateConfig} vizConfig={visualizationConfig} />
|
|
172
|
+
</Layout.Sidebar>
|
|
173
|
+
)}
|
|
174
|
+
|
|
175
|
+
{!displayNone && (
|
|
176
|
+
<Layout.Responsive isEditor={isEditor}>
|
|
177
|
+
<div
|
|
178
|
+
className={`${
|
|
179
|
+
isEditor ? ' is-editor' : ''
|
|
180
|
+
} cove-component__content col-12 cove-dashboard-filters-container`}
|
|
181
|
+
>
|
|
182
|
+
<Filters
|
|
183
|
+
show={visualizationConfig?.sharedFilterIndexes?.map(Number)}
|
|
184
|
+
filters={updateChildFilters(dashboardConfig.dashboard.sharedFilters, state.data) || []}
|
|
185
|
+
apiFilterDropdowns={apiFilterDropdowns}
|
|
186
|
+
handleOnChange={handleOnChange}
|
|
187
|
+
showSubmit={visualizationConfig.filterBehavior === FilterBehavior.Apply && !visualizationConfig.autoLoad}
|
|
188
|
+
applyFilters={applyFilters}
|
|
189
|
+
applyFiltersButtonText={visualizationConfig.applyFiltersButtonText}
|
|
190
|
+
/>
|
|
191
|
+
</div>
|
|
192
|
+
</Layout.Responsive>
|
|
193
|
+
)}
|
|
194
|
+
</Layout.VisualizationWrapper>
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export default DashboardFiltersWrapper
|
|
@@ -9,7 +9,7 @@ import _ from 'lodash'
|
|
|
9
9
|
|
|
10
10
|
type HeaderProps = {
|
|
11
11
|
back?: any
|
|
12
|
-
subEditor?:
|
|
12
|
+
subEditor?: boolean
|
|
13
13
|
visualizationKey?: string
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -96,14 +96,12 @@ const Header = (props: HeaderProps) => {
|
|
|
96
96
|
multidashboard
|
|
97
97
|
</span>
|
|
98
98
|
<br />
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/>
|
|
106
|
-
}
|
|
99
|
+
<input
|
|
100
|
+
type='text'
|
|
101
|
+
placeholder='Enter Dashboard Name Here'
|
|
102
|
+
defaultValue={config.dashboard?.title}
|
|
103
|
+
onChange={e => changeConfigValue('dashboard', 'title', e.target.value)}
|
|
104
|
+
/>
|
|
107
105
|
</div>
|
|
108
106
|
)}
|
|
109
107
|
{!subEditor && (
|
package/src/components/Row.tsx
CHANGED
|
@@ -215,31 +215,11 @@ type RowProps = { row: ConfigRow; idx: number; uuid: number | string }
|
|
|
215
215
|
|
|
216
216
|
const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
|
|
217
217
|
const { overlay } = useGlobalContext()
|
|
218
|
-
const dispatch = useContext(DashboardDispatchContext)
|
|
219
|
-
|
|
220
|
-
const configureFootnotes = () => {
|
|
221
|
-
if (!row.footnotesId) {
|
|
222
|
-
const type = 'footnotes'
|
|
223
|
-
const uid = type + Date.now()
|
|
224
|
-
const newVisualizationConfig = {
|
|
225
|
-
uid,
|
|
226
|
-
type,
|
|
227
|
-
visualizationType: type,
|
|
228
|
-
editing: true
|
|
229
|
-
}
|
|
230
|
-
dispatch({
|
|
231
|
-
type: 'ADD_FOOTNOTE',
|
|
232
|
-
payload: { id: uid, rowIndex: rowIdx, config: newVisualizationConfig as Visualization }
|
|
233
|
-
})
|
|
234
|
-
} else {
|
|
235
|
-
dispatch({ type: 'UPDATE_VISUALIZATION', payload: { vizKey: row.footnotesId, configureData: { editing: true } } })
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
218
|
return (
|
|
239
219
|
<>
|
|
240
220
|
<div className='builder-row' data-row-id={rowIdx}>
|
|
241
221
|
<RowMenu rowIdx={rowIdx} />
|
|
242
|
-
<
|
|
222
|
+
<span className='ms-2 mt-n3'>Row - {rowIdx + 1}</span>
|
|
243
223
|
<button
|
|
244
224
|
title='Configure Data'
|
|
245
225
|
className='btn btn-configure-row'
|
|
@@ -262,9 +242,6 @@ const Row: React.FC<RowProps> = ({ row, idx: rowIdx, uuid }) => {
|
|
|
262
242
|
/>
|
|
263
243
|
))}
|
|
264
244
|
</div>
|
|
265
|
-
<button className='btn btn-primary footnotes' onClick={configureFootnotes}>
|
|
266
|
-
{row.footnotesId ? 'Edit' : 'Add'} Footnotes
|
|
267
|
-
</button>
|
|
268
245
|
</div>
|
|
269
246
|
</>
|
|
270
247
|
)
|