Merge pull request 'Reaply: #3777: fix/machine-detail-view' (#3833) from ui-1 into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3833
This commit is contained in:
hsjobeki
2025-06-03 17:19:43 +00:00
7 changed files with 133 additions and 34 deletions

View File

@@ -2,6 +2,7 @@ import type { Preview } from "@kachurun/storybook-solid";
import "@/src/components/v2/index.css"; import "@/src/components/v2/index.css";
import "./preview.css"; import "./preview.css";
import "../src/index.css";
export const preview: Preview = { export const preview: Preview = {
tags: ["autodocs"], tags: ["autodocs"],

View File

@@ -0,0 +1,7 @@
div.tag-list {
@apply flex flex-wrap gap-2;
span.tag {
@apply w-fit rounded-full px-3 py-2 bg-inv-4 fg-inv-1;
}
}

View File

@@ -0,0 +1,36 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
import { TagList, TagListProps } from "./TagList";
const meta: Meta<TagListProps> = {
title: "Components/TagList",
component: TagList,
decorators: [
// wrap in a fixed width div so we can check that it wraps
(Story) => {
return (
<div style={{ width: "20em" }}>
<Story />
</div>
);
},
],
};
export default meta;
type Story = StoryObj<TagListProps>;
export const Default: Story = {
args: {
values: [
"Titan",
"Enceladus",
"Mimas",
"Dione",
"Iapetus",
"Tethys",
"Hyperion",
"Epimetheus",
],
},
};

View File

@@ -0,0 +1,21 @@
import { Component, For } from "solid-js";
import { Typography } from "@/src/components/Typography";
import "./TagList.css";
export interface TagListProps {
values: string[];
}
export const TagList: Component<TagListProps> = (props) => {
return (
<div class="tag-list">
<For each={props.values}>
{(tag) => (
<Typography hierarchy="label" size="s" inverted={true} class="tag">
{tag}
</Typography>
)}
</For>
</div>
);
};

View File

@@ -0,0 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Components/TagList Default smoke-test 1`] = `
<div style="width: 20em;">
<div class="tag-list">
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Titan
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Enceladus
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Mimas
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Dione
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Iapetus
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Tethys
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Hyperion
</span>
<span class="fnt-clr-primary fnt-clr--inverted fnt-label-s fnt-weight-normal tag">
Epimetheus
</span>
</div>
</div>
`;

View File

@@ -137,7 +137,7 @@ export const InputLabel = (props: InputLabelProps) => {
weight="bold" weight="bold"
size="xs" size="xs"
> >
{""} <>&#42;</>
</Typography> </Typography>
)} )}
{props.help && ( {props.help && (

View File

@@ -32,6 +32,7 @@ import {
FileSelectorField, FileSelectorField,
} from "@/src/components/fileSelect"; } from "@/src/components/fileSelect";
import { useClanContext } from "@/src/contexts/clan"; import { useClanContext } from "@/src/contexts/clan";
import { TagList } from "@/src/components/TagList/TagList";
type MachineFormInterface = MachineData & { type MachineFormInterface = MachineData & {
sshKey?: File; sshKey?: File;
@@ -77,10 +78,12 @@ const LoadingBar = () => (
function sleep(ms: number) { function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
interface InstallMachineProps { interface InstallMachineProps {
name?: string; name?: string;
machine: MachineData; machine: MachineData;
} }
const InstallMachine = (props: InstallMachineProps) => { const InstallMachine = (props: InstallMachineProps) => {
const { activeClanURI } = useClanContext(); const { activeClanURI } = useClanContext();
@@ -381,6 +384,7 @@ const InstallMachine = (props: InstallMachineProps) => {
interface MachineDetailsProps { interface MachineDetailsProps {
initialData: MachineData; initialData: MachineData;
} }
const MachineForm = (props: MachineDetailsProps) => { const MachineForm = (props: MachineDetailsProps) => {
const [formStore, { Form, Field }] = const [formStore, { Form, Field }] =
// TODO: retrieve the correct initial values from API // TODO: retrieve the correct initial values from API
@@ -595,49 +599,47 @@ const MachineForm = (props: MachineDetailsProps) => {
</Field> </Field>
<Field name="machine.tags" type="string[]"> <Field name="machine.tags" type="string[]">
{(field, props) => ( {(field, props) => (
<div class="flex items-center gap-4"> <div class="grid grid-cols-10 items-center">
<Typography hierarchy="label" size="default" weight="bold"> <Typography
hierarchy="label"
size="default"
weight="bold"
class="col-span-5"
>
Tags{" "} Tags{" "}
</Typography> </Typography>
<For each={field.value}> <div class="col-span-5 justify-self-end">
{(tag) => ( {/* alphabetically sort the tags */}
<span class="mx-2 w-fit rounded-full px-3 py-0.5 bg-inv-4 fg-inv-1"> <TagList values={[...(field.value || [])].sort()} />
<Typography </div>
hierarchy="label"
size="s"
inverted={true}
>
{tag}
</Typography>
</span>
)}
</For>
</div> </div>
)} )}
</Field> </Field>
</Fieldset> </Fieldset>
<Fieldset legend="Hardware"> <Typography hierarchy={"body"} size={"s"}>
<Field name="hw_config"> <Fieldset legend="Hardware">
{(field, props) => ( <Field name="hw_config">
<FieldLayout {(field, props) => (
label={<InputLabel>Hardware Configuration</InputLabel>}
field={<span>{field.value || "None"}</span>}
/>
)}
</Field>
<hr />
<Field name="disk_schema.schema_name">
{(field, props) => (
<>
<FieldLayout <FieldLayout
label={<InputLabel>Disk schema</InputLabel>} label={<InputLabel>Hardware Configuration</InputLabel>}
field={<span>{field.value || "None"}</span>} field={<span>{field.value || "None"}</span>}
/> />
</> )}
)} </Field>
</Field> <hr />
</Fieldset> <Field name="disk_schema.schema_name">
{(field, props) => (
<>
<FieldLayout
label={<InputLabel>Disk schema</InputLabel>}
field={<span>{field.value || "None"}</span>}
/>
</>
)}
</Field>
</Fieldset>
</Typography>
<Accordion title="Connection Settings"> <Accordion title="Connection Settings">
<Fieldset> <Fieldset>