Merge pull request 'Clan-app: install machine' (#1954) from hsjobeki/clan-core:hsjobeki-main into main
This commit is contained in:
@@ -127,6 +127,11 @@ def construct_value(t: type, field_value: JsonValue, loc: list[str] = []) -> Any
|
|||||||
"""
|
"""
|
||||||
if t is None and field_value:
|
if t is None and field_value:
|
||||||
raise ClanError(f"Expected None but got: {field_value}", location=f"{loc}")
|
raise ClanError(f"Expected None but got: {field_value}", location=f"{loc}")
|
||||||
|
|
||||||
|
if is_type_in_union(t, type(None)) and field_value is None:
|
||||||
|
# Sometimes the field value is None, which is valid if the type hint allows None
|
||||||
|
return None
|
||||||
|
|
||||||
# If the field is another dataclass
|
# If the field is another dataclass
|
||||||
# Field_value must be a dictionary
|
# Field_value must be a dictionary
|
||||||
if is_dataclass(t) and isinstance(field_value, dict):
|
if is_dataclass(t) and isinstance(field_value, dict):
|
||||||
@@ -160,9 +165,9 @@ def construct_value(t: type, field_value: JsonValue, loc: list[str] = []) -> Any
|
|||||||
# Union types construct the first non-None type
|
# Union types construct the first non-None type
|
||||||
elif is_union_type(t):
|
elif is_union_type(t):
|
||||||
# Unwrap the union type
|
# Unwrap the union type
|
||||||
t = unwrap_none_type(t)
|
inner = unwrap_none_type(t)
|
||||||
# Construct the field value
|
# Construct the field value
|
||||||
return construct_value(t, field_value)
|
return construct_value(inner, field_value)
|
||||||
|
|
||||||
# Nested types
|
# Nested types
|
||||||
# list
|
# list
|
||||||
|
|||||||
@@ -244,6 +244,27 @@ def test_alias_field_from_orig_name() -> None:
|
|||||||
from_dict(Person, data)
|
from_dict(Person, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_none_or_string() -> None:
|
||||||
|
"""
|
||||||
|
Field declares an alias. But the data is provided with the field name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = None
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Person:
|
||||||
|
name: Path
|
||||||
|
|
||||||
|
checked = from_dict(str | None, data)
|
||||||
|
assert checked is None
|
||||||
|
|
||||||
|
checked2 = from_dict(dict[str, str] | None, data)
|
||||||
|
assert checked2 is None
|
||||||
|
|
||||||
|
checked3 = from_dict(Person | None, data)
|
||||||
|
assert checked3 is None
|
||||||
|
|
||||||
|
|
||||||
def test_path_field() -> None:
|
def test_path_field() -> None:
|
||||||
@dataclass
|
@dataclass
|
||||||
class Person:
|
class Person:
|
||||||
|
|||||||
@@ -64,6 +64,53 @@ const InstallMachine = (props: InstallMachineProps) => {
|
|||||||
|
|
||||||
const handleInstall = async (values: InstallForm) => {
|
const handleInstall = async (values: InstallForm) => {
|
||||||
console.log("Installing", values);
|
console.log("Installing", values);
|
||||||
|
const curr_uri = activeURI();
|
||||||
|
if (!curr_uri) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!props.name || !props.targetHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = await callApi("install_machine", {
|
||||||
|
opts: {
|
||||||
|
flake: {
|
||||||
|
loc: curr_uri,
|
||||||
|
},
|
||||||
|
machine: props.name,
|
||||||
|
target_host: props.targetHost,
|
||||||
|
},
|
||||||
|
password: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (r.status === "error") {
|
||||||
|
toast.error("Failed to install machine");
|
||||||
|
}
|
||||||
|
if (r.status === "success") {
|
||||||
|
toast.success("Machine installed successfully");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDiskConfirm = async () => {
|
||||||
|
const curr_uri = activeURI();
|
||||||
|
const disk = getValue(formStore, "disk");
|
||||||
|
const disk_id = props.disks.find((d) => d.name === disk)?.id_link;
|
||||||
|
if (!curr_uri || !disk_id || !props.name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = await callApi("set_single_disk_uuid", {
|
||||||
|
base_path: curr_uri,
|
||||||
|
machine_name: props.name,
|
||||||
|
disk_uuid: disk_id,
|
||||||
|
});
|
||||||
|
if (r.status === "error") {
|
||||||
|
toast.error("Failed to set disk");
|
||||||
|
}
|
||||||
|
if (r.status === "success") {
|
||||||
|
toast.success("Disk set successfully");
|
||||||
|
setConfirmDisk(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -111,7 +158,7 @@ const InstallMachine = (props: InstallMachineProps) => {
|
|||||||
fallback={
|
fallback={
|
||||||
<button
|
<button
|
||||||
class="btn btn-primary btn-wide"
|
class="btn btn-primary btn-wide"
|
||||||
onClick={() => setConfirmDisk(true)}
|
onClick={() => handleDiskConfirm()}
|
||||||
disabled={!hasDisk()}
|
disabled={!hasDisk()}
|
||||||
>
|
>
|
||||||
<span class="material-icons">check</span>
|
<span class="material-icons">check</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user