wired-tools(store): hoist variable-key records (selectedInspectionVariableKeys, selectedVariableKeys)

Move the last two `Record<...Type, string>` useStates out of
WiredCreatorToolsView into useWiredCreatorToolsUiStore. Both writers
were already using the `prev => ({ ...prev, [key]: value })` updater
shape, so the new store setters expose `Updater<Record<...>>` to keep
existing call sites verbatim.

Initial values default to empty strings; the existing
`variableDefinitionsByType` sync effect at WiredCreatorToolsView.tsx
:1543-1574 already populates valid keys on first render and reconciles
whenever the server-side definitions change. Closing/reopening the panel
now preserves the active picker key instead of resetting it.

Tests: 4 new cases on the store (updater shape, single-key patch
preserving siblings, direct-record write path, panel-lifecycle
persistence). Suite: 197/197 (was 193/193).
This commit is contained in:
simoleo89
2026-05-18 20:36:17 +02:00
parent 3b35fa9175
commit ba77806f52
3 changed files with 79 additions and 13 deletions
@@ -54,11 +54,8 @@ export const WiredCreatorToolsView: FC<{}> = () =>
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>>({
furni: '',
user: '',
global: ''
});
const selectedInspectionVariableKeys = useWiredCreatorToolsUiStore(s => s.selectedInspectionVariableKeys);
const setSelectedInspectionVariableKeys = useWiredCreatorToolsUiStore(s => s.setSelectedInspectionVariableKeys);
const isInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.isInspectionGiveOpen);
const setIsInspectionGiveOpen = useWiredCreatorToolsUiStore(s => s.setIsInspectionGiveOpen);
const [ inspectionGiveVariableItemId, setInspectionGiveVariableItemId ] = useState(0);
@@ -87,12 +84,8 @@ export const WiredCreatorToolsView: FC<{}> = () =>
const setVariableHighlightOverlays = useWiredCreatorToolsUiStore(s => s.setVariableHighlightOverlays);
const variableHighlightObjectsRef = useRef<Array<{ category: number; objectId: number; }>>([]);
const shouldPauseVariableSnapshotRefresh = (!!editingVariable || !!editingManagedHolderVariableId || isInspectionGiveOpen || isManagedGiveOpen);
const [ selectedVariableKeys, setSelectedVariableKeys ] = useState<Record<VariablesElementType, string>>({
furni: VARIABLE_DEFINITIONS.furni[0].key,
user: VARIABLE_DEFINITIONS.user[0].key,
global: VARIABLE_DEFINITIONS.global[0].key,
context: VARIABLE_DEFINITIONS.context[0].key
});
const selectedVariableKeys = useWiredCreatorToolsUiStore(s => s.selectedVariableKeys);
const setSelectedVariableKeys = useWiredCreatorToolsUiStore(s => s.setSelectedVariableKeys);
const { roomSession = null } = useRoom();
const { ownUser: tradeOwnUser = null, otherUser: tradeOtherUser = null, isTrading = false } = useInventoryTrade();
const { roomSettings, userVariableDefinitions, userVariableAssignments, furniVariableDefinitions, furniVariableAssignments, roomVariableDefinitions, roomVariableAssignments, contextVariableDefinitions, requestUserVariables, assignUserVariable, removeUserVariable, updateUserVariableValue, assignFurniVariable, removeFurniVariable, updateFurniVariableValue, updateRoomVariableValue } = useWiredTools();
@@ -28,7 +28,9 @@ const INITIAL = {
editingVariable: null,
editingValue: '',
editingManagedHolderVariableId: 0,
editingManagedHolderValue: ''
editingManagedHolderValue: '',
selectedInspectionVariableKeys: { furni: '', user: '', global: '' },
selectedVariableKeys: { furni: '', user: '', global: '', context: '' }
};
describe('useWiredCreatorToolsUiStore', () =>
@@ -68,6 +70,8 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(state.editingValue).toBe('');
expect(state.editingManagedHolderVariableId).toBe(0);
expect(state.editingManagedHolderValue).toBe('');
expect(state.selectedInspectionVariableKeys).toEqual({ furni: '', user: '', global: '' });
expect(state.selectedVariableKeys).toEqual({ furni: '', user: '', global: '', context: '' });
});
describe('setIsVisible', () =>
@@ -404,4 +408,54 @@ describe('useWiredCreatorToolsUiStore', () =>
expect(useWiredCreatorToolsUiStore.getState().editingManagedHolderValue).toBe('');
});
});
describe('variable-key records', () =>
{
it('setSelectedInspectionVariableKeys accepts the updater shape used by give/remove handlers', () =>
{
useWiredCreatorToolsUiStore.getState().setSelectedInspectionVariableKeys(prev => ({ ...prev, furni: '@state' }));
expect(useWiredCreatorToolsUiStore.getState().selectedInspectionVariableKeys).toEqual({ furni: '@state', user: '', global: '' });
useWiredCreatorToolsUiStore.getState().setSelectedInspectionVariableKeys(prev => ({ ...prev, user: 'username' }));
expect(useWiredCreatorToolsUiStore.getState().selectedInspectionVariableKeys).toEqual({ furni: '@state', user: 'username', global: '' });
});
it('setSelectedVariableKeys preserves untouched keys when patching a single type', () =>
{
useWiredCreatorToolsUiStore.getState().setSelectedVariableKeys(prev => ({ ...prev, furni: '@state', user: 'level' }));
useWiredCreatorToolsUiStore.getState().setSelectedVariableKeys(prev => ({ ...prev, context: 'hotel.uptime' }));
expect(useWiredCreatorToolsUiStore.getState().selectedVariableKeys).toEqual({
furni: '@state',
user: 'level',
global: '',
context: 'hotel.uptime'
});
});
it('setSelectedVariableKeys accepts a direct record (definition-sync write path)', () =>
{
useWiredCreatorToolsUiStore.getState().setSelectedVariableKeys({
furni: '~teleport.target_id',
user: 'username',
global: 'hotel.uptime',
context: 'event.type'
});
expect(useWiredCreatorToolsUiStore.getState().selectedVariableKeys.furni).toBe('~teleport.target_id');
expect(useWiredCreatorToolsUiStore.getState().selectedVariableKeys.context).toBe('event.type');
});
it('variable-key records persist across the panel close/reopen lifecycle', () =>
{
useWiredCreatorToolsUiStore.getState().setSelectedVariableKeys(prev => ({ ...prev, furni: '@state' }));
useWiredCreatorToolsUiStore.getState().setSelectedInspectionVariableKeys(prev => ({ ...prev, user: 'level' }));
useWiredCreatorToolsUiStore.getState().setIsVisible(false);
useWiredCreatorToolsUiStore.getState().setIsVisible(true);
expect(useWiredCreatorToolsUiStore.getState().selectedVariableKeys.furni).toBe('@state');
expect(useWiredCreatorToolsUiStore.getState().selectedInspectionVariableKeys.user).toBe('level');
});
});
});
@@ -81,6 +81,16 @@ interface WiredCreatorToolsUiState
editingManagedHolderVariableId: number;
editingManagedHolderValue: string;
/**
* Currently selected variable key per tab/type, used as the "active"
* row in the Inspection and Variables tabs. The sync effects in
* `WiredCreatorToolsView` auto-pick the first available key whenever
* the definitions list for that type changes, so we initialize empty
* — the component's first paint populates them.
*/
selectedInspectionVariableKeys: Record<InspectionElementType, string>;
selectedVariableKeys: Record<VariablesElementType, string>;
setIsVisible: (next: Updater<boolean>) => void;
setActiveTab: (next: WiredToolsTab) => void;
setInspectionType: (next: InspectionElementType) => void;
@@ -115,6 +125,9 @@ interface WiredCreatorToolsUiState
setEditingValue: (next: string) => void;
setEditingManagedHolderVariableId: (next: number) => void;
setEditingManagedHolderValue: (next: string) => void;
setSelectedInspectionVariableKeys: (next: Updater<Record<InspectionElementType, string>>) => void;
setSelectedVariableKeys: (next: Updater<Record<VariablesElementType, string>>) => void;
}
export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiState>()((set) => ({
@@ -152,6 +165,9 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
editingManagedHolderVariableId: 0,
editingManagedHolderValue: '',
selectedInspectionVariableKeys: { furni: '', user: '', global: '' },
selectedVariableKeys: { furni: '', user: '', global: '', context: '' },
setIsVisible: (next) => set(state => ({ isVisible: apply(state.isVisible, next) })),
setActiveTab: (next) => set({ activeTab: next }),
setInspectionType: (next) => set({ inspectionType: next }),
@@ -185,5 +201,8 @@ export const useWiredCreatorToolsUiStore = createNitroStore<WiredCreatorToolsUiS
setEditingVariable: (next) => set({ editingVariable: next }),
setEditingValue: (next) => set({ editingValue: next }),
setEditingManagedHolderVariableId: (next) => set({ editingManagedHolderVariableId: next }),
setEditingManagedHolderValue: (next) => set({ editingManagedHolderValue: next })
setEditingManagedHolderValue: (next) => set({ editingManagedHolderValue: next }),
setSelectedInspectionVariableKeys: (next) => set(state => ({ selectedInspectionVariableKeys: apply(state.selectedInspectionVariableKeys, next) })),
setSelectedVariableKeys: (next) => set(state => ({ selectedVariableKeys: apply(state.selectedVariableKeys, next) }))
}));