@runwisp/ui 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/package.json +4 -5
  2. package/src/lib/actions/floating.ts +73 -0
  3. package/src/lib/actions/portal.ts +5 -1
  4. package/src/lib/components/Accordion.svelte +6 -2
  5. package/src/lib/components/AccordionItem.svelte +80 -23
  6. package/src/lib/components/Avatar.svelte +0 -1
  7. package/src/lib/components/CodeBlock.svelte +84 -35
  8. package/src/lib/components/CronInput.svelte +5 -2
  9. package/src/lib/components/DataGrid.svelte +95 -133
  10. package/src/lib/components/Drawer.svelte +2 -6
  11. package/src/lib/components/Dropdown.svelte +19 -57
  12. package/src/lib/components/EmptyState.svelte +2 -1
  13. package/src/lib/components/ErrorState.svelte +2 -1
  14. package/src/lib/components/Heading.svelte +19 -12
  15. package/src/lib/components/Kbd.svelte +25 -10
  16. package/src/lib/components/Link.svelte +7 -1
  17. package/src/lib/components/LogConsole.svelte +30 -32
  18. package/src/lib/components/Modal.svelte +44 -33
  19. package/src/lib/components/NotificationBell.svelte +2 -1
  20. package/src/lib/components/PageContainer.svelte +1 -10
  21. package/src/lib/components/PageHeader.svelte +8 -4
  22. package/src/lib/components/Popover.svelte +9 -51
  23. package/src/lib/components/Progress.svelte +19 -6
  24. package/src/lib/components/Radio.svelte +16 -4
  25. package/src/lib/components/RadioGroup.svelte +15 -2
  26. package/src/lib/components/Select.svelte +13 -45
  27. package/src/lib/components/Table.svelte +13 -4
  28. package/src/lib/components/TableBody.svelte +2 -1
  29. package/src/lib/components/TableCell.svelte +38 -8
  30. package/src/lib/components/TableHead.svelte +12 -4
  31. package/src/lib/components/TableRow.svelte +23 -3
  32. package/src/lib/components/TaskCard.svelte +1 -1
  33. package/src/lib/components/TimezoneSelect.svelte +2 -2
  34. package/src/lib/components/accordion.svelte.ts +19 -0
  35. package/src/lib/components/dashboard/RunDetailPanel.svelte +91 -63
  36. package/src/lib/components/dashboard/RunFilterPopover.svelte +7 -16
  37. package/src/lib/components/dashboard/RunsList.svelte +9 -18
  38. package/src/lib/components/dashboard/cron-format.ts +1 -1
  39. package/src/lib/components/dashboard/run-filters.test.ts +2 -58
  40. package/src/lib/components/dashboard/run-filters.ts +5 -53
  41. package/src/lib/components/dashboard/run-helpers.test.ts +17 -7
  42. package/src/lib/components/dashboard/run-helpers.ts +12 -1
  43. package/src/lib/components/dashboard/status-config.ts +38 -83
  44. package/src/lib/components/dashboard/types.ts +0 -26
  45. package/src/lib/components/radio-group.ts +11 -0
  46. package/src/lib/index.ts +8 -43
  47. package/src/lib/log-console/LogFetcher.svelte.ts +3 -14
  48. package/src/lib/log-console/highlight-scroll.test.ts +59 -0
  49. package/src/lib/log-console/highlight-scroll.ts +41 -0
  50. package/src/lib/theme.css +10 -4
  51. package/src/lib/utils/clipboard.svelte.test.ts +92 -0
  52. package/src/lib/utils/clipboard.svelte.ts +73 -0
  53. package/src/lib/utils/format.ts +65 -94
  54. package/src/lib/utils/id.test.ts +3 -7
  55. package/src/lib/utils/id.ts +3 -2
  56. package/src/lib/utils/theme.svelte.test.ts +0 -6
  57. package/src/lib/utils/theme.svelte.ts +3 -5
  58. package/src/lib/utils/toast.svelte.ts +3 -11
  59. package/src/stories/Accordion.stories.svelte +61 -0
  60. package/src/stories/CodeBlock.stories.svelte +55 -0
  61. package/src/stories/DataGrid.stories.svelte +0 -5
  62. package/src/stories/Heading.stories.svelte +31 -0
  63. package/src/stories/Kbd.stories.svelte +36 -0
  64. package/src/stories/Link.stories.svelte +38 -0
  65. package/src/stories/PageHeader.stories.svelte +31 -0
  66. package/src/stories/Progress.stories.svelte +26 -0
  67. package/src/stories/RadioGroup.stories.svelte +43 -0
  68. package/src/stories/Table.stories.svelte +69 -0
  69. package/src/svelte-shims.d.ts +0 -5
  70. package/src/lib/components/dashboard/status-config.test.ts +0 -18
@@ -138,11 +138,6 @@
138
138
 
139
139
  <Story name="Sortable" args={{ columns, data: tasks, sortKey: "name", sortDirection: "asc" }} />
140
140
 
141
- <Story
142
- name="Filterable"
143
- args={{ columns, data: tasks, filterable: true, filterPlaceholder: "Filter tasks…" }}
144
- />
145
-
146
141
  <Story name="Paginated" args={{ columns, data: tasks, paginate: true, pageSize: 2 }} />
147
142
 
148
143
  <Story name="Filters, Sort, Selection, Pagination" asChild>
@@ -0,0 +1,31 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Heading from "$lib/components/Heading.svelte";
7
+ import Text from "$lib/components/Text.svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Core/Heading",
11
+ component: Heading,
12
+ tags: ["autodocs"],
13
+ });
14
+ </script>
15
+
16
+ <Story name="Levels" asChild>
17
+ <div class="space-y-3">
18
+ <Heading level={1}>Level 1</Heading>
19
+ <Heading level={2}>Level 2</Heading>
20
+ <Heading level={3}>Level 3</Heading>
21
+ <Heading level={4}>Level 4</Heading>
22
+ </div>
23
+ </Story>
24
+
25
+ <!-- A card title: the semantic level stays, the size shrinks. -->
26
+ <Story name="Card title" asChild>
27
+ <div class="max-w-sm rounded-[4px] border border-outline bg-surface-raised p-4">
28
+ <Heading level={2} size="sm" id="resources-title">System resources</Heading>
29
+ <Text size="sm" color="muted" class="mt-2">CPU and memory over the last hour.</Text>
30
+ </div>
31
+ </Story>
@@ -0,0 +1,36 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Kbd from "$lib/components/Kbd.svelte";
7
+
8
+ const { Story } = defineMeta({
9
+ title: "Core/Kbd",
10
+ component: Kbd,
11
+ tags: ["autodocs"],
12
+ argTypes: {
13
+ size: { control: "select", options: ["xs", "sm"] },
14
+ tone: { control: "select", options: ["default", "faint", "console"] },
15
+ },
16
+ });
17
+ </script>
18
+
19
+ <Story name="Default" args={{ keys: ["Ctrl", "K"] }} />
20
+
21
+ <Story name="Faint in an input" asChild>
22
+ <div
23
+ class="flex h-9 max-w-xs items-center justify-between rounded-[3px] border border-outline bg-surface-sunken/60 px-3 font-mono text-sm text-on-surface-faint"
24
+ >
25
+ Search tasks…
26
+ <Kbd keys="⌘K" size="xs" tone="faint" />
27
+ </div>
28
+ </Story>
29
+
30
+ <Story name="Console" asChild>
31
+ <div
32
+ class="flex items-center gap-1.5 bg-[var(--rw-con-bg)] px-3 py-2 font-mono text-xs text-[var(--rw-con-dim)]"
33
+ >
34
+ Restore <Kbd keys="Esc" size="xs" tone="console" />
35
+ </div>
36
+ </Story>
@@ -0,0 +1,38 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Link from "$lib/components/Link.svelte";
7
+
8
+ const { Story } = defineMeta({
9
+ title: "Core/Link",
10
+ component: Link,
11
+ tags: ["autodocs"],
12
+ argTypes: {
13
+ variant: { control: "select", options: ["default", "muted", "primary", "danger"] },
14
+ underline: { control: "select", options: ["always", "hover", "none"] },
15
+ },
16
+ });
17
+ </script>
18
+
19
+ <Story name="Variants" asChild>
20
+ <div class="flex flex-col gap-2 text-sm">
21
+ <Link href="#tasks">Default</Link>
22
+ <Link href="#tasks" variant="muted">Muted</Link>
23
+ <Link href="#tasks" variant="primary">Primary</Link>
24
+ <Link href="#tasks" variant="danger">Danger</Link>
25
+ </div>
26
+ </Story>
27
+
28
+ <Story name="External" asChild>
29
+ <Link
30
+ href="https://docs.runwisp.com/configuration/tasks/"
31
+ external
32
+ variant="primary"
33
+ title="Opens in a new tab"
34
+ class="text-sm font-medium"
35
+ >
36
+ Task configuration docs →
37
+ </Link>
38
+ </Story>
@@ -0,0 +1,31 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import PageHeader from "$lib/components/PageHeader.svelte";
7
+ import Button from "$lib/components/Button.svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Layout/PageHeader",
11
+ component: PageHeader,
12
+ tags: ["autodocs"],
13
+ });
14
+ </script>
15
+
16
+ <Story
17
+ name="Default"
18
+ args={{ title: "Tasks", subtitle: "Scheduled tasks and background processes." }}
19
+ />
20
+
21
+ <Story name="Rich subtitle and actions" asChild>
22
+ <PageHeader title="Notifications">
23
+ {#snippet subtitle()}
24
+ Recent notifications across all tasks ·
25
+ <span class="font-mono font-medium text-primary-soft-text tabular-nums">3 unread</span>
26
+ {/snippet}
27
+ {#snippet actions()}
28
+ <Button size="sm" variant="secondary">Mark all read</Button>
29
+ {/snippet}
30
+ </PageHeader>
31
+ </Story>
@@ -63,3 +63,29 @@
63
63
  <p class="text-sm text-on-surface-muted">Processing 847 of 1,234 records</p>
64
64
  </div>
65
65
  </Story>
66
+
67
+ <Story name="Thresholds" asChild>
68
+ <div class="max-w-md space-y-4">
69
+ <Progress
70
+ value={42}
71
+ size="sm"
72
+ thresholds={{ warning: 70, danger: 90 }}
73
+ label="CPU"
74
+ showLabel
75
+ />
76
+ <Progress
77
+ value={76}
78
+ size="sm"
79
+ thresholds={{ warning: 70, danger: 90 }}
80
+ label="Memory"
81
+ showLabel
82
+ />
83
+ <Progress
84
+ value={95}
85
+ size="sm"
86
+ thresholds={{ warning: 70, danger: 90 }}
87
+ label="Disk"
88
+ showLabel
89
+ />
90
+ </div>
91
+ </Story>
@@ -0,0 +1,43 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Radio from "$lib/components/Radio.svelte";
7
+ import RadioGroup from "$lib/components/RadioGroup.svelte";
8
+
9
+ const { Story } = defineMeta({
10
+ title: "Forms/RadioGroup",
11
+ component: RadioGroup,
12
+ tags: ["autodocs"],
13
+ });
14
+ </script>
15
+
16
+ <script lang="ts">
17
+ let policy = $state("queue");
18
+ </script>
19
+
20
+ <Story name="Default" asChild>
21
+ <div class="space-y-3">
22
+ <RadioGroup name="concurrency" label="When a run is already active" bind:value={policy}>
23
+ <Radio value="queue" label="Queue" description="Start after the current run ends." />
24
+ <Radio value="skip" label="Skip" description="Drop the new firing." />
25
+ <Radio value="replace" label="Replace" description="Stop the current run first." />
26
+ </RadioGroup>
27
+ <p class="font-mono text-xs text-on-surface-muted">selected: {policy}</p>
28
+ </div>
29
+ </Story>
30
+
31
+ <Story name="Horizontal" asChild>
32
+ <RadioGroup
33
+ name="theme"
34
+ label="Theme"
35
+ value="auto"
36
+ orientation="horizontal"
37
+ hint="Follows your OS by default."
38
+ >
39
+ <Radio value="auto" label="Auto" />
40
+ <Radio value="light" label="Light" />
41
+ <Radio value="dark" label="Dark" />
42
+ </RadioGroup>
43
+ </Story>
@@ -0,0 +1,69 @@
1
+ <!-- SPDX-FileCopyrightText: PoppyCake, s.r.o. -->
2
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
3
+
4
+ <script module>
5
+ import { defineMeta } from "@storybook/addon-svelte-csf";
6
+ import Table from "$lib/components/Table.svelte";
7
+ import TableBody from "$lib/components/TableBody.svelte";
8
+ import TableCell from "$lib/components/TableCell.svelte";
9
+ import TableHead from "$lib/components/TableHead.svelte";
10
+ import TableRow from "$lib/components/TableRow.svelte";
11
+
12
+ const { Story } = defineMeta({
13
+ title: "Data/Table",
14
+ component: Table,
15
+ tags: ["autodocs"],
16
+ });
17
+
18
+ const runs = [
19
+ { id: "01J9Z3", task: "backup-db", status: "success", duration: "12s" },
20
+ { id: "01J9Z4", task: "sync-files", status: "failed", duration: "3m 1s" },
21
+ { id: "01J9Z5", task: "cleanup", status: "success", duration: "800ms" },
22
+ ];
23
+ </script>
24
+
25
+ <Story name="Default" asChild>
26
+ <Table class="max-w-xl">
27
+ <TableHead>
28
+ <TableCell header>Task</TableCell>
29
+ <TableCell header aria-sort="descending">Status</TableCell>
30
+ <TableCell header align="right">Duration</TableCell>
31
+ </TableHead>
32
+ <TableBody>
33
+ {#each runs as run (run.id)}
34
+ <TableRow border="faint" hoverable>
35
+ <TableCell class="font-mono">{run.task}</TableCell>
36
+ <TableCell class="text-on-surface-muted">{run.status}</TableCell>
37
+ <TableCell align="right" class="font-mono">{run.duration}</TableCell>
38
+ </TableRow>
39
+ {/each}
40
+ </TableBody>
41
+ </Table>
42
+ </Story>
43
+
44
+ <Story name="Compact, two-row header" asChild>
45
+ <Table class="max-w-xl">
46
+ <TableHead row={false}>
47
+ <TableRow border="faint">
48
+ <TableCell header density="compact" colspan={2}>Run</TableCell>
49
+ <TableCell header density="compact" align="right">Timing</TableCell>
50
+ </TableRow>
51
+ <TableRow>
52
+ <TableCell header density="compact">Id</TableCell>
53
+ <TableCell header density="compact">Task</TableCell>
54
+ <TableCell header density="compact" align="right">Duration</TableCell>
55
+ </TableRow>
56
+ </TableHead>
57
+ <TableBody>
58
+ {#each runs as run (run.id)}
59
+ <TableRow border="faint">
60
+ <TableCell density="compact" class="font-mono">{run.id}</TableCell>
61
+ <TableCell density="compact" class="font-mono">{run.task}</TableCell>
62
+ <TableCell density="compact" align="right" class="font-mono"
63
+ >{run.duration}</TableCell
64
+ >
65
+ </TableRow>
66
+ {/each}
67
+ </TableBody>
68
+ </Table>
69
+ </Story>
@@ -7,11 +7,6 @@ declare module "*.svelte" {
7
7
  export default component;
8
8
  }
9
9
 
10
- declare module "*.css?inline" {
11
- const css: string;
12
- export default css;
13
- }
14
-
15
10
  declare module "*.svg?raw" {
16
11
  const svg: string;
17
12
  export default svg;
@@ -1,18 +0,0 @@
1
- // Copyright (c) PoppyCake, s.r.o. SPDX-License-Identifier: Apache-2.0
2
-
3
- import { describe, expect, it } from "vitest";
4
- import { RUN_STATUSES } from "@runwisp/common";
5
- import { RUN_STATUS_CONFIG } from "./status-config.js";
6
-
7
- describe("RUN_STATUS_CONFIG", () => {
8
- it("has a non-empty description for every run status", () => {
9
- for (const status of RUN_STATUSES) {
10
- const config = RUN_STATUS_CONFIG[status];
11
- expect(config, `missing config for status "${status}"`).toBeDefined();
12
- expect(
13
- config.description.trim().length,
14
- `empty description for status "${status}"`,
15
- ).toBeGreaterThan(0);
16
- }
17
- });
18
- });