@@ -31,6 +31,7 @@ import { DropdownStatusProps } from '../internal/components/dropdown-status/inte
3131import InternalButton from '../button/internal' ;
3232import InternalFormField from '../form-field/internal' ;
3333import { matchTokenValue } from './utils' ;
34+ import InternalBox from '../box/internal' ;
3435
3536interface PropertyInputProps {
3637 asyncProps : null | DropdownStatusProps ;
@@ -215,37 +216,59 @@ export function TokenEditor({
215216 token,
216217 triggerComponent,
217218} : TokenEditorProps ) {
218- const firstToken = token . tokens [ 0 ] as InternalToken ;
219- const [ temporaryToken , setTemporaryToken ] = useState < InternalToken > ( firstToken ) ;
219+ const firstLevelTokens : InternalToken [ ] = [ ] ;
220+ for ( const tokenOrGroup of token . tokens ) {
221+ if ( 'operation' in tokenOrGroup ) {
222+ // ignore as deeply nested tokens are not supported
223+ } else {
224+ firstLevelTokens . push ( tokenOrGroup ) ;
225+ }
226+ }
227+ const [ operation , setOperation ] = useState ( token . operation ) ;
228+ const [ temp , setTemp ] = useState < InternalToken [ ] > ( firstLevelTokens ) ;
220229 const popoverRef = useRef < InternalPopoverRef > ( null ) ;
221230 const closePopover = ( ) => {
222231 popoverRef . current && popoverRef . current . dismissPopover ( ) ;
223232 } ;
224233
225- const property = temporaryToken . property ;
226- const onChangePropertyKey = ( newPropertyKey : undefined | string ) => {
227- const filteringProperty = filteringProperties . reduce < InternalFilteringProperty | undefined > (
228- ( acc , property ) => ( property . propertyKey === newPropertyKey ? property : acc ) ,
229- undefined
230- ) ;
231- const allowedOperators = filteringProperty ? getAllowedOperators ( filteringProperty ) : freeTextFiltering . operators ;
232- const operator =
233- temporaryToken . operator && allowedOperators . indexOf ( temporaryToken . operator ) !== - 1
234- ? temporaryToken . operator
235- : allowedOperators [ 0 ] ;
236- const matchedProperty = filteringProperties . find ( property => property . propertyKey === newPropertyKey ) ?? null ;
237- setTemporaryToken ( { ...temporaryToken , property : matchedProperty , operator } ) ;
238- } ;
234+ const groups = temp . map ( ( temporaryToken , index ) => {
235+ const setTemporaryToken = ( newToken : InternalToken ) => {
236+ setTemp ( prev => {
237+ const copy = [ ...prev ] ;
238+ copy [ index ] = newToken ;
239+ return copy ;
240+ } ) ;
241+ } ;
239242
240- const operator = temporaryToken . operator ;
241- const onChangeOperator = ( newOperator : ComparisonOperator ) => {
242- setTemporaryToken ( { ...temporaryToken , operator : newOperator } ) ;
243- } ;
243+ const property = temporaryToken . property ;
244+ const onChangePropertyKey = ( newPropertyKey : undefined | string ) => {
245+ const filteringProperty = filteringProperties . reduce < InternalFilteringProperty | undefined > (
246+ ( acc , property ) => ( property . propertyKey === newPropertyKey ? property : acc ) ,
247+ undefined
248+ ) ;
249+ const allowedOperators = filteringProperty ? getAllowedOperators ( filteringProperty ) : freeTextFiltering . operators ;
250+ const operator =
251+ temporaryToken . operator && allowedOperators . indexOf ( temporaryToken . operator ) !== - 1
252+ ? temporaryToken . operator
253+ : allowedOperators [ 0 ] ;
254+ const matchedProperty = filteringProperties . find ( property => property . propertyKey === newPropertyKey ) ?? null ;
255+ setTemporaryToken ( { ...temporaryToken , property : matchedProperty , operator } ) ;
256+ } ;
244257
245- const value = temporaryToken . value ;
246- const onChangeValue = ( newValue : string ) => {
247- setTemporaryToken ( { ...temporaryToken , value : newValue } ) ;
248- } ;
258+ const operator = temporaryToken . operator ;
259+ const onChangeOperator = ( newOperator : ComparisonOperator ) => {
260+ setTemporaryToken ( { ...temporaryToken , operator : newOperator } ) ;
261+ } ;
262+
263+ const value = temporaryToken . value ;
264+ const onChangeValue = ( newValue : string ) => {
265+ setTemporaryToken ( { ...temporaryToken , value : newValue } ) ;
266+ } ;
267+
268+ return { property, onChangePropertyKey, operator, onChangeOperator, value, onChangeValue } ;
269+ } ) ;
270+
271+ const operationOptions = [ { value : 'and' } , { value : 'or' } ] ;
249272
250273 return (
251274 < InternalPopover
@@ -256,47 +279,86 @@ export function TokenEditor({
256279 size = "large"
257280 position = "right"
258281 dismissAriaLabel = { i18nStrings . dismissAriaLabel }
259- __onOpen = { ( ) => setTemporaryToken ( firstToken ) }
282+ __onOpen = { ( ) => setTemp ( firstLevelTokens ) }
260283 renderWithPortal = { expandToViewport }
261284 content = {
262285 < div className = { styles [ 'token-editor' ] } >
263- < div className = { styles [ 'token-editor-form' ] } >
264- < InternalFormField label = { i18nStrings . propertyText } className = { styles [ 'token-editor-field-property' ] } >
265- < PropertyInput
266- property = { property }
267- onChangePropertyKey = { onChangePropertyKey }
268- asyncProps = { asyncProperties ? asyncProps : null }
269- filteringProperties = { filteringProperties }
270- onLoadItems = { onLoadItems }
271- customGroupsText = { customGroupsText }
272- i18nStrings = { i18nStrings }
273- freeTextFiltering = { freeTextFiltering }
286+ < InternalBox margin = { { bottom : 's' } } >
287+ { /* TODO: i18n */ }
288+ < InternalFormField label = "Operation" >
289+ < InternalSelect
290+ options = { operationOptions }
291+ selectedOption = { operationOptions . find ( option => option . value === operation ) ! }
292+ onChange = { event => setOperation ( event . detail . selectedOption . value as 'and' | 'or' ) }
274293 />
275294 </ InternalFormField >
295+ </ InternalBox >
276296
277- < InternalFormField label = { i18nStrings . operatorText } className = { styles [ 'token-editor-field-operator' ] } >
278- < OperatorInput
279- property = { property }
280- operator = { operator }
281- onChangeOperator = { onChangeOperator }
282- i18nStrings = { i18nStrings }
283- freeTextFiltering = { freeTextFiltering }
284- />
285- </ InternalFormField >
297+ { groups . map ( ( group , index ) => (
298+ < div key = { index } className = { styles [ 'token-editor-form' ] } >
299+ < InternalFormField label = { i18nStrings . propertyText } className = { styles [ 'token-editor-field-property' ] } >
300+ < PropertyInput
301+ property = { group . property }
302+ onChangePropertyKey = { group . onChangePropertyKey }
303+ asyncProps = { asyncProperties ? asyncProps : null }
304+ filteringProperties = { filteringProperties }
305+ onLoadItems = { onLoadItems }
306+ customGroupsText = { customGroupsText }
307+ i18nStrings = { i18nStrings }
308+ freeTextFiltering = { freeTextFiltering }
309+ />
310+ </ InternalFormField >
286311
287- < InternalFormField label = { i18nStrings . valueText } className = { styles [ 'token-editor-field-value' ] } >
288- < ValueInput
289- property = { property }
290- operator = { operator }
291- value = { value }
292- onChangeValue = { onChangeValue }
293- asyncProps = { asyncProps }
294- filteringOptions = { filteringOptions }
295- onLoadItems = { onLoadItems }
296- i18nStrings = { i18nStrings }
297- />
298- </ InternalFormField >
299- </ div >
312+ < InternalFormField label = { i18nStrings . operatorText } className = { styles [ 'token-editor-field-operator' ] } >
313+ < OperatorInput
314+ property = { group . property }
315+ operator = { group . operator }
316+ onChangeOperator = { group . onChangeOperator }
317+ i18nStrings = { i18nStrings }
318+ freeTextFiltering = { freeTextFiltering }
319+ />
320+ </ InternalFormField >
321+
322+ < InternalFormField label = { i18nStrings . valueText } className = { styles [ 'token-editor-field-value' ] } >
323+ < ValueInput
324+ property = { group . property }
325+ operator = { group . operator }
326+ value = { group . value }
327+ onChangeValue = { group . onChangeValue }
328+ asyncProps = { asyncProps }
329+ filteringOptions = { filteringOptions }
330+ onLoadItems = { onLoadItems }
331+ i18nStrings = { i18nStrings }
332+ />
333+ </ InternalFormField >
334+
335+ { /* TODO: i18n */ }
336+ { groups . length > 1 && (
337+ < InternalBox margin = { { top : 'xs' } } >
338+ < InternalButton
339+ iconName = "remove"
340+ onClick = { ( ) =>
341+ setTemp ( prev => {
342+ const copy = [ ...prev ] ;
343+ copy . splice ( index , 1 ) ;
344+ return copy ;
345+ } )
346+ }
347+ >
348+ Remove token
349+ </ InternalButton >
350+ </ InternalBox >
351+ ) }
352+ </ div >
353+ ) ) }
354+
355+ { /* TODO: i18n */ }
356+ < InternalButton
357+ iconName = "add-plus"
358+ onClick = { ( ) => setTemp ( prev => [ ...prev , { property : null , operator : ':' , value : null } ] ) }
359+ >
360+ Add token
361+ </ InternalButton >
300362
301363 < div className = { styles [ 'token-editor-actions' ] } >
302364 < InternalButton
@@ -311,7 +373,10 @@ export function TokenEditor({
311373 className = { styles [ 'token-editor-submit' ] }
312374 formAction = "none"
313375 onClick = { ( ) => {
314- setToken ( { operation : token . operation , tokens : [ matchTokenValue ( temporaryToken , filteringOptions ) ] } ) ;
376+ setToken ( {
377+ operation,
378+ tokens : temp . map ( temporaryToken => matchTokenValue ( temporaryToken , filteringOptions ) ) ,
379+ } ) ;
315380 closePopover ( ) ;
316381 } }
317382 >
0 commit comments