Merge pull request 'Handle error cases when switching clan' (#4879) from feat/handle-clan-switch-errors into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4879
This commit is contained in:
245
pkgs/clan-app/ui/package-lock.json
generated
245
pkgs/clan-app/ui/package-lock.json
generated
@@ -15,9 +15,10 @@
|
|||||||
"@modular-forms/solid": "^0.25.1",
|
"@modular-forms/solid": "^0.25.1",
|
||||||
"@solid-primitives/storage": "^4.3.2",
|
"@solid-primitives/storage": "^4.3.2",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
"@tanstack/eslint-plugin-query": "^5.83.1",
|
||||||
"@tanstack/solid-query": "^5.76.0",
|
"@tanstack/solid-query": "^5.85.5",
|
||||||
"@tanstack/solid-query-devtools": "^5.83.0",
|
"@tanstack/solid-query-devtools": "^5.85.5",
|
||||||
|
"@tanstack/solid-query-persist-client": "^5.85.5",
|
||||||
"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",
|
||||||
@@ -2487,12 +2488,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/eslint-plugin-query": {
|
"node_modules/@tanstack/eslint-plugin-query": {
|
||||||
"version": "5.81.2",
|
"version": "5.83.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.81.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.83.1.tgz",
|
||||||
"integrity": "sha512-h4k6P6fm5VhKP5NkK+0TTVpGGyKQdx6tk7NYYG7J7PkSu7ClpLgBihw7yzK8N3n5zPaF3IMyErxfoNiXWH/3/A==",
|
"integrity": "sha512-tdkpPFfzkTksN9BIlT/qjixSAtKrsW6PUVRwdKWaOcag7DrD1vpki3UzzdfMQGDRGeg1Ue1Dg+rcl5FJGembNg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/utils": "^8.18.1"
|
"@typescript-eslint/utils": "^8.37.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2502,10 +2503,169 @@
|
|||||||
"eslint": "^8.57.0 || ^9.0.0"
|
"eslint": "^8.57.0 || ^9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/project-service": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/tsconfig-utils": "^8.40.0",
|
||||||
|
"@typescript-eslint/types": "^8.40.0",
|
||||||
|
"debug": "^4.3.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "8.40.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "8.40.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/project-service": "8.40.0",
|
||||||
|
"@typescript-eslint/tsconfig-utils": "8.40.0",
|
||||||
|
"@typescript-eslint/types": "8.40.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "8.40.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"minimatch": "^9.0.4",
|
||||||
|
"semver": "^7.6.0",
|
||||||
|
"ts-api-utils": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/utils": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
|
"@typescript-eslint/scope-manager": "8.40.0",
|
||||||
|
"@typescript-eslint/types": "8.40.0",
|
||||||
|
"@typescript-eslint/typescript-estree": "8.40.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "8.40.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.40.0.tgz",
|
||||||
|
"integrity": "sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "8.40.0",
|
||||||
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query/node_modules/semver": {
|
||||||
|
"version": "7.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||||
|
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.83.0",
|
"version": "5.85.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.83.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.5.tgz",
|
||||||
"integrity": "sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==",
|
"integrity": "sha512-KO0WTob4JEApv69iYp1eGvfMSUkgw//IpMnq+//cORBzXf0smyRwPLrUvEe5qtAEGjwZTXrjxg+oJNP/C00t6w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2513,22 +2673,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-devtools": {
|
"node_modules/@tanstack/query-devtools": {
|
||||||
"version": "5.81.2",
|
"version": "5.84.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.81.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.84.0.tgz",
|
||||||
"integrity": "sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg==",
|
"integrity": "sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/solid-query": {
|
"node_modules/@tanstack/query-persist-client-core": {
|
||||||
"version": "5.83.0",
|
"version": "5.85.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/solid-query/-/solid-query-5.83.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.85.5.tgz",
|
||||||
"integrity": "sha512-RF8Tv9+6+Kmzj+EafbTzvzzPq+J5SzHtc1Tz3D2MZ/EvlZTH+GL5q4HNnWK3emg7CB6WzyGnTuERmmWJaZs8/w==",
|
"integrity": "sha512-2JQiyiTVaaUu8pwPqOp6tjNa64ZN+0T9eZ3lfksV4le1VuG99fTcAYmZFIydvzwWlSM7GEF/1kpl5bwW2Y1qfQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.83.0"
|
"@tanstack/query-core": "5.85.5"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/solid-query": {
|
||||||
|
"version": "5.85.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/solid-query/-/solid-query-5.85.5.tgz",
|
||||||
|
"integrity": "sha512-0o0Ibk9wqydm4JatbIjmvDu1+MofeZ1bU9BKwAbpt7HYjrLVCeddpW6zGmp41nN7t/mHJyR+ctW9oiNumCkEfg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "5.85.5"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2539,19 +2712,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/solid-query-devtools": {
|
"node_modules/@tanstack/solid-query-devtools": {
|
||||||
"version": "5.83.0",
|
"version": "5.85.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/solid-query-devtools/-/solid-query-devtools-5.83.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/solid-query-devtools/-/solid-query-devtools-5.85.5.tgz",
|
||||||
"integrity": "sha512-Z0wQlAWXz/U2bJ/paMRBTDhMoPnB9Te6GmA21sXnI+nDnAAPZRcPxFBiCgYJS3eFsvbkdRGJwoUSQrdIgy0shg==",
|
"integrity": "sha512-9rC22wILlV9Lcsi4xKPmzRkNio1NOxNT36diIS+HjpOmhsEP/aI8XkNKQa/KPhhaSN2naYaTCJamh7eBAQ0Ymg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-devtools": "5.81.2"
|
"@tanstack/query-devtools": "5.84.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/solid-query": "^5.83.0",
|
"@tanstack/solid-query": "^5.85.5",
|
||||||
|
"solid-js": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/solid-query-persist-client": {
|
||||||
|
"version": "5.85.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/solid-query-persist-client/-/solid-query-persist-client-5.85.5.tgz",
|
||||||
|
"integrity": "sha512-2aG7UnLZlfE3R4XKqYuIeXVKjJOghjsjq4EU2Ifp915FTBZcZo61sEw1zRqRlrDjEFYAs4kJUZwqViDSJYyX2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-persist-client-core": "5.85.5"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tanstack/solid-query": "^5.85.5",
|
||||||
"solid-js": "^1.6.0"
|
"solid-js": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2894,6 +3084,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz",
|
||||||
"integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==",
|
"integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.36.0",
|
"@typescript-eslint/tsconfig-utils": "^8.36.0",
|
||||||
@@ -2915,6 +3106,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz",
|
||||||
"integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==",
|
"integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.36.0",
|
"@typescript-eslint/types": "8.36.0",
|
||||||
@@ -2932,6 +3124,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz",
|
||||||
"integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==",
|
"integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2972,6 +3165,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz",
|
||||||
"integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==",
|
"integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2985,6 +3179,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz",
|
||||||
"integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==",
|
"integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.36.0",
|
"@typescript-eslint/project-service": "8.36.0",
|
||||||
@@ -3013,6 +3208,7 @@
|
|||||||
"version": "7.7.2",
|
"version": "7.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
|
||||||
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@@ -3025,6 +3221,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz",
|
||||||
"integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==",
|
"integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
@@ -3048,6 +3245,7 @@
|
|||||||
"version": "8.36.0",
|
"version": "8.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz",
|
||||||
"integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==",
|
"integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.36.0",
|
"@typescript-eslint/types": "8.36.0",
|
||||||
@@ -3065,6 +3263,7 @@
|
|||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
@@ -72,9 +72,10 @@
|
|||||||
"@modular-forms/solid": "^0.25.1",
|
"@modular-forms/solid": "^0.25.1",
|
||||||
"@solid-primitives/storage": "^4.3.2",
|
"@solid-primitives/storage": "^4.3.2",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
"@tanstack/eslint-plugin-query": "^5.83.1",
|
||||||
"@tanstack/solid-query": "^5.76.0",
|
"@tanstack/solid-query": "^5.85.5",
|
||||||
"@tanstack/solid-query-devtools": "^5.83.0",
|
"@tanstack/solid-query-devtools": "^5.85.5",
|
||||||
|
"@tanstack/solid-query-persist-client": "^5.85.5",
|
||||||
"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",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useClanListQuery } from "@/src/hooks/queries";
|
|||||||
import { Alert } from "@/src/components/Alert/Alert";
|
import { Alert } from "@/src/components/Alert/Alert";
|
||||||
|
|
||||||
export interface ListClansModalProps {
|
export interface ListClansModalProps {
|
||||||
onClose: () => void;
|
onClose?: () => void;
|
||||||
error?: {
|
error?: {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -68,7 +68,7 @@ export const ListClansModal = (props: ListClansModalProps) => {
|
|||||||
size="s"
|
size="s"
|
||||||
startIcon="Plus"
|
startIcon="Plus"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
props.onClose();
|
props.onClose?.();
|
||||||
navigateToOnboarding(navigate, true);
|
navigateToOnboarding(navigate, true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const useModalContext = () => {
|
|||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
title: string;
|
title: string;
|
||||||
onClose: () => void;
|
onClose?: () => void;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
mount?: Node;
|
mount?: Node;
|
||||||
class?: string;
|
class?: string;
|
||||||
@@ -57,13 +57,11 @@ export const Modal = (props: ModalProps) => {
|
|||||||
>
|
>
|
||||||
{props.title}
|
{props.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<KDialog.CloseButton
|
<Show when={props.onClose}>
|
||||||
onClick={() => {
|
<KDialog.CloseButton onClick={props.onClose}>
|
||||||
props.onClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon icon="Close" size="0.75rem" />
|
<Icon icon="Close" size="0.75rem" />
|
||||||
</KDialog.CloseButton>
|
</KDialog.CloseButton>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Show when={props.metaHeader}>
|
<Show when={props.metaHeader}>
|
||||||
{(metaHeader) => (
|
{(metaHeader) => (
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ export const SidebarHeader = () => {
|
|||||||
ctx?.activeClanQuery?.data?.name.charAt(0).toUpperCase();
|
ctx?.activeClanQuery?.data?.name.charAt(0).toUpperCase();
|
||||||
const clanName = () => ctx?.activeClanQuery?.data?.name;
|
const clanName = () => ctx?.activeClanQuery?.data?.name;
|
||||||
|
|
||||||
const clans = () => ctx.otherClanQueries.filter((clan) => !clan.isError);
|
const clanList = () =>
|
||||||
|
ctx.allClansQueries
|
||||||
|
.filter((it) => it.isSuccess)
|
||||||
|
.map((it) => it.data!)
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
@@ -100,13 +104,13 @@ export const SidebarHeader = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</DropdownMenu.GroupLabel>
|
</DropdownMenu.GroupLabel>
|
||||||
<div class="dropdown-group-items">
|
<div class="dropdown-group-items">
|
||||||
<For each={clans()}>
|
<For each={clanList()}>
|
||||||
{(clan) => (
|
{(clan) => (
|
||||||
<Suspense fallback={"Loading..."}>
|
<Suspense fallback={"Loading..."}>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setActiveClanURI(clan.data!.uri);
|
setActiveClanURI(clan.uri);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
@@ -114,7 +118,7 @@ export const SidebarHeader = () => {
|
|||||||
size="xs"
|
size="xs"
|
||||||
weight="medium"
|
weight="medium"
|
||||||
>
|
>
|
||||||
{clan.data?.name}
|
{clan.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { useQueries, useQuery, UseQueryResult } from "@tanstack/solid-query";
|
import {
|
||||||
|
QueryClient,
|
||||||
|
useQueries,
|
||||||
|
useQuery,
|
||||||
|
UseQueryResult,
|
||||||
|
} from "@tanstack/solid-query";
|
||||||
import { SuccessData } from "../hooks/api";
|
import { SuccessData } from "../hooks/api";
|
||||||
import { encodeBase64 } from "@/src/hooks/clan";
|
import { encodeBase64 } from "@/src/hooks/clan";
|
||||||
import { useApiClient } from "./ApiClient";
|
import { useApiClient } from "./ApiClient";
|
||||||
|
import { experimental_createQueryPersister } from "@tanstack/solid-query-persist-client";
|
||||||
|
import { ClanDetailsStore } from "@/src/stores/clanDetails";
|
||||||
|
|
||||||
export type ClanDetails = SuccessData<"get_clan_details">;
|
export type ClanDetails = SuccessData<"get_clan_details">;
|
||||||
export type ClanDetailsWithURI = ClanDetails & { uri: string };
|
export type ClanDetailsWithURI = ClanDetails & { uri: string };
|
||||||
@@ -24,6 +31,14 @@ export interface MachineDetail {
|
|||||||
export type MachinesQueryResult = UseQueryResult<ListMachines>;
|
export type MachinesQueryResult = UseQueryResult<ListMachines>;
|
||||||
export type ClanListQueryResult = UseQueryResult<ClanDetailsWithURI>[];
|
export type ClanListQueryResult = UseQueryResult<ClanDetailsWithURI>[];
|
||||||
|
|
||||||
|
export const DefaultQueryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const useMachinesQuery = (clanURI: string) => {
|
export const useMachinesQuery = (clanURI: string) => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
|
|
||||||
@@ -155,10 +170,15 @@ export const useMachineDetailsQuery = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ClanDetailsPersister = experimental_createQueryPersister({
|
||||||
|
storage: ClanDetailsStore,
|
||||||
|
});
|
||||||
|
|
||||||
export const useClanDetailsQuery = (clanURI: string) => {
|
export const useClanDetailsQuery = (clanURI: string) => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
return useQuery<ClanDetailsWithURI>(() => ({
|
return useQuery<ClanDetailsWithURI>(() => ({
|
||||||
queryKey: ["clans", encodeBase64(clanURI), "details"],
|
queryKey: ["clans", encodeBase64(clanURI), "details"],
|
||||||
|
persister: ClanDetailsPersister.persisterFn,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const call = client.fetch("get_clan_details", {
|
const call = client.fetch("get_clan_details", {
|
||||||
flake: {
|
flake: {
|
||||||
@@ -169,7 +189,7 @@ export const useClanDetailsQuery = (clanURI: string) => {
|
|||||||
|
|
||||||
if (result.status === "error") {
|
if (result.status === "error") {
|
||||||
// todo should we create some specific error types?
|
// todo should we create some specific error types?
|
||||||
console.error("Error fetching clan details:", result.errors);
|
console.error("Error fetching clan details", clanURI, result.errors);
|
||||||
throw new Error(result.errors[0].message);
|
throw new Error(result.errors[0].message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,13 +201,35 @@ export const useClanDetailsQuery = (clanURI: string) => {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useClanListQuery = (clanURIs: string[]): ClanListQueryResult => {
|
export const useClanListQuery = (
|
||||||
|
clanURIs: string[],
|
||||||
|
activeClanURI?: string,
|
||||||
|
): ClanListQueryResult => {
|
||||||
const client = useApiClient();
|
const client = useApiClient();
|
||||||
|
|
||||||
return useQueries(() => ({
|
return useQueries(() => ({
|
||||||
queries: clanURIs.map((clanURI) => ({
|
queries: clanURIs.map((clanURI) => {
|
||||||
queryKey: ["clans", encodeBase64(clanURI), "details"],
|
const queryKey = ["clans", encodeBase64(clanURI), "details"];
|
||||||
enabled: !!clanURI,
|
|
||||||
|
return {
|
||||||
|
// eslint-disable-next-line @tanstack/query/exhaustive-deps
|
||||||
|
queryKey,
|
||||||
|
persister: ClanDetailsPersister.persisterFn,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
|
// we only perform a request for the active clan
|
||||||
|
// for all others we load the cached query state
|
||||||
|
// this is due to how expensive it currently is to evaluate a flake for clan details
|
||||||
|
// it also helps when a clan folder has been moved/renamed
|
||||||
|
if (clanURI != activeClanURI) {
|
||||||
|
const cached = DefaultQueryClient.getQueryCache().find({
|
||||||
|
queryKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cached?.state?.data) {
|
||||||
|
return cached.state.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const call = client.fetch("get_clan_details", {
|
const call = client.fetch("get_clan_details", {
|
||||||
flake: {
|
flake: {
|
||||||
identifier: clanURI,
|
identifier: clanURI,
|
||||||
@@ -197,7 +239,6 @@ export const useClanListQuery = (clanURIs: string[]): ClanListQueryResult => {
|
|||||||
|
|
||||||
if (result.status === "error") {
|
if (result.status === "error") {
|
||||||
// todo should we create some specific error types?
|
// todo should we create some specific error types?
|
||||||
console.error("Error fetching clan details:", result.errors);
|
|
||||||
throw new Error(result.errors[0].message);
|
throw new Error(result.errors[0].message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +247,8 @@ export const useClanListQuery = (clanURIs: string[]): ClanListQueryResult => {
|
|||||||
...result.data,
|
...result.data,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
})),
|
};
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,14 @@
|
|||||||
import { render } from "solid-js/web";
|
import { render } from "solid-js/web";
|
||||||
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
|
import { QueryClientProvider } from "@tanstack/solid-query";
|
||||||
import { Routes } from "@/src/routes";
|
import { Routes } from "@/src/routes";
|
||||||
import { Router } from "@solidjs/router";
|
import { Router } from "@solidjs/router";
|
||||||
import { Layout } from "@/src/routes/Layout";
|
import { Layout } from "@/src/routes/Layout";
|
||||||
import { SolidQueryDevtools } from "@tanstack/solid-query-devtools";
|
import { SolidQueryDevtools } from "@tanstack/solid-query-devtools";
|
||||||
import { ApiClientProvider } from "./hooks/ApiClient";
|
import { ApiClientProvider } from "./hooks/ApiClient";
|
||||||
import { callApi } from "./hooks/api";
|
import { callApi } from "./hooks/api";
|
||||||
|
import { DefaultQueryClient } from "@/src/hooks/queries";
|
||||||
export const client = new QueryClient();
|
|
||||||
|
|
||||||
const root = document.getElementById("app");
|
const root = document.getElementById("app");
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ if (import.meta.env.DEV) {
|
|||||||
render(
|
render(
|
||||||
() => (
|
() => (
|
||||||
<ApiClientProvider client={{ fetch: callApi }}>
|
<ApiClientProvider client={{ fetch: callApi }}>
|
||||||
<QueryClientProvider client={client}>
|
<QueryClientProvider client={DefaultQueryClient}>
|
||||||
{import.meta.env.DEV && <SolidQueryDevtools initialIsOpen={true} />}
|
{import.meta.env.DEV && <SolidQueryDevtools initialIsOpen={true} />}
|
||||||
<Router root={Layout}>{Routes}</Router>
|
<Router root={Layout}>{Routes}</Router>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
@@ -35,30 +35,84 @@ import { TextInput } from "@/src/components/Form/TextInput";
|
|||||||
import { createForm, FieldValues, reset } from "@modular-forms/solid";
|
import { createForm, FieldValues, reset } from "@modular-forms/solid";
|
||||||
import { Sidebar } from "@/src/components/Sidebar/Sidebar";
|
import { Sidebar } from "@/src/components/Sidebar/Sidebar";
|
||||||
import { UseQueryResult } from "@tanstack/solid-query";
|
import { UseQueryResult } from "@tanstack/solid-query";
|
||||||
|
import { ListClansModal } from "@/src/components/ListClansModal/ListClansModal";
|
||||||
|
|
||||||
export const ClanContext = createContext<{
|
interface ClanContextProps {
|
||||||
|
clanURI: string;
|
||||||
machinesQuery: MachinesQueryResult;
|
machinesQuery: MachinesQueryResult;
|
||||||
activeClanQuery: UseQueryResult<ClanDetailsWithURI>;
|
activeClanQuery: UseQueryResult<ClanDetailsWithURI>;
|
||||||
otherClanQueries: UseQueryResult<ClanDetailsWithURI>[];
|
otherClanQueries: UseQueryResult<ClanDetailsWithURI>[];
|
||||||
}>();
|
allClansQueries: UseQueryResult<ClanDetailsWithURI>[];
|
||||||
|
|
||||||
|
isLoading(): boolean;
|
||||||
|
isError(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultClanContext implements ClanContextProps {
|
||||||
|
public readonly clanURI: string;
|
||||||
|
|
||||||
|
public readonly activeClanQuery: UseQueryResult<ClanDetailsWithURI>;
|
||||||
|
public readonly otherClanQueries: UseQueryResult<ClanDetailsWithURI>[];
|
||||||
|
public readonly allClansQueries: UseQueryResult<ClanDetailsWithURI>[];
|
||||||
|
|
||||||
|
public readonly machinesQuery: MachinesQueryResult;
|
||||||
|
|
||||||
|
allQueries: UseQueryResult[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
clanURI: string,
|
||||||
|
machinesQuery: MachinesQueryResult,
|
||||||
|
activeClanQuery: UseQueryResult<ClanDetailsWithURI>,
|
||||||
|
otherClanQueries: UseQueryResult<ClanDetailsWithURI>[],
|
||||||
|
) {
|
||||||
|
this.clanURI = clanURI;
|
||||||
|
this.machinesQuery = machinesQuery;
|
||||||
|
|
||||||
|
this.activeClanQuery = activeClanQuery;
|
||||||
|
this.otherClanQueries = otherClanQueries;
|
||||||
|
this.allClansQueries = [activeClanQuery, ...otherClanQueries];
|
||||||
|
|
||||||
|
this.allQueries = [machinesQuery, activeClanQuery, ...otherClanQueries];
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading(): boolean {
|
||||||
|
return this.allQueries.some((q) => q.isLoading);
|
||||||
|
}
|
||||||
|
|
||||||
|
isError(): boolean {
|
||||||
|
return this.activeClanQuery.isError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ClanContext = createContext<ClanContextProps>();
|
||||||
|
|
||||||
export const Clan: Component<RouteSectionProps> = (props) => {
|
export const Clan: Component<RouteSectionProps> = (props) => {
|
||||||
const clanURI = useClanURI();
|
const clanURI = useClanURI();
|
||||||
const activeClanQuery = useClanDetailsQuery(clanURI);
|
const activeClanQuery = useClanDetailsQuery(clanURI);
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (activeClanQuery.isError) {
|
||||||
|
console.error("Error loading active clan", activeClanQuery.error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const otherClanQueries = useClanListQuery(
|
const otherClanQueries = useClanListQuery(
|
||||||
clanURIs().filter((uri) => uri !== clanURI),
|
clanURIs().filter((uri) => uri != clanURI),
|
||||||
|
clanURI,
|
||||||
);
|
);
|
||||||
|
|
||||||
const machinesQuery = useMachinesQuery(clanURI);
|
const machinesQuery = useMachinesQuery(clanURI);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ClanContext.Provider
|
<ClanContext.Provider
|
||||||
value={{
|
value={
|
||||||
|
new DefaultClanContext(
|
||||||
|
clanURI,
|
||||||
machinesQuery,
|
machinesQuery,
|
||||||
activeClanQuery,
|
activeClanQuery,
|
||||||
otherClanQueries,
|
otherClanQueries,
|
||||||
}}
|
)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Sidebar class={cx(styles.sidebar)} />
|
<Sidebar class={cx(styles.sidebar)} />
|
||||||
{props.children}
|
{props.children}
|
||||||
@@ -118,14 +172,13 @@ const MockCreateMachine = (props: MockProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ClanSceneController = (props: RouteSectionProps) => {
|
const ClanSceneController = (props: RouteSectionProps) => {
|
||||||
const clanURI = useClanURI();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const ctx = useContext(ClanContext);
|
const ctx = useContext(ClanContext);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
throw new Error("ClanContext not found");
|
throw new Error("ClanContext not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [dialogHandlers, setDialogHandlers] = createSignal<{
|
const [dialogHandlers, setDialogHandlers] = createSignal<{
|
||||||
resolve: ({ id }: { id: string }) => void;
|
resolve: ({ id }: { id: string }) => void;
|
||||||
reject: (err: unknown) => void;
|
reject: (err: unknown) => void;
|
||||||
@@ -142,7 +195,7 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
const api = callApi("create_machine", {
|
const api = callApi("create_machine", {
|
||||||
opts: {
|
opts: {
|
||||||
clan_dir: {
|
clan_dir: {
|
||||||
identifier: clanURI,
|
identifier: ctx.clanURI,
|
||||||
},
|
},
|
||||||
machine: {
|
machine: {
|
||||||
name: values.name,
|
name: values.name,
|
||||||
@@ -166,29 +219,38 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
|
|
||||||
const [showModal, setShowModal] = createSignal(false);
|
const [showModal, setShowModal] = createSignal(false);
|
||||||
|
|
||||||
|
const [loadingError, setLoadingError] = createSignal<
|
||||||
|
{ title: string; description: string } | undefined
|
||||||
|
>();
|
||||||
const [loadingCooldown, setLoadingCooldown] = createSignal(false);
|
const [loadingCooldown, setLoadingCooldown] = createSignal(false);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setLoadingCooldown(true);
|
setLoadingCooldown(true);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (ctx.activeClanQuery.isError) {
|
||||||
|
setLoadingError({
|
||||||
|
title: "Error loading clan",
|
||||||
|
description: ctx.activeClanQuery.error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const [selectedIds, setSelectedIds] = createSignal<Set<string>>(new Set());
|
const [selectedIds, setSelectedIds] = createSignal<Set<string>>(new Set());
|
||||||
|
|
||||||
const onMachineSelect = (ids: Set<string>) => {
|
const onMachineSelect = (ids: Set<string>) => {
|
||||||
// Get the first selected ID and navigate to its machine details
|
// Get the first selected ID and navigate to its machine details
|
||||||
const selected = ids.values().next().value;
|
const selected = ids.values().next().value;
|
||||||
if (selected) {
|
if (selected) {
|
||||||
navigate(buildMachinePath(clanURI, selected));
|
navigate(buildMachinePath(ctx.clanURI, selected));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const machine = createMemo(() => maybeUseMachineName());
|
const machine = createMemo(() => maybeUseMachineName());
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
console.log("Selected clan:", clanURI);
|
|
||||||
});
|
|
||||||
|
|
||||||
createEffect(
|
createEffect(
|
||||||
on(machine, (machineId) => {
|
on(machine, (machineId) => {
|
||||||
if (machineId) {
|
if (machineId) {
|
||||||
@@ -203,32 +265,11 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// a combination of the individual clan details query status and the machines query status
|
|
||||||
// the cube scene needs the machines query, the sidebar needs the clans query and machines query results
|
|
||||||
// so we wait on both before removing the loader to avoid any loading artefacts
|
|
||||||
const isLoading = (): boolean => {
|
|
||||||
// check if the active clan query is still loading
|
|
||||||
if (ctx.activeClanQuery.isLoading) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the machines query first
|
|
||||||
if (ctx.machinesQuery.isLoading) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise iterate the clans query and return early if we find a queries that is still loading
|
|
||||||
for (const query of ctx.otherClanQueries) {
|
|
||||||
if (query.isLoading) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Show when={loadingError()}>
|
||||||
|
<ListClansModal error={loadingError()} />
|
||||||
|
</Show>
|
||||||
<Show when={showModal()}>
|
<Show when={showModal()}>
|
||||||
<MockCreateMachine
|
<MockCreateMachine
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
@@ -249,7 +290,7 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
</Show>
|
</Show>
|
||||||
<div
|
<div
|
||||||
class={cx({
|
class={cx({
|
||||||
[styles.fadeOut]: !ctx.machinesQuery.isLoading && loadingCooldown(),
|
[styles.fadeOut]: !ctx.isLoading() && loadingCooldown(),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Splash />
|
<Splash />
|
||||||
@@ -258,13 +299,10 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
<CubeScene
|
<CubeScene
|
||||||
selectedIds={selectedIds}
|
selectedIds={selectedIds}
|
||||||
onSelect={onMachineSelect}
|
onSelect={onMachineSelect}
|
||||||
isLoading={isLoading()}
|
isLoading={ctx.isLoading()}
|
||||||
cubesQuery={ctx.machinesQuery}
|
cubesQuery={ctx.machinesQuery}
|
||||||
onCreate={onCreate}
|
onCreate={onCreate}
|
||||||
sceneStore={() => {
|
sceneStore={() => store.sceneData?.[ctx.clanURI]}
|
||||||
const clanURI = useClanURI();
|
|
||||||
return store.sceneData?.[clanURI];
|
|
||||||
}}
|
|
||||||
setMachinePos={(machineId: string, pos: [number, number]) => {
|
setMachinePos={(machineId: string, pos: [number, number]) => {
|
||||||
console.log("calling setStore", machineId, pos);
|
console.log("calling setStore", machineId, pos);
|
||||||
setStore(
|
setStore(
|
||||||
@@ -272,13 +310,13 @@ const ClanSceneController = (props: RouteSectionProps) => {
|
|||||||
if (!s.sceneData) {
|
if (!s.sceneData) {
|
||||||
s.sceneData = {};
|
s.sceneData = {};
|
||||||
}
|
}
|
||||||
if (!s.sceneData[clanURI]) {
|
if (!s.sceneData[ctx.clanURI]) {
|
||||||
s.sceneData[clanURI] = {};
|
s.sceneData[ctx.clanURI] = {};
|
||||||
}
|
}
|
||||||
if (!s.sceneData[clanURI][machineId]) {
|
if (!s.sceneData[ctx.clanURI][machineId]) {
|
||||||
s.sceneData[clanURI][machineId] = { position: pos };
|
s.sceneData[ctx.clanURI][machineId] = { position: pos };
|
||||||
} else {
|
} else {
|
||||||
s.sceneData[clanURI][machineId].position = pos;
|
s.sceneData[ctx.clanURI][machineId].position = pos;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,12 +7,18 @@ export interface ClanStoreType {
|
|||||||
clanURIs: string[];
|
clanURIs: string[];
|
||||||
activeClanURI?: string;
|
activeClanURI?: string;
|
||||||
sceneData: Record<string, SceneData>;
|
sceneData: Record<string, SceneData>;
|
||||||
|
queryCache: {
|
||||||
|
clanDetails: Record<string, string>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const [store, setStore] = makePersisted(
|
const [store, setStore] = makePersisted(
|
||||||
createStore<ClanStoreType>({
|
createStore<ClanStoreType>({
|
||||||
clanURIs: [],
|
clanURIs: [],
|
||||||
sceneData: {},
|
sceneData: {},
|
||||||
|
queryCache: {
|
||||||
|
clanDetails: {},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "clanStore",
|
name: "clanStore",
|
||||||
|
|||||||
32
pkgs/clan-app/ui/src/stores/clanDetails.ts
Normal file
32
pkgs/clan-app/ui/src/stores/clanDetails.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { produce } from "solid-js/store";
|
||||||
|
import { AsyncStorage } from "@tanstack/query-persist-client-core";
|
||||||
|
import { setStore, store } from "@/src/stores/clan";
|
||||||
|
|
||||||
|
class ClanDetailsStoreImpl implements AsyncStorage {
|
||||||
|
entries() {
|
||||||
|
return Object.entries(store.queryCache.clanDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(key: string) {
|
||||||
|
return store.queryCache.clanDetails[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(key: string) {
|
||||||
|
setStore(
|
||||||
|
produce((state) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
|
delete state.queryCache.clanDetails[key];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(key: string, value: string) {
|
||||||
|
return setStore(
|
||||||
|
produce((state) => {
|
||||||
|
state.queryCache.clanDetails[key] = value;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ClanDetailsStore = new ClanDetailsStoreImpl();
|
||||||
Reference in New Issue
Block a user