Compare commits

...

67 Commits

Author SHA1 Message Date
a-kenji
bc290fe59f docs/testing: Document requirements for our container testing system
Document the requirements for our container testing system:
- uid-range
- auto-allocate-uids

Further document that the container tests are used by default and how to
switch to the more traditional and more supported / featureful VM
testing framework.
2025-10-29 13:47:26 +01:00
Luis Hebendanz
89e18482ed Merge pull request 'checks: Fix flakey llm test, improve performance' (#5678) from Qubasa/clan-core:fix_slow_llm into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5678
2025-10-27 16:34:21 +00:00
Qubasa
a8217b5a32 llm checks: Skip parts of the test on aarch64 for performance 2025-10-27 17:25:06 +01:00
Qubasa
bdd5de5628 checks: Fix flakey llm test, improve performance 2025-10-27 17:12:12 +01:00
Mic92
61d8bfd0d1 Merge pull request 'fix: respect directory parameter in machines_dir' (#5677) from fix-custom-directory into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5677
Reviewed-by: hsjobeki <hsjobeki@gmail.com>
2025-10-27 15:42:44 +00:00
Jörg Thalheim
b8d79c7fc2 fix: respect directory parameter in machines_dir
The machines_dir() function was hardcoding "machines" without considering
the directory parameter from buildClan/clan configuration. This caused
update-hardware-config and other commands to write files to the wrong
location when a custom directory was specified (e.g., directory = ./clan).

Solution:
1. Added relativeDirectory to inventoryClass in Nix, computed where both
   self and directory have consistent store paths during evaluation
2. Updated machines_dir() to use this pre-computed relative path from Nix
   via flake.select("clanInternals.inventoryClass.relativeDirectory")

Fixes: https://git.clan.lol/clan/clan-core/issues/2906
2025-10-27 16:37:07 +01:00
hsjobeki
fb25ab028b Merge pull request 'services: add role settings with explicit warning' (#5676) from role-settings into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5676
2025-10-27 15:33:39 +00:00
clan-bot
5b136ecaf0 Merge pull request 'Update nixpkgs-dev in devFlake' (#5675) from update-devFlake-nixpkgs-dev into main 2025-10-27 15:08:23 +00:00
clan-bot
d4733dbb0a Update nixpkgs-dev in devFlake 2025-10-27 15:01:55 +00:00
Johannes Kirschbauer
bfb30251e6 lib: replace uniqueStrings after upstreamed 2025-10-27 14:00:46 +01:00
Johannes Kirschbauer
33115f76b7 services: add role settings with explicit warning 2025-10-27 13:31:44 +01:00
pinpox
9e9208e699 Merge pull request 'yggdrasil: read peers from exports' (#5657) from yggdrasil-export-peers into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5657
2025-10-27 12:13:59 +00:00
hsjobeki
6b3fd57174 Merge pull request 'extraModules: soft deprecation for string extraModules' (#5656) from inline into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5656
2025-10-27 12:12:17 +00:00
clan-bot
3be5237cf6 Merge pull request 'Update nixpkgs-dev in devFlake' (#5674) from update-devFlake-nixpkgs-dev into main 2025-10-26 20:06:09 +00:00
clan-bot
368f80eaae Merge pull request 'Update nix-darwin' (#5665) from update-nix-darwin into main 2025-10-26 20:04:12 +00:00
clan-bot
4d7079534c Update nixpkgs-dev in devFlake 2025-10-26 20:01:51 +00:00
clan-bot
7d4cf1c551 Update nix-darwin 2025-10-26 20:00:59 +00:00
pinpox
ea088b95e9 yggdrasil: read peers from exports 2025-10-26 12:07:52 +01:00
pinpox
a7a37f5320 Update readme 2025-10-26 12:02:17 +01:00
clan-bot
8bda4880a7 Merge pull request 'Update nixpkgs-dev in devFlake' (#5673) from update-devFlake-nixpkgs-dev into main 2025-10-26 10:06:09 +00:00
clan-bot
6eb83618c0 Update nixpkgs-dev in devFlake 2025-10-26 10:01:55 +00:00
pinpox
1fe3833779 Merge pull request 'clanServices/internet: set default for host export' (#5672) from issue-5671 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5672
2025-10-25 20:44:00 +00:00
pinpox
e63f5c966e clanServices/internet: set default for host export 2025-10-25 22:37:17 +02:00
pinpox
69241183ac Merge pull request 'Fix meta.tld option' (#5670) from issue-5669 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5670
2025-10-25 20:18:28 +00:00
pinpox
0a7c65cd27 Fix meta.tld option
The option curretly keeps it default value, even if set. This fixes the
value being passed through correctly, so that the user-specified value
is actually used.

Fixes: #5669
2025-10-25 22:08:44 +02:00
clan-bot
bd13eb3e23 Merge pull request 'Update treefmt-nix' (#5660) from update-treefmt-nix into main 2025-10-25 20:06:14 +00:00
clan-bot
1e5191a16c Update treefmt-nix 2025-10-25 20:01:34 +00:00
clan-bot
1e4bf0dd4e Merge pull request 'Update nixpkgs-dev in devFlake' (#5667) from update-devFlake-nixpkgs-dev into main 2025-10-25 10:07:40 +00:00
clan-bot
4d66dc59aa Update nixpkgs-dev in devFlake 2025-10-25 10:01:59 +00:00
hsjobeki
9a442c15e9 Merge pull request 'docs: add experimental note to 'exports'' (#5662) from exports into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5662
2025-10-24 15:11:27 +00:00
clan-bot
157af90a56 Merge pull request 'Update treefmt-nix in devFlake' (#5661) from update-devFlake-treefmt-nix into main 2025-10-24 15:08:50 +00:00
Johannes Kirschbauer
24b94965d8 docs: add experimental note to 'exports' 2025-10-24 17:05:47 +02:00
clan-bot
46bcad9267 Update treefmt-nix in devFlake 2025-10-24 15:01:55 +00:00
Johannes Kirschbauer
1aba0577dc schemas: filter 'extraModules' from python classes and derived schemas 2025-10-24 16:57:26 +02:00
Luis Hebendanz
383088af2d Merge pull request 'clan_lib/llm: get_llm_turn uses state transitions instead of callback function' (#5659) from Qubasa/clan-core:llm_no_callback2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5659
2025-10-24 14:37:25 +00:00
Qubasa
c3456c1f0c clan_lib/llm: get_llm_turn uses state transitions instead of callback function 2025-10-24 16:31:09 +02:00
lassulus
183de9209f Merge pull request 'clan_lib select: fix maybe select storing miss as {}' (#5655) from select_cache_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5655
2025-10-24 12:51:33 +00:00
hsjobeki
1df5c5ff60 Merge pull request 'clanTest: throw when usage of 'self' is triggered' (#5658) from specialArgs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5658
2025-10-24 12:16:34 +00:00
Johannes Kirschbauer
e55a3b4fc6 clanTest: throw when usage of 'self' is triggered
That means we rely on a certain structure of the user flake
these assumptions cannot be made. Their flake can have any shape and is not controlled by us
2025-10-24 14:10:17 +02:00
Johannes Kirschbauer
6ee4657da3 extraModules: soft deprecation for string extraModules 2025-10-24 12:54:17 +02:00
lassulus
7294d8bcbe clan_lib select: fix maybe select storing miss as {} 2025-10-24 12:46:48 +02:00
hsjobeki
3fec5aa5b3 Merge pull request 'api: services simplify update services; update tests' (#5654) from inline into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5654
2025-10-24 10:41:26 +00:00
Johannes Kirschbauer
63e55b8631 api: services simplify update services; update tests 2025-10-24 12:19:26 +02:00
clan-bot
dd771f8dd9 Merge pull request 'Update nixpkgs-dev in devFlake' (#5653) from update-devFlake-nixpkgs-dev into main 2025-10-24 10:05:38 +00:00
clan-bot
d31a4cc7d8 Update nixpkgs-dev in devFlake 2025-10-24 10:01:53 +00:00
hsjobeki
73d4cf51af Merge pull request 'services: allow inline modules' (#5652) from inline into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5652
2025-10-23 16:48:06 +00:00
Johannes Kirschbauer
d015218226 api: update models 2025-10-23 18:43:07 +02:00
Johannes Kirschbauer
f50475fcfd services: allow inline modules 2025-10-23 18:43:07 +02:00
Johannes Kirschbauer
ae5efd9e2f inventory: fix path filter wrong length 2025-10-23 18:43:07 +02:00
hsjobeki
c2c2874e82 Merge pull request 'modules: move clan docs into clan-module' (#5651) from lib-modules into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5651
2025-10-23 15:57:38 +00:00
Johannes Kirschbauer
1f8c2a3722 modules: move clan docs into clan-module 2025-10-23 17:52:39 +02:00
hgl
50aa7eb0cf Merge pull request 'ui: use storybook-solidjs-vite for storybook' (#5649) from hgl-sb-vite into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5649
2025-10-23 15:11:01 +00:00
clan-bot
920b39a124 Merge pull request 'Update nixpkgs-dev in devFlake' (#5635) from update-devFlake-nixpkgs-dev into main 2025-10-23 15:06:59 +00:00
Glen Huang
c159ef79d2 ui: use storybook-solidjs-vite for storybook 2025-10-23 23:04:09 +08:00
clan-bot
7a95b169c1 Update nixpkgs-dev in devFlake 2025-10-23 15:02:00 +00:00
hsjobeki
0c3fd40120 Merge pull request 'inventory: clean up unused modules and submodule names' (#5638) from lib-modules into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5638
2025-10-23 13:14:37 +00:00
hgl
7268697dc5 Merge pull request 'ui: not using wasm node' (#5642) from hgl-cleanup into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5642
2025-10-23 12:52:26 +00:00
Glen Huang
ec395bada4 ui: not using wasm node
Tested both on arm64 darwin and linux that build can succeed without them
2025-10-23 20:48:59 +08:00
hsjobeki
757552671c Merge pull request 'API: init delete instance' (#5641) from instance-delete into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5641
2025-10-23 12:46:24 +00:00
Johannes Kirschbauer
04b52d5bee inventory: clean up unused modules and submodule names 2025-10-23 14:44:38 +02:00
Johannes Kirschbauer
ffeb8b892a API: init delete instance 2025-10-23 14:40:52 +02:00
hgl
26806b5750 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
2025-10-23 12:39:46 +00:00
Glen Huang
6e70054566 ui: clean up using knip 2025-10-23 20:25:47 +08:00
hsjobeki
93268e8592 Merge pull request 'modules/inventory: use filtered serialization of inventory instead' (#5634) from modules-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5634
2025-10-23 12:14:48 +00:00
Johannes Kirschbauer
a420c6ca25 inventory/tests: fixup test fixture 2025-10-23 13:51:37 +02:00
Johannes Kirschbauer
69fd13a76f clan-core-for-checks: update 2025-10-23 13:31:47 +02:00
Johannes Kirschbauer
ab3f262c22 modules/inventory: use filtered serialization of inventory
Opens up inventory for partially non-serializable parts
2025-10-23 10:37:14 +02:00
130 changed files with 1612 additions and 3092 deletions

View File

@@ -76,7 +76,6 @@ in
cmd = "su - text-user -c 'pytest -s -n0 -m service_runner -p no:cacheprovider -o addopts="" ${cli.passthru.sourceWithTests}/clan_lib/llm'" cmd = "su - text-user -c 'pytest -s -n0 -m service_runner -p no:cacheprovider -o addopts="" ${cli.passthru.sourceWithTests}/clan_lib/llm'"
print("Running tests with command: " + cmd) print("Running tests with command: " + cmd)
# Run tests as text-user (environment variables are set automatically) # Run tests as text-user (environment variables are set automatically)
peer1.succeed(cmd) peer1.succeed(cmd)
''; '';

View File

@@ -16,6 +16,7 @@
options = { options = {
host = lib.mkOption { host = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "";
description = '' description = ''
ip address or hostname (domain) of the machine ip address or hostname (domain) of the machine
''; '';

View File

@@ -39,7 +39,6 @@
... ...
}: }:
let let
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
# Collect searchDomains from all servers in this instance # Collect searchDomains from all servers in this instance
allServerSearchDomains = lib.flatten ( allServerSearchDomains = lib.flatten (
lib.mapAttrsToList (_name: machineConfig: machineConfig.settings.certificate.searchDomains or [ ]) ( lib.mapAttrsToList (_name: machineConfig: machineConfig.settings.certificate.searchDomains or [ ]) (
@@ -47,7 +46,7 @@
) )
); );
# Merge client's searchDomains with all servers' searchDomains # Merge client's searchDomains with all servers' searchDomains
searchDomains = uniqueStrings (settings.certificate.searchDomains ++ allServerSearchDomains); searchDomains = lib.uniqueStrings (settings.certificate.searchDomains ++ allServerSearchDomains);
in in
{ {
clan.core.vars.generators.openssh-ca = lib.mkIf (searchDomains != [ ]) { clan.core.vars.generators.openssh-ca = lib.mkIf (searchDomains != [ ]) {

View File

@@ -1,7 +1,23 @@
🚧🚧🚧 Experimental 🚧🚧🚧
Use at your own risk.
We are still refining its interfaces, instability and breakages are expected.
---
This module sets up [yggdrasil](https://yggdrasil-network.github.io/) across your clan. This module sets up [yggdrasil](https://yggdrasil-network.github.io/) across your clan.
Yggdrasil is designed to be a future-proof and decentralised alternative to Yggdrasil is designed to be a future-proof and decentralised alternative to the
the structured routing protocols commonly used today on the internet. Inside your clan, it will allow you to reach all of your machines. structured routing protocols commonly used today on the internet. Inside your
clan, it will allow you to reach all of your machines.
If you have other services in your inventory which export peers (e.g. the
`internet` or the services) as [service
exports](https://docs.clan.lol/reference/options/clan_service/#exports), they
will be added as yggdrasil peers automatically. This allows using the stable
yggdrasil IPv6 address to refer to other hosts and letting yggdrasil decide on
the best routing based on available connections.
## Example Usage ## Example Usage

View File

@@ -29,12 +29,13 @@
]; ];
}; };
options.peers = lib.mkOption { options.extraPeers = lib.mkOption {
type = lib.types.listOf lib.types.str; type = lib.types.listOf lib.types.str;
default = [ ]; default = [ ];
description = '' description = ''
Static peers to configure for this host. Additional static peers to configure for this host. If you use a
If not set, local peers will be auto-discovered VPN clan service, it will automatically be added as peers to other hosts.
Local peers are also auto-discovered and don't need to be added.
''; '';
example = [ example = [
"tcp://192.168.1.1:6443" "tcp://192.168.1.1:6443"
@@ -45,16 +46,67 @@
}; };
}; };
perInstance = perInstance =
{ settings, ... }: {
settings,
roles,
exports,
...
}:
{ {
nixosModule = nixosModule =
{ {
config, config,
pkgs, pkgs,
lib,
clan-core,
... ...
}: }:
let
mkPeers = ip: [
# "tcp://${ip}:6443"
"quic://${ip}:6443"
"ws://${ip}:6443"
"tls://${ip}:6443"
];
select' = clan-core.inputs.nix-select.lib.select;
# TODO make it nicer @lassulus, @picnoir wants microlens
# Get a list of all exported IPs from all VPN modules
exportedPeerIPs = builtins.foldl' (
acc: e:
if e == { } then
acc
else
acc ++ (lib.flatten (builtins.filter (s: s != "") (lib.attrValues (select' "peers.*.plain" e))))
) [ ] (lib.attrValues (select' "instances.*.networking.?peers.*.host.?plain" exports));
# Construct a list of peers in yggdrasil format
exportedPeers = lib.flatten (map mkPeers exportedPeerIPs);
in
{ {
# Set <yggdrasil ip> <hostname>.<tld> for all hosts.
# Networking modules will then add themselves as peers, so we can
# always use this to resolve a host via the best possible route,
# doing fail-over if needed.
networking.extraHosts = lib.strings.concatStringsSep "\n" (
lib.filter (n: n != "") (
map (
name:
let
ipPath = "${config.clan.core.settings.directory}/vars/per-machine/${name}/yggdrasil/address/value";
in
if builtins.pathExists ipPath then
"${builtins.readFile ipPath} ${name}.${config.clan.core.settings.tld}"
else
""
) (lib.attrNames roles.default.machines)
)
);
clan.core.vars.generators.yggdrasil = { clan.core.vars.generators.yggdrasil = {
files.privateKey = { }; files.privateKey = { };
@@ -99,7 +151,7 @@
settings = { settings = {
PrivateKeyPath = "/key"; PrivateKeyPath = "/key";
IfName = "ygg"; IfName = "ygg";
Peers = settings.peers; Peers = lib.lists.unique (exportedPeers ++ settings.extraPeers);
MulticastInterfaces = [ MulticastInterfaces = [
# Ethernet is preferred over WIFI # Ethernet is preferred over WIFI
{ {

View File

@@ -17,6 +17,13 @@
roles.default.machines.peer1 = { }; roles.default.machines.peer1 = { };
roles.default.machines.peer2 = { }; roles.default.machines.peer2 = { };
}; };
# Peers are set form exports of the internet service
instances."internet" = {
module.name = "internet";
roles.default.machines.peer1.settings.host = "peer1";
roles.default.machines.peer2.settings.host = "peer2";
};
}; };
}; };

View File

@@ -140,9 +140,6 @@
pkgs, pkgs,
... ...
}: }:
let
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
in
{ {
imports = [ imports = [
(import ./shared.nix { (import ./shared.nix {
@@ -159,7 +156,7 @@
config = { config = {
systemd.services.zerotier-inventory-autoaccept = systemd.services.zerotier-inventory-autoaccept =
let let
machines = uniqueStrings ( machines = lib.uniqueStrings (
(lib.optionals (roles ? moon) (lib.attrNames roles.moon.machines)) (lib.optionals (roles ? moon) (lib.attrNames roles.moon.machines))
++ (lib.optionals (roles ? controller) (lib.attrNames roles.controller.machines)) ++ (lib.optionals (roles ? controller) (lib.attrNames roles.controller.machines))
++ (lib.optionals (roles ? peer) (lib.attrNames roles.peer.machines)) ++ (lib.optionals (roles ? peer) (lib.attrNames roles.peer.machines))

18
devFlake/flake.lock generated
View File

@@ -3,10 +3,10 @@
"clan-core-for-checks": { "clan-core-for-checks": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1760361585, "lastModified": 1761204206,
"narHash": "sha256-v4PnSmt1hXW4dSgVWxcd1ZeEBlhO7NksNRC5cX7L5iw=", "narHash": "sha256-A4KDudGblln1yh8c95OVow2NRlHtbGZXr/pgNenyrNc=",
"ref": "main", "ref": "main",
"rev": "7e7e58eb64ef61beb0a938a6622ec0122382131b", "rev": "aabbe0dfac47b7cfbe2210bcb27fb7ecce93350f",
"shallow": true, "shallow": true,
"type": "git", "type": "git",
"url": "https://git.clan.lol/clan/clan-core" "url": "https://git.clan.lol/clan/clan-core"
@@ -105,11 +105,11 @@
}, },
"nixpkgs-dev": { "nixpkgs-dev": {
"locked": { "locked": {
"lastModified": 1761164809, "lastModified": 1761544814,
"narHash": "sha256-3uM91Lx9WZomE6MMEBorJyEyBNiHWRIxza/GganDxew=", "narHash": "sha256-t5f0A+2MtSWTfA6hzMNiotpIMGLlSQF2JnK9m6nkzIY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "3d2db9755e7815937fb7b8f089fad9b44bc416d8", "rev": "e5aa45ed6c45058ec109658b2b7352a9a062cdf3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -208,11 +208,11 @@
"nixpkgs": [] "nixpkgs": []
}, },
"locked": { "locked": {
"lastModified": 1760945191, "lastModified": 1761311587,
"narHash": "sha256-ZRVs8UqikBa4Ki3X4KCnMBtBW0ux1DaT35tgsnB1jM4=", "narHash": "sha256-Msq86cR5SjozQGCnC6H8C+0cD4rnx91BPltZ9KK613Y=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "f56b1934f5f8fcab8deb5d38d42fd692632b47c2", "rev": "2eddae033e4e74bf581c2d1dfa101f9033dbd2dc",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -150,10 +150,61 @@ Those are very similar to NixOS VM tests, as in they run virtualized nixos machi
As of now the container test driver is a downstream development in clan-core. As of now the container test driver is a downstream development in clan-core.
Basically everything stated under the NixOS VM tests sections applies here, except some limitations. Basically everything stated under the NixOS VM tests sections applies here, except some limitations.
Limitations: ### Using Container Tests vs VM Tests
- Cannot run in interactive mode, however while the container test runs, it logs a nsenter command that can be used to log into each of the container. Container tests are **enabled by default** for all tests using the clan testing framework.
- setuid binaries don't work They offer significant performance advantages over VM tests:
- **Faster startup**
- **Lower resource usage**: No full kernel boot or hardware emulation overhead
To control whether a test uses containers or VMs, use the `clan.test.useContainers` option:
```nix
{
clan = {
directory = ./.;
test.useContainers = true; # Use containers (default)
# test.useContainers = false; # Use VMs instead
};
}
```
**When to use VM tests instead of container tests:**
- Testing kernel features, modules, or boot processes
- Testing hardware-specific features
- When you need full system isolation
### System Requirements for Container Tests
Container tests require the **`uid-range`** system feature** in the Nix sandbox.
This feature allows Nix to allocate a range of UIDs for containers to use, enabling `systemd-nspawn` containers to run properly inside the Nix build sandbox.
**Configuration:**
The `uid-range` feature requires the `auto-allocate-uids` setting to be enabled in your Nix configuration.
To verify or enable it, add to your `/etc/nix/nix.conf` or NixOS configuration:
```nix
settings.experimental-features = [
"auto-allocate-uids"
];
nix.settings.auto-allocate-uids = true;
nix.settings.system-features = [ "uid-range" ];
```
**Technical details:**
- Container tests set `requiredSystemFeatures = [ "uid-range" ];` in their derivation (see `lib/test/container-test-driver/driver-module.nix:98`)
- Without this feature, containers cannot properly manage user namespaces and will fail to start
### Limitations
- Cannot run in interactive mode, however while the container test runs, it logs a nsenter command that can be used to log into each of the containers.
- Early implementation and limited by features.
### Where to find examples for NixOS container tests ### Where to find examples for NixOS container tests

12
flake.lock generated
View File

@@ -71,11 +71,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1760721282, "lastModified": 1761339987,
"narHash": "sha256-aAHphQbU9t/b2RRy2Eb8oMv+I08isXv2KUGFAFn7nCo=", "narHash": "sha256-IUaawVwItZKi64IA6kF6wQCLCzpXbk2R46dHn8sHkig=",
"owner": "nix-darwin", "owner": "nix-darwin",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "c3211fcd0c56c11ff110d346d4487b18f7365168", "rev": "7cd9aac79ee2924a85c211d21fafd394b06a38de",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -181,11 +181,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1760945191, "lastModified": 1761311587,
"narHash": "sha256-ZRVs8UqikBa4Ki3X4KCnMBtBW0ux1DaT35tgsnB1jM4=", "narHash": "sha256-Msq86cR5SjozQGCnC6H8C+0cD4rnx91BPltZ9KK613Y=",
"owner": "numtide", "owner": "numtide",
"repo": "treefmt-nix", "repo": "treefmt-nix",
"rev": "f56b1934f5f8fcab8deb5d38d42fd692632b47c2", "rev": "2eddae033e4e74bf581c2d1dfa101f9033dbd2dc",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -137,6 +137,12 @@ in
default = { }; default = { };
type = types.submoduleWith { type = types.submoduleWith {
specialArgs = { specialArgs = {
self = throw ''
'self' is banned in the use of clan.services
Use 'exports' instead: https://docs.clan.lol/reference/options/clan_service/#exports
---
If you really need to used 'self' here, that makes the module less portable
'';
inherit (config.clanSettings) inherit (config.clanSettings)
clan-core clan-core
nixpkgs nixpkgs

View File

@@ -7,14 +7,10 @@
... ...
}: }:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types uniqueStrings;
inherit (types) attrsWith submoduleWith; inherit (types) attrsWith submoduleWith;
errorContext = "Error context: ${lib.concatStringsSep "." _ctx}"; errorContext = "Error context: ${lib.concatStringsSep "." _ctx}";
# TODO:
# Remove once this gets merged upstream; performs in O(n*log(n) instead of O(n^2))
# https://github.com/NixOS/nixpkgs/pull/355616/files
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
/** /**
Merges the role- and machine-settings using the role interface Merges the role- and machine-settings using the role interface
@@ -81,6 +77,7 @@ let
applySettings = applySettings =
instanceName: instance: instanceName: instance:
lib.mapAttrs (roleName: role: { lib.mapAttrs (roleName: role: {
settings = config.instances.${instanceName}.roles.${roleName}.finalSettings.config;
machines = lib.mapAttrs (machineName: _v: { machines = lib.mapAttrs (machineName: _v: {
settings = settings =
config.instances.${instanceName}.roles.${roleName}.machines.${machineName}.finalSettings.config; config.instances.${instanceName}.roles.${roleName}.machines.${machineName}.finalSettings.config;
@@ -158,6 +155,29 @@ in
( (
{ name, ... }@role: { name, ... }@role:
{ {
options.finalSettings = mkOption {
default = evalMachineSettings instance.name role.name null role.config.settings { };
type = types.raw;
description = ''
Final evaluated settings of the curent-machine
This contains the merged and evaluated settings of the role interface,
the role settings and the machine settings.
Type: 'configuration' as returned by 'lib.evalModules'
'';
apply = lib.warn ''
=== WANRING ===
'roles.<roleName>.settings' do not contain machine specific settings.
Prefer `machines.<machineName>.settings` instead. (i.e `perInstance: roles.<roleName>.machines.<machineName>.settings`)
If you have a use-case that requires access to the original role settings without machine overrides.
Contact us via matrix (https://matrix.to/#/#clan:clan.lol) or file an issue: https://git.clan.lol
This feature will be removed in the next release
'';
};
# instances.{instanceName}.roles.{roleName}.machines # instances.{instanceName}.roles.{roleName}.machines
options.machines = mkOption { options.machines = mkOption {
description = '' description = ''
@@ -216,7 +236,7 @@ in
options.extraModules = lib.mkOption { options.extraModules = lib.mkOption {
default = [ ]; default = [ ];
type = types.listOf (types.either types.deferredModule types.str); type = types.listOf types.deferredModule;
}; };
} }
) )
@@ -483,6 +503,9 @@ in
type = types.deferredModule; type = types.deferredModule;
default = { }; default = { };
description = '' description = ''
!!! Danger "Experimental Feature"
This feature is experimental and will change in the future.
export modules defined in 'perInstance' export modules defined in 'perInstance'
mapped to their instance name mapped to their instance name
@@ -611,6 +634,9 @@ in
type = types.deferredModule; type = types.deferredModule;
default = { }; default = { };
description = '' description = ''
!!! Danger "Experimental Feature"
This feature is experimental and will change in the future.
export modules defined in 'perMachine' export modules defined in 'perMachine'
mapped to their machine name mapped to their machine name
@@ -712,6 +738,9 @@ in
exports = mkOption { exports = mkOption {
description = '' description = ''
!!! Danger "Experimental Feature"
This feature is experimental and will change in the future.
This services exports. This services exports.
Gets merged with all other services exports. Gets merged with all other services exports.
@@ -850,7 +879,11 @@ in
instanceRes.nixosModule instanceRes.nixosModule
] ]
++ (map ( ++ (map (
s: if builtins.typeOf s == "string" then "${directory}/${s}" else s s:
if builtins.typeOf s == "string" then
lib.warn "String types for 'extraModules' will be deprecated - ${s}" "${directory}/${s}"
else
lib.setDefaultModuleLocation "via inventory.instances.${instanceName}.roles.${roleName}" s
) instanceCfg.roles.${roleName}.extraModules); ) instanceCfg.roles.${roleName}.extraModules);
}; };
} }

View File

@@ -137,6 +137,7 @@ in
settings = { }; settings = { };
}; };
}; };
settings = { };
}; };
peer = { peer = {
machines = { machines = {
@@ -146,6 +147,9 @@ in
}; };
}; };
}; };
settings = {
timeout = "foo-peer";
};
}; };
}; };
settings = { settings = {

View File

@@ -102,18 +102,23 @@ in
specificRoleSettings = specificRoleSettings =
res.importedModulesEvaluated.self-A.result.allMachines.jon.passthru.instances.instance_foo.roles.peer; res.importedModulesEvaluated.self-A.result.allMachines.jon.passthru.instances.instance_foo.roles.peer;
}; };
expected = rec { expected = {
hasMachineSettings = true; hasMachineSettings = true;
hasRoleSettings = false; hasRoleSettings = true;
specificMachineSettings = { specificMachineSettings = {
timeout = "foo-peer-jon"; timeout = "foo-peer-jon";
}; };
specificRoleSettings = { specificRoleSettings = {
machines = { machines = {
jon = { jon = {
settings = specificMachineSettings; settings = {
timeout = "foo-peer-jon";
};
}; };
}; };
settings = {
timeout = "foo-peer";
};
}; };
}; };
}; };

View File

@@ -1,19 +1,20 @@
{ {
pkgs, pkgs,
lib, lib,
clan-core, clanModule,
clanLib,
}: }:
let let
eval = lib.evalModules { eval = lib.evalModules {
modules = [ modules = [
clan-core.modules.clan.default clanModule
]; ];
}; };
evalDocs = pkgs.nixosOptionsDoc { evalDocs = pkgs.nixosOptionsDoc {
options = eval.options; options = eval.options;
warningsAreErrors = false; warningsAreErrors = false;
transformOptions = clan-core.clanLib.docs.stripStorePathsFromDeclarations; transformOptions = clanLib.docs.stripStorePathsFromDeclarations;
}; };
in in
{ {

View File

@@ -1,4 +1,26 @@
{ self, lib, ... }: { self, lib, ... }:
let
clanModule = lib.modules.importApply ./default.nix { clan-core = self; };
in
{ {
flake.modules.clan.default = lib.modules.importApply ./default.nix { clan-core = self; }; flake.modules.clan.default = clanModule;
perSystem =
{
pkgs,
lib,
...
}:
let
jsonDocs = import ./eval-docs.nix {
inherit
pkgs
lib
clanModule
;
clanLib = self.clanLib;
};
in
{
legacyPackages.clan-options = jsonDocs.optionsJSON;
};
} }

View File

@@ -288,7 +288,7 @@ in
Global information about the clan. Global information about the clan.
''; '';
type = types.deferredModuleWith { type = types.deferredModuleWith {
staticModules = [ ../inventoryClass/meta-interface.nix ]; staticModules = [ ../inventoryClass/meta.nix ];
}; };
default = { }; default = { };
}; };

View File

@@ -222,6 +222,18 @@ in
inventoryClass = inventoryClass =
let let
flakeInputs = config.self.inputs; flakeInputs = config.self.inputs;
# Compute the relative directory path
selfStr = toString config.self;
dirStr = toString directory;
relativeDirectory =
if selfStr == dirStr then
""
else if lib.hasPrefix selfStr dirStr then
lib.removePrefix (selfStr + "/") dirStr
else
# This shouldn't happen in normal usage, but can occur when
# the flake is copied (e.g., in tests). Fall back to empty string.
"";
in in
{ {
_module.args = { _module.args = {
@@ -230,7 +242,12 @@ in
imports = [ imports = [
../inventoryClass/default.nix ../inventoryClass/default.nix
{ {
inherit inventory directory flakeInputs; inherit
inventory
directory
flakeInputs
relativeDirectory
;
exportsModule = config.exportsModule; exportsModule = config.exportsModule;
} }
( (

View File

@@ -1,24 +1,5 @@
{
self,
...
}:
{ {
imports = [ imports = [
./clan/flake-module.nix ./clan/flake-module.nix
]; ];
perSystem =
{
pkgs,
lib,
...
}:
let
jsonDocs = import ./eval-docs.nix {
inherit pkgs lib;
clan-core = self;
};
in
{
legacyPackages.clan-options = jsonDocs.optionsJSON;
};
} }

View File

@@ -40,12 +40,11 @@ let
name: name:
let let
v = set.${name}; v = set.${name};
loc = path ++ [ name ];
in in
if pred path v then if pred loc v then
[ [
(lib.nameValuePair name ( (lib.nameValuePair name (if lib.isAttrs v then filterAttrsRecursive' loc pred v else v))
if lib.isAttrs v then filterAttrsRecursive' (path ++ [ name ]) pred v else v
))
] ]
else else
[ ] [ ]
@@ -56,8 +55,7 @@ let
# Remove extraModules from serialization, # Remove extraModules from serialization,
# identified by: prefix + pathLength + name # identified by: prefix + pathLength + name
# inventory.instances.*.roles.*.extraModules # inventory.instances.*.roles.*.extraModules
path: _value: path: _value: !(lib.length path == 5 && ((lib.last path)) == "extraModules")
lib.length path <= 5 || lib.head path != "instances" || (lib.elemAt path 5) != "extraModules"
) exposedInventory; ) exposedInventory;
in in
{ {
@@ -83,6 +81,14 @@ in
directory = mkOption { directory = mkOption {
type = types.path; type = types.path;
}; };
relativeDirectory = mkOption {
type = types.str;
internal = true;
description = ''
The relative directory path from the flake root to the clan directory.
Empty string if directory equals the flake root.
'';
};
machines = mkOption { machines = mkOption {
type = types.attrsOf (submodule ({ type = types.attrsOf (submodule ({
options = { options = {

View File

@@ -115,7 +115,7 @@ in
meta = lib.mkOption { meta = lib.mkOption {
type = lib.types.submoduleWith { type = lib.types.submoduleWith {
modules = [ modules = [
./meta-interface.nix ./meta.nix
]; ];
}; };
}; };
@@ -359,7 +359,7 @@ in
inherit clanLib; inherit clanLib;
}; };
} }
(import ./roles-interface.nix { }) (import ./role.nix { })
]; ];
} }
); );

View File

@@ -44,12 +44,6 @@ in
description = '' description = ''
List of additionally imported `.nix` expressions. List of additionally imported `.nix` expressions.
Supported types:
- **Strings**: Interpreted relative to the 'directory' passed to `lib.clan`.
- **Paths**: should be relative to the current file.
- **Any**: Nix expression must be serializable to JSON.
!!! Note !!! Note
**The import only happens if the machine is part of the service or role.** **The import only happens if the machine is part of the service or role.**
@@ -73,15 +67,8 @@ in
} }
``` ```
''; '';
apply = value: if lib.isString value then value else builtins.seq (builtins.toJSON value) value;
default = [ ]; default = [ ];
type = types.listOf ( type = types.listOf types.raw;
types.oneOf [
types.str
types.path
(types.attrsOf types.anything)
]
);
}; };
}; };
} }

View File

@@ -1,70 +0,0 @@
{
flakeInputs,
clanLib,
}:
{ lib, config, ... }:
let
inspectModule =
inputName: moduleName: module:
let
eval = clanLib.evalService {
modules = [ module ];
prefix = [
inputName
"clan"
"modules"
moduleName
];
};
in
{
manifest = eval.config.manifest;
roles = lib.mapAttrs (_n: v: { inherit (v) description; }) eval.config.roles;
};
in
{
options.staticModules = lib.mkOption {
readOnly = true;
type = lib.types.raw;
apply = moduleSet: lib.mapAttrs (inspectModule "<clan-core>") moduleSet;
};
options.modulesPerSource = lib.mkOption {
# { sourceName :: { moduleName :: {} }}
readOnly = true;
type = lib.types.raw;
default =
let
inputsWithModules = lib.filterAttrs (_inputName: v: v ? clan.modules) flakeInputs;
in
lib.mapAttrs (
inputName: v: lib.mapAttrs (inspectModule inputName) v.clan.modules
) inputsWithModules;
};
options.moduleSchemas = lib.mkOption {
# { sourceName :: { moduleName :: { roleName :: Schema }}}
readOnly = true;
type = lib.types.raw;
default = lib.mapAttrs (
_inputName: moduleSet:
lib.mapAttrs (
_moduleName: module:
(clanLib.evalService {
modules = [ module ];
prefix = [ ];
}).config.result.api.schema
) moduleSet
) config.modulesPerSource;
};
options.templatesPerSource = lib.mkOption {
# { sourceName :: { moduleName :: {} }}
readOnly = true;
type = lib.types.raw;
default =
let
inputsWithTemplates = lib.filterAttrs (_inputName: v: v ? clan.templates) flakeInputs;
in
lib.mapAttrs (_inputName: v: lib.mapAttrs (_n: t: t) v.clan.templates) inputsWithTemplates;
};
}

View File

@@ -107,8 +107,7 @@ in
readOnly = true; readOnly = true;
}; };
tld = lib.mkOption { tld = lib.mkOption {
default = "clan"; type = types.strMatching "[a-z]+";
type = lib.types.str;
description = '' description = ''
the TLD for the clan the TLD for the clan
''; '';

View File

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

View File

@@ -1,31 +1,20 @@
import { mergeConfig } from "vite"; import type { StorybookConfig } from "storybook-solidjs-vite";
import type { StorybookConfig } from "@kachurun/storybook-solid-vite";
const config: StorybookConfig = { export default {
framework: "@kachurun/storybook-solid-vite", framework: "storybook-solidjs-vite",
stories: ["../src/**/*.mdx", "../src/**/*.stories.tsx"], stories: ["../src/**/*.mdx", "../src/**/*.stories.tsx"],
addons: [ addons: [
"@storybook/addon-links", "@storybook/addon-links",
"@storybook/addon-docs", "@storybook/addon-docs",
"@storybook/addon-a11y", "@storybook/addon-a11y",
{
name: "@storybook/addon-vitest",
options: {
cli: false,
},
},
], ],
async viteFinal(config) {
return mergeConfig(config, {
define: { "process.env": {} },
});
},
core: { core: {
disableTelemetry: true, disableTelemetry: true,
}, },
typescript: { } satisfies StorybookConfig;
reactDocgen: "react-docgen-typescript",
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
// 👇 Default prop filter, which excludes props from node_modules
propFilter: (prop: any) =>
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
},
},
};
export default config;

View File

@@ -1,4 +1,4 @@
import type { Preview } from "@kachurun/storybook-solid-vite"; import type { Preview } from "storybook-solidjs-vite";
import "../src/index.css"; import "../src/index.css";
import "./preview.css"; import "./preview.css";

View File

@@ -1,4 +1,4 @@
import { setProjectAnnotations } from "@kachurun/storybook-solid-vite"; import { setProjectAnnotations } from "storybook-solidjs-vite";
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview"; import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
import * as projectAnnotations from "./preview"; import * as projectAnnotations from "./preview";

View File

@@ -1,19 +1,9 @@
{ {
"ignore": [ "ignore": [
"gtk.webview.js", "gtk.webview.js",
"src/api/clan/client-fetch.ts",
"stylelint.config.js", "stylelint.config.js",
"util.ts",
"src/components/v2/**",
"api/**", "api/**",
"tailwind/**" "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

@@ -12,48 +12,35 @@
"check": "tsc --noEmit --skipLibCheck && eslint ./src --fix", "check": "tsc --noEmit --skipLibCheck && eslint ./src --fix",
"test": "vitest run --project unit --typecheck", "test": "vitest run --project unit --typecheck",
"vite": "vite", "vite": "vite",
"storybook": "storybook",
"knip": "knip --fix", "knip": "knip --fix",
"storybook-dev": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"test-storybook": "vitest run --project storybook", "test-storybook": "vitest run --project storybook",
"test-storybook-update-snapshots": "vitest run --project storybook --update" "test-storybook-update-snapshots": "vitest run --project storybook --update"
}, },
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/plugin-syntax-import-attributes": "^7.27.1",
"@eslint/js": "^9.3.0", "@eslint/js": "^9.3.0",
"@kachurun/storybook-solid-vite": "^9.0.11",
"@linaria/core": "^6.3.0", "@linaria/core": "^6.3.0",
"@sinonjs/fake-timers": "^14.0.0", "@storybook/addon-a11y": "^9.1.13",
"@storybook/addon-a11y": "^9.0.8", "@storybook/addon-docs": "^9.1.13",
"@storybook/addon-docs": "^9.0.8", "@storybook/addon-links": "^9.1.13",
"@storybook/addon-links": "^9.0.8", "@storybook/addon-vitest": "^9.1.13",
"@storybook/addon-viewport": "^9.0.8",
"@storybook/addon-vitest": "^9.0.8",
"@types/node": "^22.15.19", "@types/node": "^22.15.19",
"@types/sinonjs__fake-timers": "^8.1.5",
"@types/three": "^0.176.0", "@types/three": "^0.176.0",
"@typescript-eslint/parser": "^8.32.1",
"@vitest/browser": "^3.2.3", "@vitest/browser": "^3.2.3",
"@vitest/coverage-v8": "^3.2.3",
"@wyw-in-js/vite": "^0.7.0", "@wyw-in-js/vite": "^0.7.0",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"concurrently": "^9.1.2",
"eslint": "^9.27.0", "eslint": "^9.27.0",
"eslint-plugin-tailwindcss": "^3.17.0", "eslint-plugin-tailwindcss": "^3.17.0",
"eslint-plugin-unused-imports": "^4.1.4", "eslint-plugin-unused-imports": "^4.1.4",
"extend": "^3.0.2",
"http-server": "^14.1.1",
"jsdom": "^26.1.0",
"knip": "^5.61.2", "knip": "^5.61.2",
"markdown-to-jsx": "^7.7.10",
"playwright": "1.54.1", "playwright": "1.54.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",
"storybook": "^9.0.8", "storybook": "^9.1.13",
"swagger-ui-dist": "^5.26.2", "storybook-solidjs-vite": "^9.0.3",
"tailwindcss": "^3.4.3", "tailwindcss": "^3.4.3",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"typescript-eslint": "^8.32.1", "typescript-eslint": "^8.32.1",
@@ -62,11 +49,9 @@
"vite-css-modules": "^1.10.0", "vite-css-modules": "^1.10.0",
"vite-plugin-solid": "^2.8.2", "vite-plugin-solid": "^2.8.2",
"vite-plugin-solid-svg": "^0.8.1", "vite-plugin-solid-svg": "^0.8.1",
"vitest": "^3.2.3", "vitest": "^3.2.4"
"wait-on": "^8.0.3"
}, },
"dependencies": { "dependencies": {
"@floating-ui/dom": "^1.6.8",
"@kobalte/core": "^0.13.10", "@kobalte/core": "^0.13.10",
"@kobalte/tailwindcss": "^0.9.0", "@kobalte/tailwindcss": "^0.9.0",
"@modular-forms/solid": "^0.25.1", "@modular-forms/solid": "^0.25.1",
@@ -80,22 +65,6 @@
"solid-js": "^1.9.7", "solid-js": "^1.9.7",
"solid-toast": "^0.5.0", "solid-toast": "^0.5.0",
"three": "^0.176.0", "three": "^0.176.0",
"troika-three-text": "^0.52.4",
"valibot": "^1.1.0" "valibot": "^1.1.0"
},
"optionalDependencies": {
"@esbuild/darwin-arm64": "^0.25.4",
"@esbuild/darwin-x64": "^0.25.4",
"@esbuild/linux-arm64": "^0.25.4",
"@esbuild/linux-x64": "^0.25.4"
},
"overrides": {
"vite": {
"rollup": "npm:@rollup/wasm-node@^4.34.9"
},
"@rollup/rollup-darwin-x64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-linux-x64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-darwin-arm64": "npm:@rollup/wasm-node@^4.34.9",
"@rollup/rollup-linux-arm64": "npm:@rollup/wasm-node@^4.34.9"
} }
} }

View File

@@ -1,7 +1,6 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Alert, AlertProps } from "@/src/components/Alert/Alert"; import { Alert, AlertProps } from "@/src/components/Alert/Alert";
import { expect, fn } from "storybook/test"; import { expect, fn } from "storybook/test";
import { StoryContext } from "@kachurun/storybook-solid-vite";
const AlertExamples = (props: AlertProps) => ( const AlertExamples = (props: AlertProps) => (
<div class="grid w-fit grid-cols-2 gap-8"> <div class="grid w-fit grid-cols-2 gap-8">
@@ -20,14 +19,14 @@ const AlertExamples = (props: AlertProps) => (
</div> </div>
); );
const meta: Meta<AlertProps> = { const meta: Meta<typeof AlertExamples> = {
title: "Components/Alert", title: "Components/Alert",
component: AlertExamples, component: AlertExamples,
}; };
export default meta; export default meta;
type Story = StoryObj<AlertProps>; type Story = StoryObj<typeof meta>;
export const Info: Story = { export const Info: Story = {
args: { args: {
@@ -92,10 +91,13 @@ export const InfoDismiss: Story = {
args: { args: {
...Info.args, ...Info.args,
onDismiss: fn(), onDismiss: fn(),
play: async ({ canvas, step, userEvent, args }: StoryContext) => { },
await userEvent.click(canvas.getByRole("button")); render(args) {
await expect(args.onDismiss).toHaveBeenCalled(); return <Alert {...args} />;
}, },
play: async ({ canvas, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button"));
await expect(args.onDismiss).toHaveBeenCalled();
}, },
}; };

View File

@@ -1,8 +1,7 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Button, ButtonProps } from "./Button"; import { Button, ButtonProps } from "./Button";
import { Component } from "solid-js"; import { Component } from "solid-js";
import { expect, fn, within } from "storybook/test"; import { expect, fn, within } from "storybook/test";
import { StoryContext } from "@kachurun/storybook-solid-vite";
const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor; const getCursorStyle = (el: Element) => window.getComputedStyle(el).cursor;
@@ -202,7 +201,7 @@ const ButtonExamples: Component<ButtonProps> = (props) => (
</> </>
); );
const meta: Meta<ButtonProps> = { const meta: Meta<typeof ButtonExamples> = {
title: "Components/Button", title: "Components/Button",
component: ButtonExamples, component: ButtonExamples,
}; };
@@ -211,15 +210,13 @@ export default meta;
type Story = StoryObj<ButtonProps>; type Story = StoryObj<ButtonProps>;
const timeout = process.env.NODE_ENV === "test" ? 500 : 2000;
export const Primary: Story = { export const Primary: Story = {
args: { args: {
hierarchy: "primary", hierarchy: "primary",
onClick: fn(), onClick: fn(),
}, },
play: async ({ canvasElement, step, userEvent, args }: StoryContext) => { play: async ({ canvasElement, step, userEvent, args }) => {
const canvas = within(canvasElement); const canvas = within(canvasElement);
const buttons = await canvas.findAllByRole("button"); const buttons = await canvas.findAllByRole("button");
@@ -264,7 +261,7 @@ export const GhostPrimary: Story = {
}, },
play: Primary.play, play: Primary.play,
decorators: [ decorators: [
(Story: StoryObj) => ( (Story) => (
<div class="p-10 bg-def-3"> <div class="p-10 bg-def-3">
<Story /> <Story />
</div> </div>

View File

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

View File

@@ -1,7 +1,7 @@
import { CubeConstruction } from "./CubeConstruction"; import { CubeConstruction } from "./CubeConstruction";
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
const meta: Meta = { const meta: Meta<typeof CubeConstruction> = {
title: "Components/CubeConstruction", title: "Components/CubeConstruction",
component: CubeConstruction, component: CubeConstruction,
globals: { globals: {
@@ -12,7 +12,7 @@ const meta: Meta = {
export default meta; export default meta;
type Story = StoryObj; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: {}, args: {},

View File

@@ -1,14 +1,14 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Divider, DividerProps } from "@/src/components/Divider/Divider"; import { Divider } from "@/src/components/Divider/Divider";
const meta: Meta<DividerProps> = { const meta: Meta<typeof Divider> = {
title: "Components/Divider", title: "Components/Divider",
component: Divider, component: Divider,
}; };
export default meta; export default meta;
type Story = StoryObj<DividerProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = {}; export const Default: Story = {};
@@ -30,7 +30,7 @@ export const Vertical: Story = {
orientation: "vertical", orientation: "vertical",
}, },
decorators: [ decorators: [
(Story: Story) => ( (Story) => (
<div class="h-32 w-full"> <div class="h-32 w-full">
<Story /> <Story />
</div> </div>
@@ -43,5 +43,5 @@ export const VerticalInverted: Story = {
inverted: true, inverted: true,
...Vertical.args, ...Vertical.args,
}, },
decorators: [...Vertical.decorators], decorators: Vertical.decorators,
}; };

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import cx from "classnames"; import cx from "classnames";
import { Checkbox, CheckboxProps } from "@/src/components/Form/Checkbox"; import { Checkbox, CheckboxProps } from "@/src/components/Form/Checkbox";
@@ -23,17 +23,17 @@ const Examples = (props: CheckboxProps) => (
</div> </div>
); );
const meta = { const meta: Meta<typeof Examples> = {
title: "Components/Form/Checkbox", title: "Components/Form/Checkbox",
component: Examples, component: Examples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<CheckboxProps>) => { (Story, { args }) => {
return ( return (
<div <div
class={cx({ class={cx({
"w-[600px]": (context.args.orientation || "vertical") == "vertical", "w-[600px]": (args.orientation || "vertical") == "vertical",
"w-[1024px]": context.args.orientation == "horizontal", "w-[1024px]": args.orientation == "horizontal",
"bg-inv-acc-3": context.args.inverted, "bg-inv-acc-3": args.inverted,
})} })}
> >
<Story /> <Story />
@@ -41,7 +41,7 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<CheckboxProps>; };
export default meta; export default meta;

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { import {
Fieldset, Fieldset,
FieldsetFieldProps, FieldsetFieldProps,
@@ -18,17 +18,17 @@ const FieldsetExamples = (props: FieldsetProps) => (
</div> </div>
); );
const meta = { const meta: Meta<typeof FieldsetExamples> = {
title: "Components/Form/Fieldset", title: "Components/Form/Fieldset",
component: FieldsetExamples, component: FieldsetExamples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<FieldsetProps>) => { (Story, { args }) => {
return ( return (
<div <div
class={cx({ class={cx({
"w-[600px]": (context.args.orientation || "vertical") == "vertical", "w-[600px]": (args.orientation || "vertical") == "vertical",
"w-[512px]": context.args.orientation == "horizontal", "w-[512px]": args.orientation == "horizontal",
"bg-inv-acc-3": context.args.inverted, "bg-inv-acc-3": args.inverted,
})} })}
> >
<Story /> <Story />
@@ -36,7 +36,7 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<FieldsetProps>; };
export default meta; export default meta;

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import cx from "classnames"; import cx from "classnames";
import { import {
HostFileInput, HostFileInput,
@@ -31,17 +31,17 @@ const Examples = (props: HostFileInputProps) => (
</div> </div>
); );
const meta = { const meta: Meta<typeof Examples> = {
title: "Components/Form/HostFileInput", title: "Components/Form/HostFileInput",
component: Examples, component: Examples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<HostFileInputProps>) => { (Story, { args }) => {
return ( return (
<div <div
class={cx({ class={cx({
"w-[600px]": (context.args.orientation || "vertical") == "vertical", "w-[600px]": (args.orientation || "vertical") == "vertical",
"w-[1024px]": context.args.orientation == "horizontal", "w-[1024px]": args.orientation == "horizontal",
"bg-inv-acc-3": context.args.inverted, "bg-inv-acc-3": args.inverted,
})} })}
> >
<Story /> <Story />
@@ -49,7 +49,7 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<HostFileInputProps>; };
export default meta; export default meta;

View File

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

View File

@@ -1,12 +1,12 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { MachineTags, MachineTagsProps } from "./MachineTags"; import { MachineTags } from "./MachineTags";
import { createForm, setValue } from "@modular-forms/solid"; import { createForm, setValue } from "@modular-forms/solid";
import { Button } from "../Button/Button"; import { Button } from "../Button/Button";
const meta = { const meta: Meta<typeof MachineTags> = {
title: "Components/MachineTags", title: "Components/MachineTags",
component: MachineTags, component: MachineTags,
} satisfies Meta<MachineTagsProps>; };
export default meta; export default meta;

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import cx from "classnames"; import cx from "classnames";
import { TextArea, TextAreaProps } from "./TextArea"; import { TextArea, TextAreaProps } from "./TextArea";
@@ -23,17 +23,17 @@ const Examples = (props: TextAreaProps) => (
</div> </div>
); );
const meta = { const meta: Meta<typeof Examples> = {
title: "Components/Form/TextArea", title: "Components/Form/TextArea",
component: Examples, component: Examples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<TextAreaProps>) => { (Story, { args }) => {
return ( return (
<div <div
class={cx({ class={cx({
"w-[600px]": (context.args.orientation || "vertical") == "vertical", "w-[600px]": (args.orientation || "vertical") == "vertical",
"w-[1024px]": context.args.orientation == "horizontal", "w-[1024px]": args.orientation == "horizontal",
"bg-inv-acc-3": context.args.inverted, "bg-inv-acc-3": args.inverted,
})} })}
> >
<Story /> <Story />
@@ -41,7 +41,7 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<TextAreaProps>; };
export default meta; export default meta;

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import cx from "classnames"; import cx from "classnames";
import { TextInput, TextInputProps } from "@/src/components/Form/TextInput"; import { TextInput, TextInputProps } from "@/src/components/Form/TextInput";
import Icon from "../Icon/Icon"; import Icon from "../Icon/Icon";
@@ -25,17 +25,17 @@ const Examples = (props: TextInputProps) => (
</div> </div>
); );
const meta = { const meta: Meta<typeof Examples> = {
title: "Components/Form/TextInput", title: "Components/Form/TextInput",
component: Examples, component: Examples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<TextInputProps>) => { (Story, { args }) => {
return ( return (
<div <div
class={cx({ class={cx({
"w-[600px]": (context.args.orientation || "vertical") == "vertical", "w-[600px]": (args.orientation || "vertical") == "vertical",
"w-[1024px]": context.args.orientation == "horizontal", "w-[1024px]": args.orientation == "horizontal",
"bg-inv-acc-3": context.args.inverted, "bg-inv-acc-3": args.inverted,
})} })}
> >
<Story /> <Story />
@@ -43,7 +43,7 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<TextInputProps>; };
export default meta; export default meta;

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryObj, StoryContext } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Component, For } from "solid-js"; import { Component, For } from "solid-js";
import Icon, { IconProps, IconVariant } from "./Icon"; import Icon, { IconProps, IconVariant } from "./Icon";
import cx from "classnames"; import cx from "classnames";
@@ -57,12 +57,12 @@ const IconExamples: Component<IconProps> = (props) => (
</div> </div>
); );
const meta: Meta<IconProps> = { const meta: Meta<typeof IconExamples> = {
title: "Components/Icon", title: "Components/Icon",
component: IconExamples, component: IconExamples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<IconProps>) => ( (Story, { args }) => (
<div class={cx(context.args.inverted || false ? "bg-inv-acc-3" : "")}> <div class={cx(args.inverted || false ? "bg-inv-acc-3" : "")}>
<Story /> <Story />
</div> </div>
), ),
@@ -71,7 +71,7 @@ const meta: Meta<IconProps> = {
export default meta; export default meta;
type Story = StoryObj<IconProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = {}; export const Default: Story = {};

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Loader, LoaderProps } from "@/src/components/Loader/Loader"; import { Loader, LoaderProps } from "@/src/components/Loader/Loader";
const LoaderExamples = (props: LoaderProps) => ( const LoaderExamples = (props: LoaderProps) => (
@@ -9,14 +9,14 @@ const LoaderExamples = (props: LoaderProps) => (
</div> </div>
); );
const meta: Meta<LoaderProps> = { const meta: Meta<typeof LoaderExamples> = {
title: "Components/Loader", title: "Components/Loader",
component: LoaderExamples, component: LoaderExamples,
}; };
export default meta; export default meta;
type Story = StoryObj<LoaderProps>; type Story = StoryObj<typeof meta>;
export const Primary: Story = { export const Primary: Story = {
args: { args: {

View File

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

View File

@@ -1,11 +1,11 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { LoadingBar } from "./LoadingBar"; import { LoadingBar } from "./LoadingBar";
const meta: Meta = { const meta: Meta<typeof LoadingBar> = {
title: "Components/LoadingBar", title: "Components/LoadingBar",
component: LoadingBar, component: LoadingBar,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<unknown>) => { (Story) => {
return ( return (
<div class={"flex w-fit items-center justify-center bg-slate-500 p-10"}> <div class={"flex w-fit items-center justify-center bg-slate-500 p-10"}>
<Story /> <Story />
@@ -17,6 +17,6 @@ const meta: Meta = {
export default meta; export default meta;
type Story = StoryObj; type Story = StoryObj<typeof meta>;
export const Default: Story = {}; export const Default: Story = {};

View File

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

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Component, For } from "solid-js"; import { Component, For } from "solid-js";
import { Logo, LogoProps, LogoVariant } from "./Logo"; import { Logo, LogoProps, LogoVariant } from "./Logo";
import cx from "classnames"; import cx from "classnames";
@@ -11,12 +11,12 @@ const LogoExamples: Component<LogoProps> = (props) => (
</div> </div>
); );
const meta: Meta<LogoProps> = { const meta: Meta<typeof LogoExamples> = {
title: "Components/Logo", title: "Components/Logo",
component: LogoExamples, component: LogoExamples,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<LogoProps>) => ( (Story, { args }) => (
<div class={cx(context.args.inverted || false ? "bg-inv-acc-3" : "")}> <div class={cx(args.inverted || false ? "bg-inv-acc-3" : "")}>
<Story /> <Story />
</div> </div>
), ),
@@ -25,7 +25,7 @@ const meta: Meta<LogoProps> = {
export default meta; export default meta;
type Story = StoryObj<LogoProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = {}; export const Default: Story = {};

View File

@@ -1,14 +1,11 @@
import { import { MachineStatus } from "@/src/components/MachineStatus/MachineStatus";
MachineStatus, import { Meta, StoryObj } from "storybook-solidjs-vite";
MachineStatusProps,
} from "@/src/components/MachineStatus/MachineStatus";
import { Meta, StoryObj } from "@kachurun/storybook-solid";
const meta: Meta<MachineStatusProps> = { const meta: Meta<typeof MachineStatus> = {
title: "Components/MachineStatus", title: "Components/MachineStatus",
component: MachineStatus, component: MachineStatus,
decorators: [ decorators: [
(Story: StoryObj) => ( (Story) => (
<div class="p-5 bg-inv-1"> <div class="p-5 bg-inv-1">
<Story /> <Story />
</div> </div>
@@ -18,7 +15,7 @@ const meta: Meta<MachineStatusProps> = {
export default meta; export default meta;
type Story = StoryObj<MachineStatusProps>; type Story = StoryObj<typeof meta>;
export const Loading: Story = { export const Loading: Story = {
args: {}, args: {},

View File

@@ -1,17 +1,16 @@
import { TagProps } from "@/src/components/Tag/Tag"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Meta, StoryObj } from "@kachurun/storybook-solid";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import { Modal, ModalProps } from "@/src/components/Modal/Modal"; import { Modal } from "@/src/components/Modal/Modal";
import { Fieldset, FieldsetFieldProps } from "@/src/components/Form/Fieldset"; import { Fieldset, FieldsetFieldProps } from "@/src/components/Form/Fieldset";
import { TextInput } from "@/src/components/Form/TextInput"; import { TextInput } from "@/src/components/Form/TextInput";
import { TextArea } from "@/src/components/Form/TextArea"; import { TextArea } from "@/src/components/Form/TextArea";
import { Checkbox } from "@/src/components/Form/Checkbox"; import { Checkbox } from "@/src/components/Form/Checkbox";
import { Button } from "../Button/Button"; import { Button } from "../Button/Button";
const meta: Meta<ModalProps> = { const meta: Meta<typeof Modal> = {
title: "Components/Modal", title: "Components/Modal",
component: Modal, component: Modal,
render: (args: ModalProps) => ( render: (args) => (
<Modal <Modal
{...args} {...args}
children={ children={
@@ -68,7 +67,7 @@ const meta: Meta<ModalProps> = {
export default meta; export default meta;
type Story = StoryObj<TagProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

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

View File

@@ -1,14 +1,11 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { import { NavSection } from "@/src/components/NavSection/NavSection";
NavSection,
NavSectionProps,
} from "@/src/components/NavSection/NavSection";
const meta: Meta<NavSectionProps> = { const meta: Meta<typeof NavSection> = {
title: "Components/NavSection", title: "Components/NavSection",
component: NavSection, component: NavSection,
decorators: [ decorators: [
(Story: StoryObj) => ( (Story) => (
<div class="w-96"> <div class="w-96">
<Story /> <Story />
</div> </div>
@@ -18,7 +15,7 @@ const meta: Meta<NavSectionProps> = {
export default meta; export default meta;
type Story = StoryObj<NavSectionProps>; type Story = StoryObj<typeof NavSection>;
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

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

View File

@@ -1,24 +1,20 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Search, SearchProps } from "./Search"; import { Search } from "./Search";
import Icon from "../Icon/Icon"; import Icon from "../Icon/Icon";
import { Combobox } from "@kobalte/core/combobox"; import { Combobox } from "@kobalte/core/combobox";
import { Typography } from "../Typography/Typography"; import { Typography } from "../Typography/Typography";
import { import { ItemRenderOptions, SearchMultiple } from "./MultipleSearch";
ItemRenderOptions,
SearchMultiple,
SearchMultipleProps,
} from "./MultipleSearch";
import { Show } from "solid-js"; import { Show } from "solid-js";
const meta = { const meta: Meta<typeof Search> = {
title: "Components/Search", title: "Components/Search",
component: Search, component: Search,
} satisfies Meta<SearchProps<unknown>>; };
export default meta; export default meta;
type Story = StoryObj<SearchProps<unknown>>; type Story = StoryObj<typeof meta>;
// To test the virtualizer, we can generate a list of modules // To test the virtualizer, we can generate a list of modules
function generateModules(count: number): Module[] { function generateModules(count: number): Module[] {
@@ -107,7 +103,7 @@ export const Default: Story = {
); );
}, },
}, },
render: (args: SearchProps<Module>) => { render: (args) => {
return ( return (
<div class="fixed bottom-10 left-1/2 mb-2 w-[30rem] -translate-x-1/2"> <div class="fixed bottom-10 left-1/2 mb-2 w-[30rem] -translate-x-1/2">
<Search<Module> <Search<Module>
@@ -130,7 +126,7 @@ export const Loading: Story = {
options: [], options: [],
renderItem: () => <span></span>, renderItem: () => <span></span>,
}, },
render: (args: SearchProps<Module>) => { render: (args) => {
return ( return (
<div class="absolute bottom-1/3 w-3/4 px-3"> <div class="absolute bottom-1/3 w-3/4 px-3">
<Search<Module> <Search<Module>
@@ -235,7 +231,7 @@ export const Multiple: Story = {
); );
}, },
}, },
render: (args: SearchMultipleProps<MachineOrTag>) => { render: (args) => {
return ( return (
<div class="absolute bottom-1/3 w-3/4 px-3"> <div class="absolute bottom-1/3 w-3/4 px-3">
<SearchMultiple<MachineOrTag> <SearchMultiple<MachineOrTag>

View File

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

View File

@@ -1,14 +1,14 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { TagSelect, TagSelectProps } from "./TagSelect"; import { TagSelect } from "./TagSelect";
import { Tag } from "../Tag/Tag"; import { Tag } from "../Tag/Tag";
import Icon from "../Icon/Icon"; import Icon from "../Icon/Icon";
import { createSignal } from "solid-js"; import { createSignal } from "solid-js";
const meta = { const meta: Meta<typeof TagSelect> = {
title: "Components/Custom/SelectStepper", title: "Components/Custom/SelectStepper",
component: TagSelect, component: TagSelect,
} satisfies Meta<TagSelectProps<string>>; };
export default meta; export default meta;
@@ -17,7 +17,7 @@ interface Item {
label: string; label: string;
} }
type Story = StoryObj<TagSelectProps<Item>>; type Story = StoryObj<typeof meta>;
const Item = (item: Item) => ( const Item = (item: Item) => (
<Tag <Tag
@@ -42,8 +42,8 @@ export const Default: Story = {
{ value: "corge", label: "Corge" }, { value: "corge", label: "Corge" },
{ value: "grault", label: "Grault" }, { value: "grault", label: "Grault" },
], ],
} satisfies Partial<TagSelectProps<Item>>, },
render: (args: TagSelectProps<Item>) => { render: (args) => {
const [state, setState] = createSignal<Item[]>([]); const [state, setState] = createSignal<Item[]>([]);
return ( return (
<TagSelect<Item> <TagSelect<Item>

View File

@@ -1,18 +1,13 @@
import { TagProps } from "@/src/components/Tag/Tag"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid";
import { Select, SelectProps } from "./Select"; import { Select } from "./Select";
import { Fieldset } from "../Form/Fieldset"; import { Fieldset } from "../Form/Fieldset";
// const meta: Meta<SelectProps> = { const meta: Meta<typeof Select> = {
// title: "Components/Select",
// component: Select,
// };
const meta = {
title: "Components/Form/Select", title: "Components/Form/Select",
component: Select, component: Select,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext<SelectProps>) => { (Story) => {
return ( return (
<div class={`w-[600px]`}> <div class={`w-[600px]`}>
<Fieldset> <Fieldset>
@@ -22,11 +17,11 @@ const meta = {
); );
}, },
], ],
} satisfies Meta<SelectProps>; };
export default meta; export default meta;
type Story = StoryObj<TagProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

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

View File

@@ -1,10 +1,5 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { import { createMemoryHistory, MemoryRouter, Route } from "@solidjs/router";
createMemoryHistory,
MemoryRouter,
Route,
RouteSectionProps,
} from "@solidjs/router";
import { Sidebar } from "@/src/components/Sidebar/Sidebar"; import { Sidebar } from "@/src/components/Sidebar/Sidebar";
import { Suspense } from "solid-js"; import { Suspense } from "solid-js";
import { addClanURI, resetStore } from "@/src/stores/clan"; import { addClanURI, resetStore } from "@/src/stores/clan";
@@ -106,7 +101,7 @@ const staticSections = [
}, },
]; ];
const meta: Meta<RouteSectionProps> = { const meta: Meta<typeof Sidebar> = {
title: "Components/Sidebar", title: "Components/Sidebar",
component: Sidebar, component: Sidebar,
render: () => { render: () => {
@@ -144,7 +139,7 @@ const meta: Meta<RouteSectionProps> = {
export default meta; export default meta;
type Story = StoryObj<RouteSectionProps>; type Story = StoryObj<typeof meta>;
const mockFetcher = <K extends OperationNames>( const mockFetcher = <K extends OperationNames>(
method: K, method: K,

View File

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

View File

@@ -1,8 +1,5 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { import { SidebarPane } from "@/src/components/Sidebar/SidebarPane";
SidebarPane,
SidebarPaneProps,
} from "@/src/components/Sidebar/SidebarPane";
import { SidebarSection } from "./SidebarSection"; import { SidebarSection } from "./SidebarSection";
import { Divider } from "@/src/components/Divider/Divider"; import { Divider } from "@/src/components/Divider/Divider";
import { TextInput } from "@/src/components/Form/TextInput"; import { TextInput } from "@/src/components/Form/TextInput";
@@ -14,9 +11,6 @@ import { splitProps } from "solid-js";
import { Typography } from "@/src/components/Typography/Typography"; import { Typography } from "@/src/components/Typography/Typography";
import { MachineTags } from "@/src/components/Form/MachineTags"; import { MachineTags } from "@/src/components/Form/MachineTags";
import { setValue } from "@modular-forms/solid"; import { setValue } from "@modular-forms/solid";
import { StoryContext } from "@kachurun/storybook-solid-vite";
type Story = StoryObj<SidebarPaneProps>;
const profiles = { const profiles = {
ron: { ron: {
@@ -28,18 +22,13 @@ const profiles = {
}, },
}; };
const meta: Meta<SidebarPaneProps> = { const meta: Meta<typeof SidebarPane> = {
title: "Components/SidebarPane", title: "Components/SidebarPane",
component: SidebarPane, component: SidebarPane,
decorators: [
(
Story: StoryObj<SidebarPaneProps>,
context: StoryContext<SidebarPaneProps>,
) =>
() => <Story {...context.args} />,
],
}; };
type Story = StoryObj<typeof meta>;
export default meta; export default meta;
export const Default: Story = { export const Default: Story = {
@@ -51,7 +40,7 @@ export const Default: Story = {
}, },
// We have to provide children within a custom render function to ensure we aren't creating any reactivity outside the // We have to provide children within a custom render function to ensure we aren't creating any reactivity outside the
// solid-js scope. // solid-js scope.
render: (args: SidebarPaneProps) => ( render: (args) => (
<SidebarPane <SidebarPane
{...args} {...args}
children={ children={

View File

@@ -2,7 +2,7 @@ import { JSX, Show } from "solid-js";
import styles from "./SidebarSection.module.css"; import styles from "./SidebarSection.module.css";
import { Typography } from "@/src/components/Typography/Typography"; import { Typography } from "@/src/components/Typography/Typography";
export interface SidebarSectionProps { interface SidebarSectionProps {
title: string; title: string;
controls?: JSX.Element; controls?: JSX.Element;
children: 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 { Loader } from "../../components/Loader/Loader";
import { SidebarSection } from "./SidebarSection"; import { SidebarSection } from "./SidebarSection";
export interface SidebarSectionFormProps<FormValues extends FieldValues> { interface SidebarSectionFormProps<FormValues extends FieldValues> {
title: string; title: string;
schema: GenericSchema<FormValues> | GenericSchemaAsync<FormValues>; schema: GenericSchema<FormValues> | GenericSchemaAsync<FormValues>;
initialValues: PartialValues<FormValues>; initialValues: PartialValues<FormValues>;

View File

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

View File

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

View File

@@ -1,16 +1,16 @@
import { Tag, TagProps } from "@/src/components/Tag/Tag"; import { Tag } from "@/src/components/Tag/Tag";
import { Meta, type StoryContext, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import Icon from "../Icon/Icon"; import Icon from "../Icon/Icon";
const meta: Meta<TagProps> = { const meta: Meta<typeof Tag> = {
title: "Components/Tag", title: "Components/Tag",
component: Tag, component: Tag,
}; };
export default meta; export default meta;
type Story = StoryObj<TagProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: { args: {
@@ -43,7 +43,7 @@ export const WithAction: Story = {
icon: IconAction, icon: IconAction,
interactive: true, interactive: true,
}, },
play: async ({ canvas, step, userEvent, args }: StoryContext) => { play: async ({ canvas, step, userEvent, args }) => {
await userEvent.click(canvas.getByRole("button")); await userEvent.click(canvas.getByRole("button"));
// await expect(args.icon.onClick).toHaveBeenCalled(); // await expect(args.icon.onClick).toHaveBeenCalled();
}, },

View File

@@ -1,11 +1,11 @@
import { TagGroup, TagGroupProps } from "@/src/components/TagGroup/TagGroup"; import { TagGroup } from "@/src/components/TagGroup/TagGroup";
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
const meta: Meta<TagGroupProps> = { const meta: Meta<typeof TagGroup> = {
title: "Components/TagGroup", title: "Components/TagGroup",
component: TagGroup, component: TagGroup,
decorators: [ decorators: [
(Story: StoryObj) => ( (Story) => (
/* for some reason w-x from tailwind was not working */ /* for some reason w-x from tailwind was not working */
<div style="width: 196px"> <div style="width: 196px">
<Story /> <Story />
@@ -16,7 +16,7 @@ const meta: Meta<TagGroupProps> = {
export default meta; export default meta;
type Story = StoryObj<TagGroupProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

@@ -1,19 +1,18 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Toolbar, ToolbarProps } from "@/src/components/Toolbar/Toolbar"; import { Toolbar } from "@/src/components/Toolbar/Toolbar";
import { ToolbarButton } from "./ToolbarButton"; import { ToolbarButton } from "./ToolbarButton";
const meta: Meta<ToolbarProps> = { const meta: Meta<typeof Toolbar> = {
title: "Components/Toolbar", title: "Components/Toolbar",
component: Toolbar, component: Toolbar,
}; };
export default meta; export default meta;
type Story = StoryObj<ToolbarProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
// We have to specify children inside a render function to avoid issues with reactivity outside a solid-js context. // We have to specify children inside a render function to avoid issues with reactivity outside a solid-js context.
// @ts-expect-error: args in storybook is not typed correctly. This is a storybook issue.
render: (args) => ( render: (args) => (
<div class="flex h-[80vh]"> <div class="flex h-[80vh]">
<div class="mt-auto"> <div class="mt-auto">

View File

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

View File

@@ -1,18 +1,18 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Tooltip, TooltipProps } from "@/src/components/Tooltip/Tooltip"; import { Tooltip } from "@/src/components/Tooltip/Tooltip";
import { Typography } from "@/src/components/Typography/Typography"; import { Typography } from "@/src/components/Typography/Typography";
const meta: Meta<TooltipProps> = { const meta: Meta<typeof Tooltip> = {
title: "Components/Tooltip", title: "Components/Tooltip",
component: Tooltip, component: Tooltip,
decorators: [ decorators: [
(Story: StoryObj<TooltipProps>) => ( (Story) => (
<div class="p-16"> <div class="p-16">
<Story /> <Story />
</div> </div>
), ),
], ],
render: (args: TooltipProps) => ( render: (args) => (
<div class="p-16"> <div class="p-16">
<Tooltip <Tooltip
{...args} {...args}
@@ -33,7 +33,7 @@ const meta: Meta<TooltipProps> = {
export default meta; export default meta;
type Story = StoryObj<TooltipProps>; type Story = StoryObj<typeof meta>;
export const Default: Story = { export const Default: Story = {
args: { args: {

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { Family, Hierarchy, Typography, Weight } from "./Typography"; import { Family, Hierarchy, Typography, Weight } from "./Typography";
import { Component, For, Show } from "solid-js"; import { Component, For, Show } from "solid-js";
@@ -73,14 +73,14 @@ const TypographyExamples: Component<TypographyExamplesProps> = (props) => (
</table> </table>
); );
const meta: Meta<TypographyExamplesProps> = { const meta: Meta<typeof TypographyExamples> = {
title: "Components/Typography", title: "Components/Typography",
component: TypographyExamples, component: TypographyExamples,
}; };
export default meta; export default meta;
type Story = StoryObj<TypographyExamplesProps>; type Story = StoryObj<typeof meta>;
export const BodyCondensed: Story = { export const BodyCondensed: Story = {
args: { args: {

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ import { addClanURI, setActiveClanURI } from "@/src/stores/clan";
import { Params, Navigator, useParams, useSearchParams } from "@solidjs/router"; import { Params, Navigator, useParams, useSearchParams } from "@solidjs/router";
export const encodeBase64 = (value: string) => window.btoa(value); 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 () => { export const selectClanFolder = async () => {
const req = callApi("get_clan_folder", {}); const req = callApi("get_clan_folder", {});
@@ -80,7 +80,7 @@ export const navigateToClan = (navigate: Navigator, clanURI: string) => {
export const navigateToOnboarding = (navigate: Navigator, addClan: boolean) => export const navigateToOnboarding = (navigate: Navigator, addClan: boolean) =>
navigate(`/${addClan ? "?addClan=true" : ""}`); navigate(`/${addClan ? "?addClan=true" : ""}`);
export const navigateToMachine = ( const navigateToMachine = (
navigate: Navigator, navigate: Navigator,
clanURI: string, clanURI: string,
name: string, name: string,
@@ -90,7 +90,7 @@ export const navigateToMachine = (
navigate(path); navigate(path);
}; };
export const clanURIParam = (params: Params) => { const clanURIParam = (params: Params) => {
try { try {
return decodeBase64(params.clanURI); return decodeBase64(params.clanURI);
} catch (e) { } catch (e) {
@@ -101,19 +101,19 @@ export const clanURIParam = (params: Params) => {
export const useClanURI = () => clanURIParam(useParams()); export const useClanURI = () => clanURIParam(useParams());
export const machineNameParam = (params: Params) => { const machineNameParam = (params: Params) => {
return params.machineName; return params.machineName;
}; };
export const inputParam = (params: Params) => params.input; const inputParam = (params: Params) => params.input;
export const nameParam = (params: Params) => params.name; const nameParam = (params: Params) => params.name;
export const idParam = (params: Params) => params.id; const idParam = (params: Params) => params.id;
export const useMachineName = (): string => machineNameParam(useParams()); export const useMachineName = (): string => machineNameParam(useParams());
export const useInputParam = (): string => inputParam(useParams()); const useInputParam = (): string => inputParam(useParams());
export const useNameParam = (): string => nameParam(useParams()); const useNameParam = (): string => nameParam(useParams());
export const maybeUseIdParam = (): string | null => { const maybeUseIdParam = (): string | null => {
const params = useParams(); const params = useParams();
if (params.id === undefined) { if (params.id === undefined) {
return null; 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 * consider using useNotify for reactive usage on solidjs
*/ */
export function _subscribeNotify<T extends ProcessMessage>( function _subscribeNotify<T extends ProcessMessage>(
filter: (msg: T) => boolean, filter: (msg: T) => boolean,
callback: (msg: T) => void, 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 * The signal has the value of the last message where filter was true
* null in case no message was recieved yet * 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, filter: (msg: T) => boolean = () => true as boolean,
) { ) {
const [message, setMessage] = createSignal<T | null>(null); const [message, setMessage] = createSignal<T | null>(null);

View File

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

View File

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

View File

@@ -1,45 +1,43 @@
import { fn } from "storybook/test"; import { fn } from "storybook/test";
import type { Meta, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { ClanSettingsModal, ClanSettingsModalProps } from "./ClanSettingsModal"; import { ClanSettingsModal } from "./ClanSettingsModal";
const meta: Meta<ClanSettingsModalProps> = { const meta: Meta<typeof ClanSettingsModal> = {
title: "Modals/ClanSettings", title: "Modals/ClanSettings",
component: ClanSettingsModal, component: ClanSettingsModal,
}; };
export default meta; export default meta;
type Story = StoryObj<ClanSettingsModalProps>; type Story = StoryObj<typeof meta>;
const props: ClanSettingsModalProps = { export const Default: Story = {
onClose: fn(), args: {
model: { onClose: fn(),
uri: "/home/foo/my-clan", model: {
details: { uri: "/home/foo/my-clan",
name: "Sol", details: {
description: null, name: "Sol",
icon: null, description: null,
}, icon: null,
fieldsSchema: {
name: {
readonly: true,
reason: null,
readonly_members: [],
}, },
description: { fieldsSchema: {
readonly: false, name: {
reason: null, readonly: true,
readonly_members: [], reason: null,
}, readonly_members: [],
icon: { },
readonly: false, description: {
reason: null, readonly: false,
readonly_members: [], reason: null,
readonly_members: [],
},
icon: {
readonly: false,
reason: null,
readonly_members: [],
},
}, },
}, },
}, },
}; };
export const Default: Story = {
args: props,
};

View File

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

View File

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

View File

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

View File

@@ -52,7 +52,7 @@ export function createMachineMesh() {
}; };
} }
export function createCubeBase( function createCubeBase(
color: THREE.ColorRepresentation, color: THREE.ColorRepresentation,
emissive: THREE.ColorRepresentation, emissive: THREE.ColorRepresentation,
geometry: THREE.BoxGeometry, geometry: THREE.BoxGeometry,
@@ -70,7 +70,7 @@ export function createCubeBase(
} }
// Function to build rounded rect shape // 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 shape = new THREE.Shape();
const x = -w / 2; const x = -w / 2;
const y = -h / 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 // Exported so others could also emit the signal if needed
// And for testing purposes // And for testing purposes
export function emitMachineClick(id: string | null) { function emitMachineClick(id: string | null) {
setLastClickedMachine(id); setLastClickedMachine(id);
if (id) { if (id) {
// Clear after a short delay to allow re-clicking the same machine // Clear after a short delay to allow re-clicking the same machine

View File

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

View File

@@ -1,4 +1,4 @@
import { Meta, StoryObj } from "@kachurun/storybook-solid"; import { Meta, StoryObj } from "storybook-solidjs-vite";
import { Splash } from "./splash"; import { Splash } from "./splash";
const meta: Meta = { const meta: Meta = {

View File

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

View File

@@ -1,90 +0,0 @@
// @ts-nocheck
declare module "@kachurun/storybook-solid" {
import type { SolidRenderer } from "types";
import type {
AnnotatedStoryFn,
Args,
ArgsFromMeta,
ArgsStoryFn,
ComponentAnnotations,
DecoratorFunction,
LoaderFunction,
ProjectAnnotations,
StoryAnnotations,
StoryContext as GenericStoryContext,
StrictArgs,
} from "@storybook/types";
import type { Component as ComponentType, ComponentProps } from "solid-js";
import type { SetOptional, Simplify } from "type-fest";
export type {
ArgTypes,
Args,
Parameters,
StrictArgs,
} from "@storybook/types";
export type { SolidRenderer };
/**
* Metadata to configure the stories for a component.
*
* @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export)
*/
export type Meta<TCmpOrArgs = Args> =
TCmpOrArgs extends ComponentType<any>
? ComponentAnnotations<SolidRenderer, ComponentProps<TCmpOrArgs>>
: ComponentAnnotations<SolidRenderer, TCmpOrArgs>;
/**
* Story function that represents a CSFv2 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
export type StoryFn<TCmpOrArgs = Args> =
TCmpOrArgs extends ComponentType<any>
? AnnotatedStoryFn<SolidRenderer, ComponentProps<TCmpOrArgs>>
: AnnotatedStoryFn<SolidRenderer, TCmpOrArgs>;
/**
* Story function that represents a CSFv3 component example.
*
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/
export type StoryObj<TMetaOrCmpOrArgs = Args> = TMetaOrCmpOrArgs extends {
render?: ArgsStoryFn<SolidRenderer, any>;
component?: infer Component;
args?: infer DefaultArgs;
}
? Simplify<
(Component extends ComponentType<any>
? ComponentProps<Component>
: unknown) &
ArgsFromMeta<SolidRenderer, TMetaOrCmpOrArgs>
> extends infer TArgs
? StoryAnnotations<
SolidRenderer,
TArgs,
SetOptional<
TArgs,
keyof TArgs & keyof (DefaultArgs & ActionArgs<TArgs>)
>
>
: never
: TMetaOrCmpOrArgs extends ComponentType<any>
? StoryAnnotations<SolidRenderer, ComponentProps<TMetaOrCmpOrArgs>>
: StoryAnnotations<SolidRenderer, TMetaOrCmpOrArgs>;
type ActionArgs<TArgs> = {
[P in keyof TArgs as TArgs[P] extends (...args: any[]) => any
? ((...args: any[]) => void) extends TArgs[P]
? P
: never
: never]: TArgs[P];
};
export type Decorator<TArgs = StrictArgs> = DecoratorFunction<
SolidRenderer,
TArgs
>;
export type Loader<TArgs = StrictArgs> = LoaderFunction<SolidRenderer, TArgs>;
export type StoryContext<TArgs = StrictArgs> = GenericStoryContext<
SolidRenderer,
TArgs
>;
export type Preview = ProjectAnnotations<SolidRenderer>;
}
//# sourceMappingURL=index.d.ts.map

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { AddMachine } from "@/src/workflows/AddMachine/AddMachine"; import { AddMachine } from "@/src/workflows/AddMachine/AddMachine";
import { import {
createMemoryHistory, createMemoryHistory,
@@ -62,7 +62,7 @@ const meta: Meta<typeof AddMachine> = {
title: "workflows/add-machine", title: "workflows/add-machine",
component: AddMachine, component: AddMachine,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext) => { (Story) => {
const Routes: RouteDefinition[] = [ const Routes: RouteDefinition[] = [
{ {
path: "/clans/:clanURI", path: "/clans/:clanURI",

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { InstallModal } from "./InstallMachine"; import { InstallModal } from "./InstallMachine";
import { import {
createMemoryHistory, createMemoryHistory,
@@ -161,7 +161,7 @@ const meta: Meta<typeof InstallModal> = {
title: "workflows/install", title: "workflows/install",
component: InstallModal, component: InstallModal,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext) => { (Story) => {
const Routes: RouteDefinition[] = [ const Routes: RouteDefinition[] = [
{ {
path: "/clans/:clanURI", path: "/clans/:clanURI",
@@ -198,10 +198,9 @@ const meta: Meta<typeof InstallModal> = {
export default meta; export default meta;
type Story = StoryObj<typeof InstallModal>; type Story = StoryObj<typeof meta>;
export const Init: Story = { export const Init: Story = {
description: "Welcome step for the installation workflow",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -209,7 +208,6 @@ export const Init: Story = {
}, },
}; };
export const CreateInstallerProse: Story = { export const CreateInstallerProse: Story = {
description: "Prose step for creating an installer",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -217,7 +215,6 @@ export const CreateInstallerProse: Story = {
}, },
}; };
export const CreateInstallerImage: Story = { export const CreateInstallerImage: Story = {
description: "Configure the image to install",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -225,7 +222,6 @@ export const CreateInstallerImage: Story = {
}, },
}; };
export const CreateInstallerDisk: Story = { export const CreateInstallerDisk: Story = {
description: "Select a disk to install the image on",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -233,7 +229,6 @@ export const CreateInstallerDisk: Story = {
}, },
}; };
export const CreateInstallerProgress: Story = { export const CreateInstallerProgress: Story = {
description: "Showed while the USB stick is being flashed",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -241,7 +236,6 @@ export const CreateInstallerProgress: Story = {
}, },
}; };
export const CreateInstallerDone: Story = { export const CreateInstallerDone: Story = {
description: "Installation done step",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -249,7 +243,6 @@ export const CreateInstallerDone: Story = {
}, },
}; };
export const InstallConfigureAddress: Story = { export const InstallConfigureAddress: Story = {
description: "Installation configure address step",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -257,7 +250,6 @@ export const InstallConfigureAddress: Story = {
}, },
}; };
export const InstallCheckHardware: Story = { export const InstallCheckHardware: Story = {
description: "Installation check hardware step",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -265,7 +257,6 @@ export const InstallCheckHardware: Story = {
}, },
}; };
export const InstallSelectDisk: Story = { export const InstallSelectDisk: Story = {
description: "Select disk to install the system on",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -273,7 +264,6 @@ export const InstallSelectDisk: Story = {
}, },
}; };
export const InstallVars: Story = { export const InstallVars: Story = {
description: "Fill required credentials and data for the installation",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -281,7 +271,6 @@ export const InstallVars: Story = {
}, },
}; };
export const InstallSummary: Story = { export const InstallSummary: Story = {
description: "Summary of the installation steps",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -289,7 +278,6 @@ export const InstallSummary: Story = {
}, },
}; };
export const InstallProgress: Story = { export const InstallProgress: Story = {
description: "Shown while the installation is in progress",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",
@@ -297,7 +285,6 @@ export const InstallProgress: Story = {
}, },
}; };
export const InstallDone: Story = { export const InstallDone: Story = {
description: "Shown after the installation is done",
args: { args: {
open: true, open: true,
machineName: "Test Machine", machineName: "Test Machine",

View File

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

View File

@@ -1,4 +1,4 @@
import type { Meta, StoryContext, StoryObj } from "@kachurun/storybook-solid"; import type { Meta, StoryObj } from "storybook-solidjs-vite";
import { import {
createMemoryHistory, createMemoryHistory,
MemoryRouter, MemoryRouter,
@@ -134,7 +134,7 @@ const meta: Meta<typeof UpdateModal> = {
title: "workflows/update", title: "workflows/update",
component: UpdateModal, component: UpdateModal,
decorators: [ decorators: [
(Story: StoryObj, context: StoryContext) => { (Story) => {
const Routes: RouteDefinition[] = [ const Routes: RouteDefinition[] = [
{ {
path: "/clans/:clanURI", path: "/clans/:clanURI",
@@ -174,14 +174,12 @@ export default meta;
type Story = StoryObj<typeof UpdateModal>; type Story = StoryObj<typeof UpdateModal>;
export const Init: Story = { export const Init: Story = {
description: "Welcome step for the update workflow",
args: { args: {
open: true, open: true,
machineName: "Jon", machineName: "Jon",
}, },
}; };
export const Address: Story = { export const Address: Story = {
description: "Welcome step for the update workflow",
args: { args: {
open: true, open: true,
machineName: "Jon", machineName: "Jon",
@@ -189,7 +187,6 @@ export const Address: Story = {
}, },
}; };
export const UpdateProgress: Story = { export const UpdateProgress: Story = {
description: "Welcome step for the update workflow",
args: { args: {
open: true, open: true,
machineName: "Jon", machineName: "Jon",

View File

@@ -84,7 +84,7 @@ const UpdateStepper = (props: UpdateStepperProps) => {
); );
}; };
export interface UpdateModalProps { interface UpdateModalProps {
machineName: string; machineName: string;
open: boolean; open: boolean;
initialStep?: UpdateSteps[number]["id"]; initialStep?: UpdateSteps[number]["id"];
@@ -92,7 +92,7 @@ export interface UpdateModalProps {
onClose?: () => void; onClose?: () => void;
} }
export const UpdateHeader = (props: { machineName: string }) => { const UpdateHeader = (props: { machineName: string }) => {
return ( return (
<Typography hierarchy="label" size="default"> <Typography hierarchy="label" size="default">
Update: {props.machineName} Update: {props.machineName}
@@ -206,8 +206,8 @@ const steps = [
}, },
] as const; ] as const;
export type UpdateSteps = typeof steps; type UpdateSteps = typeof steps;
export type PromptValues = Record<string, Record<string, string>>; type PromptValues = Record<string, Record<string, string>>;
export const UpdateModal = (props: UpdateModalProps) => { export const UpdateModal = (props: UpdateModalProps) => {
const stepper = createStepper( 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 { Button as KButton } from "@kobalte/core/button";
import usbLogo from "@/logos/usb-stick-min.png?url"; import usbLogo from "@/logos/usb-stick-min.png?url";
export const InstallHeader = (props: { machineName: string }) => { const InstallHeader = (props: { machineName: string }) => {
return ( return (
<Typography hierarchy="label" size="default"> <Typography hierarchy="label" size="default">
Installing: {props.machineName} Installing: {props.machineName}

Some files were not shown because too many files have changed in this diff Show More