Files
Wand-Enhancer-k1tbyte/web-panel/src/features/remote-panel/state.ts
T
kitbyte 13759b1db6 feat: ship 1.0.8.0 release automation and runtime overhaul
- reduce ASAR IO overhead with streamed archive reads, buffered copies, faster relative-path handling and placeholder integrity records
- fix in-place app.asar.unpacked packing/extraction self-copy cases that caused locked-file failures
- tighten JS patch discovery with candidate bundle filters and search hints
- require prebuilt remote-panel dist artifacts and clean up embedded bridge/script packaging
- add unified build entrypoints for PowerShell, cmd and bash and move native CMake output under .tmp
- add release metadata validation, changelog section extraction, pre-commit hook and GitHub Actions validation/release pipelines
- make CHANGELOG the source of truth for release notes and document the tag-driven release flow
- add updater release notes UI with latest/full changelog loading and localize the new update strings
- modularize bridge renderer scripts, add installed apps and game status sync, and support remote launch/stop commands
- centralize bridge protocol, IPC and WebSocket constants and improve LAN IP selection for QR pairing
- refactor remote panel controls/state enums, persist accent color, polish library/session UI and refresh assets
2026-05-06 13:07:09 +03:00

167 lines
5.2 KiB
TypeScript

import { readInitialRemoteUrl, readInitialWebSocketUrl } from './constants';
import type { GameStatusPayload, InstalledAppSummary, InstalledAppsPayload, TrainerMetaPayload } from './protocol';
export enum EConnectionStatus {
Idle = 'idle',
Connecting = 'connecting',
Connected = 'connected',
Error = 'error',
}
export type PanelState = {
connectionStatus: EConnectionStatus;
wsUrl: string;
remoteUrl: string;
trainerMeta: TrainerMetaPayload | null;
gameStatus: GameStatusPayload | null;
installedApps: InstalledAppSummary[];
installedAppsUpdatedAt: string | null;
values: Record<string, unknown>;
pendingTargets: Record<string, boolean>;
pinnedTargets: Record<string, true>;
lastError: string | null;
};
export type PanelAction =
| { type: 'setWsUrl'; wsUrl: string }
| { type: 'setRemoteUrl'; remoteUrl: string }
| { type: 'connecting' }
| { type: 'connected' }
| { type: 'disconnected' }
| { type: 'trainerMeta'; payload: TrainerMetaPayload }
| { type: 'gameStatus'; payload: GameStatusPayload }
| { type: 'installedApps'; payload: InstalledAppsPayload }
| { type: 'trainerValues'; payload: Record<string, unknown> }
| { type: 'valueChanged'; target: string; value: unknown }
| { type: 'setPending'; target: string; pending: boolean }
| { type: 'trainerChanged' }
| { type: 'setPinnedTargets'; pinned: Record<string, true> }
| { type: 'togglePinnedTarget'; target: string }
| { type: 'error'; message: string | null };
export function createInitialPanelState(): PanelState {
return {
connectionStatus: EConnectionStatus.Idle,
wsUrl: readInitialWebSocketUrl(),
remoteUrl: readInitialRemoteUrl(),
trainerMeta: null,
gameStatus: null,
installedApps: [],
installedAppsUpdatedAt: null,
values: {},
pendingTargets: {},
pinnedTargets: {},
lastError: null,
};
}
export function panelReducer(state: PanelState, action: PanelAction): PanelState {
switch (action.type) {
case 'setWsUrl':
return {
...state,
wsUrl: action.wsUrl,
};
case 'setRemoteUrl':
return {
...state,
remoteUrl: action.remoteUrl,
};
case 'connecting':
return {
...state,
connectionStatus: EConnectionStatus.Connecting,
lastError: null,
};
case 'connected':
return {
...state,
connectionStatus: EConnectionStatus.Connected,
lastError: null,
};
case 'disconnected':
return {
...state,
connectionStatus: EConnectionStatus.Idle,
trainerMeta: null,
gameStatus: null,
values: {},
pendingTargets: {},
lastError: null,
};
case 'trainerMeta':
return {
...state,
trainerMeta: action.payload,
pendingTargets: {},
};
case 'gameStatus':
return {
...state,
gameStatus: action.payload,
};
case 'installedApps':
return {
...state,
installedApps: action.payload.apps,
installedAppsUpdatedAt: action.payload.updatedAt,
};
case 'trainerValues':
return {
...state,
values: action.payload,
};
case 'valueChanged':
return {
...state,
values: {
...state.values,
[action.target]: action.value,
},
pendingTargets: {
...state.pendingTargets,
[action.target]: false,
},
};
case 'setPending':
return {
...state,
pendingTargets: {
...state.pendingTargets,
[action.target]: action.pending,
},
};
case 'trainerChanged':
return {
...state,
trainerMeta: null,
values: {},
pendingTargets: {},
pinnedTargets: {},
};
case 'setPinnedTargets':
return {
...state,
pinnedTargets: action.pinned,
};
case 'togglePinnedTarget': {
const next = { ...state.pinnedTargets };
if (next[action.target]) {
delete next[action.target];
} else {
next[action.target] = true;
}
return {
...state,
pinnedTargets: next,
};
}
case 'error':
return {
...state,
connectionStatus: action.message && state.connectionStatus !== EConnectionStatus.Connected ? EConnectionStatus.Error : state.connectionStatus,
lastError: action.message,
};
}
}