| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | import { css } from '@emotion/css'; | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  | import React from 'react'; | 
					
						
							| 
									
										
										
										
											2022-04-22 21:33:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 19:03:18 +08:00
										 |  |  | import { StandardEditorProps, StringFieldConfigSettings, GrafanaTheme2 } from '@grafana/data'; | 
					
						
							| 
									
										
										
										
											2022-11-03 21:54:18 +08:00
										 |  |  | import { config } from '@grafana/runtime'; | 
					
						
							|  |  |  | import { stylesFactory, Button, Icon, Input } from '@grafana/ui'; | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 19:03:18 +08:00
										 |  |  | type Props = StandardEditorProps<string[], StringFieldConfigSettings>; | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  | interface State { | 
					
						
							|  |  |  |   showAdd: boolean; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class StringArrayEditor extends React.PureComponent<Props, State> { | 
					
						
							|  |  |  |   state = { | 
					
						
							|  |  |  |     showAdd: false, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onRemoveString = (index: number) => { | 
					
						
							|  |  |  |     const { value, onChange } = this.props; | 
					
						
							|  |  |  |     const copy = [...value]; | 
					
						
							|  |  |  |     copy.splice(index, 1); | 
					
						
							|  |  |  |     onChange(copy); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-14 17:51:44 +08:00
										 |  |  |   onValueChange = (e: React.KeyboardEvent<HTMLInputElement> | React.FocusEvent<HTMLInputElement>, idx: number) => { | 
					
						
							|  |  |  |     if ('key' in e) { | 
					
						
							|  |  |  |       if (e.key !== 'Enter') { | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const { value, onChange } = this.props; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Form event, or Enter
 | 
					
						
							| 
									
										
										
										
											2023-03-14 17:51:44 +08:00
										 |  |  |     const v = e.currentTarget.value.trim(); | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |     if (idx < 0) { | 
					
						
							|  |  |  |       if (v) { | 
					
						
							| 
									
										
										
										
											2023-03-14 17:51:44 +08:00
										 |  |  |         e.currentTarget.value = ''; // reset last value
 | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |         onChange([...value, v]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.setState({ showAdd: false }); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!v) { | 
					
						
							|  |  |  |       return this.onRemoveString(idx); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const copy = [...value]; | 
					
						
							|  |  |  |     copy[idx] = v; | 
					
						
							|  |  |  |     onChange(copy); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   render() { | 
					
						
							|  |  |  |     const { value, item } = this.props; | 
					
						
							|  |  |  |     const { showAdd } = this.state; | 
					
						
							| 
									
										
										
										
											2022-11-03 21:54:18 +08:00
										 |  |  |     const styles = getStyles(config.theme2); | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |     const placeholder = item.settings?.placeholder || 'Add text'; | 
					
						
							|  |  |  |     return ( | 
					
						
							|  |  |  |       <div> | 
					
						
							|  |  |  |         {value.map((v, index) => { | 
					
						
							|  |  |  |           return ( | 
					
						
							|  |  |  |             <Input | 
					
						
							|  |  |  |               className={styles.textInput} | 
					
						
							|  |  |  |               key={`${index}/${v}`} | 
					
						
							|  |  |  |               defaultValue={v || ''} | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |               onBlur={(e) => this.onValueChange(e, index)} | 
					
						
							|  |  |  |               onKeyDown={(e) => this.onValueChange(e, index)} | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |               suffix={<Icon className={styles.trashIcon} name="trash-alt" onClick={() => this.onRemoveString(index)} />} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         })} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         {showAdd ? ( | 
					
						
							|  |  |  |           <Input | 
					
						
							|  |  |  |             autoFocus | 
					
						
							|  |  |  |             className={styles.textInput} | 
					
						
							|  |  |  |             placeholder={placeholder} | 
					
						
							|  |  |  |             defaultValue={''} | 
					
						
							| 
									
										
										
										
											2021-01-20 14:59:48 +08:00
										 |  |  |             onBlur={(e) => this.onValueChange(e, -1)} | 
					
						
							|  |  |  |             onKeyDown={(e) => this.onValueChange(e, -1)} | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |             suffix={<Icon name="plus-circle" />} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |         ) : ( | 
					
						
							|  |  |  |           <Button icon="plus" size="sm" variant="secondary" onClick={() => this.setState({ showAdd: true })}> | 
					
						
							|  |  |  |             {placeholder} | 
					
						
							|  |  |  |           </Button> | 
					
						
							|  |  |  |         )} | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 21:54:18 +08:00
										 |  |  | const getStyles = stylesFactory((theme: GrafanaTheme2) => { | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |   return { | 
					
						
							| 
									
										
										
										
											2023-11-29 23:26:19 +08:00
										 |  |  |     textInput: css({ | 
					
						
							|  |  |  |       marginBottom: '5px', | 
					
						
							|  |  |  |       '&:hover': { | 
					
						
							|  |  |  |         border: `1px solid ${theme.components.input.borderHover}`, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }), | 
					
						
							|  |  |  |     trashIcon: css({ | 
					
						
							|  |  |  |       color: theme.colors.text.secondary, | 
					
						
							|  |  |  |       cursor: 'pointer', | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-29 23:26:19 +08:00
										 |  |  |       '&:hover': { | 
					
						
							|  |  |  |         color: theme.colors.text.primary, | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }), | 
					
						
							| 
									
										
										
										
											2020-05-30 04:03:45 +08:00
										 |  |  |   }; | 
					
						
							|  |  |  | }); |