From f31addfcc50a670afc0c693a609fde28869b14bf Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Tue, 3 Oct 2023 10:45:33 +0200 Subject: [PATCH 01/25] console: Fix bytes --- pkg/webui/components/input/byte.js | 253 ++++++++++++++--------------- 1 file changed, 124 insertions(+), 129 deletions(-) diff --git a/pkg/webui/components/input/byte.js b/pkg/webui/components/input/byte.js index 3f0a0c2129..0cf440b053 100644 --- a/pkg/webui/components/input/byte.js +++ b/pkg/webui/components/input/byte.js @@ -55,139 +55,134 @@ const upper = str => str.toUpperCase() const clean = str => (typeof str === 'string' ? str.replace(voidChars, '') : str) -const ByteInput = ({ - onBlur, - value, - className, - min, - max, - onChange, - placeholder, - showPerChar, - unbounded, - ...rest -}) => { - const onCopy = useCallback(evt => { - const input = evt.target - const selectedValue = input.value.substr( - input.selectionStart, - input.selectionEnd - input.selectionStart, - ) - evt.clipboardData.setData('text/plain', clean(selectedValue)) - evt.preventDefault() - }, []) - - const onPaste = useCallback( - evt => { - // Ignore empty pastes. - if (evt?.clipboardData?.getData('text/plain')?.length === 0) { - return - } - const val = evt.target.value - const cleanedSelection = clean( - val.substr( - evt.target.selectionStart, - Math.max(1, evt.target.selectionEnd - evt.target.selectionStart), - ), +const ByteInput = React.forwardRef( + ( + { onBlur, value, className, min, max, onChange, placeholder, showPerChar, unbounded, ...rest }, + ref, + ) => { + const onCopy = useCallback(evt => { + const input = evt.target + const selectedValue = input.value.substr( + input.selectionStart, + input.selectionEnd - input.selectionStart, ) + evt.clipboardData.setData('text/plain', clean(selectedValue)) + evt.preventDefault() + }, []) + + const onPaste = useCallback( + evt => { + // Ignore empty pastes. + if (evt?.clipboardData?.getData('text/plain')?.length === 0) { + return + } + const val = evt.target.value + const cleanedSelection = clean( + val.substr( + evt.target.selectionStart, + Math.max(1, evt.target.selectionEnd - evt.target.selectionStart), + ), + ) + + // To avoid the masked input from cutting off characters when the cursor + // is placed in the mask placeholders, the placeholder chars are removed before + // the paste is applied, unless the user made a selection to paste into. + // This will ensure a consistent pasting experience. + if (!unbounded && cleanedSelection === '') { + evt.target.value = val.replace(voidChars, '') + } + }, + [unbounded], + ) - // To avoid the masked input from cutting off characters when the cursor - // is placed in the mask placeholders, the placeholder chars are removed before - // the paste is applied, unless the user made a selection to paste into. - // This will ensure a consistent pasting experience. - if (!unbounded && cleanedSelection === '') { - evt.target.value = val.replace(voidChars, '') - } - }, - [unbounded], - ) - - const onChangeCallback = useCallback( - evt => { - const data = evt?.nativeEvent?.data - - // Due to the way that react-text-mask works, it is not possible to - // store the cleaned value, since it would create ambiguity between - // values like `AA` and `AA `. This causes backspaces to not work - // if it targets the space character, since the deleted space would - // be re-added right away. Hence, unbounded inputs need to remove - // the space paddings manually. - let newValue = unbounded ? evt.target.value : clean(evt.target.value) - - // Make sure values entered at the end of the input (with placeholders) - // are added as expected. `selectionStart` cannot be used due to - // inconsistent behavior on Android phones. - if ( - evt.target.value.endsWith(PLACEHOLDER_CHAR) && - data && - hex.test(data) && - value === newValue - ) { - newValue += data - } - - onChange({ - target: { - name: evt.target.name, - value: newValue, - }, - }) - }, - [onChange, value, unbounded], - ) - - const onBlurCallback = useCallback( - evt => { - onBlur({ - relatedTarget: evt.relatedTarget, - target: { - name: evt.target.name, - value: clean(evt.target.value), - }, - }) - }, - [onBlur], - ) - - const onCut = useCallback(evt => { - evt.preventDefault() - // Recreate cut action by deleting and reusing copy handler. - document.execCommand('copy') - document.execCommand('delete') - }, []) - - // Instead of calculating the max width dynamically, which leads to various issues - // with pasting, it's better to use a high max value for unbounded inputs instead. - const calculatedMax = max || 4096 - - if (!unbounded && typeof max !== 'number') { - warn( - 'Byte input has been setup without `max` prop. Always use a max prop unless using `unbounded`', + const onChangeCallback = useCallback( + evt => { + const data = evt?.nativeEvent?.data + + // Due to the way that react-text-mask works, it is not possible to + // store the cleaned value, since it would create ambiguity between + // values like `AA` and `AA `. This causes backspaces to not work + // if it targets the space character, since the deleted space would + // be re-added right away. Hence, unbounded inputs need to remove + // the space paddings manually. + let newValue = unbounded ? evt.target.value : clean(evt.target.value) + + // Make sure values entered at the end of the input (with placeholders) + // are added as expected. `selectionStart` cannot be used due to + // inconsistent behavior on Android phones. + if ( + evt.target.value.endsWith(PLACEHOLDER_CHAR) && + data && + hex.test(data) && + value === newValue + ) { + newValue += data + } + + onChange({ + target: { + name: evt.target.name, + value: newValue, + }, + }) + }, + [onChange, value, unbounded], ) - } - return ( - - ) -} + const onBlurCallback = useCallback( + evt => { + onBlur({ + relatedTarget: evt.relatedTarget, + target: { + name: evt.target.name, + value: clean(evt.target.value), + }, + }) + }, + [onBlur], + ) + + const onCut = useCallback(evt => { + evt.preventDefault() + // Recreate cut action by deleting and reusing copy handler. + document.execCommand('copy') + document.execCommand('delete') + }, []) + + // Instead of calculating the max width dynamically, which leads to various issues + // with pasting, it's better to use a high max value for unbounded inputs instead. + const calculatedMax = max || 4096 + + if (!unbounded && typeof max !== 'number') { + warn( + 'Byte input has been setup without `max` prop. Always use a max prop unless using `unbounded`', + ) + } + + return ( + + ) + }, +) ByteInput.propTypes = { className: PropTypes.string, From ddb8356ff08714cdcd04d266ede56b6eba72bb47 Mon Sep 17 00:00:00 2001 From: Darya Plotnytska Date: Tue, 3 Oct 2023 10:45:59 +0200 Subject: [PATCH 02/25] console: Update key value map --- pkg/webui/components/key-value-map/entry.js | 11 +++++++++-- pkg/webui/components/key-value-map/index.js | 14 +++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/pkg/webui/components/key-value-map/entry.js b/pkg/webui/components/key-value-map/entry.js index 05e25355df..c215335e39 100644 --- a/pkg/webui/components/key-value-map/entry.js +++ b/pkg/webui/components/key-value-map/entry.js @@ -39,6 +39,8 @@ const Entry = ({ valuePlaceholder, keyPlaceholder, additionalInputProps, + removeMessage, + icon, }) => { const _getKeyInputName = useMemo(() => `${name}[${index}].key`, [index, name]) @@ -115,10 +117,11 @@ const Entry = ({