Archived
fix: restore fallback machine navigation after deletion
This commit is contained in:
@@ -455,9 +455,9 @@ export class PiWebApp extends LitElement {
|
||||
setNamespacedQueryKey(TERMINAL_ROUTE_NAMESPACE, "terminal", surface.selectedTerminalId, { replace: true });
|
||||
}
|
||||
|
||||
private async selectMachineWithMemory(machine: Machine): Promise<void> {
|
||||
private async selectMachineWithMemory(machine: Machine, options: { rememberCurrent?: boolean } = {}): Promise<void> {
|
||||
if (this.state.selectedMachine?.id === machine.id) return;
|
||||
if (!this.routeRestoreInProgress) this.rememberCurrentMachineNavigation();
|
||||
if (options.rememberCurrent !== false && !this.routeRestoreInProgress) this.rememberCurrentMachineNavigation();
|
||||
const seq = ++this.machineNavigationRestoreSeq;
|
||||
const snapshot = this.machineNavigation.latest(machine.id) ?? emptyMachineNavigationSnapshot(machine.id);
|
||||
await this.restoreRouteFor(routeFromMachineNavigationSnapshot(snapshot), false, snapshot.surface, snapshot.view);
|
||||
@@ -1044,7 +1044,11 @@ export class PiWebApp extends LitElement {
|
||||
private async removeMachine(machine: Machine | undefined = this.state.selectedMachine): Promise<void> {
|
||||
if (machine === undefined || machine.kind === "local") return;
|
||||
if (!window.confirm(`Remove ${machine.name}?\n\nThis only removes it from this PI WEB gateway.`)) return;
|
||||
await this.machines.deleteMachine(machine);
|
||||
const wasSelected = this.state.selectedMachine?.id === machine.id;
|
||||
if (wasSelected) this.rememberCurrentMachineNavigation();
|
||||
const fallback = await this.machines.deleteMachine(machine, { selectFallback: !wasSelected });
|
||||
if (!this.state.machines.some((candidate) => candidate.id === machine.id)) this.machineNavigation.forget(machine.id);
|
||||
if (wasSelected && fallback !== undefined) await this.selectMachineWithMemory(fallback, { rememberCurrent: false });
|
||||
}
|
||||
|
||||
private openSelectedMachine(): void {
|
||||
|
||||
@@ -72,4 +72,42 @@ describe("MachineController", () => {
|
||||
expect(state.machineStatuses[remoteMachine.id]).toMatchObject({ machineId: remoteMachine.id, ok: false, status: "offline", error: "Internal Server Error" });
|
||||
expect(state.error).toContain("Remote is offline");
|
||||
});
|
||||
|
||||
it("returns the fallback machine without selecting it when requested", async () => {
|
||||
let state: AppState = { ...initialAppState(), machines: [localMachine, remoteMachine], selectedMachine: remoteMachine };
|
||||
const setState = (patch: Partial<AppState>) => { state = { ...state, ...patch }; };
|
||||
const updateUrl = vi.fn();
|
||||
const projects = { loadProjects: vi.fn() };
|
||||
|
||||
vi.spyOn(api, "deleteMachine").mockResolvedValue({ deleted: true });
|
||||
|
||||
const controller = new MachineController(() => state, setState, updateUrl, projects);
|
||||
|
||||
const fallback = await controller.deleteMachine(remoteMachine, { selectFallback: false });
|
||||
|
||||
expect(fallback).toEqual(localMachine);
|
||||
expect(state.machines).toEqual([localMachine]);
|
||||
expect(state.selectedMachine).toEqual(remoteMachine);
|
||||
expect(projects.loadProjects).not.toHaveBeenCalled();
|
||||
expect(updateUrl).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("selects the fallback machine after deleting the selected machine by default", async () => {
|
||||
let state: AppState = { ...initialAppState(), machines: [localMachine, remoteMachine], selectedMachine: remoteMachine, selectedProject: { id: "p1", name: "Project", path: "/repo", createdAt: "now" } };
|
||||
const setState = (patch: Partial<AppState>) => { state = { ...state, ...patch }; };
|
||||
const updateUrl = vi.fn();
|
||||
const projects = { loadProjects: vi.fn() };
|
||||
|
||||
vi.spyOn(api, "deleteMachine").mockResolvedValue({ deleted: true });
|
||||
|
||||
const controller = new MachineController(() => state, setState, updateUrl, projects);
|
||||
|
||||
const fallback = await controller.deleteMachine(remoteMachine);
|
||||
|
||||
expect(fallback).toEqual(localMachine);
|
||||
expect(state.selectedMachine).toEqual(localMachine);
|
||||
expect(state.selectedProject).toBeUndefined();
|
||||
expect(projects.loadProjects).toHaveBeenCalledOnce();
|
||||
expect(updateUrl).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,20 +59,27 @@ export class MachineController {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteMachine(machine: Machine | undefined = this.getState().selectedMachine): Promise<void> {
|
||||
if (machine === undefined) return;
|
||||
async deleteMachine(machine: Machine | undefined = this.getState().selectedMachine, options: { selectFallback?: boolean } = {}): Promise<Machine | undefined> {
|
||||
if (machine === undefined) return undefined;
|
||||
if (machine.kind === "local") {
|
||||
this.setState({ error: "The local machine cannot be removed." });
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const wasSelected = this.getState().selectedMachine?.id === machine.id;
|
||||
await api.deleteMachine(machine.id);
|
||||
const machines = this.getState().machines.filter((candidate) => candidate.id !== machine.id);
|
||||
const local = machines.find((candidate) => candidate.id === "local") ?? machines[0];
|
||||
this.setState({ machines, machineStatuses: omitKey(this.getState().machineStatuses, machine.id) });
|
||||
if (this.getState().selectedMachine?.id === machine.id && local !== undefined) await this.selectMachine(local);
|
||||
if (wasSelected && local !== undefined) {
|
||||
if (options.selectFallback === false) return local;
|
||||
await this.selectMachine(local);
|
||||
return local;
|
||||
}
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
this.setState({ error: String(error) });
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user