clan-app: Propagate op_key to callApi callers.

This commit is contained in:
Qubasa
2025-06-13 12:41:50 +02:00
parent 371fe3181e
commit 2df223c7e8
19 changed files with 110 additions and 76 deletions

View File

@@ -88,6 +88,20 @@ const handleCancel = async <K extends OperationNames>(
) => {
console.log("Canceling operation: ", ops_key);
const { promise, op_key } = _callApi("cancel_task", { task_id: ops_key });
promise.catch((error) => {
toast.custom(
(t) => (
<ErrorToastComponent
t={t}
message={"Unexpected error: " + (error?.message || String(error))}
/>
),
{
duration: 5000,
},
);
console.error("Unhandled promise rejection in callApi:", error);
});
const resp = await promise;
if (resp.status === "error") {
@@ -109,13 +123,27 @@ const handleCancel = async <K extends OperationNames>(
console.log("Cancel response: ", resp);
};
export const callApi = async <K extends OperationNames>(
export const callApi = <K extends OperationNames>(
method: K,
args: OperationArgs<K>,
): Promise<OperationResponse<K>> => {
): { promise: Promise<OperationResponse<K>>; op_key: string } => {
console.log("Calling API", method, args);
const { promise, op_key } = _callApi(method, args);
promise.catch((error) => {
toast.custom(
(t) => (
<ErrorToastComponent
t={t}
message={"Unexpected error: " + (error?.message || String(error))}
/>
),
{
duration: 5000,
},
);
console.error("Unhandled promise rejection in callApi:", error);
});
const toastId = toast.custom(
(
@@ -132,7 +160,7 @@ export const callApi = async <K extends OperationNames>(
},
);
const response = await promise;
const new_promise = promise.then((response) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const cancelled = (promise as any).cancelled;
if (cancelled) {
@@ -155,5 +183,7 @@ export const callApi = async <K extends OperationNames>(
} else {
toast.remove(toastId);
}
return response as OperationResponse<K>;
return response;
});
return { promise: new_promise, op_key: op_key };
};

View File

@@ -1,10 +0,0 @@
export interface Machine {
machine: {
name: string;
flake: {
identifier: string;
};
override_target_host: string | null;
private_key: string | null;
};
}

View File

@@ -7,7 +7,7 @@ export const instance_name = (machine_name: string) =>
export async function get_iwd_service(base_path: string, machine_name: string) {
const r = await callApi("get_inventory", {
flake: { identifier: base_path },
});
}).promise;
if (r.status == "error") {
return null;
}

View File

@@ -142,11 +142,25 @@ export const ApiTester = () => {
</Field>
<Field name="payload">
{(field, fieldProps) => (
<TextInput
label={"payload"}
<div class="flex flex-col my-2">
<label class="mb-1 font-medium" for="payload-textarea">
payload
</label>
<textarea
id="payload-textarea"
class="border rounded p-2 text-sm min-h-[120px] resize-y focus:outline-none focus:ring-2 focus:ring-blue-400"
placeholder={`{\n "key": "value"\n}`}
value={field.value || ""}
inputProps={fieldProps}
{...fieldProps}
onInput={(e) => {
fieldProps.onInput?.(e);
}}
spellcheck={false}
autocomplete="off"
autocorrect="off"
autocapitalize="off"
/>
</div>
)}
</Field>
<Button class="m-2" disabled={query.isFetching}>

View File

@@ -72,7 +72,7 @@ export const FileSelectorField: Component<FileSelectorOpts<string>> = (
filters: fileDialogOptions.filters,
initial_folder: fileDialogOptions.initial_folder,
},
});
}).promise;
if (
response.status === "success" &&

View File

@@ -62,7 +62,7 @@ export const MachineListItem = (props: MachineListItemProps) => {
nix_options: [],
password: null,
},
});
}).promise;
setInstalling(false);
};
@@ -91,7 +91,7 @@ export const MachineListItem = (props: MachineListItemProps) => {
},
override_target_host: info?.deploy.targetHost,
},
});
}).promise;
setUpdating(false);
};

View File

@@ -7,7 +7,7 @@ export const registerClan = async () => {
try {
const loc = await callApi("open_file", {
file_request: { mode: "select_folder" },
});
}).promise;
if (loc.status === "success" && loc.data) {
const data = loc.data[0];
addClanURI(data);
@@ -32,7 +32,7 @@ export const selectSshKeys = async (): Promise<FileList> => {
mode: "open_file",
initial_folder: "~/.ssh",
},
});
}).promise;
if (response.status === "success" && response.data) {
// Add synthetic files to the DataTransfer object
// FileList cannot be instantiated directly.

View File

@@ -15,7 +15,7 @@ export const clanMetaQuery = (uri: string | undefined = undefined) =>
const result = await callApi("show_clan_meta", {
flake: { identifier: clanURI! },
});
}).promise;
console.log("result", result);

View File

@@ -1,4 +1,4 @@
import { createQuery } from "@tanstack/solid-query";
import { useQuery } from "@tanstack/solid-query";
import { callApi } from "../api";
import toast from "solid-toast";
@@ -9,7 +9,7 @@ export const createModulesQuery = (
uri: string | undefined,
filter?: ModulesFilter,
) =>
createQuery(() => ({
useQuery(() => ({
queryKey: [uri, "list_modules"],
placeholderData: {
localModules: {},
@@ -20,7 +20,7 @@ export const createModulesQuery = (
if (uri) {
const response = await callApi("list_modules", {
base_path: uri,
});
}).promise;
if (response.status === "error") {
console.error("Failed to fetch data");
} else {
@@ -35,7 +35,7 @@ export const createModulesQuery = (
}));
export const tagsQuery = (uri: string | undefined) =>
createQuery<string[]>(() => ({
useQuery<string[]>(() => ({
queryKey: [uri, "tags"],
placeholderData: [],
queryFn: async () => {
@@ -43,7 +43,7 @@ export const tagsQuery = (uri: string | undefined) =>
const response = await callApi("get_inventory", {
flake: { identifier: uri },
});
}).promise;
if (response.status === "error") {
console.error("Failed to fetch data");
} else {
@@ -56,7 +56,7 @@ export const tagsQuery = (uri: string | undefined) =>
}));
export const machinesQuery = (uri: string | undefined) =>
createQuery<string[]>(() => ({
useQuery<string[]>(() => ({
queryKey: [uri, "machines"],
placeholderData: [],
queryFn: async () => {
@@ -64,7 +64,7 @@ export const machinesQuery = (uri: string | undefined) =>
const response = await callApi("get_inventory", {
flake: { identifier: uri },
});
}).promise;
if (response.status === "error") {
console.error("Failed to fetch data");
} else {

View File

@@ -33,7 +33,7 @@ export const CreateClan = () => {
const { template, ...meta } = values;
const response = await callApi("open_file", {
file_request: { mode: "save" },
});
}).promise;
if (response.status !== "success") {
toast.error("Cannot select clan directory");
@@ -56,7 +56,7 @@ export const CreateClan = () => {
machines: {},
},
},
});
}).promise;
toast.dismiss(loading_toast);
if (r.status === "error") {
@@ -67,7 +67,7 @@ export const CreateClan = () => {
// Will generate a key if it doesn't exist, and add a user to the clan
const k = await callApi("keygen", {
flake_dir: target_dir[0],
});
}).promise;
if (k.status === "error") {
toast.error("Failed to generate key");

View File

@@ -37,7 +37,7 @@ const EditClanForm = (props: EditClanFormProps) => {
flake: { identifier: props.directory },
meta: values,
},
});
}).promise;
})(),
{
loading: "Updating clan...",

View File

@@ -13,7 +13,7 @@ export function DiskView() {
// Example of calling an API
const result = await callApi("get_inventory", {
flake: { identifier: currUri },
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
}

View File

@@ -98,7 +98,7 @@ export const Flash = () => {
const deviceQuery = createQuery(() => ({
queryKey: ["block_devices"],
queryFn: async () => {
const result = await callApi("show_block_devices", {});
const result = await callApi("show_block_devices", {}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},
@@ -108,7 +108,7 @@ export const Flash = () => {
const keymapQuery = createQuery(() => ({
queryKey: ["list_keymaps"],
queryFn: async () => {
const result = await callApi("list_possible_keymaps", {});
const result = await callApi("list_possible_keymaps", {}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},
@@ -118,7 +118,7 @@ export const Flash = () => {
const langQuery = createQuery(() => ({
queryKey: ["list_languages"],
queryFn: async () => {
const result = await callApi("list_possible_languages", {});
const result = await callApi("list_possible_languages", {}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},
@@ -174,7 +174,7 @@ export const Flash = () => {
write_efi_boot_entries: false,
debug: false,
graphical: true,
}),
}).promise,
{
error: (errors) => `Error flashing disk: ${errors}`,
loading: "Flashing ... This may take up to 15minutes.",

View File

@@ -56,7 +56,7 @@ export function CreateMachine() {
identifier: active_dir,
},
},
});
}).promise;
if (response.status === "success") {
toast.success(`Successfully created ${values.opts.machine.name}`);

View File

@@ -7,7 +7,7 @@ import {
setValue,
} from "@modular-forms/solid";
import { useNavigate, useParams, useSearchParams } from "@solidjs/router";
import { createQuery, useQuery, useQueryClient } from "@tanstack/solid-query";
import { useQuery, useQueryClient } from "@tanstack/solid-query";
import { createEffect, createSignal, For, Match, Show, Switch } from "solid-js";
import { Button } from "../../components/Button/Button";
@@ -130,7 +130,7 @@ const InstallMachine = (props: InstallMachineProps) => {
placeholders: diskValues.placeholders,
schema_name: diskValues.schema,
force: true,
});
}).promise;
}
setProgressText("Installing machine ... (2/5)");
@@ -425,7 +425,7 @@ const MachineForm = (props: MachineDetailsProps) => {
values.machine.tags || props.initialData.machine.tags || [],
),
},
});
}).promise;
await queryClient.invalidateQueries({
queryKey: [curr_uri, "machine", machineName(), "get_machine_details"],
});
@@ -433,7 +433,7 @@ const MachineForm = (props: MachineDetailsProps) => {
return null;
};
const generatorsQuery = createQuery(() => ({
const generatorsQuery = useQuery(() => ({
queryKey: [activeClanURI(), machineName(), "generators"],
queryFn: async () => {
const machine_name = machineName();
@@ -444,7 +444,7 @@ const MachineForm = (props: MachineDetailsProps) => {
const result = await callApi("get_generators_closure", {
base_dir: base_dir,
machine_name: machine_name,
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},
@@ -489,7 +489,7 @@ const MachineForm = (props: MachineDetailsProps) => {
},
override_target_host: target,
},
});
}).promise;
};
createEffect(() => {
@@ -717,7 +717,7 @@ export const MachineDetails = () => {
},
name: params.id,
},
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
}

View File

@@ -43,7 +43,7 @@ export const DiskStep = (props: StepProps<DiskValues>) => {
},
name: props.machine_id,
},
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},

View File

@@ -62,7 +62,7 @@ export const HWStep = (props: StepProps<HardwareValues>) => {
},
name: props.machine_id,
},
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},

View File

@@ -153,7 +153,7 @@ export const VarsStep = (props: VarsStepProps) => {
base_dir: props.dir,
machine_name: props.machine_id,
full_closure: props.fullClosure,
});
}).promise;
if (result.status === "error") throw new Error("Failed to fetch data");
return result.data;
},
@@ -170,7 +170,7 @@ export const VarsStep = (props: VarsStepProps) => {
base_dir: props.dir,
generators: generatorsQuery.data.map((generator) => generator.name),
all_prompt_values: values,
});
}).promise;
queryClient.invalidateQueries({
queryKey: [props.dir, props.machine_id, "generators"],
});

View File

@@ -36,7 +36,7 @@ export const MachineListView: Component = () => {
flake: {
identifier: uri,
},
});
}).promise;
console.log("response", response);
if (response.status === "error") {
console.error("Failed to fetch data");