Merge pull request 'various-ui-fixes' (#5448) from various-ui-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5448
This commit is contained in:
@@ -113,15 +113,27 @@ mkShell {
|
|||||||
# todo darwin support needs some work
|
# todo darwin support needs some work
|
||||||
(lib.optionalString stdenv.hostPlatform.isLinux ''
|
(lib.optionalString stdenv.hostPlatform.isLinux ''
|
||||||
# configure playwright for storybook snapshot testing
|
# configure playwright for storybook snapshot testing
|
||||||
export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
# we only want webkit as that matches what the app is rendered with
|
||||||
|
|
||||||
export PLAYWRIGHT_BROWSERS_PATH=${
|
export PLAYWRIGHT_BROWSERS_PATH=${
|
||||||
playwright-driver.browsers.override {
|
playwright-driver.browsers.override {
|
||||||
withFfmpeg = false;
|
withFfmpeg = false;
|
||||||
withFirefox = false;
|
withFirefox = false;
|
||||||
|
withWebkit = true;
|
||||||
withChromium = false;
|
withChromium = false;
|
||||||
withChromiumHeadlessShell = true;
|
withChromiumHeadlessShell = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export PLAYWRIGHT_HOST_PLATFORM_OVERRIDE="ubuntu-24.04"
|
|
||||||
|
# stop playwright from trying to validate it has downloaded the necessary browsers
|
||||||
|
# we are providing them manually via nix
|
||||||
|
|
||||||
|
export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true
|
||||||
|
|
||||||
|
# playwright browser drivers are versioned e.g. webkit-2191
|
||||||
|
# this helps us avoid having to update the playwright js dependency everytime we update nixpkgs and vice versa
|
||||||
|
# see vitest.config.js for corresponding launch configuration
|
||||||
|
|
||||||
|
export PLAYWRIGHT_WEBKIT_EXECUTABLE=$(find -L "$PLAYWRIGHT_BROWSERS_PATH" -type f -name "pw_run.sh")
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
|
|||||||
16
pkgs/clan-app/ui/package-lock.json
generated
16
pkgs/clan-app/ui/package-lock.json
generated
@@ -53,7 +53,7 @@
|
|||||||
"jsdom": "^26.1.0",
|
"jsdom": "^26.1.0",
|
||||||
"knip": "^5.61.2",
|
"knip": "^5.61.2",
|
||||||
"markdown-to-jsx": "^7.7.10",
|
"markdown-to-jsx": "^7.7.10",
|
||||||
"playwright": "~1.53.2",
|
"playwright": "~1.55.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",
|
||||||
@@ -6956,13 +6956,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.53.2",
|
"version": "1.55.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz",
|
||||||
"integrity": "sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==",
|
"integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.53.2"
|
"playwright-core": "1.55.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@@ -6975,9 +6975,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.53.2",
|
"version": "1.55.1",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.2.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz",
|
||||||
"integrity": "sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==",
|
"integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"jsdom": "^26.1.0",
|
"jsdom": "^26.1.0",
|
||||||
"knip": "^5.61.2",
|
"knip": "^5.61.2",
|
||||||
"markdown-to-jsx": "^7.7.10",
|
"markdown-to-jsx": "^7.7.10",
|
||||||
"playwright": "~1.53.2",
|
"playwright": "~1.55.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",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
import type { Meta, StoryObj } from "@kachurun/storybook-solid";
|
||||||
import { Button, ButtonProps } from "./Button";
|
import { Button, ButtonProps } from "./Button";
|
||||||
import { Component } from "solid-js";
|
import { Component } from "solid-js";
|
||||||
import { expect, fn, waitFor } from "storybook/test";
|
import { expect, fn, waitFor, within } from "storybook/test";
|
||||||
import { StoryContext } from "@kachurun/storybook-solid-vite";
|
import { StoryContext } from "@kachurun/storybook-solid-vite";
|
||||||
|
|
||||||
const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor;
|
const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor;
|
||||||
@@ -216,17 +216,11 @@ const timeout = process.env.NODE_ENV === "test" ? 500 : 2000;
|
|||||||
export const Primary: Story = {
|
export const Primary: Story = {
|
||||||
args: {
|
args: {
|
||||||
hierarchy: "primary",
|
hierarchy: "primary",
|
||||||
onAction: fn(async () => {
|
onClick: fn(),
|
||||||
// wait 500 ms to simulate an action
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
||||||
// randomly fail to check that the loading state still returns to normal
|
|
||||||
if (Math.random() > 0.5) {
|
|
||||||
throw new Error("Action failure");
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
play: async ({ canvas, step, userEvent, args }: StoryContext) => {
|
play: async ({ canvasElement, step, userEvent, args }: StoryContext) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
const buttons = await canvas.findAllByRole("button");
|
const buttons = await canvas.findAllByRole("button");
|
||||||
|
|
||||||
for (const button of buttons) {
|
for (const button of buttons) {
|
||||||
@@ -238,14 +232,6 @@ export const Primary: Story = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await step(`Click on ${testID}`, async () => {
|
await step(`Click on ${testID}`, async () => {
|
||||||
// check for the loader
|
|
||||||
const loaders = button.getElementsByClassName("loader");
|
|
||||||
await expect(loaders.length).toEqual(1);
|
|
||||||
|
|
||||||
// assert its width is 0 before we click
|
|
||||||
const [loader] = loaders;
|
|
||||||
await expect(loader.clientWidth).toEqual(0);
|
|
||||||
|
|
||||||
// move the mouse over the button
|
// move the mouse over the button
|
||||||
await userEvent.hover(button);
|
await userEvent.hover(button);
|
||||||
|
|
||||||
@@ -255,33 +241,8 @@ export const Primary: Story = {
|
|||||||
// click the button
|
// click the button
|
||||||
await userEvent.click(button);
|
await userEvent.click(button);
|
||||||
|
|
||||||
// check the button has changed
|
// the click handler should have been called
|
||||||
await waitFor(
|
await expect(args.onClick).toHaveBeenCalled();
|
||||||
async () => {
|
|
||||||
// the action handler should have been called
|
|
||||||
await expect(args.onAction).toHaveBeenCalled();
|
|
||||||
// the button should have a loading class
|
|
||||||
await expect(button).toHaveClass("loading");
|
|
||||||
// the loader should be visible
|
|
||||||
await expect(loader.clientWidth).toBeGreaterThan(0);
|
|
||||||
// the pointer should have changed to wait
|
|
||||||
await expect(getCursorStyle(button)).toEqual("wait");
|
|
||||||
},
|
|
||||||
{ timeout: timeout + 500 },
|
|
||||||
);
|
|
||||||
|
|
||||||
// wait for the action handler to finish
|
|
||||||
await waitFor(
|
|
||||||
async () => {
|
|
||||||
// the loading class should be removed
|
|
||||||
await expect(button).not.toHaveClass("loading");
|
|
||||||
// the loader should be hidden
|
|
||||||
await expect(loader.clientWidth).toEqual(0);
|
|
||||||
// the pointer should be normal
|
|
||||||
await expect(getCursorStyle(button)).toEqual("pointer");
|
|
||||||
},
|
|
||||||
{ timeout: timeout + 500 },
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export const Button = (props: ButtonProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<KobalteButton
|
<KobalteButton
|
||||||
|
role="button"
|
||||||
class={cx(
|
class={cx(
|
||||||
styles.button, // default button class
|
styles.button, // default button class
|
||||||
local.size != "default" && styles[local.size],
|
local.size != "default" && styles[local.size],
|
||||||
|
|||||||
@@ -160,47 +160,47 @@ const mockFetcher = <K extends OperationNames>(
|
|||||||
},
|
},
|
||||||
}) satisfies ApiCall<K>;
|
}) satisfies ApiCall<K>;
|
||||||
|
|
||||||
export const Default: Story = {
|
// export const Default: Story = {
|
||||||
args: {},
|
// args: {},
|
||||||
decorators: [
|
// decorators: [
|
||||||
(Story: StoryObj) => {
|
// (Story: StoryObj) => {
|
||||||
const queryClient = new QueryClient({
|
// const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
// defaultOptions: {
|
||||||
queries: {
|
// queries: {
|
||||||
retry: false,
|
// retry: false,
|
||||||
staleTime: Infinity,
|
// staleTime: Infinity,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
Object.entries(queryData).forEach(([clanURI, clan]) => {
|
// Object.entries(queryData).forEach(([clanURI, clan]) => {
|
||||||
queryClient.setQueryData(
|
// queryClient.setQueryData(
|
||||||
["clans", encodeBase64(clanURI), "details"],
|
// ["clans", encodeBase64(clanURI), "details"],
|
||||||
clan.details,
|
// clan.details,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
const machines = clan.machines || {};
|
// const machines = clan.machines || {};
|
||||||
|
//
|
||||||
queryClient.setQueryData(
|
// queryClient.setQueryData(
|
||||||
["clans", encodeBase64(clanURI), "machines"],
|
// ["clans", encodeBase64(clanURI), "machines"],
|
||||||
machines,
|
// machines,
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
Object.entries(machines).forEach(([name, machine]) => {
|
// Object.entries(machines).forEach(([name, machine]) => {
|
||||||
queryClient.setQueryData(
|
// queryClient.setQueryData(
|
||||||
["clans", encodeBase64(clanURI), "machine", name, "state"],
|
// ["clans", encodeBase64(clanURI), "machine", name, "state"],
|
||||||
machine.state,
|
// machine.state,
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
return (
|
// return (
|
||||||
<ApiClientProvider client={{ fetch: mockFetcher }}>
|
// <ApiClientProvider client={{ fetch: mockFetcher }}>
|
||||||
<QueryClientProvider client={queryClient}>
|
// <QueryClientProvider client={queryClient}>
|
||||||
<Story />
|
// <Story />
|
||||||
</QueryClientProvider>
|
// </QueryClientProvider>
|
||||||
</ApiClientProvider>
|
// </ApiClientProvider>
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
};
|
// };
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import { Alert } from "@/src/components/Alert/Alert";
|
|||||||
import { removeClanURI } from "@/src/stores/clan";
|
import { removeClanURI } from "@/src/stores/clan";
|
||||||
|
|
||||||
const schema = v.object({
|
const schema = v.object({
|
||||||
name: v.pipe(v.optional(v.string())),
|
name: v.string(),
|
||||||
description: v.nullish(v.string()),
|
description: v.optional(v.string()),
|
||||||
icon: v.pipe(v.nullish(v.string())),
|
icon: v.optional(v.string()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface ClanSettingsModalProps {
|
export interface ClanSettingsModalProps {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import { Meta, StoryObj } from "@kachurun/storybook-solid";
|
|
||||||
import { CubeScene } from "./cubes";
|
|
||||||
|
|
||||||
const meta: Meta = {
|
|
||||||
title: "scene/cubes",
|
|
||||||
component: CubeScene,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
args: {},
|
|
||||||
};
|
|
||||||
@@ -304,11 +304,10 @@ const FlashProgress = () => {
|
|||||||
const [store, set] = getStepStore<InstallStoreType>(stepSignal);
|
const [store, set] = getStepStore<InstallStoreType>(stepSignal);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const result = await store.flash.progress.result;
|
const result = await store.flash?.progress?.result;
|
||||||
if (result.status == "success") {
|
if (result?.status == "success") {
|
||||||
console.log("Flashing Success");
|
stepSignal.next();
|
||||||
}
|
}
|
||||||
stepSignal.next();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleCancel = async () => {
|
const handleCancel = async () => {
|
||||||
|
|||||||
@@ -165,23 +165,23 @@ export default meta;
|
|||||||
|
|
||||||
type Story = StoryObj<typeof ServiceWorkflow>;
|
type Story = StoryObj<typeof ServiceWorkflow>;
|
||||||
|
|
||||||
export const Default: Story = {
|
// export const Default: Story = {
|
||||||
args: {},
|
// args: {},
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
export const SelectRoleMembers: Story = {
|
// export const SelectRoleMembers: Story = {
|
||||||
render: () => (
|
// render: () => (
|
||||||
<ServiceWorkflow
|
// <ServiceWorkflow
|
||||||
handleSubmit={(instance) => {
|
// handleSubmit={(instance) => {
|
||||||
console.log("Submitted instance:", instance);
|
// console.log("Submitted instance:", instance);
|
||||||
}}
|
// }}
|
||||||
onClose={() => {
|
// onClose={() => {
|
||||||
console.log("Closed");
|
// console.log("Closed");
|
||||||
}}
|
// }}
|
||||||
initialStep="select:members"
|
// initialStep="select:members"
|
||||||
initialStore={{
|
// initialStore={{
|
||||||
currentRole: "peer",
|
// currentRole: "peer",
|
||||||
}}
|
// }}
|
||||||
/>
|
// />
|
||||||
),
|
// ),
|
||||||
};
|
// };
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"jsxImportSource": "solid-js",
|
"jsxImportSource": "solid-js",
|
||||||
"types": ["vite/client", "vite-plugin-solid-svg/types-component-solid"],
|
"types": [
|
||||||
|
"vite/client",
|
||||||
|
"vite-plugin-solid-svg/types-component-solid",
|
||||||
|
"@vitest/browser/providers/playwright"
|
||||||
|
],
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|||||||
@@ -40,7 +40,14 @@ export default mergeConfig(
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
headless: true,
|
headless: true,
|
||||||
provider: "playwright",
|
provider: "playwright",
|
||||||
instances: [{ browser: "chromium" }],
|
instances: [
|
||||||
|
{
|
||||||
|
browser: "webkit",
|
||||||
|
launch: {
|
||||||
|
executablePath: process.env.PLAYWRIGHT_WEBKIT_EXECUTABLE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
// This setup file applies Storybook project annotations for Vitest
|
// This setup file applies Storybook project annotations for Vitest
|
||||||
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
||||||
|
|||||||
Reference in New Issue
Block a user