wired-tools: hoist inline editor state (variables + managed holder) to the store

Move the four inline-editor useStates out of WiredCreatorToolsView and
into useWiredCreatorToolsUiStore:

- editingVariable / editingValue — Inspection-tab variables-table
  inline edit (current key being edited + in-flight input text).
- editingManagedHolderVariableId / editingManagedHolderValue — same
  pair for the Variable Manage panel's holder rows (id 0 = none).

WiredInspectionTabView drops three more props (editingVariable,
editingValue, onEditingValueChange) and consumes the store directly
for the read sides + the per-keystroke setEditingValue. The cancel /
keydown / begin handlers stay in the parent because they wrap
shouldPauseVariableSnapshotRefresh-aware logic plus selection
bookkeeping that doesn't belong to a pure tab body.

The shouldPauseVariableSnapshotRefresh derived flag still reads from
the same store now-backed values; no behaviour change on the polling
suppression path.

Tests: three new cases (set+read pair, null-clear, managed-holder
0-as-sentinel reset). 193/193 passing.
This commit is contained in:
simoleo89
2026-05-16 12:37:29 +02:00
parent c1aafffd09
commit 181ca096d0
4 changed files with 97 additions and 17 deletions
@@ -50,8 +50,10 @@ export const WiredCreatorToolsView: FC<{}> = () =>
const setMonitorHistorySeverityFilter = useWiredCreatorToolsUiStore(s => s.setMonitorHistorySeverityFilter); const setMonitorHistorySeverityFilter = useWiredCreatorToolsUiStore(s => s.setMonitorHistorySeverityFilter);
const monitorHistoryTypeFilter = useWiredCreatorToolsUiStore(s => s.monitorHistoryTypeFilter); const monitorHistoryTypeFilter = useWiredCreatorToolsUiStore(s => s.monitorHistoryTypeFilter);
const setMonitorHistoryTypeFilter = useWiredCreatorToolsUiStore(s => s.setMonitorHistoryTypeFilter); const setMonitorHistoryTypeFilter = useWiredCreatorToolsUiStore(s => s.setMonitorHistoryTypeFilter);
const [ editingVariable, setEditingVariable ] = useState<string>(null); const editingVariable = useWiredCreatorToolsUiStore(s => s.editingVariable);
const [ editingValue, setEditingValue ] = useState(''); const setEditingVariable = useWiredCreatorToolsUiStore(s => s.setEditingVariable);
const editingValue = useWiredCreatorToolsUiStore(s => s.editingValue);
const setEditingValue = useWiredCreatorToolsUiStore(s => s.setEditingValue);
const [ selectedInspectionVariableKeys, setSelectedInspectionVariableKeys ] = useState<Record<InspectionElementType, string>>({ const [ selectedInspectionVariableKeys, setSelectedInspectionVariableKeys ] = useState<Record<InspectionElementType, string>>({
furni: '', furni: '',
user: '', user: '',
@@ -71,8 +73,10 @@ export const WiredCreatorToolsView: FC<{}> = () =>
const setVariableManagePage = useWiredCreatorToolsUiStore(s => s.setVariableManagePage); const setVariableManagePage = useWiredCreatorToolsUiStore(s => s.setVariableManagePage);
const [ selectedManagedVariableEntry, setSelectedManagedVariableEntry ] = useState<VariableManageEntry>(null); const [ selectedManagedVariableEntry, setSelectedManagedVariableEntry ] = useState<VariableManageEntry>(null);
const [ selectedManagedHolderVariableId, setSelectedManagedHolderVariableId ] = useState(0); const [ selectedManagedHolderVariableId, setSelectedManagedHolderVariableId ] = useState(0);
const [ editingManagedHolderVariableId, setEditingManagedHolderVariableId ] = useState(0); const editingManagedHolderVariableId = useWiredCreatorToolsUiStore(s => s.editingManagedHolderVariableId);
const [ editingManagedHolderValue, setEditingManagedHolderValue ] = useState(''); const setEditingManagedHolderVariableId = useWiredCreatorToolsUiStore(s => s.setEditingManagedHolderVariableId);
const editingManagedHolderValue = useWiredCreatorToolsUiStore(s => s.editingManagedHolderValue);
const setEditingManagedHolderValue = useWiredCreatorToolsUiStore(s => s.setEditingManagedHolderValue);
const isManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.isManagedGiveOpen); const isManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.isManagedGiveOpen);
const setIsManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsManagedGiveOpen); const setIsManagedGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsManagedGiveOpen);
const [ managedGiveVariableItemId, setManagedGiveVariableItemId ] = useState(0); const [ managedGiveVariableItemId, setManagedGiveVariableItemId ] = useState(0);
@@ -3121,9 +3125,6 @@ export const WiredCreatorToolsView: FC<{}> = () =>
setSelectedInspectionVariableKeys(prev => ({ ...prev, [inspectionType]: variable.key })); setSelectedInspectionVariableKeys(prev => ({ ...prev, [inspectionType]: variable.key }));
beginVariableEdit(variable); beginVariableEdit(variable);
} } } }
editingVariable={ editingVariable }
editingValue={ editingValue }
onEditingValueChange={ setEditingValue }
onCancelVariableEdit={ cancelVariableEdit } onCancelVariableEdit={ cancelVariableEdit }
onVariableInputKeyDown={ onVariableInputKeyDown } onVariableInputKeyDown={ onVariableInputKeyDown }
onBeginVariableEdit={ variable => onBeginVariableEdit={ variable =>
@@ -34,10 +34,10 @@ export interface WiredInspectionTabViewProps
selectedInspectionVariableKey: string; selectedInspectionVariableKey: string;
onSelectInspectionVariable: (variable: InspectionVariable) => void; onSelectInspectionVariable: (variable: InspectionVariable) => void;
// inline editor // inline editor — `editingVariable` / `editingValue` come from the
editingVariable: string; // store; this tab only needs the cancel / keydown / begin handlers
editingValue: string; // since each tab consumer wraps `onBeginVariableEdit` with its own
onEditingValueChange: (value: string) => void; // bookkeeping (variable-key tracking).
onCancelVariableEdit: () => void; onCancelVariableEdit: () => void;
onVariableInputKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void; onVariableInputKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;
onBeginVariableEdit: (variable: InspectionVariable) => void; onBeginVariableEdit: (variable: InspectionVariable) => void;
@@ -73,9 +73,6 @@ export const WiredInspectionTabView = (props: WiredInspectionTabViewProps) =>
displayedVariables, displayedVariables,
selectedInspectionVariableKey, selectedInspectionVariableKey,
onSelectInspectionVariable, onSelectInspectionVariable,
editingVariable,
editingValue,
onEditingValueChange,
onCancelVariableEdit, onCancelVariableEdit,
onVariableInputKeyDown, onVariableInputKeyDown,
onBeginVariableEdit, onBeginVariableEdit,
@@ -94,6 +91,9 @@ export const WiredInspectionTabView = (props: WiredInspectionTabViewProps) =>
const setInspectionType = useWiredCreatorToolsUiStore(s => s.setInspectionType); const setInspectionType = useWiredCreatorToolsUiStore(s => s.setInspectionType);
const isInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.isInspectionGiveOpen); const isInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.isInspectionGiveOpen);
const setIsInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsInspectionGiveOpen); const setIsInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsInspectionGiveOpen);
const editingVariable = useWiredCreatorToolsUiStore(s => s.editingVariable);
const editingValue = useWiredCreatorToolsUiStore(s => s.editingValue);
const setEditingValue = useWiredCreatorToolsUiStore(s => s.setEditingValue);
return ( return (
<div className="p-3 min-h-[360px] flex gap-4"> <div className="p-3 min-h-[360px] flex gap-4">
@@ -173,7 +173,7 @@ export const WiredInspectionTabView = (props: WiredInspectionTabViewProps) =>
value={ editingValue } value={ editingValue }
onClick={ event => event.stopPropagation() } onClick={ event => event.stopPropagation() }
onBlur={ onCancelVariableEdit } onBlur={ onCancelVariableEdit }
onChange={ event => onEditingValueChange(event.target.value) } onChange={ event => setEditingValue(event.target.value) }
onKeyDownCapture={ onVariableInputKeyDown } /> } onKeyDownCapture={ onVariableInputKeyDown } /> }
{ (editingVariable !== variable.key) && !variable.editable && <span className={ variable.valueClassName }>{ variable.value }</span> } { (editingVariable !== variable.key) && !variable.editable && <span className={ variable.valueClassName }>{ variable.value }</span> }
{ (editingVariable !== variable.key) && variable.editable && { (editingVariable !== variable.key) && variable.editable &&
@@ -24,7 +24,11 @@ const INITIAL = {
selectedUserLiveState: null, selectedUserLiveState: null,
selectedUserActionVersion: 0, selectedUserActionVersion: 0,
isVariableHighlightActive: false, isVariableHighlightActive: false,
variableHighlightOverlays: [] variableHighlightOverlays: [],
editingVariable: null,
editingValue: '',
editingManagedHolderVariableId: 0,
editingManagedHolderValue: ''
}; };
describe('useWiredCreatorToolsUiStore', () => describe('useWiredCreatorToolsUiStore', () =>
@@ -60,6 +64,10 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(state.selectedUserActionVersion).toBe(0); expect(state.selectedUserActionVersion).toBe(0);
expect(state.isVariableHighlightActive).toBe(false); expect(state.isVariableHighlightActive).toBe(false);
expect(state.variableHighlightOverlays).toEqual([]); expect(state.variableHighlightOverlays).toEqual([]);
expect(state.editingVariable).toBeNull();
expect(state.editingValue).toBe('');
expect(state.editingManagedHolderVariableId).toBe(0);
expect(state.editingManagedHolderValue).toBe('');
}); });
describe('setIsVisible', () => describe('setIsVisible', () =>
@@ -356,4 +364,44 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(useWiredCreatorToolsUiStore.getState().variableHighlightOverlays).toEqual([ overlay ]); expect(useWiredCreatorToolsUiStore.getState().variableHighlightOverlays).toEqual([ overlay ]);
}); });
}); });
describe('inline editor', () =>
{
it('setEditingVariable + setEditingValue track the in-flight edit', () =>
{
useWiredCreatorToolsUiStore.getState().setEditingVariable('@state');
useWiredCreatorToolsUiStore.getState().setEditingValue('3');
expect(useWiredCreatorToolsUiStore.getState().editingVariable).toBe('@state');
expect(useWiredCreatorToolsUiStore.getState().editingValue).toBe('3');
});
it('setEditingVariable(null) clears the edit (commit / cancel path)', () =>
{
useWiredCreatorToolsUiStore.getState().setEditingVariable('@state');
useWiredCreatorToolsUiStore.getState().setEditingValue('3');
useWiredCreatorToolsUiStore.getState().setEditingVariable(null);
useWiredCreatorToolsUiStore.getState().setEditingValue('');
expect(useWiredCreatorToolsUiStore.getState().editingVariable).toBeNull();
expect(useWiredCreatorToolsUiStore.getState().editingValue).toBe('');
});
it('managed-holder editor pair uses 0 as "no row being edited"', () =>
{
useWiredCreatorToolsUiStore.getState().setEditingManagedHolderVariableId(42);
useWiredCreatorToolsUiStore.getState().setEditingManagedHolderValue('15');
expect(useWiredCreatorToolsUiStore.getState().editingManagedHolderVariableId).toBe(42);
expect(useWiredCreatorToolsUiStore.getState().editingManagedHolderValue).toBe('15');
// Reset path used after commit / on blur.
useWiredCreatorToolsUiStore.getState().setEditingManagedHolderVariableId(0);
useWiredCreatorToolsUiStore.getState().setEditingManagedHolderValue('');
expect(useWiredCreatorToolsUiStore.getState().editingManagedHolderVariableId).toBe(0);
expect(useWiredCreatorToolsUiStore.getState().editingManagedHolderValue).toBe('');
});
});
}); });
@@ -65,6 +65,22 @@ interface WiredCreatorToolsUiState
isVariableHighlightActive: boolean; isVariableHighlightActive: boolean;
variableHighlightOverlays: VariableHighlightOverlay[]; variableHighlightOverlays: VariableHighlightOverlay[];
/**
* Inline-editor state for the Inspection-tab variables table.
* `editingVariable` is the key of the variable whose value is being
* edited (null = none); `editingValue` is the in-flight text input.
* The "managed holder" pair plays the same role for the Variable
* Manage panel's holder rows (id 0 = none).
*
* The component uses these together with `shouldPauseVariableSnapshotRefresh`
* to suppress the periodic variables poll while an edit is open
* (so typing isn't clobbered by an incoming snapshot).
*/
editingVariable: string | null;
editingValue: string;
editingManagedHolderVariableId: number;
editingManagedHolderValue: string;
setIsVisible: (next: Updater<boolean>) => void; setIsVisible: (next: Updater<boolean>) => void;
setActiveTab: (next: WiredToolsTab) => void; setActiveTab: (next: WiredToolsTab) => void;
setInspectionType: (next: InspectionElementType) => void; setInspectionType: (next: InspectionElementType) => void;
@@ -94,6 +110,11 @@ interface WiredCreatorToolsUiState
setIsVariableHighlightActive: (next: Updater<boolean>) => void; setIsVariableHighlightActive: (next: Updater<boolean>) => void;
setVariableHighlightOverlays: (next: VariableHighlightOverlay[]) => void; setVariableHighlightOverlays: (next: VariableHighlightOverlay[]) => void;
setEditingVariable: (next: string | null) => void;
setEditingValue: (next: string) => void;
setEditingManagedHolderVariableId: (next: number) => void;
setEditingManagedHolderValue: (next: string) => void;
} }
export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiState>()((set) => ({ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiState>()((set) => ({
@@ -126,6 +147,11 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
isVariableHighlightActive: false, isVariableHighlightActive: false,
variableHighlightOverlays: [], variableHighlightOverlays: [],
editingVariable: null,
editingValue: '',
editingManagedHolderVariableId: 0,
editingManagedHolderValue: '',
setIsVisible: (next) => set(state => ({ isVisible: apply(state.isVisible, next) })), setIsVisible: (next) => set(state => ({ isVisible: apply(state.isVisible, next) })),
setActiveTab: (next) => set({ activeTab: next }), setActiveTab: (next) => set({ activeTab: next }),
setInspectionType: (next) => set({ inspectionType: next }), setInspectionType: (next) => set({ inspectionType: next }),
@@ -154,5 +180,10 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
setSelectedUserActionVersion: (next) => set(state => ({ selectedUserActionVersion: apply(state.selectedUserActionVersion, next) })), setSelectedUserActionVersion: (next) => set(state => ({ selectedUserActionVersion: apply(state.selectedUserActionVersion, next) })),
setIsVariableHighlightActive: (next) => set(state => ({ isVariableHighlightActive: apply(state.isVariableHighlightActive, next) })), setIsVariableHighlightActive: (next) => set(state => ({ isVariableHighlightActive: apply(state.isVariableHighlightActive, next) })),
setVariableHighlightOverlays: (next) => set({ variableHighlightOverlays: next }) setVariableHighlightOverlays: (next) => set({ variableHighlightOverlays: next }),
setEditingVariable: (next) => set({ editingVariable: next }),
setEditingValue: (next) => set({ editingValue: next }),
setEditingManagedHolderVariableId: (next) => set({ editingManagedHolderVariableId: next }),
setEditingManagedHolderValue: (next) => set({ editingManagedHolderValue: next })
})); }));