Fix stale state updates on key-value editor (#7654)

This commit is contained in:
James Gatz 2024-07-03 16:27:22 +02:00 committed by GitHub
parent 9fea3a1894
commit e4b0a6325f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -59,9 +59,9 @@ const EditableOneLineEditorModal = ({
const handler = createKeybindingsHandler({
'Enter': e => {
e.preventDefault();
setIsOpen(false);
onChange(value);
setValue(value);
setIsOpen(false);
},
});
@ -205,30 +205,32 @@ export const KeyValueEditor: FC<Props> = ({
getKey: item => item.id,
});
function upsertPair(pair: typeof pairsList.items[0]) {
const upsertPair = useCallback(function upsertPair(pair: typeof pairsList.items[0]) {
if (pairsList.getItem(pair.id)) {
pairsList.update(pair.id, pair);
onChange(pairsList.items.map(item => (item.id === pair.id ? pair : item)));
const items = pairsList.items.map(item => (item.id === pair.id ? pair : item));
onChange(items);
} else {
const id = pair.id === 'pair-empty' ? generateId('pair') : pair.id;
pairsList.append({ ...pair, id });
onChange(pairsList.items.concat(pair));
const items = pairsList.items.concat(pair);
onChange(items);
}
}, [onChange, pairsList]);
}
function removePair(id: string) {
const removePair = useCallback(function removePair(id: string) {
if (pairsList.getItem(id)) {
pairsList.remove(id);
onChange(pairsList.items.filter(pair => pair.id !== id));
const items = pairsList.items.filter(pair => pair.id !== id);
onChange(items);
}
}
}, [onChange, pairsList]);
function removeAllPairs() {
const removeAllPairs = useCallback(function removeAllPairs() {
pairsList.setSelectedKeys(new Set(pairsList.items.map(item => item.id)));
pairsList.removeSelectedItems();
onChange([]);
}
}, [onChange, pairsList]);
const { dragAndDropHooks } = useDragAndDrop({
getItems: keys =>
@ -395,7 +397,7 @@ export const KeyValueEditor: FC<Props> = ({
dependencies={[showDescription, nunjucksEnabled]}
className="flex pt-1 flex-col w-full overflow-y-auto flex-1 relative"
dragAndDropHooks={dragAndDropHooks}
items={items}
items={items.map(pair => ({ ...pair, upsertPair, removePair }))}
>
{pair => {
const isFile = pair.type === 'file';
@ -409,7 +411,7 @@ export const KeyValueEditor: FC<Props> = ({
defaultValue={pair.value}
readOnly={isDisabled}
getAutocompleteConstants={() => handleGetAutocompleteValueConstants?.(pair) || []}
onChange={value => upsertPair({ ...pair, value })}
onChange={value => pair.upsertPair({ ...pair, value })}
/>
);
@ -421,7 +423,7 @@ export const KeyValueEditor: FC<Props> = ({
disabled={isDisabled}
className="px-2 py-1 w-full fle flex-shrink-0 flex-1 items-center justify-center gap-2 aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm overflow-hidden"
path={pair.fileName || ''}
onChange={fileName => upsertPair({ ...pair, fileName })}
onChange={fileName => pair.upsertPair({ ...pair, fileName })}
/>
);
}
@ -437,8 +439,8 @@ export const KeyValueEditor: FC<Props> = ({
defaultValue: pair.value,
enableRender: nunjucksEnabled,
mode: pair.multiline && typeof pair.multiline === 'string' ? pair.multiline : 'text/plain',
onChange: (value: string) => upsertPair({ ...pair, value }),
onModeChange: (mode: string) => upsertPair({ ...pair, multiline: mode }),
onChange: (value: string) => pair.upsertPair({ ...pair, value }),
onModeChange: (mode: string) => pair.upsertPair({ ...pair, multiline: mode }),
})}
>
<i className="fa fa-pencil-square-o space-right" />
@ -466,7 +468,7 @@ export const KeyValueEditor: FC<Props> = ({
defaultValue={pair.name}
readOnly={isDisabled}
getAutocompleteConstants={() => handleGetAutocompleteNameConstants?.(pair) || []}
onChange={name => upsertPair({ ...pair, name })}
onChange={name => pair.upsertPair({ ...pair, name })}
/>
{valueEditor}
{showDescription && (
@ -475,7 +477,7 @@ export const KeyValueEditor: FC<Props> = ({
placeholder={descriptionPlaceholder || 'Description'}
defaultValue={pair.description || ''}
readOnly={isDisabled}
onChange={description => upsertPair({ ...pair, description })}
onChange={description => pair.upsertPair({ ...pair, description })}
/>
)}
<Toolbar className="flex items-center gap-1">
@ -497,14 +499,14 @@ export const KeyValueEditor: FC<Props> = ({
id: 'text',
name: 'Text',
textValue: 'Text',
onAction: () => upsertPair({ ...pair, type: 'text', multiline: false }),
onAction: () => pair.upsertPair({ ...pair, type: 'text', multiline: false }),
},
...allowMultiline ? [
{
id: 'multiline-text',
name: 'Multiline text',
textValue: 'Multiline text',
onAction: () => upsertPair({ ...pair, type: 'text', multiline: true }),
onAction: () => pair.upsertPair({ ...pair, type: 'text', multiline: true }),
},
] : [],
...allowFile ? [
@ -512,7 +514,7 @@ export const KeyValueEditor: FC<Props> = ({
id: 'file',
name: 'File',
textValue: 'File',
onAction: () => upsertPair({ ...pair, type: 'file' }),
onAction: () => pair.upsertPair({ ...pair, type: 'file' }),
},
] : [],
]}
@ -533,7 +535,7 @@ export const KeyValueEditor: FC<Props> = ({
</MenuTrigger>
<ToggleButton
className="flex items-center justify-center h-7 aspect-square rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm"
onChange={isSelected => upsertPair({ ...pair, disabled: !isSelected })}
onChange={isSelected => pair.upsertPair({ ...pair, disabled: !isSelected })}
isSelected={!pair.disabled}
>
<Icon icon={pair.disabled ? 'square' : 'check-square'} />
@ -543,7 +545,7 @@ export const KeyValueEditor: FC<Props> = ({
className="flex items-center disabled:opacity-50 justify-center h-7 aspect-square aria-pressed:bg-[--hl-sm] rounded-sm text-[--color-font] hover:bg-[--hl-xs] focus:ring-inset ring-1 ring-transparent focus:ring-[--hl-md] transition-all text-sm"
confirmMessage=''
doneMessage=''
onClick={() => removePair(pair.id)}
onClick={() => pair.removePair(pair.id)}
>
<Icon icon="trash-can" />
</PromptButton>