@cdc/data-bite 1.1.4 → 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/LICENSE +201 -0
- package/README.md +4 -4
- package/dist/cdcdatabite.js +8 -8
- package/examples/example-config.json +24 -24
- package/examples/example-data.json +833 -833
- package/examples/gallery/calculated-average.json +3167 -0
- package/examples/gallery/calculated-with-pic.json +3173 -0
- package/examples/gallery/max-value.json +3167 -0
- package/examples/gallery/sum-of-data.json +3161 -0
- package/examples/private/WCMSRD-12345.json +1026 -1026
- package/examples/private/double.json +0 -0
- package/examples/private/totals.json +67 -0
- package/package.json +3 -3
- package/src/CdcDataBite.tsx +278 -329
- package/src/components/CircleCallout.js +8 -6
- package/src/components/EditorPanel.js +418 -300
- package/src/context.tsx +3 -3
- package/src/data/initial-state.js +37 -37
- package/src/index.html +22 -17
- package/src/index.tsx +9 -9
- package/src/scss/bite.scss +111 -44
- package/src/scss/editor-panel.scss +83 -71
- package/src/scss/main.scss +17 -9
- package/src/scss/variables.scss +1 -1
|
@@ -1,166 +1,185 @@
|
|
|
1
1
|
import React, { memo, useContext, useEffect, useState } from 'react'
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
Accordion,
|
|
5
|
-
AccordionItem,
|
|
6
|
-
AccordionItemButton,
|
|
7
|
-
AccordionItemHeading,
|
|
8
|
-
AccordionItemPanel,
|
|
9
|
-
} from 'react-accessible-accordion'
|
|
3
|
+
import { Accordion, AccordionItem, AccordionItemButton, AccordionItemHeading, AccordionItemPanel } from 'react-accessible-accordion'
|
|
10
4
|
|
|
11
5
|
import { useDebounce } from 'use-debounce'
|
|
12
6
|
import Context from '../context'
|
|
13
|
-
import WarningImage from '
|
|
7
|
+
import WarningImage from '@cdc/core/assets/icon-warning-circle.svg'
|
|
14
8
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
15
9
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
16
10
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
17
11
|
import { BITE_LOCATIONS, DATA_FUNCTIONS, IMAGE_POSITIONS, DATA_OPERATORS } from '../CdcDataBite'
|
|
18
12
|
|
|
19
|
-
const TextField = memo(({label, section = null, subsection = null, fieldName, updateField, value: stateValue, tooltip, type =
|
|
20
|
-
const [
|
|
13
|
+
const TextField = memo(({ label, section = null, subsection = null, fieldName, updateField, value: stateValue, tooltip, type = 'input', i = null, min = null, max = null, ...attributes }) => {
|
|
14
|
+
const [value, setValue] = useState(stateValue)
|
|
21
15
|
|
|
22
|
-
const [
|
|
16
|
+
const [debouncedValue] = useDebounce(value, 500)
|
|
23
17
|
|
|
24
18
|
useEffect(() => {
|
|
25
|
-
if('string' === typeof debouncedValue && stateValue !== debouncedValue
|
|
19
|
+
if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
|
|
26
20
|
updateField(section, subsection, fieldName, debouncedValue, i)
|
|
27
21
|
}
|
|
28
22
|
}, [debouncedValue, section, subsection, fieldName, i, stateValue, updateField])
|
|
29
23
|
|
|
30
|
-
let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}
|
|
24
|
+
let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
|
|
31
25
|
|
|
32
|
-
const onChange =
|
|
26
|
+
const onChange = e => {
|
|
33
27
|
//TODO: This block gives a warning/error in the console, but it still works.
|
|
34
|
-
if('number' !== type || min === null){
|
|
35
|
-
setValue(e.target.value)
|
|
28
|
+
if ('number' !== type || min === null) {
|
|
29
|
+
setValue(e.target.value)
|
|
36
30
|
} else {
|
|
37
|
-
if(!e.target.value || (
|
|
38
|
-
setValue(e.target.value)
|
|
31
|
+
if (!e.target.value || (parseFloat(min) <= parseFloat(e.target.value)) & (parseFloat(max) >= parseFloat(e.target.value))) {
|
|
32
|
+
setValue(e.target.value)
|
|
39
33
|
} else {
|
|
40
|
-
setValue(min.toString())
|
|
34
|
+
setValue(min.toString())
|
|
41
35
|
}
|
|
42
36
|
}
|
|
43
|
-
}
|
|
37
|
+
}
|
|
44
38
|
|
|
45
|
-
let formElement = <input type=
|
|
39
|
+
let formElement = <input type='text' name={name} onChange={onChange} {...attributes} value={value} />
|
|
46
40
|
|
|
47
|
-
if('textarea' === type) {
|
|
48
|
-
formElement =
|
|
49
|
-
<textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
|
|
50
|
-
)
|
|
41
|
+
if ('textarea' === type) {
|
|
42
|
+
formElement = <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
|
|
51
43
|
}
|
|
52
44
|
|
|
53
|
-
if('number' === type) {
|
|
54
|
-
formElement = <input type=
|
|
45
|
+
if ('number' === type) {
|
|
46
|
+
formElement = <input type='number' name={name} onChange={onChange} {...attributes} value={value} />
|
|
55
47
|
}
|
|
56
48
|
|
|
57
49
|
return (
|
|
58
50
|
<>
|
|
59
|
-
{label && label.length > 0 &&
|
|
51
|
+
{label && label.length > 0 && (
|
|
60
52
|
<label>
|
|
61
|
-
<span className=
|
|
53
|
+
<span className='edit-label column-heading'>
|
|
54
|
+
{label}
|
|
55
|
+
{tooltip}
|
|
56
|
+
</span>
|
|
62
57
|
{formElement}
|
|
63
58
|
</label>
|
|
64
|
-
}
|
|
59
|
+
)}
|
|
65
60
|
{(!label || label.length === 0) && formElement}
|
|
66
61
|
</>
|
|
67
62
|
)
|
|
68
63
|
})
|
|
69
64
|
|
|
70
|
-
const CheckBox = memo(({label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes}) => (
|
|
71
|
-
<label className=
|
|
72
|
-
<input
|
|
73
|
-
|
|
65
|
+
const CheckBox = memo(({ label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes }) => (
|
|
66
|
+
<label className='checkbox'>
|
|
67
|
+
<input
|
|
68
|
+
type='checkbox'
|
|
69
|
+
name={fieldName}
|
|
70
|
+
checked={value}
|
|
71
|
+
onChange={() => {
|
|
72
|
+
updateField(section, subsection, fieldName, !value)
|
|
73
|
+
}}
|
|
74
|
+
{...attributes}
|
|
75
|
+
/>
|
|
76
|
+
<span className='edit-label column-heading'>{label}</span>
|
|
77
|
+
<span className='cove-icon'>{tooltip}</span>
|
|
74
78
|
</label>
|
|
75
79
|
))
|
|
76
80
|
|
|
77
|
-
const Select = memo(({label, value, options, fieldName, section = null, subsection = null, required = false, updateField, initial: initialValue, ...attributes}) => {
|
|
78
|
-
let optionsJsx = ''
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
const Select = memo(({ label, value, options, fieldName, section = null, subsection = null, required = false, updateField, initial: initialValue, ...attributes }) => {
|
|
82
|
+
let optionsJsx = ''
|
|
83
|
+
if (Array.isArray(options)) {
|
|
84
|
+
//Handle basic array
|
|
85
|
+
optionsJsx = options.map(optionName => (
|
|
86
|
+
<option value={optionName} key={optionName}>
|
|
87
|
+
{optionName}
|
|
88
|
+
</option>
|
|
89
|
+
))
|
|
90
|
+
} else {
|
|
91
|
+
//Handle object with value/name pairs
|
|
92
|
+
optionsJsx = []
|
|
83
93
|
for (const [optionValue, optionName] of Object.entries(options)) {
|
|
84
|
-
optionsJsx.push(
|
|
94
|
+
optionsJsx.push(
|
|
95
|
+
<option value={optionValue} key={optionValue}>
|
|
96
|
+
{optionName}
|
|
97
|
+
</option>
|
|
98
|
+
)
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
|
|
88
|
-
if(initialValue) {
|
|
89
|
-
optionsJsx.unshift(
|
|
102
|
+
if (initialValue) {
|
|
103
|
+
optionsJsx.unshift(
|
|
104
|
+
<option value='' key='initial'>
|
|
105
|
+
{initialValue}
|
|
106
|
+
</option>
|
|
107
|
+
)
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
return (
|
|
93
111
|
<label>
|
|
94
|
-
<span className=
|
|
95
|
-
<select
|
|
112
|
+
<span className='edit-label'>{label}</span>
|
|
113
|
+
<select
|
|
114
|
+
className={required && !value ? 'warning' : ''}
|
|
115
|
+
name={fieldName}
|
|
116
|
+
value={value}
|
|
117
|
+
onChange={event => {
|
|
118
|
+
updateField(section, subsection, fieldName, event.target.value)
|
|
119
|
+
}}
|
|
120
|
+
{...attributes}
|
|
121
|
+
>
|
|
96
122
|
{optionsJsx}
|
|
97
123
|
</select>
|
|
98
124
|
</label>
|
|
99
125
|
)
|
|
100
126
|
})
|
|
101
127
|
|
|
102
|
-
const headerColors = ['theme-blue','theme-purple','theme-brown','theme-teal','theme-pink','theme-orange','theme-slate','theme-indigo','theme-cyan','theme-green','theme-amber']
|
|
128
|
+
const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
|
|
103
129
|
|
|
104
130
|
const EditorPanel = memo(() => {
|
|
105
|
-
const {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
isDashboard,
|
|
112
|
-
} = useContext(Context);
|
|
113
|
-
|
|
114
|
-
const [ displayPanel, setDisplayPanel ] = useState(true);
|
|
115
|
-
const enforceRestrictions = (updatedConfig) => {
|
|
116
|
-
//If there are any dependencies between fields, etc../
|
|
117
|
-
};
|
|
131
|
+
const { config, updateConfig, loading, data, setParentConfig, isDashboard } = useContext(Context)
|
|
132
|
+
|
|
133
|
+
const [displayPanel, setDisplayPanel] = useState(true)
|
|
134
|
+
const enforceRestrictions = updatedConfig => {
|
|
135
|
+
//If there are any dependencies between fields, etc../
|
|
136
|
+
}
|
|
118
137
|
|
|
119
138
|
const updateField = (section, subsection, fieldName, newValue) => {
|
|
120
139
|
// Top level
|
|
121
|
-
if(
|
|
122
|
-
let updatedConfig = {...config, [fieldName]: newValue}
|
|
140
|
+
if (null === section && null === subsection) {
|
|
141
|
+
let updatedConfig = { ...config, [fieldName]: newValue }
|
|
123
142
|
|
|
124
|
-
if (
|
|
125
|
-
updatedConfig.filterValue = ''
|
|
143
|
+
if ('filterColumn' === fieldName) {
|
|
144
|
+
updatedConfig.filterValue = ''
|
|
126
145
|
}
|
|
127
146
|
|
|
128
|
-
enforceRestrictions(updatedConfig)
|
|
147
|
+
enforceRestrictions(updatedConfig)
|
|
129
148
|
|
|
130
|
-
updateConfig(updatedConfig)
|
|
149
|
+
updateConfig(updatedConfig)
|
|
131
150
|
return
|
|
132
151
|
}
|
|
133
152
|
|
|
134
|
-
const isArray = Array.isArray(config[section])
|
|
153
|
+
const isArray = Array.isArray(config[section])
|
|
135
154
|
|
|
136
|
-
let sectionValue = isArray ? [...config[section], newValue] : {...config[section], [fieldName]: newValue}
|
|
155
|
+
let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
|
|
137
156
|
|
|
138
|
-
if(null !== subsection) {
|
|
139
|
-
if(isArray) {
|
|
157
|
+
if (null !== subsection) {
|
|
158
|
+
if (isArray) {
|
|
140
159
|
sectionValue = [...config[section]]
|
|
141
|
-
sectionValue[subsection] = {...sectionValue[subsection], [fieldName]: newValue}
|
|
142
|
-
} else if(typeof newValue ===
|
|
160
|
+
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
|
|
161
|
+
} else if (typeof newValue === 'string') {
|
|
143
162
|
sectionValue[subsection] = newValue
|
|
144
163
|
} else {
|
|
145
|
-
sectionValue = {...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue}}
|
|
164
|
+
sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
|
|
146
165
|
}
|
|
147
166
|
}
|
|
148
167
|
|
|
149
|
-
let updatedConfig = {...config, [section]: sectionValue}
|
|
168
|
+
let updatedConfig = { ...config, [section]: sectionValue }
|
|
150
169
|
|
|
151
|
-
enforceRestrictions(updatedConfig)
|
|
170
|
+
enforceRestrictions(updatedConfig)
|
|
152
171
|
|
|
153
172
|
updateConfig(updatedConfig)
|
|
154
173
|
}
|
|
155
174
|
|
|
156
175
|
const missingRequiredSections = () => {
|
|
157
176
|
//Whether to show error message if something is required to show a data-bite and isn't filled in
|
|
158
|
-
return false
|
|
159
|
-
}
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
160
179
|
|
|
161
180
|
useEffect(() => {
|
|
162
181
|
// Pass up to Editor if needed
|
|
163
|
-
if(setParentConfig) {
|
|
182
|
+
if (setParentConfig) {
|
|
164
183
|
const newConfig = convertStateToConfig()
|
|
165
184
|
|
|
166
185
|
setParentConfig(newConfig)
|
|
@@ -169,36 +188,46 @@ const EditorPanel = memo(() => {
|
|
|
169
188
|
}, [config])
|
|
170
189
|
|
|
171
190
|
const onBackClick = () => {
|
|
172
|
-
setDisplayPanel(!displayPanel)
|
|
191
|
+
setDisplayPanel(!displayPanel)
|
|
173
192
|
}
|
|
174
193
|
|
|
175
194
|
const Error = () => {
|
|
176
195
|
return (
|
|
177
|
-
<section className=
|
|
178
|
-
<section className=
|
|
196
|
+
<section className='waiting'>
|
|
197
|
+
<section className='waiting-container'>
|
|
179
198
|
<h3>Error With Configuration</h3>
|
|
180
199
|
<p>{config.runtime.editorErrorMessage}</p>
|
|
181
200
|
</section>
|
|
182
201
|
</section>
|
|
183
|
-
)
|
|
202
|
+
)
|
|
184
203
|
}
|
|
185
204
|
|
|
186
205
|
const Confirm = () => {
|
|
187
206
|
return (
|
|
188
|
-
<section className=
|
|
189
|
-
<section className=
|
|
207
|
+
<section className='waiting'>
|
|
208
|
+
<section className='waiting-container'>
|
|
190
209
|
<h3>Finish Configuring</h3>
|
|
191
210
|
<p>Set all required options to the left and confirm below to display a preview of the chart.</p>
|
|
192
|
-
<button
|
|
211
|
+
<button
|
|
212
|
+
className='btn'
|
|
213
|
+
style={{ margin: '1em auto' }}
|
|
214
|
+
disabled={missingRequiredSections()}
|
|
215
|
+
onClick={e => {
|
|
216
|
+
e.preventDefault()
|
|
217
|
+
updateConfig({ ...config, newViz: false })
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
I'm Done
|
|
221
|
+
</button>
|
|
193
222
|
</section>
|
|
194
223
|
</section>
|
|
195
|
-
)
|
|
224
|
+
)
|
|
196
225
|
}
|
|
197
226
|
|
|
198
227
|
const convertStateToConfig = () => {
|
|
199
228
|
let strippedState = JSON.parse(JSON.stringify(config))
|
|
200
229
|
//if(false === missingRequiredSections()) {
|
|
201
|
-
|
|
230
|
+
//strippedState.newViz
|
|
202
231
|
//}
|
|
203
232
|
delete strippedState.runtime
|
|
204
233
|
|
|
@@ -206,364 +235,452 @@ const EditorPanel = memo(() => {
|
|
|
206
235
|
}
|
|
207
236
|
|
|
208
237
|
// Filters -----------------------------------------------
|
|
209
|
-
const removeFilter =
|
|
210
|
-
let filters = [...config.filters]
|
|
238
|
+
const removeFilter = index => {
|
|
239
|
+
let filters = [...config.filters]
|
|
211
240
|
|
|
212
|
-
filters.splice(index, 1)
|
|
241
|
+
filters.splice(index, 1)
|
|
213
242
|
|
|
214
|
-
updateConfig({...config, filters})
|
|
243
|
+
updateConfig({ ...config, filters })
|
|
215
244
|
}
|
|
216
245
|
|
|
217
246
|
const updateFilterProp = (name, index, value) => {
|
|
218
|
-
let filters = [...config.filters]
|
|
247
|
+
let filters = [...config.filters]
|
|
219
248
|
|
|
220
|
-
filters[index][name] = value
|
|
249
|
+
filters[index][name] = value
|
|
221
250
|
|
|
222
|
-
updateConfig({...config, filters})
|
|
251
|
+
updateConfig({ ...config, filters })
|
|
223
252
|
}
|
|
224
253
|
|
|
225
254
|
const addNewFilter = () => {
|
|
226
|
-
let filters = config.filters ? [...config.filters] : []
|
|
255
|
+
let filters = config.filters ? [...config.filters] : []
|
|
227
256
|
|
|
228
|
-
filters.push({values: []})
|
|
257
|
+
filters.push({ values: [] })
|
|
229
258
|
|
|
230
|
-
updateConfig({...config, filters})
|
|
259
|
+
updateConfig({ ...config, filters })
|
|
231
260
|
}
|
|
232
261
|
|
|
233
262
|
const getColumns = (filter = true) => {
|
|
234
263
|
let columns = {}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
264
|
+
if (data.length) {
|
|
265
|
+
data.map(row => {
|
|
266
|
+
return Object.keys(row).forEach(columnName => (columns[columnName] = true))
|
|
267
|
+
})
|
|
268
|
+
}
|
|
241
269
|
|
|
242
270
|
return Object.keys(columns)
|
|
243
271
|
}
|
|
244
272
|
|
|
245
|
-
const getFilterColumnValues =
|
|
273
|
+
const getFilterColumnValues = index => {
|
|
246
274
|
let filterDataOptions = []
|
|
247
|
-
const filterColumnName = config.filters[index].columnName
|
|
275
|
+
const filterColumnName = config.filters[index].columnName
|
|
248
276
|
if (data && filterColumnName) {
|
|
249
|
-
data.forEach(function(row) {
|
|
250
|
-
if (
|
|
251
|
-
filterDataOptions.push(row[filterColumnName])
|
|
277
|
+
data.forEach(function (row) {
|
|
278
|
+
if (undefined !== row[filterColumnName] && -1 === filterDataOptions.indexOf(row[filterColumnName])) {
|
|
279
|
+
filterDataOptions.push(row[filterColumnName])
|
|
252
280
|
}
|
|
253
281
|
})
|
|
254
|
-
filterDataOptions.sort()
|
|
282
|
+
filterDataOptions.sort()
|
|
255
283
|
}
|
|
256
|
-
return filterDataOptions
|
|
284
|
+
return filterDataOptions
|
|
257
285
|
}
|
|
258
286
|
|
|
259
287
|
// Dynamic Images ----------------------------------------
|
|
260
288
|
const updateDynamicImage = (name, index, subindex = null, value) => {
|
|
261
|
-
let imageOptions = [...config.imageData.options]
|
|
262
|
-
null === subindex ? imageOptions[index][name] = value : imageOptions[index].arguments[subindex][name] = value
|
|
289
|
+
let imageOptions = [...config.imageData.options]
|
|
290
|
+
null === subindex ? (imageOptions[index][name] = value) : (imageOptions[index].arguments[subindex][name] = value)
|
|
263
291
|
|
|
264
|
-
let payload = {...config.imageData, options: imageOptions}
|
|
265
|
-
updateConfig({...config, imageData: payload})
|
|
292
|
+
let payload = { ...config.imageData, options: imageOptions }
|
|
293
|
+
updateConfig({ ...config, imageData: payload })
|
|
266
294
|
}
|
|
267
295
|
|
|
268
296
|
const setDynamicArgument = (optionIndex, name, value) => {
|
|
269
297
|
let imageArguments = [...config.imageData.options[optionIndex].arguments]
|
|
270
|
-
|
|
271
|
-
let argumentsPayload = {...config.imageData.options[optionIndex], arguments: imageArguments}
|
|
298
|
+
imageArguments[1] = { ...imageArguments[1], [name]: value }
|
|
299
|
+
let argumentsPayload = { ...config.imageData.options[optionIndex], arguments: imageArguments }
|
|
272
300
|
let optionsPayload = [...config.imageData.options]
|
|
273
|
-
|
|
274
|
-
let payload = {...config.imageData, options: optionsPayload}
|
|
275
|
-
updateConfig({...config, imageData: payload})
|
|
301
|
+
optionsPayload[optionIndex] = argumentsPayload
|
|
302
|
+
let payload = { ...config.imageData, options: optionsPayload }
|
|
303
|
+
updateConfig({ ...config, imageData: payload })
|
|
276
304
|
}
|
|
277
305
|
|
|
278
|
-
const removeDynamicArgument =
|
|
306
|
+
const removeDynamicArgument = optionIndex => {
|
|
279
307
|
if (config.imageData.options[optionIndex].arguments.length > 1) {
|
|
280
308
|
let imageArguments = [...config.imageData.options[optionIndex].arguments]
|
|
281
|
-
|
|
282
|
-
let argumentsPayload = {...config.imageData.options[optionIndex], arguments: imageArguments}
|
|
309
|
+
imageArguments.pop()
|
|
310
|
+
let argumentsPayload = { ...config.imageData.options[optionIndex], arguments: imageArguments }
|
|
283
311
|
let optionsPayload = [...config.imageData.options]
|
|
284
|
-
|
|
285
|
-
let payload = {...config.imageData, options: optionsPayload}
|
|
286
|
-
updateConfig({...config, imageData: payload})
|
|
312
|
+
optionsPayload[optionIndex] = argumentsPayload
|
|
313
|
+
let payload = { ...config.imageData, options: optionsPayload }
|
|
314
|
+
updateConfig({ ...config, imageData: payload })
|
|
287
315
|
}
|
|
288
316
|
}
|
|
289
317
|
|
|
290
318
|
const addDynamicImage = () => {
|
|
291
|
-
let imageOptions = config.imageData.options ? [
|
|
292
|
-
imageOptions.push({ source: '', arguments: [{ operator: '', threshold: ''}], alt: '', secondArgument: false })
|
|
319
|
+
let imageOptions = config.imageData.options ? [...config.imageData.options] : []
|
|
320
|
+
imageOptions.push({ source: '', arguments: [{ operator: '', threshold: '' }], alt: '', secondArgument: false })
|
|
293
321
|
|
|
294
|
-
let payload = {...config.imageData, options: imageOptions}
|
|
295
|
-
updateConfig({...config, imageData: payload})
|
|
322
|
+
let payload = { ...config.imageData, options: imageOptions }
|
|
323
|
+
updateConfig({ ...config, imageData: payload })
|
|
296
324
|
}
|
|
297
325
|
|
|
298
|
-
const removeDynamicImage =
|
|
299
|
-
let imageOptions = [...config.imageData.options]
|
|
300
|
-
imageOptions.splice(index, 1)
|
|
326
|
+
const removeDynamicImage = index => {
|
|
327
|
+
let imageOptions = [...config.imageData.options]
|
|
328
|
+
imageOptions.splice(index, 1)
|
|
301
329
|
|
|
302
|
-
let payload = {...config.imageData, options: imageOptions}
|
|
303
|
-
updateConfig({...config, imageData: payload})
|
|
330
|
+
let payload = { ...config.imageData, options: imageOptions }
|
|
331
|
+
updateConfig({ ...config, imageData: payload })
|
|
304
332
|
}
|
|
305
333
|
|
|
306
334
|
// General -----------------------------------------------
|
|
307
|
-
if(loading) {
|
|
335
|
+
if (loading) {
|
|
308
336
|
return null
|
|
309
337
|
}
|
|
310
338
|
|
|
311
339
|
return (
|
|
312
|
-
<ErrorBoundary component=
|
|
313
|
-
{!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />
|
|
340
|
+
<ErrorBoundary component='EditorPanel'>
|
|
341
|
+
{!config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
|
|
314
342
|
{(!config.dataColumn || !config.dataFunction) && <Confirm />}
|
|
315
343
|
<button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick} />
|
|
316
344
|
<section className={displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}>
|
|
317
|
-
<div className=
|
|
318
|
-
<section className=
|
|
345
|
+
<div className='heading-2'>Configure Data Bite</div>
|
|
346
|
+
<section className='form-container'>
|
|
319
347
|
<form>
|
|
320
348
|
<Accordion allowZeroExpanded={true}>
|
|
321
|
-
<AccordionItem>
|
|
349
|
+
<AccordionItem>
|
|
350
|
+
{' '}
|
|
351
|
+
{/* General */}
|
|
322
352
|
<AccordionItemHeading>
|
|
323
|
-
<AccordionItemButton>
|
|
324
|
-
General
|
|
325
|
-
</AccordionItemButton>
|
|
353
|
+
<AccordionItemButton>General</AccordionItemButton>
|
|
326
354
|
</AccordionItemHeading>
|
|
327
355
|
<AccordionItemPanel>
|
|
328
|
-
<Select value={config.biteStyle} fieldName=
|
|
329
|
-
<TextField value={config.title} fieldName=
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
<
|
|
343
|
-
Enter
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
356
|
+
<Select value={config.biteStyle} fieldName='biteStyle' label='Data Bite Style' updateField={updateField} options={BITE_LOCATIONS} initial='Select' />
|
|
357
|
+
<TextField value={config.title} fieldName='title' label='Title' placeholder='Data Bite Title' updateField={updateField} />
|
|
358
|
+
|
|
359
|
+
<TextField
|
|
360
|
+
type='textarea'
|
|
361
|
+
value={config.biteBody}
|
|
362
|
+
fieldName='biteBody'
|
|
363
|
+
label='Message'
|
|
364
|
+
updateField={updateField}
|
|
365
|
+
tooltip={
|
|
366
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
367
|
+
<Tooltip.Target>
|
|
368
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
369
|
+
</Tooltip.Target>
|
|
370
|
+
<Tooltip.Content>
|
|
371
|
+
<p>Enter the message text for the visualization. The following HTML tags are supported: strong, em, sup, and sub.</p>
|
|
372
|
+
</Tooltip.Content>
|
|
373
|
+
</Tooltip>
|
|
374
|
+
}
|
|
375
|
+
/>
|
|
376
|
+
<TextField
|
|
377
|
+
value={config.subtext}
|
|
378
|
+
fieldName='subtext'
|
|
379
|
+
label='Subtext/Citation'
|
|
380
|
+
placeholder='Data Bite Subtext or Citation'
|
|
381
|
+
updateField={updateField}
|
|
382
|
+
tooltip={
|
|
383
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
384
|
+
<Tooltip.Target>
|
|
385
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
386
|
+
</Tooltip.Target>
|
|
387
|
+
<Tooltip.Content>
|
|
388
|
+
<p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
|
|
389
|
+
</Tooltip.Content>
|
|
390
|
+
</Tooltip>
|
|
391
|
+
}
|
|
392
|
+
/>
|
|
355
393
|
</AccordionItemPanel>
|
|
356
394
|
</AccordionItem>
|
|
357
395
|
|
|
358
|
-
<AccordionItem>
|
|
396
|
+
<AccordionItem>
|
|
397
|
+
{' '}
|
|
398
|
+
{/*Data*/}
|
|
359
399
|
<AccordionItemHeading>
|
|
360
|
-
<AccordionItemButton>
|
|
361
|
-
Data {(!config.dataColumn || !config.dataFunction) && <WarningImage width="25" className="warning-icon" />}
|
|
362
|
-
</AccordionItemButton>
|
|
400
|
+
<AccordionItemButton>Data {(!config.dataColumn || !config.dataFunction) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
|
|
363
401
|
</AccordionItemHeading>
|
|
364
402
|
<AccordionItemPanel>
|
|
365
|
-
<ul className=
|
|
366
|
-
<li className=
|
|
367
|
-
<Select value={config.dataColumn ||
|
|
368
|
-
<Select value={config.dataFunction ||
|
|
403
|
+
<ul className='column-edit'>
|
|
404
|
+
<li className='two-col'>
|
|
405
|
+
<Select value={config.dataColumn || ''} fieldName='dataColumn' label='Data Column' updateField={updateField} initial='Select' required={true} options={getColumns()} />
|
|
406
|
+
<Select value={config.dataFunction || ''} fieldName='dataFunction' label='Data Function' updateField={updateField} initial='Select' required={true} options={DATA_FUNCTIONS} />
|
|
369
407
|
</li>
|
|
370
408
|
</ul>
|
|
371
|
-
<span className=
|
|
372
|
-
<ul className=
|
|
373
|
-
<li className=
|
|
374
|
-
<TextField value={config.dataFormat.prefix} section=
|
|
375
|
-
<TextField value={config.dataFormat.suffix} section=
|
|
376
|
-
<TextField
|
|
409
|
+
<span className='divider-heading'>Number Formatting</span>
|
|
410
|
+
<ul className='column-edit'>
|
|
411
|
+
<li className='three-col'>
|
|
412
|
+
<TextField value={config.dataFormat.prefix} section='dataFormat' fieldName='prefix' label='Prefix' updateField={updateField} />
|
|
413
|
+
<TextField value={config.dataFormat.suffix} section='dataFormat' fieldName='suffix' label='Suffix' updateField={updateField} />
|
|
414
|
+
<TextField type='number' value={config.dataFormat.roundToPlace} section='dataFormat' fieldName='roundToPlace' label='Round' updateField={updateField} min='0' max='99' />
|
|
377
415
|
</li>
|
|
378
416
|
</ul>
|
|
379
|
-
<CheckBox value={config.dataFormat.commas} section=
|
|
380
|
-
<CheckBox value={config.dataFormat.ignoreZeros} section=
|
|
381
|
-
<hr className=
|
|
417
|
+
<CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
|
|
418
|
+
<CheckBox value={config.dataFormat.ignoreZeros} section='dataFormat' fieldName='ignoreZeros' label='Ignore Zeros' updateField={updateField} />
|
|
419
|
+
<hr className='accordion__divider' />
|
|
382
420
|
|
|
383
|
-
<label style={{marginBottom: '1rem'}}>
|
|
384
|
-
<span className=
|
|
421
|
+
<label style={{ marginBottom: '1rem' }}>
|
|
422
|
+
<span className='edit-label'>
|
|
385
423
|
Data Point Filters
|
|
386
424
|
<Tooltip style={{ textTransform: 'none' }}>
|
|
387
|
-
<Tooltip.Target
|
|
425
|
+
<Tooltip.Target>
|
|
426
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
427
|
+
</Tooltip.Target>
|
|
388
428
|
<Tooltip.Content>
|
|
389
|
-
<p>To refine the highlighted data point, specify one or more filters (e.g., "Male" and
|
|
390
|
-
"Female" for a column called "Sex").</p>
|
|
429
|
+
<p>To refine the highlighted data point, specify one or more filters (e.g., "Male" and "Female" for a column called "Sex").</p>
|
|
391
430
|
</Tooltip.Content>
|
|
392
431
|
</Tooltip>
|
|
393
432
|
</span>
|
|
394
433
|
</label>
|
|
395
|
-
{
|
|
396
|
-
|
|
397
|
-
<ul className="filters-list">
|
|
434
|
+
{config.filters && (
|
|
435
|
+
<ul className='filters-list'>
|
|
398
436
|
{config.filters.map((filter, index) => (
|
|
399
|
-
<fieldset className=
|
|
400
|
-
<button
|
|
437
|
+
<fieldset className='edit-block' key={index}>
|
|
438
|
+
<button
|
|
439
|
+
type='button'
|
|
440
|
+
className='remove-column'
|
|
441
|
+
onClick={() => {
|
|
442
|
+
removeFilter(index)
|
|
443
|
+
}}
|
|
444
|
+
>
|
|
445
|
+
Remove
|
|
446
|
+
</button>
|
|
401
447
|
<label>
|
|
402
|
-
<span className=
|
|
403
|
-
<select
|
|
404
|
-
|
|
448
|
+
<span className='edit-label column-heading'>Column</span>
|
|
449
|
+
<select
|
|
450
|
+
value={filter.columnName ? filter.columnName : ''}
|
|
451
|
+
onChange={e => {
|
|
452
|
+
updateFilterProp('columnName', index, e.target.value)
|
|
453
|
+
}}
|
|
454
|
+
>
|
|
455
|
+
<option value=''>- Select Option -</option>
|
|
405
456
|
{getColumns().map((dataKey, index) => (
|
|
406
|
-
<option value={dataKey} key={index}>
|
|
457
|
+
<option value={dataKey} key={index}>
|
|
458
|
+
{dataKey}
|
|
459
|
+
</option>
|
|
407
460
|
))}
|
|
408
461
|
</select>
|
|
409
462
|
</label>
|
|
410
463
|
<label>
|
|
411
|
-
<span className=
|
|
412
|
-
<select
|
|
413
|
-
|
|
464
|
+
<span className='edit-label column-heading'>Column Value</span>
|
|
465
|
+
<select
|
|
466
|
+
value={filter.columnValue}
|
|
467
|
+
onChange={e => {
|
|
468
|
+
updateFilterProp('columnValue', index, e.target.value)
|
|
469
|
+
}}
|
|
470
|
+
>
|
|
471
|
+
<option value=''>- Select Option -</option>
|
|
414
472
|
{getFilterColumnValues(index).map((dataKey, index) => (
|
|
415
|
-
<option value={dataKey} key={index}>
|
|
473
|
+
<option value={dataKey} key={index}>
|
|
474
|
+
{dataKey}
|
|
475
|
+
</option>
|
|
416
476
|
))}
|
|
417
477
|
</select>
|
|
418
478
|
</label>
|
|
419
479
|
</fieldset>
|
|
420
480
|
))}
|
|
421
481
|
</ul>
|
|
422
|
-
}
|
|
423
|
-
{(!config.filters || config.filters.length === 0) &&
|
|
482
|
+
)}
|
|
483
|
+
{(!config.filters || config.filters.length === 0) && (
|
|
424
484
|
<div>
|
|
425
|
-
<fieldset className=
|
|
426
|
-
<p style={{textAlign:
|
|
485
|
+
<fieldset className='edit-block'>
|
|
486
|
+
<p style={{ textAlign: 'center' }}>There are currently no filters.</p>
|
|
427
487
|
</fieldset>
|
|
428
488
|
</div>
|
|
429
|
-
}
|
|
430
|
-
<button type=
|
|
489
|
+
)}
|
|
490
|
+
<button type='button' onClick={addNewFilter} className='btn full-width'>
|
|
491
|
+
Add Filter
|
|
492
|
+
</button>
|
|
431
493
|
</AccordionItemPanel>
|
|
432
494
|
</AccordionItem>
|
|
433
495
|
|
|
434
|
-
<AccordionItem>
|
|
496
|
+
<AccordionItem>
|
|
497
|
+
{' '}
|
|
498
|
+
{/*Visual*/}
|
|
435
499
|
<AccordionItemHeading>
|
|
436
|
-
<AccordionItemButton>
|
|
437
|
-
Visual
|
|
438
|
-
</AccordionItemButton>
|
|
500
|
+
<AccordionItemButton>Visual</AccordionItemButton>
|
|
439
501
|
</AccordionItemHeading>
|
|
440
502
|
<AccordionItemPanel>
|
|
441
|
-
<TextField type=
|
|
442
|
-
<Select value={config.fontSize} fieldName=
|
|
443
|
-
<
|
|
444
|
-
|
|
445
|
-
<
|
|
446
|
-
<
|
|
447
|
-
|
|
448
|
-
|
|
503
|
+
<TextField type='number' value={config.biteFontSize} fieldName='biteFontSize' label='Bite Font Size' updateField={updateField} min='17' max='65' />
|
|
504
|
+
<Select value={config.fontSize} fieldName='fontSize' label='Overall Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
|
|
505
|
+
<div className='checkbox-group'>
|
|
506
|
+
<CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Display Border' updateField={updateField} />
|
|
507
|
+
<CheckBox value={config.visual?.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme' updateField={updateField} />
|
|
508
|
+
<CheckBox value={config.visual?.accent} section='visual' fieldName='accent' label='Use Accent Style' updateField={updateField} />
|
|
509
|
+
<CheckBox value={config.visual?.background} section='visual' fieldName='background' label='Use Theme Background Color' updateField={updateField} />
|
|
510
|
+
<CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
|
|
511
|
+
</div>
|
|
512
|
+
<label>
|
|
513
|
+
<span className='edit-label'>Theme</span>
|
|
514
|
+
<ul className='color-palette'>
|
|
515
|
+
{headerColors.map(palette => (
|
|
516
|
+
<li
|
|
517
|
+
title={palette}
|
|
518
|
+
key={palette}
|
|
519
|
+
onClick={() => {
|
|
520
|
+
updateConfig({ ...config, theme: palette })
|
|
521
|
+
}}
|
|
522
|
+
className={config.theme === palette ? 'selected ' + palette : palette}
|
|
523
|
+
/>
|
|
449
524
|
))}
|
|
450
525
|
</ul>
|
|
451
526
|
</label>
|
|
452
|
-
{/* <div className="cove-accordion__panel-section">
|
|
453
|
-
<CheckBox value={config.visual.border} section="visual" fieldName="border" label="Display Border" updateField={updateField} />
|
|
454
|
-
<CheckBox value={config.visual.borderColorTheme} section="visual" fieldName="borderColorTheme" label="Use Border Color Theme" updateField={updateField} />
|
|
455
|
-
<CheckBox value={config.visual.accent} section="visual" fieldName="accent" label="Use Accent Style" updateField={updateField} />
|
|
456
|
-
<CheckBox value={config.visual.background} section="visual" fieldName="background" label="Use Theme Background Color" updateField={updateField} />
|
|
457
|
-
<CheckBox value={config.visual.hideBackgroundColor} section="visual" fieldName="hideBackgroundColor" label="Hide Background Color" updateField={updateField} />
|
|
458
|
-
</div> */}
|
|
459
527
|
</AccordionItemPanel>
|
|
460
528
|
</AccordionItem>
|
|
461
529
|
|
|
462
|
-
{['title', 'body', 'graphic'].includes(config.biteStyle) &&
|
|
463
|
-
<AccordionItem>
|
|
530
|
+
{['title', 'body', 'graphic'].includes(config.biteStyle) && (
|
|
531
|
+
<AccordionItem>
|
|
532
|
+
{' '}
|
|
533
|
+
{/*Image & Dynamic Images*/}
|
|
464
534
|
<AccordionItemHeading>
|
|
465
535
|
<AccordionItemButton>
|
|
466
|
-
Image
|
|
536
|
+
Image
|
|
537
|
+
{['dynamic'].includes(config.imageData.display) && 's'}
|
|
467
538
|
</AccordionItemButton>
|
|
468
539
|
</AccordionItemHeading>
|
|
469
|
-
|
|
470
540
|
<AccordionItemPanel>
|
|
471
|
-
<Select value={config.imageData.display ||
|
|
472
|
-
<Select value={config.bitePosition ||
|
|
473
|
-
{['static'].includes(config.imageData.display) &&
|
|
541
|
+
<Select value={config.imageData.display || ''} section='imageData' fieldName='display' label='Image Display Type' updateField={updateField} options={['none', 'static', 'dynamic']} />
|
|
542
|
+
<Select value={config.bitePosition || ''} fieldName='bitePosition' label='Image/Graphic Position' updateField={updateField} initial='Select' options={IMAGE_POSITIONS} />
|
|
543
|
+
{['static'].includes(config.imageData.display) && (
|
|
474
544
|
<>
|
|
475
|
-
<TextField value={config.imageData.url} section=
|
|
476
|
-
<TextField value={config.imageData.alt} section=
|
|
545
|
+
<TextField value={config.imageData.url} section='imageData' fieldName='url' label='Image URL' updateField={updateField} />
|
|
546
|
+
<TextField value={config.imageData.alt} section='imageData' fieldName='alt' label='Alt Text' updateField={updateField} />
|
|
477
547
|
</>
|
|
478
|
-
}
|
|
548
|
+
)}
|
|
479
549
|
|
|
480
|
-
{[
|
|
550
|
+
{['dynamic'].includes(config.imageData.display) && (
|
|
481
551
|
<>
|
|
482
|
-
<TextField value={config.imageData.url ||
|
|
483
|
-
<TextField value={config.imageData.alt} section=
|
|
552
|
+
<TextField value={config.imageData.url || ''} section='imageData' fieldName='url' label='Image URL (default)' updateField={updateField} />
|
|
553
|
+
<TextField value={config.imageData.alt} section='imageData' fieldName='alt' label='Alt Text (default)' updateField={updateField} />
|
|
484
554
|
|
|
485
|
-
<hr className=
|
|
555
|
+
<hr className='accordion__divider' />
|
|
486
556
|
|
|
487
|
-
{(!config.imageData.options || config.imageData.options.length === 0) && <p style={{textAlign:
|
|
488
|
-
{config.imageData.options && config.imageData.options.length > 0 &&
|
|
557
|
+
{(!config.imageData.options || config.imageData.options.length === 0) && <p style={{ textAlign: 'center' }}>There are currently no dynamic images.</p>}
|
|
558
|
+
{config.imageData.options && config.imageData.options.length > 0 && (
|
|
489
559
|
<>
|
|
490
560
|
<ul>
|
|
491
561
|
{config.imageData.options.map((option, index) => (
|
|
492
|
-
<fieldset className=
|
|
493
|
-
<button
|
|
562
|
+
<fieldset className='edit-block' key={index}>
|
|
563
|
+
<button
|
|
564
|
+
type='button'
|
|
565
|
+
className='remove-column'
|
|
566
|
+
onClick={() => {
|
|
567
|
+
removeDynamicImage(index)
|
|
568
|
+
}}
|
|
569
|
+
>
|
|
570
|
+
Remove
|
|
571
|
+
</button>
|
|
494
572
|
<label>
|
|
495
|
-
<span className=
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
</div>
|
|
501
|
-
<div className=
|
|
502
|
-
<select
|
|
503
|
-
|
|
573
|
+
<span className='edit-label column-heading'>
|
|
574
|
+
<strong>{'Image #' + (index + 1)}</strong>
|
|
575
|
+
</span>
|
|
576
|
+
|
|
577
|
+
<div className='accordion__panel-row align-center'>
|
|
578
|
+
<div className='accordion__panel-col flex-auto'>If Value</div>
|
|
579
|
+
<div className='accordion__panel-col flex-auto'>
|
|
580
|
+
<select
|
|
581
|
+
value={option.arguments[0]?.operator || ''}
|
|
582
|
+
onChange={e => {
|
|
583
|
+
updateDynamicImage('operator', index, 0, e.target.value)
|
|
584
|
+
}}
|
|
585
|
+
>
|
|
586
|
+
<option value='' disabled />
|
|
504
587
|
{DATA_OPERATORS.map((operator, index) => (
|
|
505
|
-
<option value={operator} key={index}>
|
|
588
|
+
<option value={operator} key={index}>
|
|
589
|
+
{operator}
|
|
590
|
+
</option>
|
|
506
591
|
))}
|
|
507
592
|
</select>
|
|
508
593
|
</div>
|
|
509
|
-
<div className=
|
|
510
|
-
<input
|
|
594
|
+
<div className='accordion__panel-col flex-grow flex-shrink'>
|
|
595
|
+
<input
|
|
596
|
+
type='number'
|
|
597
|
+
value={option.arguments[0]?.threshold || ''}
|
|
598
|
+
onChange={e => {
|
|
599
|
+
updateDynamicImage('threshold', index, 0, e.target.value)
|
|
600
|
+
}}
|
|
601
|
+
/>
|
|
511
602
|
</div>
|
|
512
603
|
</div>
|
|
513
604
|
|
|
514
|
-
<div className=
|
|
515
|
-
<div className=
|
|
516
|
-
<select
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
605
|
+
<div className='accordion__panel-row mb-2 align-center'>
|
|
606
|
+
<div className='accordion__panel-col flex-grow'>
|
|
607
|
+
<select
|
|
608
|
+
className='border-dashed text-center'
|
|
609
|
+
value={option.secondArgument ? 'and' : 'then'}
|
|
610
|
+
onChange={e => {
|
|
611
|
+
if ('then' === e.target.value) {
|
|
612
|
+
updateDynamicImage('secondArgument', index, null, false)
|
|
613
|
+
removeDynamicArgument(index)
|
|
614
|
+
}
|
|
615
|
+
if ('and' === e.target.value) {
|
|
616
|
+
updateDynamicImage('secondArgument', index, null, true)
|
|
617
|
+
}
|
|
618
|
+
}}
|
|
619
|
+
>
|
|
520
620
|
<option value={'then'}>Then</option>
|
|
521
621
|
<option value={'and'}>And</option>
|
|
522
622
|
</select>
|
|
523
623
|
</div>
|
|
524
624
|
</div>
|
|
525
625
|
|
|
526
|
-
{option.secondArgument && true === option.secondArgument &&
|
|
626
|
+
{option.secondArgument && true === option.secondArgument && (
|
|
527
627
|
<>
|
|
528
|
-
<div className=
|
|
529
|
-
<div className=
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
628
|
+
<div className='accordion__panel-row align-center'>
|
|
629
|
+
<div className='accordion__panel-col flex-auto'>If Value</div>
|
|
630
|
+
<div className='accordion__panel-col flex-auto'>
|
|
631
|
+
<select
|
|
632
|
+
value={option.arguments[1]?.operator || ''}
|
|
633
|
+
onChange={e => {
|
|
634
|
+
setDynamicArgument(index, 'operator', e.target.value)
|
|
635
|
+
}}
|
|
636
|
+
>
|
|
637
|
+
<option value='' disabled />
|
|
535
638
|
{DATA_OPERATORS.map((operator, index) => (
|
|
536
|
-
<option value={operator} key={index}>
|
|
639
|
+
<option value={operator} key={index}>
|
|
640
|
+
{operator}
|
|
641
|
+
</option>
|
|
537
642
|
))}
|
|
538
643
|
</select>
|
|
539
644
|
</div>
|
|
540
|
-
<div className=
|
|
541
|
-
<input
|
|
645
|
+
<div className='accordion__panel-col flex-grow flex-shrink'>
|
|
646
|
+
<input
|
|
647
|
+
type='number'
|
|
648
|
+
value={option.arguments[1]?.threshold || ''}
|
|
649
|
+
onChange={e => {
|
|
650
|
+
setDynamicArgument(index, 'threshold', e.target.value)
|
|
651
|
+
}}
|
|
652
|
+
/>
|
|
542
653
|
</div>
|
|
543
654
|
</div>
|
|
544
|
-
<div className=
|
|
545
|
-
<div className=
|
|
546
|
-
Then
|
|
547
|
-
</div>
|
|
655
|
+
<div className='accordion__panel-row mb-2 align-center text-center text-capitalize'>
|
|
656
|
+
<div className='accordion__panel-col flex-grow'>Then</div>
|
|
548
657
|
</div>
|
|
549
658
|
</>
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
<div className=
|
|
553
|
-
<div className=
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
659
|
+
)}
|
|
660
|
+
|
|
661
|
+
<div className='accordion__panel-row mb-2 align-center'>
|
|
662
|
+
<div className='accordion__panel-col flex-auto'>Show</div>
|
|
663
|
+
<div className='accordion__panel-col flex-grow'>
|
|
664
|
+
<input
|
|
665
|
+
type='text'
|
|
666
|
+
value={option.source || ''}
|
|
667
|
+
onChange={e => {
|
|
668
|
+
updateDynamicImage('source', index, null, e.target.value)
|
|
669
|
+
}}
|
|
670
|
+
/>
|
|
558
671
|
</div>
|
|
559
672
|
</div>
|
|
560
673
|
|
|
561
|
-
<div className=
|
|
562
|
-
<div className=
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
674
|
+
<div className='accordion__panel-row mb-2 align-center'>
|
|
675
|
+
<div className='accordion__panel-col flex-auto'>Alt Text</div>
|
|
676
|
+
<div className='accordion__panel-col flex-grow'>
|
|
677
|
+
<input
|
|
678
|
+
type='text'
|
|
679
|
+
value={option.alt || ''}
|
|
680
|
+
onChange={e => {
|
|
681
|
+
updateDynamicImage('alt', index, null, e.target.value)
|
|
682
|
+
}}
|
|
683
|
+
/>
|
|
567
684
|
</div>
|
|
568
685
|
</div>
|
|
569
686
|
</label>
|
|
@@ -571,14 +688,15 @@ const EditorPanel = memo(() => {
|
|
|
571
688
|
))}
|
|
572
689
|
</ul>
|
|
573
690
|
</>
|
|
574
|
-
}
|
|
575
|
-
<button type=
|
|
691
|
+
)}
|
|
692
|
+
<button type='button' onClick={addDynamicImage} className='btn full-width'>
|
|
693
|
+
Add Dynamic Image
|
|
694
|
+
</button>
|
|
576
695
|
</>
|
|
577
|
-
}
|
|
696
|
+
)}
|
|
578
697
|
</AccordionItemPanel>
|
|
579
698
|
</AccordionItem>
|
|
580
|
-
}
|
|
581
|
-
|
|
699
|
+
)}
|
|
582
700
|
</Accordion>
|
|
583
701
|
</form>
|
|
584
702
|
</section>
|
|
@@ -587,4 +705,4 @@ const EditorPanel = memo(() => {
|
|
|
587
705
|
)
|
|
588
706
|
})
|
|
589
707
|
|
|
590
|
-
export default EditorPanel
|
|
708
|
+
export default EditorPanel
|