feat(node): configure system environment through the desktop workflow
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { desktopAction, request } from "./api";
|
||||
|
||||
export interface EnvironmentStep { id: string; state: string; detail: string }
|
||||
export interface EnvironmentRun { schema: string; profile_revision: string; run_id: string; state: string; updated_at: number; steps: EnvironmentStep[] }
|
||||
export interface EnvironmentStatus { available: boolean; profile: {revision: string; steps:{id:string;label:string;description:string}[]}; run: EnvironmentRun | null }
|
||||
|
||||
export function useEnvironment(authorized: boolean, failure: (error: unknown) => void) {
|
||||
const [value, setValue] = useState<EnvironmentStatus | null>(null);
|
||||
const [pending, setPending] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {setValue(await request<EnvironmentStatus>("/api/environment"));}
|
||||
catch(error) {failure(error);}
|
||||
finally {setLoading(false);}
|
||||
},[failure]);
|
||||
// Native progress survives a service restart and never depends on a stale
|
||||
// HTTP session. Reopening an existing run uses the read-only status API.
|
||||
useEffect(() => {
|
||||
function progress(event:Event) {
|
||||
const run=(event as CustomEvent<EnvironmentRun>).detail;
|
||||
if(run?.schema==="missioncore.node.environment/v1") setValue(current=>current?{...current,available:true,run}:current);
|
||||
}
|
||||
function complete(event:Event) {
|
||||
const result=(event as CustomEvent<{ok:boolean;error?:string;reloading?:boolean}>).detail;
|
||||
if(!result?.reloading) setPending(false);
|
||||
if(result?.error) failure(new Error(result.error));
|
||||
// The native launcher renews login after service changes. No immediate
|
||||
// request with the expired cookie is made here.
|
||||
}
|
||||
const sessionReady=()=>setPending(false);
|
||||
window.addEventListener("mission-core-session-ready",sessionReady);
|
||||
window.addEventListener("mission-core-environment-progress",progress);
|
||||
window.addEventListener("mission-core-environment-result",complete);
|
||||
return()=>{window.removeEventListener("mission-core-session-ready",sessionReady);window.removeEventListener("mission-core-environment-progress",progress);window.removeEventListener("mission-core-environment-result",complete);};
|
||||
},[failure]);
|
||||
useEffect(()=>{if(authorized&&!pending) void refresh();},[authorized,pending,refresh]);
|
||||
useEffect(()=>{
|
||||
if(!authorized||pending||value?.run?.state!=="running") return;
|
||||
const timer=setTimeout(()=>void refresh(),2000);return()=>clearTimeout(timer);
|
||||
},[authorized,pending,value,refresh]);
|
||||
function start() {
|
||||
if(pending||value?.run?.state==="running") return;
|
||||
if(!desktopAction("configure-system")) {failure(new Error("Откройте установленное приложение Node для настройки окружения."));return;}
|
||||
setValue(current=>current?{...current,run:null}:current);
|
||||
setPending(true);
|
||||
}
|
||||
return {value,pending,loading,refresh,start,running:pending||value?.run?.state==="running"};
|
||||
}
|
||||
Reference in New Issue
Block a user