From 6565223b96ff48c961c8ceecf33144a8c92c97b1 Mon Sep 17 00:00:00 2001 From: sokol Date: Wed, 18 Feb 2026 15:51:13 +0300 Subject: [PATCH] fix: env ID generation and React state synchronization --- src/App.tsx | 102 ++++++++++++------------------ src/componets/env/Environment.tsx | 6 +- 2 files changed, 47 insertions(+), 61 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 6dc88a8..3b358f9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,78 +11,55 @@ import logo from './assets/cgg.png' class AppState { private constructor( public config: Config = new Config(), - public envs: Env[] = [ - ], ) { } static readonly Instance = new AppState(); public loadConfig(cfg: Config) { this.config = cfg; - this.envs = cfg.envs; // Reference the same array as config - } - - public addEnv(env: Env): number { - this.envs.push(env); - // Also update config.envs since they reference the same array - this.config.envs = this.envs; - return this.envs.length - 1; } public async saveEnv(env: Env): Promise { - // Create a promise that resolves after 1 second + // Simulate async save with 1 second delay return await new Promise((resolve) => { setTimeout(() => { - let idx = this.envs.findIndex(x => x.id === env.id); - if (idx > -1) { - this.envs[idx] = env; - console.log("UPDATED envs", this.envs); - } - resolve(idx); // Resolve the promise after updating + console.log("Saved env:", env.name); + resolve(0); }, 1000); }); } - - public removeEnv(envId: number) { - const idx = this.envs.findIndex(x => x.id === envId); - if (idx > -1) { - this.envs.splice(idx, 1); - // Also update config.envs since they reference the same array - this.config.envs = this.envs; - } - } - - // Update the internal envs reference to match React state - public syncEnvs(newEnvs: Env[]) { - this.envs = newEnvs; - this.config.envs = newEnvs; - } } function App() { - const [envs, setEnvs] = useState(AppState.Instance.envs); + const [config, setConfig] = useState(() => AppState.Instance.config); + const [envs, setEnvs] = useState(() => AppState.Instance.config.envs); const [selectedEnv, setSelectedEnv] = useState(0); - const [config, setConfig] = useState(AppState.Instance.config); // Ensure selectedEnv is always valid const validSelectedEnv = Math.min(selectedEnv, Math.max(0, envs.length - 1)); const currentEnv = envs[validSelectedEnv]; async function handleEnvChanged(env: Env) { - // Synchronously update the env in the array - let idx = AppState.Instance.envs.findIndex(x => x.id === env.id); - if (idx > -1) { - AppState.Instance.envs[idx] = env; - // Also update config.envs since they reference the same array - AppState.Instance.config.envs = AppState.Instance.envs; - const newEnvs = [...AppState.Instance.envs]; - setEnvs(newEnvs); - AppState.Instance.syncEnvs(newEnvs); // Keep AppState in sync with React state - setConfig(AppState.Instance.config); // Trigger re-render for config - } + // Optimistic update - update React state immediately + setEnvs(prevEnvs => { + const newEnvs = [...prevEnvs]; + const idx = newEnvs.findIndex(x => x.id === env.id); + if (idx > -1) { + newEnvs[idx] = env; + } + return newEnvs; + }); + + // Also update config.envs to keep it in sync + setConfig(prevConfig => { + const newConfig = new Config(); + newConfig.envs = prevConfig.envs.map(e => e.id === env.id ? env : e); + newConfig.template = prevConfig.template; + return newConfig; + }); - // Then do the async save (for consistency with existing behavior) - await AppState.Instance.saveEnv(env); + // Fire off async save in background (no need to wait) + AppState.Instance.saveEnv(env); } function handleEnvSelected(idx: number) { @@ -90,20 +67,25 @@ function App() { } function handleEnvAdded(env: Env): number { - const idx = AppState.Instance.addEnv(env); - const newEnvs = [...AppState.Instance.envs]; - setEnvs(newEnvs); - AppState.Instance.syncEnvs(newEnvs); // Keep AppState in sync with React state - setConfig(AppState.Instance.config); // Trigger re-render for config - return idx; + const newIdx = envs.length; + setEnvs(prevEnvs => [...prevEnvs, env]); + setConfig(prevConfig => { + const newConfig = new Config(); + newConfig.envs = [...prevConfig.envs, env]; + newConfig.template = prevConfig.template; + return newConfig; + }); + return newIdx; } function handleEnvRemoved(envId: number) { - AppState.Instance.removeEnv(envId); - const newEnvs = [...AppState.Instance.envs]; - setEnvs(newEnvs); - AppState.Instance.syncEnvs(newEnvs); // Keep AppState in sync with React state - setConfig(AppState.Instance.config); // Trigger re-render for config + setEnvs(prevEnvs => prevEnvs.filter(e => e.id !== envId)); + setConfig(prevConfig => { + const newConfig = new Config(); + newConfig.envs = prevConfig.envs.filter(e => e.id !== envId); + newConfig.template = prevConfig.template; + return newConfig; + }); } return ( @@ -112,8 +94,8 @@ function App() {
{ AppState.Instance.loadConfig(x); - setEnvs(AppState.Instance.envs); - setConfig(AppState.Instance.config); + setEnvs(x.envs); + setConfig(x); }} />
{envs.length > 0 ? diff --git a/src/componets/env/Environment.tsx b/src/componets/env/Environment.tsx index 9fd69f7..8da6008 100644 --- a/src/componets/env/Environment.tsx +++ b/src/componets/env/Environment.tsx @@ -44,8 +44,12 @@ export function Environment(props: { envs: Env[], onChanged: (env: Env) => void, const name = prompt("Enter new environment name:"); if (!name || name.trim() === "") return; + // Calculate next integer ID based on max existing ID + const maxId = props.envs.reduce((max, e) => Math.max(max, e.id ?? 0), -1); + const newId = maxId + 1; + const newEnv = new Env( - Math.random() * 10000, + newId, name.trim(), [...currEnv.params] );