UI: module list toggle {list,grid} view
This commit is contained in:
@@ -1,48 +1,179 @@
|
|||||||
import { callApi, SuccessData } from "@/src/api";
|
import { SuccessData } from "@/src/api";
|
||||||
import { activeURI } from "@/src/App";
|
import { activeURI } from "@/src/App";
|
||||||
|
import { Button } from "@/src/components/button";
|
||||||
|
import { Header } from "@/src/layout/header";
|
||||||
import { createModulesQuery } from "@/src/queries";
|
import { createModulesQuery } from "@/src/queries";
|
||||||
import { A, useNavigate } from "@solidjs/router";
|
import { A, useNavigate } from "@solidjs/router";
|
||||||
import { createQuery, useQueryClient } from "@tanstack/solid-query";
|
import { createSignal, For, Match, Switch } from "solid-js";
|
||||||
import { createEffect, For, Match, Switch } from "solid-js";
|
import { Typography } from "@/src/components/Typography";
|
||||||
import { SolidMarkdown } from "solid-markdown";
|
import { Menu } from "@/src/components/Menu";
|
||||||
|
import { makePersisted } from "@solid-primitives/storage";
|
||||||
|
import { useQueryClient } from "@tanstack/solid-query";
|
||||||
|
import cx from "classnames";
|
||||||
|
import Icon from "@/src/components/icon";
|
||||||
|
|
||||||
export type ModuleInfo = SuccessData<"list_modules">[string];
|
export type ModuleInfo = SuccessData<"list_modules">[string];
|
||||||
|
|
||||||
const ModuleListItem = (props: { name: string; info: ModuleInfo }) => {
|
interface CategoryProps {
|
||||||
|
categories: string[];
|
||||||
|
}
|
||||||
|
const Categories = (props: CategoryProps) => {
|
||||||
|
return (
|
||||||
|
<span class="ml-6 inline-flex h-full align-middle">
|
||||||
|
{props.categories.map((category) => (
|
||||||
|
<span class="badge badge-secondary">{category}</span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface RolesProps {
|
||||||
|
roles: string[];
|
||||||
|
}
|
||||||
|
const Roles = (props: RolesProps) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<Typography hierarchy="body" size="xs">
|
||||||
|
Service Typography{" "}
|
||||||
|
</Typography>
|
||||||
|
</span>
|
||||||
|
{props.roles.map((role) => (
|
||||||
|
<span class="badge badge-ghost">{role}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ModuleItem = (props: {
|
||||||
|
name: string;
|
||||||
|
info: ModuleInfo;
|
||||||
|
class?: string;
|
||||||
|
}) => {
|
||||||
const { name, info } = props;
|
const { name, info } = props;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="stat">
|
<div class={cx("stat rounded-lg shadow-md", props.class)}>
|
||||||
<div class="stat-figure text-primary-800">
|
<div class="stat-figure text-primary-800">
|
||||||
<div class="join">more</div>
|
<div class="join">
|
||||||
|
<Menu popoverid={`menu-${props.name}`} label={<Icon icon={"More"} />}>
|
||||||
|
<ul class="menu z-[1] w-52 rounded-box bg-base-100 p-2 shadow">
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/modules/details/${name}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Configure
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<A href={`/modules/details/${name}`}>
|
<A href={`/modules/details/${name}`}>
|
||||||
<div class="stat-value underline">{name}</div>
|
<div class="stat-value underline">
|
||||||
|
{name}
|
||||||
|
<Categories categories={info.categories} />
|
||||||
|
</div>
|
||||||
</A>
|
</A>
|
||||||
|
|
||||||
<div>{info.description}</div>
|
<div class="w-full">
|
||||||
<div>{JSON.stringify(info.constraints)}</div>
|
<Typography hierarchy="body" size="default">
|
||||||
|
{info.description}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Roles roles={info.roles || []} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModuleList = () => {
|
export const ModuleList = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const modulesQuery = createModulesQuery(activeURI(), {
|
const modulesQuery = createModulesQuery(activeURI(), {
|
||||||
features: ["inventory"],
|
features: ["inventory"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [view, setView] = makePersisted(createSignal<"list" | "grid">("list"), {
|
||||||
|
name: "modules_view",
|
||||||
|
storage: localStorage,
|
||||||
|
});
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
// Invalidates the cache for of all types of machine list at once
|
||||||
|
queryKey: [activeURI(), "list_modules"],
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Switch fallback="Shit">
|
<>
|
||||||
<Match when={modulesQuery.isLoading}>Loading....</Match>
|
<Header
|
||||||
<Match when={modulesQuery.data}>
|
title="Modules"
|
||||||
<div>
|
toolbar={
|
||||||
Show Modules
|
<>
|
||||||
<For each={modulesQuery.data}>
|
<span class="tooltip tooltip-bottom" data-tip="Reload">
|
||||||
{([k, v]) => <ModuleListItem info={v} name={k} />}
|
<Button
|
||||||
</For>
|
variant="light"
|
||||||
</div>
|
size="s"
|
||||||
</Match>
|
onClick={() => refresh()}
|
||||||
</Switch>
|
startIcon={<Icon icon="Update" />}
|
||||||
|
></Button>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="border border-def-3">
|
||||||
|
<span class="tooltip tooltip-bottom" data-tip="List View">
|
||||||
|
<Button
|
||||||
|
onclick={() => setView("list")}
|
||||||
|
variant={view() == "list" ? "dark" : "light"}
|
||||||
|
size="s"
|
||||||
|
startIcon={<Icon icon="List" />}
|
||||||
|
></Button>
|
||||||
|
</span>
|
||||||
|
<span class="tooltip tooltip-bottom" data-tip="Grid View">
|
||||||
|
<Button
|
||||||
|
onclick={() => setView("grid")}
|
||||||
|
variant={view() == "grid" ? "dark" : "light"}
|
||||||
|
size="s"
|
||||||
|
startIcon={<Icon icon="Grid" />}
|
||||||
|
></Button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span class="tooltip tooltip-bottom" data-tip="New Machine">
|
||||||
|
<Button
|
||||||
|
size="s"
|
||||||
|
variant="light"
|
||||||
|
startIcon={<Icon icon="CaretUp" />}
|
||||||
|
>
|
||||||
|
Import Module
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Switch fallback="Error">
|
||||||
|
<Match when={modulesQuery.isFetching}>Loading....</Match>
|
||||||
|
<Match when={modulesQuery.data}>
|
||||||
|
<div
|
||||||
|
class="my-4 flex flex-wrap gap-6 px-3 py-2"
|
||||||
|
classList={{
|
||||||
|
"flex-col": view() === "list",
|
||||||
|
"": view() === "grid",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<For each={modulesQuery.data}>
|
||||||
|
{([k, v]) => (
|
||||||
|
<ModuleItem
|
||||||
|
info={v}
|
||||||
|
name={k}
|
||||||
|
class={view() == "grid" ? cx("max-w-md") : ""}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user