Merge pull request 'ui: clean up using knip' (#5633) from hgl-storybook into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5633
This commit is contained in:
1
pkgs/clan-app/ui/.gitignore
vendored
1
pkgs/clan-app/ui/.gitignore
vendored
@@ -2,5 +2,4 @@ app/api
|
|||||||
app/.fonts
|
app/.fonts
|
||||||
|
|
||||||
.vite
|
.vite
|
||||||
storybook-static
|
|
||||||
*.css.d.ts
|
*.css.d.ts
|
||||||
@@ -1,19 +1,9 @@
|
|||||||
{
|
{
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"gtk.webview.js",
|
"gtk.webview.js",
|
||||||
|
"src/api/clan/client-fetch.ts",
|
||||||
"stylelint.config.js",
|
"stylelint.config.js",
|
||||||
"util.ts",
|
|
||||||
"src/components/v2/**",
|
|
||||||
"api/**",
|
"api/**",
|
||||||
"tailwind/**"
|
"tailwind/**"
|
||||||
],
|
|
||||||
"ignoreDependencies": [
|
|
||||||
"@babel/plugin-syntax-import-attributes",
|
|
||||||
"@storybook/addon-viewport",
|
|
||||||
"@typescript-eslint/parser",
|
|
||||||
"@vitest/coverage-v8",
|
|
||||||
"http-server",
|
|
||||||
"playwright",
|
|
||||||
"wait-on"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1382
pkgs/clan-app/ui/package-lock.json
generated
1382
pkgs/clan-app/ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -20,40 +20,28 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-syntax-import-attributes": "^7.27.1",
|
|
||||||
"@eslint/js": "^9.3.0",
|
"@eslint/js": "^9.3.0",
|
||||||
"@kachurun/storybook-solid-vite": "^9.0.11",
|
"@kachurun/storybook-solid-vite": "^9.0.11",
|
||||||
"@linaria/core": "^6.3.0",
|
"@linaria/core": "^6.3.0",
|
||||||
"@sinonjs/fake-timers": "^14.0.0",
|
|
||||||
"@storybook/addon-a11y": "^9.0.8",
|
"@storybook/addon-a11y": "^9.0.8",
|
||||||
"@storybook/addon-docs": "^9.0.8",
|
"@storybook/addon-docs": "^9.0.8",
|
||||||
"@storybook/addon-links": "^9.0.8",
|
"@storybook/addon-links": "^9.0.8",
|
||||||
"@storybook/addon-viewport": "^9.0.8",
|
|
||||||
"@storybook/addon-vitest": "^9.0.8",
|
"@storybook/addon-vitest": "^9.0.8",
|
||||||
"@types/node": "^22.15.19",
|
"@types/node": "^22.15.19",
|
||||||
"@types/sinonjs__fake-timers": "^8.1.5",
|
|
||||||
"@types/three": "^0.176.0",
|
"@types/three": "^0.176.0",
|
||||||
"@typescript-eslint/parser": "^8.32.1",
|
|
||||||
"@vitest/browser": "^3.2.3",
|
"@vitest/browser": "^3.2.3",
|
||||||
"@vitest/coverage-v8": "^3.2.3",
|
|
||||||
"@wyw-in-js/vite": "^0.7.0",
|
"@wyw-in-js/vite": "^0.7.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"concurrently": "^9.1.2",
|
|
||||||
"eslint": "^9.27.0",
|
"eslint": "^9.27.0",
|
||||||
"eslint-plugin-tailwindcss": "^3.17.0",
|
"eslint-plugin-tailwindcss": "^3.17.0",
|
||||||
"eslint-plugin-unused-imports": "^4.1.4",
|
"eslint-plugin-unused-imports": "^4.1.4",
|
||||||
"extend": "^3.0.2",
|
|
||||||
"http-server": "^14.1.1",
|
|
||||||
"jsdom": "^26.1.0",
|
|
||||||
"knip": "^5.61.2",
|
"knip": "^5.61.2",
|
||||||
"markdown-to-jsx": "^7.7.10",
|
|
||||||
"playwright": "1.54.1",
|
"playwright": "1.54.1",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"postcss-url": "^10.1.3",
|
"postcss-url": "^10.1.3",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"storybook": "^9.0.8",
|
"storybook": "^9.0.8",
|
||||||
"swagger-ui-dist": "^5.26.2",
|
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"typescript-eslint": "^8.32.1",
|
"typescript-eslint": "^8.32.1",
|
||||||
@@ -62,11 +50,9 @@
|
|||||||
"vite-css-modules": "^1.10.0",
|
"vite-css-modules": "^1.10.0",
|
||||||
"vite-plugin-solid": "^2.8.2",
|
"vite-plugin-solid": "^2.8.2",
|
||||||
"vite-plugin-solid-svg": "^0.8.1",
|
"vite-plugin-solid-svg": "^0.8.1",
|
||||||
"vitest": "^3.2.3",
|
"vitest": "^3.2.4"
|
||||||
"wait-on": "^8.0.3"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/dom": "^1.6.8",
|
|
||||||
"@kobalte/core": "^0.13.10",
|
"@kobalte/core": "^0.13.10",
|
||||||
"@kobalte/tailwindcss": "^0.9.0",
|
"@kobalte/tailwindcss": "^0.9.0",
|
||||||
"@modular-forms/solid": "^0.25.1",
|
"@modular-forms/solid": "^0.25.1",
|
||||||
@@ -80,7 +66,6 @@
|
|||||||
"solid-js": "^1.9.7",
|
"solid-js": "^1.9.7",
|
||||||
"solid-toast": "^0.5.0",
|
"solid-toast": "^0.5.0",
|
||||||
"three": "^0.176.0",
|
"three": "^0.176.0",
|
||||||
"troika-three-text": "^0.52.4",
|
|
||||||
"valibot": "^1.1.0"
|
"valibot": "^1.1.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import Icon, { IconVariant } from "@/src/components/Icon/Icon";
|
|||||||
import { Loader } from "@/src/components/Loader/Loader";
|
import { Loader } from "@/src/components/Loader/Loader";
|
||||||
import { getInClasses, joinByDash, keepTruthy } from "@/src/util";
|
import { getInClasses, joinByDash, keepTruthy } from "@/src/util";
|
||||||
|
|
||||||
export type Size = "default" | "s" | "xs";
|
type Size = "default" | "s" | "xs";
|
||||||
export type Hierarchy = "primary" | "secondary";
|
type Hierarchy = "primary" | "secondary";
|
||||||
export type Elasticity = "default" | "fit";
|
type Elasticity = "default" | "fit";
|
||||||
|
|
||||||
export type Action = () => Promise<void>;
|
type Action = () => Promise<void>;
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import styles from "./Label.module.css";
|
|||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { getInClasses } from "@/src/util";
|
import { getInClasses } from "@/src/util";
|
||||||
|
|
||||||
export type Size = "default" | "s";
|
type Size = "default" | "s";
|
||||||
|
|
||||||
export type LabelComponent =
|
type LabelComponent =
|
||||||
| typeof TextField.Label
|
| typeof TextField.Label
|
||||||
| typeof Checkbox.Label
|
| typeof Checkbox.Label
|
||||||
| typeof Combobox.Label
|
| typeof Combobox.Label
|
||||||
| typeof Select.Label;
|
| typeof Select.Label;
|
||||||
|
|
||||||
export type DescriptionComponent =
|
type DescriptionComponent =
|
||||||
| typeof TextField.Description
|
| typeof TextField.Description
|
||||||
| typeof Checkbox.Description
|
| typeof Checkbox.Description
|
||||||
| typeof Combobox.Description
|
| typeof Combobox.Description
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { CollectionNode } from "@kobalte/core";
|
|||||||
import styles from "./MachineTags.module.css";
|
import styles from "./MachineTags.module.css";
|
||||||
import { keepTruthy } from "@/src/util";
|
import { keepTruthy } from "@/src/util";
|
||||||
|
|
||||||
export interface MachineTag {
|
interface MachineTag {
|
||||||
value: string;
|
value: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { JSX, mergeProps } from "solid-js";
|
|||||||
|
|
||||||
import styles from "./Orienter.module.css";
|
import styles from "./Orienter.module.css";
|
||||||
|
|
||||||
export interface OrienterProps {
|
interface OrienterProps {
|
||||||
orientation?: "vertical" | "horizontal";
|
orientation?: "vertical" | "horizontal";
|
||||||
align?: "center" | "start";
|
align?: "center" | "start";
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mergeProps } from "solid-js";
|
|||||||
import styles from "./Loader.module.css";
|
import styles from "./Loader.module.css";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
|
|
||||||
export type Hierarchy = "primary" | "secondary";
|
type Hierarchy = "primary" | "secondary";
|
||||||
|
|
||||||
export interface LoaderProps {
|
export interface LoaderProps {
|
||||||
hierarchy?: Hierarchy;
|
hierarchy?: Hierarchy;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { JSX } from "solid-js";
|
|||||||
import styles from "./LoadingBar.module.css";
|
import styles from "./LoadingBar.module.css";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
|
|
||||||
export type LoadingBarProps = JSX.HTMLAttributes<HTMLDivElement> & {};
|
type LoadingBarProps = JSX.HTMLAttributes<HTMLDivElement> & {};
|
||||||
export const LoadingBar = (props: LoadingBarProps) => (
|
export const LoadingBar = (props: LoadingBarProps) => (
|
||||||
<div {...props} class={cx(styles.loading_bar, props.class)} />
|
<div {...props} class={cx(styles.loading_bar, props.class)} />
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import Icon from "../Icon/Icon";
|
|||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { Dynamic } from "solid-js/web";
|
import { Dynamic } from "solid-js/web";
|
||||||
|
|
||||||
export interface ModalContextType {
|
interface ModalContextType {
|
||||||
portalRef: HTMLDivElement;
|
portalRef: HTMLDivElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { CollectionNode } from "@kobalte/core/*";
|
|||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { Loader } from "../Loader/Loader";
|
import { Loader } from "../Loader/Loader";
|
||||||
|
|
||||||
export interface Option {
|
interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { CollectionNode } from "@kobalte/core/*";
|
|||||||
import { Loader } from "../Loader/Loader";
|
import { Loader } from "../Loader/Loader";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
|
|
||||||
export interface Option {
|
interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import cx from "classnames";
|
|||||||
import { useModalContext } from "../Modal/Modal";
|
import { useModalContext } from "../Modal/Modal";
|
||||||
import { keepTruthy } from "@/src/util";
|
import { keepTruthy } from "@/src/util";
|
||||||
|
|
||||||
export interface Option {
|
interface Option {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import { SidebarBody } from "@/src/components/Sidebar/SidebarBody";
|
|||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
import { splitProps } from "solid-js";
|
import { splitProps } from "solid-js";
|
||||||
|
|
||||||
export interface LinkProps {
|
interface LinkProps {
|
||||||
path: string;
|
path: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SectionProps {
|
interface SectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
links: LinkProps[];
|
links: LinkProps[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { JSX, Show } from "solid-js";
|
|||||||
import styles from "./SidebarSection.module.css";
|
import styles from "./SidebarSection.module.css";
|
||||||
import { Typography } from "@/src/components/Typography/Typography";
|
import { Typography } from "@/src/components/Typography/Typography";
|
||||||
|
|
||||||
export interface SidebarSectionProps {
|
interface SidebarSectionProps {
|
||||||
title: string;
|
title: string;
|
||||||
controls?: JSX.Element;
|
controls?: JSX.Element;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { Button } from "@/src/components/Button/Button";
|
|||||||
import { Loader } from "../../components/Loader/Loader";
|
import { Loader } from "../../components/Loader/Loader";
|
||||||
import { SidebarSection } from "./SidebarSection";
|
import { SidebarSection } from "./SidebarSection";
|
||||||
|
|
||||||
export interface SidebarSectionFormProps<FormValues extends FieldValues> {
|
interface SidebarSectionFormProps<FormValues extends FieldValues> {
|
||||||
title: string;
|
title: string;
|
||||||
schema: GenericSchema<FormValues> | GenericSchemaAsync<FormValues>;
|
schema: GenericSchema<FormValues> | GenericSchemaAsync<FormValues>;
|
||||||
initialValues: PartialValues<FormValues>;
|
initialValues: PartialValues<FormValues>;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import styles from "./SidebarSectionInstall.module.css";
|
|||||||
import { Alert } from "../Alert/Alert";
|
import { Alert } from "../Alert/Alert";
|
||||||
import { useClanContext } from "@/src/routes/Clan/Clan";
|
import { useClanContext } from "@/src/routes/Clan/Clan";
|
||||||
|
|
||||||
export interface SidebarSectionInstallProps {
|
interface SidebarSectionInstallProps {
|
||||||
clanURI: string;
|
clanURI: string;
|
||||||
machineName: string;
|
machineName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import styles from "./SidebarSectionInstall.module.css";
|
|||||||
import { UpdateModal } from "@/src/workflows/InstallMachine/UpdateMachine";
|
import { UpdateModal } from "@/src/workflows/InstallMachine/UpdateMachine";
|
||||||
import { useClanContext } from "@/src/routes/Clan/Clan";
|
import { useClanContext } from "@/src/routes/Clan/Clan";
|
||||||
|
|
||||||
export interface SidebarSectionUpdateProps {
|
interface SidebarSectionUpdateProps {
|
||||||
clanURI: string;
|
clanURI: string;
|
||||||
machineName: string;
|
machineName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Icon, { IconVariant } from "@/src/components/Icon/Icon";
|
|||||||
import type { JSX } from "solid-js";
|
import type { JSX } from "solid-js";
|
||||||
import { Tooltip } from "../Tooltip/Tooltip";
|
import { Tooltip } from "../Tooltip/Tooltip";
|
||||||
|
|
||||||
export interface ToolbarButtonProps
|
interface ToolbarButtonProps
|
||||||
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
icon: IconVariant;
|
icon: IconVariant;
|
||||||
description: JSX.Element;
|
description: JSX.Element;
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ import { getInClasses } from "@/src/util";
|
|||||||
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
|
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
|
||||||
export type Weight = "normal" | "medium" | "bold";
|
export type Weight = "normal" | "medium" | "bold";
|
||||||
export type Family = "regular" | "mono";
|
export type Family = "regular" | "mono";
|
||||||
export type Transform = "uppercase" | "lowercase" | "capitalize";
|
type Transform = "uppercase" | "lowercase" | "capitalize";
|
||||||
export interface SizeForHierarchy {
|
interface SizeForHierarchy {
|
||||||
body: "default" | "s" | "xs" | "xxs";
|
body: "default" | "s" | "xs" | "xxs";
|
||||||
headline: "default" | "m" | "l" | "xl" | "xxl";
|
headline: "default" | "m" | "l" | "xl" | "xxl";
|
||||||
title: "default" | "m" | "l";
|
title: "default" | "m" | "l";
|
||||||
label: "default" | "s" | "xs" | "xxs";
|
label: "default" | "s" | "xs" | "xxs";
|
||||||
teaser: "default";
|
teaser: "default";
|
||||||
}
|
}
|
||||||
export interface TagForHierarchy {
|
interface TagForHierarchy {
|
||||||
body: "span" | "p" | "div";
|
body: "span" | "p" | "div";
|
||||||
headline: "h1" | "h2" | "h3" | "h4";
|
headline: "h1" | "h2" | "h3" | "h4";
|
||||||
title: "h1" | "h2" | "h3" | "h4";
|
title: "h1" | "h2" | "h3" | "h4";
|
||||||
@@ -40,7 +40,7 @@ const defaultTagMap = {
|
|||||||
label: "span",
|
label: "span",
|
||||||
teaser: "h3",
|
teaser: "h3",
|
||||||
} as const;
|
} as const;
|
||||||
export interface TypographyProps<H extends Hierarchy> {
|
interface TypographyProps<H extends Hierarchy> {
|
||||||
hierarchy: H;
|
hierarchy: H;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
size?: SizeForHierarchy[H];
|
size?: SizeForHierarchy[H];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createContext, JSX, useContext } from "solid-js";
|
import { createContext, JSX, useContext } from "solid-js";
|
||||||
import { ApiCall, OperationArgs, OperationNames } from "./api";
|
import { ApiCall, OperationArgs, OperationNames } from "./api";
|
||||||
|
|
||||||
export interface ApiClient {
|
interface ApiClient {
|
||||||
fetch: Fetcher;
|
fetch: Fetcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { addClanURI, setActiveClanURI } from "@/src/stores/clan";
|
|||||||
import { Params, Navigator, useParams, useSearchParams } from "@solidjs/router";
|
import { Params, Navigator, useParams, useSearchParams } from "@solidjs/router";
|
||||||
|
|
||||||
export const encodeBase64 = (value: string) => window.btoa(value);
|
export const encodeBase64 = (value: string) => window.btoa(value);
|
||||||
export const decodeBase64 = (value: string) => window.atob(value);
|
const decodeBase64 = (value: string) => window.atob(value);
|
||||||
|
|
||||||
export const selectClanFolder = async () => {
|
export const selectClanFolder = async () => {
|
||||||
const req = callApi("get_clan_folder", {});
|
const req = callApi("get_clan_folder", {});
|
||||||
@@ -80,7 +80,7 @@ export const navigateToClan = (navigate: Navigator, clanURI: string) => {
|
|||||||
export const navigateToOnboarding = (navigate: Navigator, addClan: boolean) =>
|
export const navigateToOnboarding = (navigate: Navigator, addClan: boolean) =>
|
||||||
navigate(`/${addClan ? "?addClan=true" : ""}`);
|
navigate(`/${addClan ? "?addClan=true" : ""}`);
|
||||||
|
|
||||||
export const navigateToMachine = (
|
const navigateToMachine = (
|
||||||
navigate: Navigator,
|
navigate: Navigator,
|
||||||
clanURI: string,
|
clanURI: string,
|
||||||
name: string,
|
name: string,
|
||||||
@@ -90,7 +90,7 @@ export const navigateToMachine = (
|
|||||||
navigate(path);
|
navigate(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const clanURIParam = (params: Params) => {
|
const clanURIParam = (params: Params) => {
|
||||||
try {
|
try {
|
||||||
return decodeBase64(params.clanURI);
|
return decodeBase64(params.clanURI);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -101,19 +101,19 @@ export const clanURIParam = (params: Params) => {
|
|||||||
|
|
||||||
export const useClanURI = () => clanURIParam(useParams());
|
export const useClanURI = () => clanURIParam(useParams());
|
||||||
|
|
||||||
export const machineNameParam = (params: Params) => {
|
const machineNameParam = (params: Params) => {
|
||||||
return params.machineName;
|
return params.machineName;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const inputParam = (params: Params) => params.input;
|
const inputParam = (params: Params) => params.input;
|
||||||
export const nameParam = (params: Params) => params.name;
|
const nameParam = (params: Params) => params.name;
|
||||||
export const idParam = (params: Params) => params.id;
|
const idParam = (params: Params) => params.id;
|
||||||
|
|
||||||
export const useMachineName = (): string => machineNameParam(useParams());
|
export const useMachineName = (): string => machineNameParam(useParams());
|
||||||
export const useInputParam = (): string => inputParam(useParams());
|
const useInputParam = (): string => inputParam(useParams());
|
||||||
export const useNameParam = (): string => nameParam(useParams());
|
const useNameParam = (): string => nameParam(useParams());
|
||||||
|
|
||||||
export const maybeUseIdParam = (): string | null => {
|
const maybeUseIdParam = (): string | null => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
if (params.id === undefined) {
|
if (params.id === undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import { useMutation, useQueryClient } from "@tanstack/solid-query";
|
|
||||||
import { callApi, OperationArgs } from "@/src/hooks/api";
|
|
||||||
import { encodeBase64 } from "@/src/hooks/clan";
|
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
|
||||||
|
|
||||||
export const updateMachine = useMutation(() => ({
|
|
||||||
mutationFn: async (args: OperationArgs<"set_machine">) => {
|
|
||||||
const call = callApi("set_machine", args);
|
|
||||||
return {
|
|
||||||
args,
|
|
||||||
...call,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
onSuccess: async ({ args }) => {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
flake: { identifier },
|
|
||||||
} = args.machine;
|
|
||||||
|
|
||||||
await queryClient.invalidateQueries({
|
|
||||||
queryKey: ["clans", encodeBase64(identifier), "machine", name],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
@@ -44,7 +44,7 @@ window.notifyBus = (msg: ProcessMessage) => {
|
|||||||
*
|
*
|
||||||
* consider using useNotify for reactive usage on solidjs
|
* consider using useNotify for reactive usage on solidjs
|
||||||
*/
|
*/
|
||||||
export function _subscribeNotify<T extends ProcessMessage>(
|
function _subscribeNotify<T extends ProcessMessage>(
|
||||||
filter: (msg: T) => boolean,
|
filter: (msg: T) => boolean,
|
||||||
callback: (msg: T) => void,
|
callback: (msg: T) => void,
|
||||||
) {
|
) {
|
||||||
@@ -65,7 +65,7 @@ export function _subscribeNotify<T extends ProcessMessage>(
|
|||||||
* The signal has the value of the last message where filter was true
|
* The signal has the value of the last message where filter was true
|
||||||
* null in case no message was recieved yet
|
* null in case no message was recieved yet
|
||||||
*/
|
*/
|
||||||
export function useNotify<T extends ProcessMessage = ProcessMessage>(
|
function useNotify<T extends ProcessMessage = ProcessMessage>(
|
||||||
filter: (msg: T) => boolean = () => true as boolean,
|
filter: (msg: T) => boolean = () => true as boolean,
|
||||||
) {
|
) {
|
||||||
const [message, setMessage] = createSignal<T | null>(null);
|
const [message, setMessage] = createSignal<T | null>(null);
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ export interface ClanDetails {
|
|||||||
fieldsSchema: SuccessData<"get_clan_details_schema">;
|
fieldsSchema: SuccessData<"get_clan_details_schema">;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Tags = SuccessData<"list_tags">;
|
type Tags = SuccessData<"list_tags">;
|
||||||
export type Machine = SuccessData<"get_machine">;
|
export type Machine = SuccessData<"get_machine">;
|
||||||
|
|
||||||
export type MachineState = SuccessData<"get_machine_state">;
|
type MachineState = SuccessData<"get_machine_state">;
|
||||||
export type MachineStatus = MachineState["status"];
|
export type MachineStatus = MachineState["status"];
|
||||||
|
|
||||||
export type ListMachines = SuccessData<"list_machines">;
|
type ListMachines = SuccessData<"list_machines">;
|
||||||
export type MachineDetails = SuccessData<"get_machine_details">;
|
type MachineDetails = SuccessData<"get_machine_details">;
|
||||||
|
|
||||||
export type ListServiceModules = SuccessData<"list_service_modules">;
|
type ListServiceModules = SuccessData<"list_service_modules">;
|
||||||
export type ListServiceInstances = SuccessData<"list_service_instances">;
|
export type ListServiceInstances = SuccessData<"list_service_instances">;
|
||||||
|
|
||||||
export interface MachineDetail {
|
export interface MachineDetail {
|
||||||
@@ -35,7 +35,7 @@ export interface MachineDetail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type MachinesQueryResult = UseQueryResult<ListMachines>;
|
export type MachinesQueryResult = UseQueryResult<ListMachines>;
|
||||||
export type ClanListQueryResult = UseQueryResult<ClanDetails>[];
|
type ClanListQueryResult = UseQueryResult<ClanDetails>[];
|
||||||
|
|
||||||
export const DefaultQueryClient = new QueryClient({
|
export const DefaultQueryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
@@ -67,7 +67,7 @@ export const useMachinesQuery = (clanURI: string) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const machineKey = (clanUri: string, machineName: string) => [
|
const machineKey = (clanUri: string, machineName: string) => [
|
||||||
...clanKey(clanUri),
|
...clanKey(clanUri),
|
||||||
"machine",
|
"machine",
|
||||||
encodeBase64(machineName),
|
encodeBase64(machineName),
|
||||||
@@ -174,7 +174,7 @@ export const useMachineStateQuery = (clanURI: string, machineName: string) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useServiceModulesQuery = (clanURI: string) => {
|
const useServiceModulesQuery = (clanURI: string) => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
|
|
||||||
return useQuery<ListServiceModules>(() => ({
|
return useQuery<ListServiceModules>(() => ({
|
||||||
@@ -222,10 +222,7 @@ export const useServiceInstancesQuery = (clanURI: string) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useMachineDetailsQuery = (
|
const useMachineDetailsQuery = (clanURI: string, machineName: string) => {
|
||||||
clanURI: string,
|
|
||||||
machineName: string,
|
|
||||||
) => {
|
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
return useQuery<MachineDetails>(() => ({
|
return useQuery<MachineDetails>(() => ({
|
||||||
queryKey: [machineKey(clanURI, machineName), "details"],
|
queryKey: [machineKey(clanURI, machineName), "details"],
|
||||||
@@ -251,7 +248,7 @@ export const useMachineDetailsQuery = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ClanDetailsPersister = experimental_createQueryPersister({
|
const ClanDetailsPersister = experimental_createQueryPersister({
|
||||||
storage: ClanDetailsStore,
|
storage: ClanDetailsStore,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -373,10 +370,10 @@ export const useClanListQuery = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MachineFlashOptions = SuccessData<"get_machine_flash_options">;
|
type MachineFlashOptions = SuccessData<"get_machine_flash_options">;
|
||||||
export type MachineFlashOptionsQuery = UseQueryResult<MachineFlashOptions>;
|
type MachineFlashOptionsQuery = UseQueryResult<MachineFlashOptions>;
|
||||||
|
|
||||||
export const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
|
const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
return useQuery<MachineFlashOptions>(() => ({
|
return useQuery<MachineFlashOptions>(() => ({
|
||||||
queryKey: ["flash_options"],
|
queryKey: ["flash_options"],
|
||||||
@@ -395,8 +392,8 @@ export const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SystemStorageOptions = SuccessData<"list_system_storage_devices">;
|
type SystemStorageOptions = SuccessData<"list_system_storage_devices">;
|
||||||
export type SystemStorageOptionsQuery = UseQueryResult<SystemStorageOptions>;
|
type SystemStorageOptionsQuery = UseQueryResult<SystemStorageOptions>;
|
||||||
|
|
||||||
export const useSystemStorageOptions = (): SystemStorageOptionsQuery => {
|
export const useSystemStorageOptions = (): SystemStorageOptionsQuery => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
@@ -417,10 +414,8 @@ export const useSystemStorageOptions = (): SystemStorageOptionsQuery => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MachineHardwareSummary =
|
type MachineHardwareSummary = SuccessData<"get_machine_hardware_summary">;
|
||||||
SuccessData<"get_machine_hardware_summary">;
|
type MachineHardwareSummaryQuery = UseQueryResult<MachineHardwareSummary>;
|
||||||
export type MachineHardwareSummaryQuery =
|
|
||||||
UseQueryResult<MachineHardwareSummary>;
|
|
||||||
|
|
||||||
export const useMachineHardwareSummary = (
|
export const useMachineHardwareSummary = (
|
||||||
clanUri: string,
|
clanUri: string,
|
||||||
@@ -457,8 +452,8 @@ export const useMachineHardwareSummary = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MachineDiskSchema = SuccessData<"get_machine_disk_schemas">;
|
type MachineDiskSchema = SuccessData<"get_machine_disk_schemas">;
|
||||||
export type MachineDiskSchemaQuery = UseQueryResult<MachineDiskSchema>;
|
type MachineDiskSchemaQuery = UseQueryResult<MachineDiskSchema>;
|
||||||
|
|
||||||
export const useMachineDiskSchemas = (
|
export const useMachineDiskSchemas = (
|
||||||
clanUri: string,
|
clanUri: string,
|
||||||
@@ -496,7 +491,7 @@ export const useMachineDiskSchemas = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type MachineGenerators = SuccessData<"get_generators">;
|
export type MachineGenerators = SuccessData<"get_generators">;
|
||||||
export type MachineGeneratorsQuery = UseQueryResult<MachineGenerators>;
|
type MachineGeneratorsQuery = UseQueryResult<MachineGenerators>;
|
||||||
|
|
||||||
export const useMachineGenerators = (
|
export const useMachineGenerators = (
|
||||||
clanUri: string,
|
clanUri: string,
|
||||||
@@ -538,7 +533,7 @@ export const useMachineGenerators = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ServiceModulesQuery = ReturnType<typeof useServiceModules>;
|
type ServiceModulesQuery = ReturnType<typeof useServiceModules>;
|
||||||
export type ServiceModules = SuccessData<"list_service_modules">;
|
export type ServiceModules = SuccessData<"list_service_modules">;
|
||||||
export const useServiceModules = (clanUri: string) => {
|
export const useServiceModules = (clanUri: string) => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
@@ -566,7 +561,7 @@ export const useServiceModules = (clanUri: string) => {
|
|||||||
export const clanKey = (clanUri: string) => ["clans", encodeBase64(clanUri)];
|
export const clanKey = (clanUri: string) => ["clans", encodeBase64(clanUri)];
|
||||||
|
|
||||||
export type ServiceInstancesQuery = ReturnType<typeof useServiceInstances>;
|
export type ServiceInstancesQuery = ReturnType<typeof useServiceInstances>;
|
||||||
export type ServiceInstances = SuccessData<"list_service_instances">;
|
type ServiceInstances = SuccessData<"list_service_instances">;
|
||||||
export const useServiceInstances = (clanUri: string) => {
|
export const useServiceInstances = (clanUri: string) => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
return useQuery(() => ({
|
return useQuery(() => ({
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import {
|
|||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
import { createStore, SetStoreFunction, Store } from "solid-js/store";
|
import { createStore, SetStoreFunction, Store } from "solid-js/store";
|
||||||
|
|
||||||
export interface StepBase {
|
interface StepBase {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Step<ExtraFields = unknown> = StepBase & ExtraFields;
|
type Step<ExtraFields = unknown> = StepBase & ExtraFields;
|
||||||
|
|
||||||
export interface StepOptions<Id, StoreType> {
|
interface StepOptions<Id, StoreType> {
|
||||||
initialStep: Id;
|
initialStep: Id;
|
||||||
initialStoreData?: StoreType;
|
initialStoreData?: StoreType;
|
||||||
}
|
}
|
||||||
@@ -95,10 +95,7 @@ export function createStepper<
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StoreTuple<T> = [get: Store<T>, set: SetStoreFunction<T>];
|
type StoreTuple<T> = [get: Store<T>, set: SetStoreFunction<T>];
|
||||||
export interface StepperReturn<
|
interface StepperReturn<T extends readonly Step[], StepId = T[number]["id"]> {
|
||||||
T extends readonly Step[],
|
|
||||||
StepId = T[number]["id"],
|
|
||||||
> {
|
|
||||||
_store: never;
|
_store: never;
|
||||||
activeStep: Accessor<StepId>;
|
activeStep: Accessor<StepId>;
|
||||||
setActiveStep: (id: StepId) => void;
|
setActiveStep: (id: StepId) => void;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useClanListQuery } from "@/src/hooks/queries";
|
|||||||
import { Alert } from "@/src/components/Alert/Alert";
|
import { Alert } from "@/src/components/Alert/Alert";
|
||||||
import { NavSection } from "@/src/components/NavSection/NavSection";
|
import { NavSection } from "@/src/components/NavSection/NavSection";
|
||||||
|
|
||||||
export interface ListClansModalProps {
|
interface ListClansModalProps {
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
error?: {
|
error?: {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import { ListClansModal } from "@/src/modals/ListClansModal/ListClansModal";
|
|||||||
import { AddMachine } from "@/src/workflows/AddMachine/AddMachine";
|
import { AddMachine } from "@/src/workflows/AddMachine/AddMachine";
|
||||||
import { SelectService } from "@/src/workflows/Service/SelectServiceFlyout";
|
import { SelectService } from "@/src/workflows/Service/SelectServiceFlyout";
|
||||||
|
|
||||||
export type WorldMode = "default" | "select" | "service" | "create" | "move";
|
type WorldMode = "default" | "select" | "service" | "create" | "move";
|
||||||
|
|
||||||
function createClanContext(
|
function createClanContext(
|
||||||
clanURI: string,
|
clanURI: string,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ type FieldNames = "name" | "description" | "machineClass";
|
|||||||
|
|
||||||
type FormValues = v.InferInput<typeof schema>;
|
type FormValues = v.InferInput<typeof schema>;
|
||||||
|
|
||||||
export interface SectionGeneralProps {
|
interface SectionGeneralProps {
|
||||||
clanURI: string;
|
clanURI: string;
|
||||||
machineName: string;
|
machineName: string;
|
||||||
onSubmit: (values: FormValues) => Promise<void>;
|
onSubmit: (values: FormValues) => Promise<void>;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function createMachineMesh() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createCubeBase(
|
function createCubeBase(
|
||||||
color: THREE.ColorRepresentation,
|
color: THREE.ColorRepresentation,
|
||||||
emissive: THREE.ColorRepresentation,
|
emissive: THREE.ColorRepresentation,
|
||||||
geometry: THREE.BoxGeometry,
|
geometry: THREE.BoxGeometry,
|
||||||
@@ -70,7 +70,7 @@ export function createCubeBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function to build rounded rect shape
|
// Function to build rounded rect shape
|
||||||
export function roundedRectShape(w: number, h: number, r: number) {
|
function roundedRectShape(w: number, h: number, r: number) {
|
||||||
const shape = new THREE.Shape();
|
const shape = new THREE.Shape();
|
||||||
const x = -w / 2;
|
const x = -w / 2;
|
||||||
const y = -h / 2;
|
const y = -h / 2;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const [lastClickedMachine, setLastClickedMachine] = createSignal<string | null>(
|
|||||||
|
|
||||||
// Exported so others could also emit the signal if needed
|
// Exported so others could also emit the signal if needed
|
||||||
// And for testing purposes
|
// And for testing purposes
|
||||||
export function emitMachineClick(id: string | null) {
|
function emitMachineClick(id: string | null) {
|
||||||
setLastClickedMachine(id);
|
setLastClickedMachine(id);
|
||||||
if (id) {
|
if (id) {
|
||||||
// Clear after a short delay to allow re-clicking the same machine
|
// Clear after a short delay to allow re-clicking the same machine
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const [highlightGroups, setHighlightGroups] = createStore<
|
|||||||
>({});
|
>({});
|
||||||
|
|
||||||
// Add highlight
|
// Add highlight
|
||||||
export function highlight(group: string, nodeId: string) {
|
function highlight(group: string, nodeId: string) {
|
||||||
setHighlightGroups(group, (prev = new Set()) => {
|
setHighlightGroups(group, (prev = new Set()) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
next.add(nodeId);
|
next.add(nodeId);
|
||||||
@@ -16,7 +16,7 @@ export function highlight(group: string, nodeId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove highlight
|
// Remove highlight
|
||||||
export function unhighlight(group: string, nodeId: string) {
|
function unhighlight(group: string, nodeId: string) {
|
||||||
setHighlightGroups(group, (prev = new Set()) => {
|
setHighlightGroups(group, (prev = new Set()) => {
|
||||||
const next = new Set(prev);
|
const next = new Set(prev);
|
||||||
next.delete(nodeId);
|
next.delete(nodeId);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { makePersisted } from "@solid-primitives/storage";
|
|||||||
|
|
||||||
export type SceneData = Record<string, { position: [number, number] }>;
|
export type SceneData = Record<string, { position: [number, number] }>;
|
||||||
|
|
||||||
export interface ClanStoreType {
|
interface ClanStoreType {
|
||||||
clanURIs: string[];
|
clanURIs: string[];
|
||||||
activeClanURI?: string;
|
activeClanURI?: string;
|
||||||
sceneData: Record<string, SceneData>;
|
sceneData: Record<string, SceneData>;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const AddMachineStepper = (props: AddMachineStepperProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface AddMachineProps {
|
interface AddMachineProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCreated: (id: string) => void;
|
onCreated: (id: string) => void;
|
||||||
initialStep?: AddMachineSteps[number]["id"];
|
initialStep?: AddMachineSteps[number]["id"];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Typography } from "@/src/components/Typography/Typography";
|
|||||||
import { Show } from "solid-js";
|
import { Show } from "solid-js";
|
||||||
import { Alert } from "@/src/components/Alert/Alert";
|
import { Alert } from "@/src/components/Alert/Alert";
|
||||||
|
|
||||||
export interface StepProgressProps {
|
interface StepProgressProps {
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const InstallStepper = (props: InstallStepperProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface InstallModalProps {
|
interface InstallModalProps {
|
||||||
machineName: string;
|
machineName: string;
|
||||||
initialStep?: InstallSteps[number]["id"];
|
initialStep?: InstallSteps[number]["id"];
|
||||||
mount?: Node;
|
mount?: Node;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const UpdateStepper = (props: UpdateStepperProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface UpdateModalProps {
|
interface UpdateModalProps {
|
||||||
machineName: string;
|
machineName: string;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
initialStep?: UpdateSteps[number]["id"];
|
initialStep?: UpdateSteps[number]["id"];
|
||||||
@@ -92,7 +92,7 @@ export interface UpdateModalProps {
|
|||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UpdateHeader = (props: { machineName: string }) => {
|
const UpdateHeader = (props: { machineName: string }) => {
|
||||||
return (
|
return (
|
||||||
<Typography hierarchy="label" size="default">
|
<Typography hierarchy="label" size="default">
|
||||||
Update: {props.machineName}
|
Update: {props.machineName}
|
||||||
@@ -206,8 +206,8 @@ const steps = [
|
|||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type UpdateSteps = typeof steps;
|
type UpdateSteps = typeof steps;
|
||||||
export type PromptValues = Record<string, Record<string, string>>;
|
type PromptValues = Record<string, Record<string, string>>;
|
||||||
|
|
||||||
export const UpdateModal = (props: UpdateModalProps) => {
|
export const UpdateModal = (props: UpdateModalProps) => {
|
||||||
const stepper = createStepper(
|
const stepper = createStepper(
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import { Loader } from "@/src/components/Loader/Loader";
|
|||||||
import { Button as KButton } from "@kobalte/core/button";
|
import { Button as KButton } from "@kobalte/core/button";
|
||||||
import usbLogo from "@/logos/usb-stick-min.png?url";
|
import usbLogo from "@/logos/usb-stick-min.png?url";
|
||||||
|
|
||||||
export const InstallHeader = (props: { machineName: string }) => {
|
const InstallHeader = (props: { machineName: string }) => {
|
||||||
return (
|
return (
|
||||||
<Typography hierarchy="label" size="default">
|
<Typography hierarchy="label" size="default">
|
||||||
Installing: {props.machineName}
|
Installing: {props.machineName}
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ const steps = [
|
|||||||
{ id: "settings", content: () => <div>Adjust settings here.</div> },
|
{ id: "settings", content: () => <div>Adjust settings here.</div> },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type ServiceSteps = typeof steps;
|
type ServiceSteps = typeof steps;
|
||||||
|
|
||||||
interface ServiceWorkflowProps {
|
interface ServiceWorkflowProps {
|
||||||
initialStep?: ServiceSteps[number]["id"];
|
initialStep?: ServiceSteps[number]["id"];
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export interface ServiceStoreType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Ideally we would impot this from a backend model package
|
// TODO: Ideally we would impot this from a backend model package
|
||||||
export interface InventoryInstance {
|
interface InventoryInstance {
|
||||||
name: string;
|
name: string;
|
||||||
module: {
|
module: {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -33,7 +33,7 @@ export type SubmitServiceHandler = (
|
|||||||
action: "create" | "update",
|
action: "create" | "update",
|
||||||
) => void | Promise<void>;
|
) => void | Promise<void>;
|
||||||
|
|
||||||
export type ModuleItem = ServiceModules["modules"][number];
|
type ModuleItem = ServiceModules["modules"][number];
|
||||||
|
|
||||||
export interface Module {
|
export interface Module {
|
||||||
value: string;
|
value: string;
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
export function isValidHostname(value: string | null | undefined) {
|
|
||||||
if (typeof value !== "string") return false;
|
|
||||||
|
|
||||||
const validHostnameChars = /^[a-zA-Z0-9-.]{1,253}\.?$/g;
|
|
||||||
|
|
||||||
if (!validHostnameChars.test(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.endsWith(".")) {
|
|
||||||
value = value.slice(0, value.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.length > 253) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const labels = value.split(".");
|
|
||||||
|
|
||||||
const isValid = labels.every(function (label) {
|
|
||||||
const validLabelChars = /^([a-zA-Z0-9-]+)$/g;
|
|
||||||
|
|
||||||
const validLabel =
|
|
||||||
validLabelChars.test(label) &&
|
|
||||||
label.length < 64 &&
|
|
||||||
!label.startsWith("-") &&
|
|
||||||
!label.endsWith("-");
|
|
||||||
|
|
||||||
return validLabel;
|
|
||||||
});
|
|
||||||
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user