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:
hgl
2025-10-23 12:39:46 +00:00
42 changed files with 185 additions and 1465 deletions

View File

@@ -2,5 +2,4 @@ app/api
app/.fonts
.vite
storybook-static
*.css.d.ts

View File

@@ -1,19 +1,9 @@
{
"ignore": [
"gtk.webview.js",
"src/api/clan/client-fetch.ts",
"stylelint.config.js",
"util.ts",
"src/components/v2/**",
"api/**",
"tailwind/**"
],
"ignoreDependencies": [
"@babel/plugin-syntax-import-attributes",
"@storybook/addon-viewport",
"@typescript-eslint/parser",
"@vitest/coverage-v8",
"http-server",
"playwright",
"wait-on"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -20,40 +20,28 @@
},
"license": "MIT",
"devDependencies": {
"@babel/plugin-syntax-import-attributes": "^7.27.1",
"@eslint/js": "^9.3.0",
"@kachurun/storybook-solid-vite": "^9.0.11",
"@linaria/core": "^6.3.0",
"@sinonjs/fake-timers": "^14.0.0",
"@storybook/addon-a11y": "^9.0.8",
"@storybook/addon-docs": "^9.0.8",
"@storybook/addon-links": "^9.0.8",
"@storybook/addon-viewport": "^9.0.8",
"@storybook/addon-vitest": "^9.0.8",
"@types/node": "^22.15.19",
"@types/sinonjs__fake-timers": "^8.1.5",
"@types/three": "^0.176.0",
"@typescript-eslint/parser": "^8.32.1",
"@vitest/browser": "^3.2.3",
"@vitest/coverage-v8": "^3.2.3",
"@wyw-in-js/vite": "^0.7.0",
"autoprefixer": "^10.4.19",
"classnames": "^2.5.1",
"concurrently": "^9.1.2",
"eslint": "^9.27.0",
"eslint-plugin-tailwindcss": "^3.17.0",
"eslint-plugin-unused-imports": "^4.1.4",
"extend": "^3.0.2",
"http-server": "^14.1.1",
"jsdom": "^26.1.0",
"knip": "^5.61.2",
"markdown-to-jsx": "^7.7.10",
"playwright": "1.54.1",
"postcss": "^8.4.38",
"postcss-url": "^10.1.3",
"prettier": "^3.2.5",
"storybook": "^9.0.8",
"swagger-ui-dist": "^5.26.2",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",
"typescript-eslint": "^8.32.1",
@@ -62,11 +50,9 @@
"vite-css-modules": "^1.10.0",
"vite-plugin-solid": "^2.8.2",
"vite-plugin-solid-svg": "^0.8.1",
"vitest": "^3.2.3",
"wait-on": "^8.0.3"
"vitest": "^3.2.4"
},
"dependencies": {
"@floating-ui/dom": "^1.6.8",
"@kobalte/core": "^0.13.10",
"@kobalte/tailwindcss": "^0.9.0",
"@modular-forms/solid": "^0.25.1",
@@ -80,7 +66,6 @@
"solid-js": "^1.9.7",
"solid-toast": "^0.5.0",
"three": "^0.176.0",
"troika-three-text": "^0.52.4",
"valibot": "^1.1.0"
},
"optionalDependencies": {

View File

@@ -8,11 +8,11 @@ import Icon, { IconVariant } from "@/src/components/Icon/Icon";
import { Loader } from "@/src/components/Loader/Loader";
import { getInClasses, joinByDash, keepTruthy } from "@/src/util";
export type Size = "default" | "s" | "xs";
export type Hierarchy = "primary" | "secondary";
export type Elasticity = "default" | "fit";
type Size = "default" | "s" | "xs";
type Hierarchy = "primary" | "secondary";
type Elasticity = "default" | "fit";
export type Action = () => Promise<void>;
type Action = () => Promise<void>;
export interface ButtonProps
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {

View File

@@ -10,15 +10,15 @@ import styles from "./Label.module.css";
import cx from "classnames";
import { getInClasses } from "@/src/util";
export type Size = "default" | "s";
type Size = "default" | "s";
export type LabelComponent =
type LabelComponent =
| typeof TextField.Label
| typeof Checkbox.Label
| typeof Combobox.Label
| typeof Select.Label;
export type DescriptionComponent =
type DescriptionComponent =
| typeof TextField.Description
| typeof Checkbox.Description
| typeof Combobox.Description

View File

@@ -19,7 +19,7 @@ import { CollectionNode } from "@kobalte/core";
import styles from "./MachineTags.module.css";
import { keepTruthy } from "@/src/util";
export interface MachineTag {
interface MachineTag {
value: string;
disabled?: boolean;
}

View File

@@ -3,7 +3,7 @@ import { JSX, mergeProps } from "solid-js";
import styles from "./Orienter.module.css";
export interface OrienterProps {
interface OrienterProps {
orientation?: "vertical" | "horizontal";
align?: "center" | "start";
children: JSX.Element;

View File

@@ -3,7 +3,7 @@ import { mergeProps } from "solid-js";
import styles from "./Loader.module.css";
import cx from "classnames";
export type Hierarchy = "primary" | "secondary";
type Hierarchy = "primary" | "secondary";
export interface LoaderProps {
hierarchy?: Hierarchy;

View File

@@ -2,7 +2,7 @@ import { JSX } from "solid-js";
import styles from "./LoadingBar.module.css";
import cx from "classnames";
export type LoadingBarProps = JSX.HTMLAttributes<HTMLDivElement> & {};
type LoadingBarProps = JSX.HTMLAttributes<HTMLDivElement> & {};
export const LoadingBar = (props: LoadingBarProps) => (
<div {...props} class={cx(styles.loading_bar, props.class)} />
);

View File

@@ -14,7 +14,7 @@ import Icon from "../Icon/Icon";
import cx from "classnames";
import { Dynamic } from "solid-js/web";
export interface ModalContextType {
interface ModalContextType {
portalRef: HTMLDivElement;
}

View File

@@ -16,7 +16,7 @@ import { CollectionNode } from "@kobalte/core/*";
import cx from "classnames";
import { Loader } from "../Loader/Loader";
export interface Option {
interface Option {
value: string;
label: string;
disabled?: boolean;

View File

@@ -8,7 +8,7 @@ import { CollectionNode } from "@kobalte/core/*";
import { Loader } from "../Loader/Loader";
import cx from "classnames";
export interface Option {
interface Option {
value: string;
label: string;
disabled?: boolean;

View File

@@ -16,7 +16,7 @@ import cx from "classnames";
import { useModalContext } from "../Modal/Modal";
import { keepTruthy } from "@/src/util";
export interface Option {
interface Option {
value: string;
label: string;
disabled?: boolean;

View File

@@ -4,12 +4,12 @@ import { SidebarBody } from "@/src/components/Sidebar/SidebarBody";
import cx from "classnames";
import { splitProps } from "solid-js";
export interface LinkProps {
interface LinkProps {
path: string;
label?: string;
}
export interface SectionProps {
interface SectionProps {
title: string;
links: LinkProps[];
}

View File

@@ -2,7 +2,7 @@ import { JSX, Show } from "solid-js";
import styles from "./SidebarSection.module.css";
import { Typography } from "@/src/components/Typography/Typography";
export interface SidebarSectionProps {
interface SidebarSectionProps {
title: string;
controls?: JSX.Element;
children: JSX.Element;

View File

@@ -18,7 +18,7 @@ import { Button } from "@/src/components/Button/Button";
import { Loader } from "../../components/Loader/Loader";
import { SidebarSection } from "./SidebarSection";
export interface SidebarSectionFormProps<FormValues extends FieldValues> {
interface SidebarSectionFormProps<FormValues extends FieldValues> {
title: string;
schema: GenericSchema<FormValues> | GenericSchemaAsync<FormValues>;
initialValues: PartialValues<FormValues>;

View File

@@ -7,7 +7,7 @@ import styles from "./SidebarSectionInstall.module.css";
import { Alert } from "../Alert/Alert";
import { useClanContext } from "@/src/routes/Clan/Clan";
export interface SidebarSectionInstallProps {
interface SidebarSectionInstallProps {
clanURI: string;
machineName: string;
}

View File

@@ -6,7 +6,7 @@ import styles from "./SidebarSectionInstall.module.css";
import { UpdateModal } from "@/src/workflows/InstallMachine/UpdateMachine";
import { useClanContext } from "@/src/routes/Clan/Clan";
export interface SidebarSectionUpdateProps {
interface SidebarSectionUpdateProps {
clanURI: string;
machineName: string;
}

View File

@@ -5,7 +5,7 @@ import Icon, { IconVariant } from "@/src/components/Icon/Icon";
import type { JSX } from "solid-js";
import { Tooltip } from "../Tooltip/Tooltip";
export interface ToolbarButtonProps
interface ToolbarButtonProps
extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
icon: IconVariant;
description: JSX.Element;

View File

@@ -9,15 +9,15 @@ import { getInClasses } from "@/src/util";
export type Hierarchy = "body" | "title" | "headline" | "label" | "teaser";
export type Weight = "normal" | "medium" | "bold";
export type Family = "regular" | "mono";
export type Transform = "uppercase" | "lowercase" | "capitalize";
export interface SizeForHierarchy {
type Transform = "uppercase" | "lowercase" | "capitalize";
interface SizeForHierarchy {
body: "default" | "s" | "xs" | "xxs";
headline: "default" | "m" | "l" | "xl" | "xxl";
title: "default" | "m" | "l";
label: "default" | "s" | "xs" | "xxs";
teaser: "default";
}
export interface TagForHierarchy {
interface TagForHierarchy {
body: "span" | "p" | "div";
headline: "h1" | "h2" | "h3" | "h4";
title: "h1" | "h2" | "h3" | "h4";
@@ -40,7 +40,7 @@ const defaultTagMap = {
label: "span",
teaser: "h3",
} as const;
export interface TypographyProps<H extends Hierarchy> {
interface TypographyProps<H extends Hierarchy> {
hierarchy: H;
children: JSX.Element;
size?: SizeForHierarchy[H];

View File

@@ -1,7 +1,7 @@
import { createContext, JSX, useContext } from "solid-js";
import { ApiCall, OperationArgs, OperationNames } from "./api";
export interface ApiClient {
interface ApiClient {
fetch: Fetcher;
}

View File

@@ -3,7 +3,7 @@ import { addClanURI, setActiveClanURI } from "@/src/stores/clan";
import { Params, Navigator, useParams, useSearchParams } from "@solidjs/router";
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 () => {
const req = callApi("get_clan_folder", {});
@@ -80,7 +80,7 @@ export const navigateToClan = (navigate: Navigator, clanURI: string) => {
export const navigateToOnboarding = (navigate: Navigator, addClan: boolean) =>
navigate(`/${addClan ? "?addClan=true" : ""}`);
export const navigateToMachine = (
const navigateToMachine = (
navigate: Navigator,
clanURI: string,
name: string,
@@ -90,7 +90,7 @@ export const navigateToMachine = (
navigate(path);
};
export const clanURIParam = (params: Params) => {
const clanURIParam = (params: Params) => {
try {
return decodeBase64(params.clanURI);
} catch (e) {
@@ -101,19 +101,19 @@ export const clanURIParam = (params: Params) => {
export const useClanURI = () => clanURIParam(useParams());
export const machineNameParam = (params: Params) => {
const machineNameParam = (params: Params) => {
return params.machineName;
};
export const inputParam = (params: Params) => params.input;
export const nameParam = (params: Params) => params.name;
export const idParam = (params: Params) => params.id;
const inputParam = (params: Params) => params.input;
const nameParam = (params: Params) => params.name;
const idParam = (params: Params) => params.id;
export const useMachineName = (): string => machineNameParam(useParams());
export const useInputParam = (): string => inputParam(useParams());
export const useNameParam = (): string => nameParam(useParams());
const useInputParam = (): string => inputParam(useParams());
const useNameParam = (): string => nameParam(useParams());
export const maybeUseIdParam = (): string | null => {
const maybeUseIdParam = (): string | null => {
const params = useParams();
if (params.id === undefined) {
return null;

View File

@@ -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],
});
},
}));

View File

@@ -44,7 +44,7 @@ window.notifyBus = (msg: ProcessMessage) => {
*
* consider using useNotify for reactive usage on solidjs
*/
export function _subscribeNotify<T extends ProcessMessage>(
function _subscribeNotify<T extends ProcessMessage>(
filter: (msg: T) => boolean,
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
* 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,
) {
const [message, setMessage] = createSignal<T | null>(null);

View File

@@ -16,16 +16,16 @@ export interface ClanDetails {
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 MachineState = SuccessData<"get_machine_state">;
type MachineState = SuccessData<"get_machine_state">;
export type MachineStatus = MachineState["status"];
export type ListMachines = SuccessData<"list_machines">;
export type MachineDetails = SuccessData<"get_machine_details">;
type ListMachines = SuccessData<"list_machines">;
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 interface MachineDetail {
@@ -35,7 +35,7 @@ export interface MachineDetail {
}
export type MachinesQueryResult = UseQueryResult<ListMachines>;
export type ClanListQueryResult = UseQueryResult<ClanDetails>[];
type ClanListQueryResult = UseQueryResult<ClanDetails>[];
export const DefaultQueryClient = new QueryClient({
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),
"machine",
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();
return useQuery<ListServiceModules>(() => ({
@@ -222,10 +222,7 @@ export const useServiceInstancesQuery = (clanURI: string) => {
}));
};
export const useMachineDetailsQuery = (
clanURI: string,
machineName: string,
) => {
const useMachineDetailsQuery = (clanURI: string, machineName: string) => {
const client = useApiClient();
return useQuery<MachineDetails>(() => ({
queryKey: [machineKey(clanURI, machineName), "details"],
@@ -251,7 +248,7 @@ export const useMachineDetailsQuery = (
}));
};
export const ClanDetailsPersister = experimental_createQueryPersister({
const ClanDetailsPersister = experimental_createQueryPersister({
storage: ClanDetailsStore,
});
@@ -373,10 +370,10 @@ export const useClanListQuery = (
}));
};
export type MachineFlashOptions = SuccessData<"get_machine_flash_options">;
export type MachineFlashOptionsQuery = UseQueryResult<MachineFlashOptions>;
type MachineFlashOptions = SuccessData<"get_machine_flash_options">;
type MachineFlashOptionsQuery = UseQueryResult<MachineFlashOptions>;
export const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
const client = useApiClient();
return useQuery<MachineFlashOptions>(() => ({
queryKey: ["flash_options"],
@@ -395,8 +392,8 @@ export const useMachineFlashOptions = (): MachineFlashOptionsQuery => {
}));
};
export type SystemStorageOptions = SuccessData<"list_system_storage_devices">;
export type SystemStorageOptionsQuery = UseQueryResult<SystemStorageOptions>;
type SystemStorageOptions = SuccessData<"list_system_storage_devices">;
type SystemStorageOptionsQuery = UseQueryResult<SystemStorageOptions>;
export const useSystemStorageOptions = (): SystemStorageOptionsQuery => {
const client = useApiClient();
@@ -417,10 +414,8 @@ export const useSystemStorageOptions = (): SystemStorageOptionsQuery => {
}));
};
export type MachineHardwareSummary =
SuccessData<"get_machine_hardware_summary">;
export type MachineHardwareSummaryQuery =
UseQueryResult<MachineHardwareSummary>;
type MachineHardwareSummary = SuccessData<"get_machine_hardware_summary">;
type MachineHardwareSummaryQuery = UseQueryResult<MachineHardwareSummary>;
export const useMachineHardwareSummary = (
clanUri: string,
@@ -457,8 +452,8 @@ export const useMachineHardwareSummary = (
}));
};
export type MachineDiskSchema = SuccessData<"get_machine_disk_schemas">;
export type MachineDiskSchemaQuery = UseQueryResult<MachineDiskSchema>;
type MachineDiskSchema = SuccessData<"get_machine_disk_schemas">;
type MachineDiskSchemaQuery = UseQueryResult<MachineDiskSchema>;
export const useMachineDiskSchemas = (
clanUri: string,
@@ -496,7 +491,7 @@ export const useMachineDiskSchemas = (
};
export type MachineGenerators = SuccessData<"get_generators">;
export type MachineGeneratorsQuery = UseQueryResult<MachineGenerators>;
type MachineGeneratorsQuery = UseQueryResult<MachineGenerators>;
export const useMachineGenerators = (
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 const useServiceModules = (clanUri: string) => {
const client = useApiClient();
@@ -566,7 +561,7 @@ export const useServiceModules = (clanUri: string) => {
export const clanKey = (clanUri: string) => ["clans", encodeBase64(clanUri)];
export type ServiceInstancesQuery = ReturnType<typeof useServiceInstances>;
export type ServiceInstances = SuccessData<"list_service_instances">;
type ServiceInstances = SuccessData<"list_service_instances">;
export const useServiceInstances = (clanUri: string) => {
const client = useApiClient();
return useQuery(() => ({

View File

@@ -7,13 +7,13 @@ import {
} from "solid-js";
import { createStore, SetStoreFunction, Store } from "solid-js/store";
export interface StepBase {
interface StepBase {
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;
initialStoreData?: StoreType;
}
@@ -95,10 +95,7 @@ export function createStepper<
}
type StoreTuple<T> = [get: Store<T>, set: SetStoreFunction<T>];
export interface StepperReturn<
T extends readonly Step[],
StepId = T[number]["id"],
> {
interface StepperReturn<T extends readonly Step[], StepId = T[number]["id"]> {
_store: never;
activeStep: Accessor<StepId>;
setActiveStep: (id: StepId) => void;

View File

@@ -8,7 +8,7 @@ import { useClanListQuery } from "@/src/hooks/queries";
import { Alert } from "@/src/components/Alert/Alert";
import { NavSection } from "@/src/components/NavSection/NavSection";
export interface ListClansModalProps {
interface ListClansModalProps {
onClose?: () => void;
error?: {
title: string;

View File

@@ -39,7 +39,7 @@ import { ListClansModal } from "@/src/modals/ListClansModal/ListClansModal";
import { AddMachine } from "@/src/workflows/AddMachine/AddMachine";
import { SelectService } from "@/src/workflows/Service/SelectServiceFlyout";
export type WorldMode = "default" | "select" | "service" | "create" | "move";
type WorldMode = "default" | "select" | "service" | "create" | "move";
function createClanContext(
clanURI: string,

View File

@@ -22,7 +22,7 @@ type FieldNames = "name" | "description" | "machineClass";
type FormValues = v.InferInput<typeof schema>;
export interface SectionGeneralProps {
interface SectionGeneralProps {
clanURI: string;
machineName: string;
onSubmit: (values: FormValues) => Promise<void>;

View File

@@ -52,7 +52,7 @@ export function createMachineMesh() {
};
}
export function createCubeBase(
function createCubeBase(
color: THREE.ColorRepresentation,
emissive: THREE.ColorRepresentation,
geometry: THREE.BoxGeometry,
@@ -70,7 +70,7 @@ export function createCubeBase(
}
// 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 x = -w / 2;
const y = -h / 2;

View File

@@ -80,7 +80,7 @@ const [lastClickedMachine, setLastClickedMachine] = createSignal<string | null>(
// Exported so others could also emit the signal if needed
// And for testing purposes
export function emitMachineClick(id: string | null) {
function emitMachineClick(id: string | null) {
setLastClickedMachine(id);
if (id) {
// Clear after a short delay to allow re-clicking the same machine

View File

@@ -7,7 +7,7 @@ const [highlightGroups, setHighlightGroups] = createStore<
>({});
// Add highlight
export function highlight(group: string, nodeId: string) {
function highlight(group: string, nodeId: string) {
setHighlightGroups(group, (prev = new Set()) => {
const next = new Set(prev);
next.add(nodeId);
@@ -16,7 +16,7 @@ export function highlight(group: string, nodeId: string) {
}
// Remove highlight
export function unhighlight(group: string, nodeId: string) {
function unhighlight(group: string, nodeId: string) {
setHighlightGroups(group, (prev = new Set()) => {
const next = new Set(prev);
next.delete(nodeId);

View File

@@ -3,7 +3,7 @@ import { makePersisted } from "@solid-primitives/storage";
export type SceneData = Record<string, { position: [number, number] }>;
export interface ClanStoreType {
interface ClanStoreType {
clanURIs: string[];
activeClanURI?: string;
sceneData: Record<string, SceneData>;

View File

@@ -32,7 +32,7 @@ const AddMachineStepper = (props: AddMachineStepperProps) => {
);
};
export interface AddMachineProps {
interface AddMachineProps {
onClose: () => void;
onCreated: (id: string) => void;
initialStep?: AddMachineSteps[number]["id"];

View File

@@ -8,7 +8,7 @@ import { Typography } from "@/src/components/Typography/Typography";
import { Show } from "solid-js";
import { Alert } from "@/src/components/Alert/Alert";
export interface StepProgressProps {
interface StepProgressProps {
onDone: () => void;
}

View File

@@ -29,7 +29,7 @@ const InstallStepper = (props: InstallStepperProps) => {
);
};
export interface InstallModalProps {
interface InstallModalProps {
machineName: string;
initialStep?: InstallSteps[number]["id"];
mount?: Node;

View File

@@ -84,7 +84,7 @@ const UpdateStepper = (props: UpdateStepperProps) => {
);
};
export interface UpdateModalProps {
interface UpdateModalProps {
machineName: string;
open: boolean;
initialStep?: UpdateSteps[number]["id"];
@@ -92,7 +92,7 @@ export interface UpdateModalProps {
onClose?: () => void;
}
export const UpdateHeader = (props: { machineName: string }) => {
const UpdateHeader = (props: { machineName: string }) => {
return (
<Typography hierarchy="label" size="default">
Update: {props.machineName}
@@ -206,8 +206,8 @@ const steps = [
},
] as const;
export type UpdateSteps = typeof steps;
export type PromptValues = Record<string, Record<string, string>>;
type UpdateSteps = typeof steps;
type PromptValues = Record<string, Record<string, string>>;
export const UpdateModal = (props: UpdateModalProps) => {
const stepper = createStepper(

View File

@@ -39,7 +39,7 @@ import { Loader } from "@/src/components/Loader/Loader";
import { Button as KButton } from "@kobalte/core/button";
import usbLogo from "@/logos/usb-stick-min.png?url";
export const InstallHeader = (props: { machineName: string }) => {
const InstallHeader = (props: { machineName: string }) => {
return (
<Typography hierarchy="label" size="default">
Installing: {props.machineName}

View File

@@ -462,7 +462,7 @@ const steps = [
{ id: "settings", content: () => <div>Adjust settings here.</div> },
] as const;
export type ServiceSteps = typeof steps;
type ServiceSteps = typeof steps;
interface ServiceWorkflowProps {
initialStep?: ServiceSteps[number]["id"];

View File

@@ -14,7 +14,7 @@ export interface ServiceStoreType {
}
// TODO: Ideally we would impot this from a backend model package
export interface InventoryInstance {
interface InventoryInstance {
name: string;
module: {
name: string;
@@ -33,7 +33,7 @@ export type SubmitServiceHandler = (
action: "create" | "update",
) => void | Promise<void>;
export type ModuleItem = ServiceModules["modules"][number];
type ModuleItem = ServiceModules["modules"][number];
export interface Module {
value: string;

View File

@@ -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;
}