formatter.nix: Add prettier

This commit is contained in:
Qubasa
2024-08-02 18:56:53 +02:00
parent 3e9ebbc90f
commit fb4ceebccf
23 changed files with 272 additions and 252 deletions

View File

@@ -1,6 +1,6 @@
name: deploy name: deploy
on: on:
push: push:
branches: branches:
- main - main
jobs: jobs:

View File

@@ -1,9 +1,16 @@
{% extends "base.html" %} {% extends "base.html" %} {% block extrahead %}
<meta
{% block extrahead %} property="og:title"
<meta property="og:title" content="Clan - Documentation, Blog & Getting Started Guide" /> content="Clan - Documentation, Blog & Getting Started Guide"
<meta property="og:description" content="Documentation for Clan. The peer-to-peer machine deployment framework." /> />
<meta property="og:image" content="https://clan.lol/static/dark-favicon/128x128.png" /> <meta
property="og:description"
content="Documentation for Clan. The peer-to-peer machine deployment framework."
/>
<meta
property="og:image"
content="https://clan.lol/static/dark-favicon/128x128.png"
/>
<meta property="og:url" content="https://docs.clan.lol" /> <meta property="og:url" content="https://docs.clan.lol" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:site_name" content="Clan" /> <meta property="og:site_name" content="Clan" />

View File

@@ -1,13 +1,13 @@
@font-face { @font-face {
font-family: "Roboto"; font-family: "Roboto";
src: url(./Roboto-Regular.ttf) format('truetype'); src: url(./Roboto-Regular.ttf) format("truetype");
} }
@font-face { @font-face {
font-family: "Fira Code"; font-family: "Fira Code";
src: url(./FiraCode-VF.ttf) format('truetype'); src: url(./FiraCode-VF.ttf) format("truetype");
} }
:root { :root {
--md-text-font: "Roboto"; --md-text-font: "Roboto";
--md-code-font: "Fira Code"; --md-code-font: "Fira Code";
} }

View File

@@ -11,6 +11,39 @@
treefmt.programs.nixfmt.enable = true; treefmt.programs.nixfmt.enable = true;
treefmt.programs.nixfmt.package = pkgs.nixfmt-rfc-style; treefmt.programs.nixfmt.package = pkgs.nixfmt-rfc-style;
treefmt.programs.deadnix.enable = true; treefmt.programs.deadnix.enable = true;
treefmt.settings.global.excludes = [
"*.png"
"*.jpeg"
"*.gitignore"
".vscode/*"
"*.toml"
"*.clan-flake"
"*.code-workspace"
"*.pub"
"*.typed"
"*.age"
"*.list"
"*.desktop"
];
treefmt.programs.prettier = {
enable = true;
includes = [
"*.cjs"
"*.css"
"*.html"
"*.js"
"*.json5"
"*.jsx"
"*.mdx"
"*.mjs"
"*.scss"
"*.ts"
"*.tsx"
"*.vue"
"*.yaml"
"*.yml"
];
};
treefmt.programs.mypy.directories = treefmt.programs.mypy.directories =
{ {

View File

@@ -1,66 +1,63 @@
/* Insert custom styles here */ /* Insert custom styles here */
navigation-view { navigation-view {
padding: 5px; padding: 5px;
/* padding-left: 5px; /* padding-left: 5px;
padding-right: 5px; padding-right: 5px;
padding-bottom: 5px; */ padding-bottom: 5px; */
} }
avatar { avatar {
margin: 2px; margin: 2px;
} }
.trust { .trust {
padding-top: 25px; padding-top: 25px;
padding-bottom: 25px; padding-bottom: 25px;
} }
.join-list { .join-list {
margin-top: 1px; margin-top: 1px;
margin-left: 2px; margin-left: 2px;
margin-right: 2px; margin-right: 2px;
} }
.progress-bar { .progress-bar {
margin-right: 25px; margin-right: 25px;
min-width: 200px; min-width: 200px;
} }
.group-list { .group-list {
background-color: inherit; background-color: inherit;
} }
.group-list > .activatable:hover { .group-list > .activatable:hover {
background-color: unset; background-color: unset;
} }
.group-list > row { .group-list > row {
margin-top: 12px; margin-top: 12px;
border-bottom: unset; border-bottom: unset;
} }
.vm-list { .vm-list {
margin-top: 25px; margin-top: 25px;
margin-bottom: 25px; margin-bottom: 25px;
} }
.no-shadow { .no-shadow {
box-shadow: none; box-shadow: none;
} }
.search-entry { .search-entry {
margin-bottom: 12px; margin-bottom: 12px;
} }
searchbar { searchbar {
margin-bottom: 25px; margin-bottom: 25px;
} }
.log-view { .log-view {
margin-top: 12px; margin-top: 12px;
font-family: monospace; font-family: monospace;
padding: 8px; padding: 8px;
} }

View File

@@ -1,26 +1,24 @@
{ {
// Use IntelliSense to learn about possible attributes. // Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes. // Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Clan Webui", "name": "Clan Webui",
"type": "python", "type": "python",
"request": "launch", "request": "launch",
"module": "clan_cli.webui", "module": "clan_cli.webui",
"justMyCode": false, "justMyCode": false,
"args": [ "--reload", "--no-open", "--log-level", "debug" ], "args": ["--reload", "--no-open", "--log-level", "debug"]
},
}, {
{ "name": "Clan Cli VMs",
"name": "Clan Cli VMs", "type": "python",
"type": "python", "request": "launch",
"request": "launch", "module": "clan_cli",
"module": "clan_cli", "justMyCode": false,
"justMyCode": false, "args": ["vms"]
"args": [ "vms" ], }
]
}
]
} }

View File

@@ -1,22 +1,22 @@
{ {
"python.testing.pytestArgs": [ "python.testing.pytestArgs": [
// Coverage is not supported by vscode: // Coverage is not supported by vscode:
// https://github.com/Microsoft/vscode-python/issues/693 // https://github.com/Microsoft/vscode-python/issues/693
// Note that this will make pytest fail if pytest-cov is not installed, // Note that this will make pytest fail if pytest-cov is not installed,
// if that's the case, then this option needs to be be removed (overrides // if that's the case, then this option needs to be be removed (overrides
// can be set at a workspace level, it's up to you to decide what's the // can be set at a workspace level, it's up to you to decide what's the
// best approach). You might also prefer to only set this option // best approach). You might also prefer to only set this option
// per-workspace (wherever coverage is used). // per-workspace (wherever coverage is used).
"--no-cov", "--no-cov",
"tests" "tests"
], ],
"python.testing.unittestEnabled": false, "python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true, "python.testing.pytestEnabled": true,
"search.exclude": { "search.exclude": {
"**/.direnv": true "**/.direnv": true
}, },
"python.linting.mypyPath": "mypy", "python.linting.mypyPath": "mypy",
"python.linting.mypyEnabled": true, "python.linting.mypyEnabled": true,
"python.linting.enabled": true, "python.linting.enabled": true,
"python.defaultInterpreterPath": "python" "python.defaultInterpreterPath": "python"
} }

View File

@@ -1,23 +1,23 @@
secret-key: ENC[AES256_GCM,data:gjX4OmCUdd3TlA4p,iv:3yZVpyd6FqkITQY0nU2M1iubmzvkR6PfkK2m/s6nQh8=,tag:Abgp9xkiFFylZIyAlap6Ew==,type:str] secret-key: ENC[AES256_GCM,data:gjX4OmCUdd3TlA4p,iv:3yZVpyd6FqkITQY0nU2M1iubmzvkR6PfkK2m/s6nQh8=,tag:Abgp9xkiFFylZIyAlap6Ew==,type:str]
nested: nested:
secret-key: ENC[AES256_GCM,data:iUMgDhhIjwvd7wL4,iv:jiJIrh12dSu/sXX+z9ITVoEMNDMjwIlFBnyv40oN4LE=,tag:G9VmAa66Km1sc7JEhW5AvA==,type:str] secret-key: ENC[AES256_GCM,data:iUMgDhhIjwvd7wL4,iv:jiJIrh12dSu/sXX+z9ITVoEMNDMjwIlFBnyv40oN4LE=,tag:G9VmAa66Km1sc7JEhW5AvA==,type:str]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
azure_kv: [] azure_kv: []
hc_vault: [] hc_vault: []
age: age:
- recipient: age14tva0txcrl0zes05x7gkx56qd6wd9q3nwecjac74xxzz4l47r44sv3fz62 - recipient: age14tva0txcrl0zes05x7gkx56qd6wd9q3nwecjac74xxzz4l47r44sv3fz62
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0eWdRVjlydXlXOVZFQ3lO YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0eWdRVjlydXlXOVZFQ3lO
bzU1eG9Iam5Ka29Sdlo0cHJ4b1R6bjdNSzBjCkgwRndCbWZQWHlDU0x1cWRmaGVt bzU1eG9Iam5Ka29Sdlo0cHJ4b1R6bjdNSzBjCkgwRndCbWZQWHlDU0x1cWRmaGVt
N29lbjR6UjN0L2RhaXEzSG9zQmRsZGsKLS0tIEdsdWgxSmZwU3BWUDVxVWRSSC9M N29lbjR6UjN0L2RhaXEzSG9zQmRsZGsKLS0tIEdsdWgxSmZwU3BWUDVxVWRSSC9M
eVZ6bjgwZnR2TTM5MkRYZWNFSFplQWsKmSzv12/dftL9jx2y35UZUGVK6xWdatE8 eVZ6bjgwZnR2TTM5MkRYZWNFSFplQWsKmSzv12/dftL9jx2y35UZUGVK6xWdatE8
BGJiCvMlp0BQNrh2s/+YaEaBa48w8LL79U/XJnEZ+ZUwxmlbSTn6Hg== BGJiCvMlp0BQNrh2s/+YaEaBa48w8LL79U/XJnEZ+ZUwxmlbSTn6Hg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2023-08-08T14:27:20Z" lastmodified: "2023-08-08T14:27:20Z"
mac: ENC[AES256_GCM,data:iRWWX+L5Q5nKn3fBCLaWoz/mvqGnNnRd93gJmYXDZbRjFoHa9IFJZst5QDIDa1ZRYUe6G0/+lV5SBi+vwRm1pHysJ3c0ZWYjBP+e1jw3jLXxLV5gACsDC8by+6rFUCho0Xgu+Nqu2ehhNenjQQnCvDH5ivWbW70KFT5ynNgR9Tw=,iv:RYnnbLMC/hNfMwWPreMq9uvY0khajwQTZENO/P34ckY=,tag:Xi1PS5vM1c+sRkroHkPn1Q==,type:str] mac: ENC[AES256_GCM,data:iRWWX+L5Q5nKn3fBCLaWoz/mvqGnNnRd93gJmYXDZbRjFoHa9IFJZst5QDIDa1ZRYUe6G0/+lV5SBi+vwRm1pHysJ3c0ZWYjBP+e1jw3jLXxLV5gACsDC8by+6rFUCho0Xgu+Nqu2ehhNenjQQnCvDH5ivWbW70KFT5ynNgR9Tw=,iv:RYnnbLMC/hNfMwWPreMq9uvY0khajwQTZENO/P34ckY=,tag:Xi1PS5vM1c+sRkroHkPn1Q==,type:str]
pgp: [] pgp: []
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.7.3 version: 3.7.3

View File

@@ -1,66 +1,63 @@
/* Insert custom styles here */ /* Insert custom styles here */
navigation-view { navigation-view {
padding: 5px; padding: 5px;
/* padding-left: 5px; /* padding-left: 5px;
padding-right: 5px; padding-right: 5px;
padding-bottom: 5px; */ padding-bottom: 5px; */
} }
avatar { avatar {
margin: 2px; margin: 2px;
} }
.trust { .trust {
padding-top: 25px; padding-top: 25px;
padding-bottom: 25px; padding-bottom: 25px;
} }
.join-list { .join-list {
margin-top: 1px; margin-top: 1px;
margin-left: 2px; margin-left: 2px;
margin-right: 2px; margin-right: 2px;
} }
.progress-bar { .progress-bar {
margin-right: 25px; margin-right: 25px;
min-width: 200px; min-width: 200px;
} }
.group-list { .group-list {
background-color: inherit; background-color: inherit;
} }
.group-list > .activatable:hover { .group-list > .activatable:hover {
background-color: unset; background-color: unset;
} }
.group-list > row { .group-list > row {
margin-top: 12px; margin-top: 12px;
border-bottom: unset; border-bottom: unset;
} }
.vm-list { .vm-list {
margin-top: 25px; margin-top: 25px;
margin-bottom: 25px; margin-bottom: 25px;
} }
.no-shadow { .no-shadow {
box-shadow: none; box-shadow: none;
} }
.search-entry { .search-entry {
margin-bottom: 12px; margin-bottom: 12px;
} }
searchbar { searchbar {
margin-bottom: 25px; margin-bottom: 25px;
} }
.log-view { .log-view {
margin-top: 12px; margin-top: 12px;
font-family: monospace; font-family: monospace;
padding: 8px; padding: 8px;
} }

View File

@@ -28,5 +28,5 @@ export default tseslint.config(
"no-unused-vars": "off", "no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "off",
}, },
} },
); );

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<title>Solid App</title> <title>Solid App</title>

View File

@@ -134,19 +134,21 @@ export const callApi = <K extends OperationNames>(
}); });
}; };
const deserialize = <T>(fn: (response: T) => void) => (str: string) => { const deserialize =
try { <T>(fn: (response: T) => void) =>
const r = JSON.parse(str) as T; (str: string) => {
console.log("Received: ", r); try {
fn(r); const r = JSON.parse(str) as T;
} catch (e) { console.log("Received: ", r);
console.log("Error parsing JSON: ", e); fn(r);
window.localStorage.setItem("error", str); } catch (e) {
console.error(str); console.log("Error parsing JSON: ", e);
console.error("See localStorage 'error'"); window.localStorage.setItem("error", str);
alert(`Error parsing JSON: ${e}`); console.error(str);
} console.error("See localStorage 'error'");
}; alert(`Error parsing JSON: ${e}`);
}
};
// Create the API object // Create the API object

View File

@@ -94,18 +94,21 @@ export const MachineListItem = (props: MachineListItemProps) => {
<div class="flex flex-row flex-wrap gap-4 py-2"> <div class="flex flex-row flex-wrap gap-4 py-2">
<div class="badge badge-primary flex flex-row gap-1 py-4 align-middle"> <div class="badge badge-primary flex flex-row gap-1 py-4 align-middle">
<span>System:</span> <span>System:</span>
{hwInfo()[name]?.system {hwInfo()[name]?.system ? (
? <span class="text-primary">{hwInfo()[name]?.system}</span> <span class="text-primary">{hwInfo()[name]?.system}</span>
: <span class="text-warning">Not set</span>} ) : (
<span class="text-warning">Not set</span>
)}
</div> </div>
<div class="badge badge-ghost flex flex-row gap-1 py-4 align-middle"> <div class="badge badge-ghost flex flex-row gap-1 py-4 align-middle">
<span>Target Host:</span> <span>Target Host:</span>
{deploymentInfo()[name] {deploymentInfo()[name] ? (
? <span class="text-primary">{deploymentInfo()[name]}</span> <span class="text-primary">{deploymentInfo()[name]}</span>
: <span class="text-warning">Not set</span>} ) : (
{ <span class="text-warning">Not set</span>
/* <Show )}
{/* <Show
when={deploymentInfo()[name]} when={deploymentInfo()[name]}
fallback={ fallback={
<Switch fallback={<div class="skeleton h-8 w-full"></div>}> <Switch fallback={<div class="skeleton h-8 w-full"></div>}>
@@ -116,8 +119,7 @@ export const MachineListItem = (props: MachineListItemProps) => {
} }
> >
{(i) => + i()} {(i) => + i()}
</Show> */ </Show> */}
}
</div> </div>
</div> </div>
{/* Show only the first error at the bottom */} {/* Show only the first error at the bottom */}

View File

@@ -1,10 +1,10 @@
@import 'material-icons/iconfont/filled.css'; @import "material-icons/iconfont/filled.css";
/* List of icons: https://marella.me/material-icons/demo/ */ /* List of icons: https://marella.me/material-icons/demo/ */
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
html { html {
overflow-x: hidden; overflow-x: hidden;
overflow-y: scroll; overflow-y: scroll;
} }

View File

@@ -32,8 +32,7 @@ export const Layout: Component<LayoutProps> = (props) => {
for="toplevel-drawer" for="toplevel-drawer"
aria-label="close sidebar" aria-label="close sidebar"
class="drawer-overlay" class="drawer-overlay"
> ></label>
</label>
<Sidebar route={route} setRoute={setRoute} /> <Sidebar route={route} setRoute={setRoute} />
</div> </div>
</div> </div>

View File

@@ -27,35 +27,35 @@ export const BlockDevicesView: Component = () => {
</button> </button>
</div> </div>
<div class="flex max-w-screen-lg flex-col gap-4"> <div class="flex max-w-screen-lg flex-col gap-4">
{isFetching {isFetching ? (
? <span class="loading loading-bars"></span> <span class="loading loading-bars"></span>
: ( ) : (
<Show when={devices}> <Show when={devices}>
{(devices) => ( {(devices) => (
<For each={devices().blockdevices}> <For each={devices().blockdevices}>
{(device) => ( {(device) => (
<div class="stats shadow"> <div class="stats shadow">
<div class="stat w-28 py-8"> <div class="stat w-28 py-8">
<div class="stat-title">Name</div> <div class="stat-title">Name</div>
<div class="stat-value"> <div class="stat-value">
{" "} {" "}
<span class="material-icons">storage</span>{" "} <span class="material-icons">storage</span>{" "}
{device.name} {device.name}
</div>
<div class="stat-desc"></div>
</div>
<div class="stat w-28">
<div class="stat-title">Size</div>
<div class="stat-value">{device.size}</div>
<div class="stat-desc"></div>
</div> </div>
<div class="stat-desc"></div>
</div> </div>
)}
</For> <div class="stat w-28">
)} <div class="stat-title">Size</div>
</Show> <div class="stat-value">{device.size}</div>
)} <div class="stat-desc"></div>
</div>
</div>
)}
</For>
)}
</Show>
)}
</div> </div>
</div> </div>
); );

View File

@@ -1,16 +1,14 @@
import { route } from "@/src/App"; import { callApi, OperationResponse } from "@/src/api";
import { callApi, OperationArgs, OperationResponse, pyApi } from "@/src/api";
import { import {
createForm, createForm,
required, required,
FieldValues,
setValue, setValue,
SubmitHandler,
} from "@modular-forms/solid"; } from "@modular-forms/solid";
import { createQuery } from "@tanstack/solid-query"; import { createQuery } from "@tanstack/solid-query";
import { createEffect, createSignal, For } from "solid-js"; import { createEffect, createSignal, For } from "solid-js";
import { effect } from "solid-js/web";
type FlashFormValues = { interface FlashFormValues extends FieldValues {
machine: { machine: {
devicePath: string; devicePath: string;
flake: string; flake: string;
@@ -19,7 +17,7 @@ type FlashFormValues = {
language: string; language: string;
keymap: string; keymap: string;
sshKeys: string[]; sshKeys: string[];
}; }
type BlockDevices = Extract< type BlockDevices = Extract<
OperationResponse<"show_block_devices">, OperationResponse<"show_block_devices">,
@@ -59,10 +57,7 @@ export const Flash = () => {
} }
}); });
const { const { data: devices, isFetching } = createQuery(() => ({
data: devices,
isFetching,
} = createQuery(() => ({
queryKey: ["block_devices"], queryKey: ["block_devices"],
queryFn: async () => { queryFn: async () => {
const result = await callApi("show_block_devices", {}); const result = await callApi("show_block_devices", {});
@@ -72,10 +67,7 @@ export const Flash = () => {
staleTime: 1000 * 60 * 2, // 1 minutes staleTime: 1000 * 60 * 2, // 1 minutes
})); }));
const { const { data: keymaps, isFetching: isFetchingKeymaps } = createQuery(() => ({
data: keymaps,
isFetching: isFetchingKeymaps,
} = createQuery(() => ({
queryKey: ["list_keymaps"], queryKey: ["list_keymaps"],
queryFn: async () => { queryFn: async () => {
const result = await callApi("list_possible_keymaps", {}); const result = await callApi("list_possible_keymaps", {});
@@ -85,18 +77,17 @@ export const Flash = () => {
staleTime: 1000 * 60 * 15, // 15 minutes staleTime: 1000 * 60 * 15, // 15 minutes
})); }));
const { const { data: languages, isFetching: isFetchingLanguages } = createQuery(
data: languages, () => ({
isFetching: isFetchingLanguages, queryKey: ["list_languages"],
} = createQuery(() => ({ queryFn: async () => {
queryKey: ["list_languages"], const result = await callApi("list_possible_languages", {});
queryFn: async () => { if (result.status === "error") throw new Error("Failed to fetch data");
const result = await callApi("list_possible_languages", {}); return result.data;
if (result.status === "error") throw new Error("Failed to fetch data"); },
return result.data; staleTime: 1000 * 60 * 15, // 15 minutes
}, }),
staleTime: 1000 * 60 * 15, // 15 minutes );
}));
const handleSubmit = async (values: FlashFormValues) => { const handleSubmit = async (values: FlashFormValues) => {
setIsFlashing(true); setIsFlashing(true);
@@ -109,7 +100,7 @@ export const Flash = () => {
}, },
}, },
mode: "format", mode: "format",
disks: { "main": values.disk }, disks: { main: values.disk },
system_config: { system_config: {
language: values.language, language: values.language,
keymap: values.keymap, keymap: values.keymap,
@@ -191,7 +182,9 @@ export const Flash = () => {
class="select select-bordered w-full" class="select select-bordered w-full"
{...props} {...props}
> >
<option value="" disabled>Select a disk</option> <option value="" disabled>
Select a disk
</option>
<For each={devices?.blockdevices}> <For each={devices?.blockdevices}>
{(device) => ( {(device) => (
<option value={device.path}> <option value={device.path}>
@@ -227,11 +220,7 @@ export const Flash = () => {
> >
<option>en_US.UTF-8</option> <option>en_US.UTF-8</option>
<For each={languages}> <For each={languages}>
{(language) => ( {(language) => <option value={language}>{language}</option>}
<option value={language}>
{language}
</option>
)}
</For> </For>
</select> </select>
<div class="label"> <div class="label">
@@ -261,17 +250,12 @@ export const Flash = () => {
> >
<option>en</option> <option>en</option>
<For each={keymaps}> <For each={keymaps}>
{(keymap) => ( {(keymap) => <option value={keymap}>{keymap}</option>}
<option value={keymap}>
{keymap}
</option>
)}
</For> </For>
</select> </select>
<div class="label"> <div class="label">
{isFetchingKeymaps && ( {isFetchingKeymaps && (
<span class="label-text <span class="label-text-alt">
-alt">
<span class="loading loading-bars"></span> <span class="loading loading-bars"></span>
</span> </span>
)} )}
@@ -312,9 +296,11 @@ export const Flash = () => {
)} )}
</Field> </Field>
<button class="btn btn-error" type="submit" disabled={isFlashing()}> <button class="btn btn-error" type="submit" disabled={isFlashing()}>
{isFlashing() {isFlashing() ? (
? <span class="loading loading-spinner"></span> <span class="loading loading-spinner"></span>
: <span class="material-icons">bolt</span>} ) : (
<span class="material-icons">bolt</span>
)}
{isFlashing() ? "Flashing..." : "Flash Installer"} {isFlashing() ? "Flashing..." : "Flash Installer"}
</button> </button>
</Form> </Form>

View File

@@ -91,8 +91,7 @@ export const MachineListView: Component = () => {
<span class="material-icons ">add</span> <span class="material-icons ">add</span>
</button> </button>
</div> </div>
{ {/* <Show when={services()}>
/* <Show when={services()}>
{(services) => ( {(services) => (
<For each={Object.values(services())}> <For each={Object.values(services())}>
{(service) => ( {(service) => (
@@ -138,8 +137,7 @@ export const MachineListView: Component = () => {
)} )}
</For> </For>
)} )}
</Show> */ </Show> */}
}
<Switch> <Switch>
<Match when={loading()}> <Match when={loading()}>
{/* Loading skeleton */} {/* Loading skeleton */}

View File

@@ -33,17 +33,17 @@ export const registerClan = async () => {
}); });
console.log({ loc }, loc.status); console.log({ loc }, loc.status);
if (loc.status === "success" && loc.data) { if (loc.status === "success" && loc.data) {
// @ts-expect-error: data is a string const data = loc.data[0];
setClanList((s) => { setClanList((s) => {
const res = new Set([...s, loc.data]); const res = new Set([...s, data]);
return Array.from(res); return Array.from(res);
}); });
setActiveURI(loc.data); setActiveURI(data);
setRoute((r) => { setRoute((r) => {
if (r === "welcome") return "machines"; if (r === "welcome") return "machines";
return r; return r;
}); });
return loc.data; return data;
} }
} catch (e) { } catch (e) {
// //
@@ -145,7 +145,7 @@ const ClanDetails = (props: ClanDetailsProps) => {
return false; return false;
} }
return true; return true;
}) }),
); );
}} }}
> >

View File

@@ -44,13 +44,13 @@ describe.concurrent("API types work properly", () => {
.parameter(0) .parameter(0)
.toMatchTypeOf< .toMatchTypeOf<
| { | {
status: "success"; status: "success";
data: { data: {
machine_name: string; machine_name: string;
machine_icon?: string | null; machine_icon?: string | null;
machine_description?: string | null; machine_description?: string | null;
}; };
} }
| { status: "error"; errors: any } | { status: "error"; errors: any }
>(); >();
}); });

View File

@@ -20,7 +20,8 @@ export function isValidHostname(value: string | null | undefined) {
const isValid = labels.every(function (label) { const isValid = labels.every(function (label) {
const validLabelChars = /^([a-zA-Z0-9-]+)$/g; const validLabelChars = /^([a-zA-Z0-9-]+)$/g;
const validLabel = validLabelChars.test(label) && const validLabel =
validLabelChars.test(label) &&
label.length < 64 && label.length < 64 &&
!label.startsWith("-") && !label.startsWith("-") &&
!label.endsWith("-"); !label.endsWith("-");