API: init icon resolve
All checks were successful
buildbot/nix-build .#checks.aarch64-darwin.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-iso-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-ts-api Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-no-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-deb Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-rpm Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-age Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-archlinux Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-bash Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-e2fsprogs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-fakeroot Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.renderClanOptions Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-git Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-nix Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-openssh Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.check-for-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-mypy" Build done.
buildbot/nix-build .#checks.x86_64-linux.package-default Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-qemu" Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-apk Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sops Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-zbar Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-example-valid Build done.
buildbot/nix-build .#checks.x86_64-linux.borgbackup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-pytest Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.treefmt Build done.
buildbot/nix-build .#checks.x86_64-linux.package-editor Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-rsync Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sshpass Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-tor Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-default Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.container Build done.
buildbot/nix-build .#checks.x86_64-linux.deltachat Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.matrix-synapse Build done.
buildbot/nix-build .#checks.x86_64-linux.module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-impure-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.package-merge-after-ci Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-nix-unit-tests Build done.
buildbot/nix-build .#checks.x86_64-linux.package-moonlight-sunshine-accept Build done.
buildbot/nix-build .#checks.x86_64-linux.package-tea-create-pr Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotier-members Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotierone Build done.
buildbot/nix-build .#checks.x86_64-linux.postgresql Build done.
buildbot/nix-build .#checks.x86_64-linux.package-pending-reviews Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-function-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.template-minimal Build done.
buildbot/nix-build .#checks.x86_64-linux.package-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-deploy-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.secrets Build done.
buildbot/nix-build .#checks.x86_64-linux.zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.wayland-proxy-virtwl Build done.
buildbot/nix-build .#checks.x86_64-linux.syncthing Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-without-core Build done.
buildbot/nix-build .#checks.x86_64-linux.package-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-install-test-ubuntu-22-04 Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-with-core Build done.
buildbot/nix-build .#checks.x86_64-linux.test-backups Build done.
checks / checks-impure (pull_request) Successful in 2m14s
buildbot/nix-build .#checks.x86_64-linux.flash Build done.
buildbot/nix-build .#checks.x86_64-linux.test-installation Build done.
buildbot/nix-eval Build done.

This commit is contained in:
Johannes Kirschbauer 2024-06-12 13:21:25 +02:00
parent 1f3c4f4ac3
commit 6743ff96a9
Signed by: hsjobeki
SSH Key Fingerprint: SHA256:vX3utDqig7Ph5L0JPv87ZTPb/w7cMzREKVZzzLFg9qU
8 changed files with 181 additions and 183 deletions

View File

@ -2,6 +2,7 @@ import argparse
import json
import logging
from pathlib import Path
from urllib.parse import urlparse
from clan_cli.api import API
from clan_cli.clan.create import ClanMetaInfo
@ -22,6 +23,7 @@ def show_clan_meta(uri: str | Path) -> ClanMetaInfo:
]
)
res = "{}"
try:
proc = run_no_stdout(cmd)
res = proc.stdout.strip()
@ -33,10 +35,36 @@ def show_clan_meta(uri: str | Path) -> ClanMetaInfo:
)
clan_meta = json.loads(res)
# Check if icon is a URL such as http:// or https://
# Check if icon is an relative path
# All other schemas such as file://, ftp:// are not yet supported.
icon_path: str | None = None
if meta_icon := clan_meta.get("icon"):
scheme = urlparse(meta_icon).scheme
if scheme in ["http", "https"]:
icon_path = meta_icon
elif scheme in [""]:
if Path(meta_icon).is_absolute():
raise ClanError(
"Invalid absolute path",
location=f"show_clan {uri}",
description="Icon path must be a URL or a relative path.",
)
else:
icon_path = str((Path(uri) / meta_icon).resolve())
else:
raise ClanError(
"Invalid schema",
location=f"show_clan {uri}",
description="Icon path must be a URL or a relative path.",
)
return ClanMetaInfo(
name=clan_meta.get("name"),
description=clan_meta.get("description", None),
icon=clan_meta.get("icon", None),
icon=icon_path,
)

View File

@ -1,13 +1,12 @@
const fs = require("fs");
const path = require("path");
import fs from "node:fs";
import postcss from "postcss";
import path from "node:path";
import css_url from "postcss-url";
const distPath = path.resolve(__dirname, "dist");
const distPath = path.resolve("dist");
const manifestPath = path.join(distPath, ".vite/manifest.json");
const outputPath = path.join(distPath, "index.html");
const postcss = require("postcss");
const css_url = require("postcss-url");
fs.readFile(manifestPath, { encoding: "utf8" }, (err, data) => {
if (err) {
return console.error("Failed to read manifest:", err);

View File

@ -2,6 +2,7 @@
"name": "@clan/webview-ui",
"version": "0.0.1",
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",

View File

@ -1,6 +1,8 @@
module.exports = {
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
export default config;

View File

@ -17,6 +17,8 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
console.log(import.meta.env);
if (import.meta.env.DEV) {
console.log("Development mode");
// Load the debugger in development mode
await import("solid-devtools");
window.webkit = window.webkit || {
messageHandlers: {
gtk: {
@ -28,12 +30,11 @@ if (import.meta.env.DEV) {
console.log("mock", { mock });
window.clan[method](JSON.stringify(mock));
}, 1000);
}, 200);
},
},
},
};
}
postMessage;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
render(() => <App />, root!);

View File

@ -19,21 +19,17 @@ interface ClanDetailsProps {
directory: string;
}
interface MetaFieldsProps {
interface ClanFormProps {
directory?: string;
meta: ClanMeta;
actions: JSX.Element;
editable?: boolean;
directory?: string;
}
const fn = (e: SubmitEvent) => {
e.preventDefault();
console.log("form submit", e.currentTarget);
};
export default function Login() {
const [, { Form, Field }] = createForm<ClanMeta>({
initialValues: { name: "MyClan" },
export const ClanForm = (props: ClanFormProps) => {
const { meta, actions, editable = true, directory } = props;
const [formStore, { Form, Field }] = createForm<ClanMeta>({
initialValues: meta,
});
const handleSubmit: SubmitHandler<ClanMeta> = (values, event) => {
@ -52,156 +48,120 @@ export default function Login() {
console.log("submit", values);
};
return (
<div class="card-body">
<div class="card card-compact w-96 bg-base-100 shadow-xl">
<Form onSubmit={handleSubmit}>
<Field
name="name"
validate={[required("Please enter a unique name for the clan.")]}
>
{(field, props) => (
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text block after:ml-0.5 after:text-primary after:content-['*']">
Name
</span>
</div>
<input
{...props}
type="email"
required
placeholder="your.mail@example.com"
class="input w-full max-w-xs"
classList={{ "input-error": !!field.error }}
value={field.value}
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
)}
</Field>
<Field name="description">
{(field, props) => (
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Description</span>
</div>
<input
{...props}
required
type="text"
placeholder="Some words about your clan"
class="input w-full max-w-xs"
classList={{ "input-error": !!field.error }}
value={field.value || ""}
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
)}
</Field>
<Field name="icon">
{(field, props) => (
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Select icon</span>
</div>
<input
type="file"
class="file-input file-input-bordered w-full max-w-xs"
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
<>
<figure>
<Show
when={field.value}
fallback={
<span class="material-icons aspect-square size-60 rounded-lg text-[18rem]">
group
</span>
}
>
{(icon) => (
<img
class="aspect-square size-60 rounded-lg"
src={icon()}
alt="Clan Logo"
/>
)}
</Show>
</figure>
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Select icon</span>
</div>
<input
type="file"
class="file-input file-input-bordered w-full max-w-xs"
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
</>
)}
</Field>
<div class="card-actions justify-end">
<button class="btn btn-primary" type="submit">
Create
</button>
<div class="card-body">
<div class="card-body">
<Field
name="name"
validate={[required("Please enter a unique name for the clan.")]}
>
{(field, props) => (
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text block after:ml-0.5 after:text-primary after:content-['*']">
Name
</span>
</div>
<input
{...props}
type="email"
required
placeholder="your.mail@example.com"
class="input w-full max-w-xs"
classList={{ "input-error": !!field.error }}
value={field.value}
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
)}
</Field>
<Field name="description">
{(field, props) => (
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">Description</span>
</div>
<input
{...props}
required
type="text"
placeholder="Some words about your clan"
class="input w-full max-w-xs"
classList={{ "input-error": !!field.error }}
value={field.value || ""}
/>
<div class="label">
{field.error && (
<span class="label-text-alt">{field.error}</span>
)}
</div>
</label>
)}
</Field>
{actions}
</div>
</div>
</Form>
</div>
);
}
export const EditMetaFields = (props: MetaFieldsProps) => {
const { meta, editable, actions, directory } = props;
const [editing, setEditing] = createSignal<
keyof MetaFieldsProps["meta"] | null
>(null);
return (
<div class="card card-compact w-96 bg-base-100 shadow-xl">
<figure>
<img
src="https://www.shutterstock.com/image-vector/modern-professional-ninja-mascot-logo-260nw-1729854862.jpg"
alt="Clan Logo"
/>
</figure>
<div class="card-body">
<Login />
{/* <form onSubmit={fn}> */}
{/* <h2 class="card-title justify-between">
<input
classList={{
[cx("text-slate-600")]: editing() !== "name",
}}
readOnly={editing() !== "name"}
class="w-full"
autofocus
onBlur={() => setEditing(null)}
type="text"
value={meta?.name}
onInput={(e) => {
console.log(e.currentTarget.value);
}}
/>
<Show when={editable}>
<button class="btn btn-square btn-ghost btn-sm">
<span
class="material-icons"
onClick={() => {
if (editing() !== "name") setEditing("name");
else {
setEditing(null);
}
}}
>
<Show when={editing() !== "name"} fallback="check">
edit
</Show>
</span>
</button>
</Show>
</h2>
<div class="flex gap-1 align-middle leading-8">
<i class="material-icons">description</i>
<span>{meta?.description || "No description"}</span>
</div>
<Show when={directory}>
<div class="flex gap-1 align-middle leading-8">
<i class="material-icons">folder</i>
<span>{directory}</span>
</div>
</Show>
{actions} */}
{/* </form> */}
</div>
</div>
);
};
// export const EditMetaFields = (props: MetaFieldsProps) => {
// const { meta, editable, actions, directory } = props;
// const [editing, setEditing] = createSignal<
// keyof MetaFieldsProps["meta"] | null
// >(null);
// return (
// );
// };
type ClanMeta = Extract<
OperationResponse<"show_clan_meta">,
{ status: "success" }
@ -209,7 +169,7 @@ type ClanMeta = Extract<
export const ClanDetails = (props: ClanDetailsProps) => {
const { directory } = props;
const [, setLoading] = createSignal(false);
const [loading, setLoading] = createSignal(false);
const [errors, setErrors] = createSignal<
| Extract<
OperationResponse<"show_clan_meta">,
@ -237,23 +197,30 @@ export const ClanDetails = (props: ClanDetailsProps) => {
});
return (
<Switch fallback={"loading"}>
<Match when={loading()}>
<div>Loading</div>
</Match>
<Match when={data()}>
<EditMetaFields
directory={directory}
// @ts-expect-error: TODO: figure out how solid allows type narrowing this
meta={data()}
actions={
<div class="card-actions justify-between">
<button class="btn btn-link" onClick={() => loadMeta()}>
Refresh
</button>
<button class="btn btn-primary">Open</button>
</div>
}
/>
{(data) => {
const meta = data();
return (
<ClanForm
directory={directory}
meta={meta}
actions={
<div class="card-actions justify-between">
<button class="btn btn-link" onClick={() => loadMeta()}>
Refresh
</button>
<button class="btn btn-primary">Open</button>
</div>
}
/>
);
}}
</Match>
<Match when={errors()}>
<button class="btn btn-link" onClick={() => loadMeta()}>
<button class="btn btn-secondary" onClick={() => loadMeta()}>
Retry
</button>
<For each={errors()}>

View File

@ -1,7 +1,7 @@
import { pyApi } from "@/src/api";
import { Match, Switch, createEffect, createSignal } from "solid-js";
import toast from "solid-toast";
import { ClanDetails, EditMetaFields } from "./clanDetails";
import { ClanDetails, ClanForm } from "./clanDetails";
export const clan = () => {
const [mode, setMode] = createSignal<"init" | "open" | "create">("init");
@ -53,16 +53,16 @@ export const clan = () => {
<ClanDetails directory={clanDir() || ""} />
</Match>
<Match when={mode() === "create"}>
<EditMetaFields
<ClanForm
actions={
<div class="card-actions justify-end">
<button
class="btn btn-primary"
onClick={() => {
pyApi.open_file.dispatch({
file_request: { mode: "save" },
});
}}
// onClick={() => {
// pyApi.open_file.dispatch({
// file_request: { mode: "save" },
// });
// }}
>
Save
</button>

View File

@ -1,6 +1,6 @@
import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid";
// import devtools from "solid-devtools/vite";
import devtools from "solid-devtools/vite";
import path from "node:path";
export default defineConfig({
@ -14,7 +14,7 @@ export default defineConfig({
Uncomment the following line to enable solid-devtools.
For more info see https://github.com/thetarnav/solid-devtools/tree/main/packages/extension#readme
*/
// devtools(),
devtools(),
solidPlugin(),
],
server: {