@cobaltcore-dev/aurora 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -77
- package/dist/client/AuroraApp.d.ts +15 -0
- package/dist/client/{AuthProvider-D-5Jpa6F.mjs → AuthProvider-Co4d0WzB.mjs} +3 -3
- package/dist/client/{AuthProvider-D-5Jpa6F.mjs.map → AuthProvider-Co4d0WzB.mjs.map} +1 -1
- package/dist/client/{ContentHeader-BXZoN3B9.mjs → ContentHeader-xQVhO2yT.mjs} +20 -20
- package/dist/client/{ContentHeader-BXZoN3B9.mjs.map → ContentHeader-xQVhO2yT.mjs.map} +1 -1
- package/dist/client/{DeleteFlavorModal-BusYn32r.mjs → DeleteFlavorModal-CHTUZ3YV.mjs} +211 -202
- package/dist/client/DeleteFlavorModal-CHTUZ3YV.mjs.map +1 -0
- package/dist/client/{EditSecurityGroupModal-DK3WYikA.mjs → EditSecurityGroupModal-CWHHx2Xk.mjs} +22 -22
- package/dist/client/{EditSecurityGroupModal-DK3WYikA.mjs.map → EditSecurityGroupModal-CWHHx2Xk.mjs.map} +1 -1
- package/dist/client/{FiltersInput-OVeIJzIo.mjs → FiltersInput-UKJpNFdr.mjs} +10 -10
- package/dist/client/{FiltersInput-OVeIJzIo.mjs.map → FiltersInput-UKJpNFdr.mjs.map} +1 -1
- package/dist/client/{FloatingIpActionModals-Dok7fJss.mjs → FloatingIpActionModals-caXn6bYo.mjs} +54 -54
- package/dist/client/{FloatingIpActionModals-Dok7fJss.mjs.map → FloatingIpActionModals-caXn6bYo.mjs.map} +1 -1
- package/dist/client/{ImageToastNotifications-BG9LPnXf.mjs → ImageToastNotifications-BWimIzu_.mjs} +227 -227
- package/dist/client/{ImageToastNotifications-BG9LPnXf.mjs.map → ImageToastNotifications-BWimIzu_.mjs.map} +1 -1
- package/dist/client/{RouteError-pDEWC_k7.mjs → RouteError-CUj_m3gu.mjs} +6 -6
- package/dist/client/{RouteError-pDEWC_k7.mjs.map → RouteError-CUj_m3gu.mjs.map} +1 -1
- package/dist/client/{SortInput-DXWSqSny.mjs → SortInput-GQlQBlAj.mjs} +6 -6
- package/dist/client/{SortInput-DXWSqSny.mjs.map → SortInput-GQlQBlAj.mjs.map} +1 -1
- package/dist/client/{_auth-CJj1Cnbm.mjs → _auth-DXJkv9QO.mjs} +3 -3
- package/dist/client/{_auth-CJj1Cnbm.mjs.map → _auth-DXJkv9QO.mjs.map} +1 -1
- package/dist/client/_flavorId-C5dc1N_j.mjs +194 -0
- package/dist/client/_flavorId-C5dc1N_j.mjs.map +1 -0
- package/dist/client/{_flavorId-BoNcxYmF.mjs → _flavorId-sUWG0xuy.mjs} +15 -15
- package/dist/client/_flavorId-sUWG0xuy.mjs.map +1 -0
- package/dist/client/{_floatingIpId-DF_BSJN6.mjs → _floatingIpId-COK_TBrz2.mjs} +42 -42
- package/dist/client/_floatingIpId-COK_TBrz2.mjs.map +1 -0
- package/dist/client/{_floatingIpId-D33bOEmH.mjs → _floatingIpId-CT4y-60o.mjs} +3 -3
- package/dist/client/{_floatingIpId-D33bOEmH.mjs.map → _floatingIpId-CT4y-60o.mjs.map} +1 -1
- package/dist/client/_imageId-n3RcnhAR.mjs +534 -0
- package/dist/client/_imageId-n3RcnhAR.mjs.map +1 -0
- package/dist/client/{_pcaId-CbBhBrX1.mjs → _pcaId-B-f_6kqs.mjs} +99 -99
- package/dist/client/{_pcaId-CbBhBrX1.mjs.map → _pcaId-B-f_6kqs.mjs.map} +1 -1
- package/dist/client/{_pcaId-BYCoeK6_.mjs → _pcaId-ChnM_t-9.mjs} +3 -3
- package/dist/client/{_pcaId-BYCoeK6_.mjs.map → _pcaId-ChnM_t-9.mjs.map} +1 -1
- package/dist/client/_projectId-26bw-_rm.mjs +46 -0
- package/dist/client/_projectId-26bw-_rm.mjs.map +1 -0
- package/dist/client/{_projectId-BwLMEMGC.mjs → _projectId-BK9UqeYw.mjs} +14 -14
- package/dist/client/{_projectId-BwLMEMGC.mjs.map → _projectId-BK9UqeYw.mjs.map} +1 -1
- package/dist/client/{_projectId-D35MN1kY.mjs → _projectId-CCtpAQ8m.mjs} +78 -95
- package/dist/client/_projectId-CCtpAQ8m.mjs.map +1 -0
- package/dist/client/{_projectId-OW2xkK43.mjs → _projectId-Dhb4AyBD.mjs} +3 -3
- package/dist/client/{_projectId-OW2xkK43.mjs.map → _projectId-Dhb4AyBD.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-B-Z-CzLp.mjs → _securityGroupId-CR1mKICQ.mjs} +3 -3
- package/dist/client/{_securityGroupId-B-Z-CzLp.mjs.map → _securityGroupId-CR1mKICQ.mjs.map} +1 -1
- package/dist/client/{_securityGroupId-B1bOYRbX.mjs → _securityGroupId-DroYG6cA.mjs} +254 -255
- package/dist/client/{_securityGroupId-B1bOYRbX.mjs.map → _securityGroupId-DroYG6cA.mjs.map} +1 -1
- package/dist/client/about-969pIiZ9.mjs +92 -0
- package/dist/client/{about-DLn1ShhF.mjs.map → about-969pIiZ9.mjs.map} +1 -1
- package/dist/client/aurora-DDzsst74.mjs +19 -0
- package/dist/client/{aurora-CRcxVUCo.mjs.map → aurora-DDzsst74.mjs.map} +1 -1
- package/dist/client/{build-BJDfnAyi.mjs → build-DracvfrJ.mjs} +5 -5
- package/dist/client/{build-BJDfnAyi.mjs.map → build-DracvfrJ.mjs.map} +1 -1
- package/dist/client/{buildFilterParams-TeyosGyK.mjs → buildFilterParams-DoZzMKX9.mjs} +1 -1
- package/dist/client/{buildFilterParams-TeyosGyK.mjs.map → buildFilterParams-DoZzMKX9.mjs.map} +1 -1
- package/dist/client/{cn-C3laVXMm.mjs → cn-DM4Cy3jv.mjs} +1 -1
- package/dist/client/{cn-C3laVXMm.mjs.map → cn-DM4Cy3jv.mjs.map} +1 -1
- package/dist/client/{constants-B-P2r5F1.mjs → constants-4lVQXort.mjs} +22 -22
- package/dist/client/{constants-B-P2r5F1.mjs.map → constants-4lVQXort.mjs.map} +1 -1
- package/dist/client/{containers-BjWqjNOx.mjs → containers-DGY2hoWw.mjs} +3 -3
- package/dist/client/{containers-BjWqjNOx.mjs.map → containers-DGY2hoWw.mjs.map} +1 -1
- package/dist/client/containers-ZMFTRaQL.mjs +3277 -0
- package/dist/client/containers-ZMFTRaQL.mjs.map +1 -0
- package/dist/client/{containers-DsRWc1L5.mjs → containers-xfsYgRyf.mjs} +2 -2
- package/dist/client/{containers-DsRWc1L5.mjs.map → containers-xfsYgRyf.mjs.map} +1 -1
- package/dist/client/{flavors-D8oElC2K.mjs → flavors-C4GtoybP.mjs} +2 -2
- package/dist/client/{flavors-D8oElC2K.mjs.map → flavors-C4GtoybP.mjs.map} +1 -1
- package/dist/client/{flavors-qvgPSI7J.mjs → flavors-CpirO_nr.mjs} +167 -148
- package/dist/client/flavors-CpirO_nr.mjs.map +1 -0
- package/dist/client/{flavors-BXPYAFyQ.mjs → flavors-DWMZ6TuJ.mjs} +2 -2
- package/dist/client/{flavors-BXPYAFyQ.mjs.map → flavors-DWMZ6TuJ.mjs.map} +1 -1
- package/dist/client/{floatingips-Fa6ocNUu.mjs → floatingips-BUf_oLRl.mjs} +74 -75
- package/dist/client/{floatingips-Fa6ocNUu.mjs.map → floatingips-BUf_oLRl.mjs.map} +1 -1
- package/dist/client/{formatBytes-tQBEnPoL.mjs → formatBytes-CZv_XyCY.mjs} +1 -1
- package/dist/client/{formatBytes-tQBEnPoL.mjs.map → formatBytes-CZv_XyCY.mjs.map} +1 -1
- package/dist/client/{helpers--JWXi40U.mjs → helpers-1PpYf-fC.mjs} +1 -1
- package/dist/client/{helpers--JWXi40U.mjs.map → helpers-1PpYf-fC.mjs.map} +1 -1
- package/dist/client/hooks-dSArr2Ca.mjs +2 -0
- package/dist/client/{images-tYfyOkX8.mjs → images-CsonlmFx.mjs} +3 -3
- package/dist/client/{images-tYfyOkX8.mjs.map → images-CsonlmFx.mjs.map} +1 -1
- package/dist/client/{images-CSFfefAu.mjs → images-Da1t5KPh.mjs} +507 -535
- package/dist/client/images-Da1t5KPh.mjs.map +1 -0
- package/dist/client/{images-DM9I8G0p.mjs → images-NBf2bV43.mjs} +2 -2
- package/dist/client/{images-DM9I8G0p.mjs.map → images-NBf2bV43.mjs.map} +1 -1
- package/dist/client/{images-CTLCY-yY.mjs → images-QnWf63uj.mjs} +2 -2
- package/dist/client/{images-CTLCY-yY.mjs.map → images-QnWf63uj.mjs.map} +1 -1
- package/dist/client/index.js +252 -258
- package/dist/client/index.js.map +1 -1
- package/dist/client/{md-BivyCkGC.mjs → md-sBiSNVSQ.mjs} +7 -7
- package/dist/client/{md-BivyCkGC.mjs.map → md-sBiSNVSQ.mjs.map} +1 -1
- package/dist/client/{network-rYLHyf15.mjs → network-DuZm76BZ.mjs} +2 -2
- package/dist/client/{network-rYLHyf15.mjs.map → network-DuZm76BZ.mjs.map} +1 -1
- package/dist/client/{objects-BciXwZ00.mjs → objects-B89dYCBq.mjs} +3 -3
- package/dist/client/{objects-BciXwZ00.mjs.map → objects-B89dYCBq.mjs.map} +1 -1
- package/dist/client/{objects-Cdew99tK.mjs → objects-CuFLUOe1.mjs} +2 -2
- package/dist/client/{objects-Cdew99tK.mjs.map → objects-CuFLUOe1.mjs.map} +1 -1
- package/dist/client/objects-H0NN_Sja.mjs +5460 -0
- package/dist/client/objects-H0NN_Sja.mjs.map +1 -0
- package/dist/client/{pca-oc7J0_Xd.mjs → pca-C-UFjicP.mjs} +42 -42
- package/dist/client/{pca-oc7J0_Xd.mjs.map → pca-C-UFjicP.mjs.map} +1 -1
- package/dist/client/{pca-COmKvp3J.mjs → pca-CtU6REww.mjs} +2 -2
- package/dist/client/{pca-COmKvp3J.mjs.map → pca-CtU6REww.mjs.map} +1 -1
- package/dist/client/{projects-Dl5XkXUP.mjs → projects-C-sjd9T5.mjs} +3 -3
- package/dist/client/{projects-Dl5XkXUP.mjs.map → projects-C-sjd9T5.mjs.map} +1 -1
- package/dist/client/{projects-BUabCzvw.mjs → projects-DNXsDnJM.mjs} +25 -21
- package/dist/client/projects-DNXsDnJM.mjs.map +1 -0
- package/dist/client/{projects-DI_L4oDw.mjs → projects-dhnQkuvV.mjs} +2 -2
- package/dist/client/{projects-DI_L4oDw.mjs.map → projects-dhnQkuvV.mjs.map} +1 -1
- package/dist/client/{projects-HoQ0gE5Y.mjs → projects-yiK0HGSA.mjs} +2 -2
- package/dist/client/{projects-HoQ0gE5Y.mjs.map → projects-yiK0HGSA.mjs.map} +1 -1
- package/dist/client/{securitygroups-BjkmHk2J.mjs → securitygroups-wHdrxZXd.mjs} +72 -73
- package/dist/client/{securitygroups-BjkmHk2J.mjs.map → securitygroups-wHdrxZXd.mjs.map} +1 -1
- package/dist/client/{trpcClient-BxguzNYF.mjs → trpcClient-BzPUgiM2.mjs} +1 -1
- package/dist/client/{trpcClient-BxguzNYF.mjs.map → trpcClient-BzPUgiM2.mjs.map} +1 -1
- package/dist/client/{useErrorTranslation-TZVwIAzq.mjs → useErrorTranslation-Dc0eE8Zt.mjs} +1 -1
- package/dist/client/{useErrorTranslation-TZVwIAzq.mjs.map → useErrorTranslation-Dc0eE8Zt.mjs.map} +1 -1
- package/dist/client/useListWithFiltering-DrgUwXef.mjs +157 -0
- package/dist/client/useListWithFiltering-DrgUwXef.mjs.map +1 -0
- package/dist/client/{useModal-DxxlilRm.mjs → useModal-DCs1OJh7.mjs} +1 -1
- package/dist/client/{useModal-DxxlilRm.mjs.map → useModal-DCs1OJh7.mjs.map} +1 -1
- package/dist/client/{useProjectId-OQv2KBbG.mjs → useProjectId-DBc5lpoU.mjs} +1 -1
- package/dist/client/{useProjectId-OQv2KBbG.mjs.map → useProjectId-DBc5lpoU.mjs.map} +1 -1
- package/dist/server/index.js +1281 -432
- package/package.json +6 -5
- package/dist/client/DeleteFlavorModal-BusYn32r.mjs.map +0 -1
- package/dist/client/ListToolbar-BojRTNbo.mjs +0 -129
- package/dist/client/ListToolbar-BojRTNbo.mjs.map +0 -1
- package/dist/client/_flavorId-BRonXvCo.mjs +0 -188
- package/dist/client/_flavorId-BRonXvCo.mjs.map +0 -1
- package/dist/client/_flavorId-BoNcxYmF.mjs.map +0 -1
- package/dist/client/_floatingIpId-DF_BSJN6.mjs.map +0 -1
- package/dist/client/_imageId-BL0I5_pv.mjs +0 -527
- package/dist/client/_imageId-BL0I5_pv.mjs.map +0 -1
- package/dist/client/_projectId-5NiasyXm.mjs +0 -26
- package/dist/client/_projectId-5NiasyXm.mjs.map +0 -1
- package/dist/client/_projectId-D35MN1kY.mjs.map +0 -1
- package/dist/client/about-DLn1ShhF.mjs +0 -92
- package/dist/client/aurora-CRcxVUCo.mjs +0 -19
- package/dist/client/containers-J7WFA18U.mjs +0 -3120
- package/dist/client/containers-J7WFA18U.mjs.map +0 -1
- package/dist/client/flavors-qvgPSI7J.mjs.map +0 -1
- package/dist/client/hooks-DEjb9d1F.mjs +0 -2
- package/dist/client/images-CSFfefAu.mjs.map +0 -1
- package/dist/client/objects-DaElrban.mjs +0 -5340
- package/dist/client/objects-DaElrban.mjs.map +0 -1
- package/dist/client/overview-BMhjFMIV.mjs +0 -15
- package/dist/client/overview-BMhjFMIV.mjs.map +0 -1
- package/dist/client/overview-BYIRj7_X.mjs +0 -15
- package/dist/client/overview-BYIRj7_X.mjs.map +0 -1
- package/dist/client/overview-DRCKNBH2.mjs +0 -15
- package/dist/client/overview-DRCKNBH2.mjs.map +0 -1
- package/dist/client/overview-urYLOVQE.mjs +0 -173
- package/dist/client/overview-urYLOVQE.mjs.map +0 -1
- package/dist/client/projects-BUabCzvw.mjs.map +0 -1
- package/dist/client/useListWithFiltering-CbhHJO4V.mjs +0 -32
- package/dist/client/useListWithFiltering-CbhHJO4V.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -18,39 +18,31 @@ npm install react react-dom fastify
|
|
|
18
18
|
|
|
19
19
|
Aurora has two entry points: `server` and `client`.
|
|
20
20
|
|
|
21
|
-
### Server
|
|
21
|
+
### Server
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
24
|
import path from "path"
|
|
25
25
|
import { createServer } from "@cobaltcore-dev/aurora/server"
|
|
26
26
|
|
|
27
|
-
createServer({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
cephRegion: process.env.CEPH_REGION, // Ceph/S3 region for object storage
|
|
34
|
-
imageMetadataExcludedProperties: process.env.IMAGE_METADATA_EXCLUDED_PROPERTIES, // comma-separated
|
|
35
|
-
insecureCookies: process.env.INSECURE_COOKIES === "true", // disable Secure flag locally
|
|
36
|
-
}).then((server) => server.listen({ host: "0.0.0.0", port: 4000 }))
|
|
27
|
+
const server = await createServer({
|
|
28
|
+
identityEndpoint: "https://keystone.example.com/v3/",
|
|
29
|
+
policyDir: path.resolve(__dirname, "../policies"),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
server.listen({ host: "0.0.0.0", port: 4000 })
|
|
37
33
|
```
|
|
38
34
|
|
|
39
|
-
### Client
|
|
35
|
+
### Client
|
|
40
36
|
|
|
41
37
|
```tsx
|
|
42
38
|
import { AuroraApp } from "@cobaltcore-dev/aurora/client"
|
|
43
|
-
import "@cobaltcore-dev/aurora/client/style.css" // include once at your app root
|
|
44
39
|
|
|
45
40
|
export function App() {
|
|
46
41
|
return (
|
|
47
42
|
<AuroraApp
|
|
48
|
-
bffEndpoint="/polaris-bff"
|
|
49
|
-
theme="theme-light"
|
|
50
|
-
onThemeChange={(theme) =>
|
|
51
|
-
// called when user toggles — persist however you like
|
|
52
|
-
localStorage.setItem("theme", theme)
|
|
53
|
-
}}
|
|
43
|
+
bffEndpoint="/polaris-bff"
|
|
44
|
+
theme="theme-light"
|
|
45
|
+
onThemeChange={(theme) => localStorage.setItem("theme", theme)}
|
|
54
46
|
/>
|
|
55
47
|
)
|
|
56
48
|
}
|
|
@@ -60,80 +52,84 @@ export function App() {
|
|
|
60
52
|
|
|
61
53
|
### `createServer(config)`
|
|
62
54
|
|
|
63
|
-
| Option | Type | Default | Description |
|
|
64
|
-
| --------------------------------- | --------- | -------------------------- | ---------------------------------------------------------------- |
|
|
65
|
-
| `identityEndpoint` | `string` | — | OpenStack Keystone v3 URL
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
55
|
+
| Option | Type | Required | Default | Description |
|
|
56
|
+
| --------------------------------- | --------- | -------- | -------------------------- | ---------------------------------------------------------------- |
|
|
57
|
+
| `identityEndpoint` | `string` | yes | — | OpenStack Keystone v3 URL |
|
|
58
|
+
| `policyDir` | `string` | yes | — | Absolute path to a directory of OpenStack policy YAML files |
|
|
59
|
+
| `bffEndpoint` | `string` | no | `"/polaris-bff"` | URL prefix for all tRPC routes |
|
|
60
|
+
| `viteRoot` | `string` | no | — | Directory that contains `dist/client/` in production |
|
|
61
|
+
| `defaultEndpointInterface` | `string` | no | `"public"` | OpenStack service catalog interface |
|
|
62
|
+
| `proxyUrl` | `string` | no | — | HTTP proxy for OpenStack calls (dev only, ignored in production) |
|
|
63
|
+
| `cephRegion` | `string` | no | — | Ceph RGW region for S3 operations |
|
|
64
|
+
| `imageMetadataExcludedProperties` | `string` | no | — | Comma-separated image metadata keys to hide in the UI |
|
|
65
|
+
| `cookieName` | `string` | no | `"dashboard-session-auth"` | Override the session cookie name |
|
|
66
|
+
| `crossDomainCookie` | `boolean` | no | `true` | Share cookie across subdomains |
|
|
67
|
+
| `insecureCookies` | `boolean` | no | `false` | Disable `Secure` flag — only for HTTP-only local dev |
|
|
75
68
|
|
|
76
69
|
### `<AuroraApp />`
|
|
77
70
|
|
|
78
|
-
| Prop | Type | Default | Description
|
|
79
|
-
| --------------- | ------------------------------- | ---------------- |
|
|
80
|
-
| `bffEndpoint` | `string` | `"/polaris-bff"` | Must match the server's `bffEndpoint`
|
|
81
|
-
| `theme` | `"theme-light" \| "theme-dark"` | `"theme-light"` | Initial theme
|
|
82
|
-
| `onThemeChange` | `(theme) => void` | — | Called when the user toggles the theme
|
|
71
|
+
| Prop | Type | Default | Description |
|
|
72
|
+
| --------------- | ------------------------------- | ---------------- | -------------------------------------------------- |
|
|
73
|
+
| `bffEndpoint` | `string` | `"/polaris-bff"` | Must match the server's `bffEndpoint` |
|
|
74
|
+
| `theme` | `"theme-light" \| "theme-dark"` | `"theme-light"` | Initial theme |
|
|
75
|
+
| `onThemeChange` | `(theme) => void` | — | Called when the user toggles the theme |
|
|
76
|
+
| `appName` | `string` | `"Aurora"` | App name shown in the header breadcrumb and logo |
|
|
77
|
+
| `slots` | `Slots` | — | Optional UI extension points — see [Slots](#slots) |
|
|
83
78
|
|
|
84
|
-
##
|
|
79
|
+
## Slots
|
|
85
80
|
|
|
86
|
-
|
|
81
|
+
Slots let you inject your own React components into specific locations inside `AuroraApp` without forking the package. Each slot receives an `auroraContext` object with a `client` (tRPC client) for making API calls.
|
|
87
82
|
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
DEFAULT_ENDPOINT_INTERFACE="public"
|
|
91
|
-
BFF_ENDPOINT="/polaris-bff"
|
|
92
|
-
PORT="4000"
|
|
83
|
+
```tsx
|
|
84
|
+
import type { SlotProps } from "@cobaltcore-dev/aurora/client"
|
|
93
85
|
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
function MyLogo(_props: SlotProps) {
|
|
87
|
+
return <img src="/my-logo.svg" alt="My App" style={{ height: "1.5rem" }} />
|
|
88
|
+
}
|
|
96
89
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
function MyBanner({ auroraContext }: SlotProps) {
|
|
91
|
+
// auroraContext.client gives you access to the tRPC API
|
|
92
|
+
return <div>Custom sidebar content</div>
|
|
93
|
+
}
|
|
101
94
|
|
|
102
|
-
|
|
95
|
+
function MyFooter(_props: SlotProps) {
|
|
96
|
+
return (
|
|
97
|
+
<footer>
|
|
98
|
+
<a href="/imprint">Imprint</a> · <a href="/privacy">Privacy</a>
|
|
99
|
+
</footer>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
;<AuroraApp
|
|
104
|
+
slots={{
|
|
105
|
+
logo: MyLogo,
|
|
106
|
+
sideNavBanner: MyBanner,
|
|
107
|
+
pageFooter: MyFooter,
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
106
110
|
```
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
<AuroraApp bffEndpoint={import.meta.env.VITE_BFF_ENDPOINT} />
|
|
110
|
-
```
|
|
112
|
+
### Available slots
|
|
111
113
|
|
|
112
|
-
|
|
114
|
+
| Slot | Location | Renders in shadow DOM |
|
|
115
|
+
| --------------- | ----------------------------------------------- | --------------------- |
|
|
116
|
+
| `logo` | Page header, replacing the default Aurora logo | No |
|
|
117
|
+
| `sideNavBanner` | Bottom of the project side navigation | Yes |
|
|
118
|
+
| `pageFooter` | Page footer, replacing the default empty footer | No |
|
|
113
119
|
|
|
114
|
-
|
|
120
|
+
**Shadow DOM isolation:** Slots rendered in a shadow DOM cannot inherit styles from the host page. If your slot component uses a CSS framework, inject the styles inline:
|
|
115
121
|
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
import { defineConfig } from "vite"
|
|
119
|
-
import react from "@vitejs/plugin-react-swc"
|
|
120
|
-
import viteFastify from "@fastify/vite/plugin"
|
|
121
|
-
|
|
122
|
-
export default defineConfig(({ mode }) => ({
|
|
123
|
-
root: "./src/client",
|
|
124
|
-
build: { outDir: "../../dist/client" },
|
|
125
|
-
plugins: [mode !== "production" && viteFastify(), react()],
|
|
126
|
-
}))
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
## Running the app
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
# Development (hot-reload)
|
|
133
|
-
tsx watch --env-file=.env src/server/server.ts
|
|
122
|
+
```tsx
|
|
123
|
+
import styles from "my-lib/styles.css?inline"
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
function MyBanner(_props: SlotProps) {
|
|
126
|
+
return (
|
|
127
|
+
<>
|
|
128
|
+
<style>{styles}</style>
|
|
129
|
+
<div>...</div>
|
|
130
|
+
</>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
137
133
|
```
|
|
138
134
|
|
|
139
135
|
## License
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { TrpcClient } from './trpcClient';
|
|
3
|
+
/** Context object passed to every slot component. */
|
|
3
4
|
export type SlotProps = {
|
|
4
5
|
auroraContext: {
|
|
6
|
+
/** tRPC client for making API calls to the Aurora BFF. */
|
|
5
7
|
client: TrpcClient;
|
|
6
8
|
};
|
|
7
9
|
};
|
|
10
|
+
/** Named extension points where consumers can inject their own React components. */
|
|
8
11
|
export type Slots = {
|
|
12
|
+
/** Replaces the default Aurora logo in the page header. Renders outside shadow DOM — inherits header styles. */
|
|
13
|
+
logo?: FC<SlotProps>;
|
|
14
|
+
/** Rendered at the bottom of the project side navigation. Renders inside a shadow DOM. */
|
|
9
15
|
sideNavBanner?: FC<SlotProps>;
|
|
16
|
+
/** Replaces the default page footer. Renders outside shadow DOM — inherits page styles. */
|
|
17
|
+
pageFooter?: FC<SlotProps>;
|
|
10
18
|
};
|
|
19
|
+
/** Props for the top-level `<AuroraApp />` component. */
|
|
11
20
|
export type AuroraAppProps = {
|
|
21
|
+
/** Initial theme. Defaults to `"theme-light"`. */
|
|
12
22
|
theme?: "theme-dark" | "theme-light";
|
|
23
|
+
/** URL prefix for all tRPC routes. Must match the server's `bffEndpoint`. Defaults to `"/polaris-bff"`. */
|
|
13
24
|
bffEndpoint?: string;
|
|
25
|
+
/** Called when the user toggles the theme. Use this to persist the selection. */
|
|
14
26
|
onThemeChange?: (theme: "theme-dark" | "theme-light") => void;
|
|
27
|
+
/** Optional UI extension points. */
|
|
15
28
|
slots?: Slots;
|
|
29
|
+
/** App name shown in the header breadcrumb and as the default logo title. Defaults to `"Aurora"`. */
|
|
30
|
+
appName?: string;
|
|
16
31
|
};
|
|
17
32
|
export declare const AuroraApp: FC<AuroraAppProps>;
|
|
@@ -2,7 +2,7 @@ import { jsx as e } from "react/jsx-runtime";
|
|
|
2
2
|
import t, { useCallback as n, useEffect as r, useRef as i, useState as a } from "react";
|
|
3
3
|
import { useRouter as o } from "@tanstack/react-router";
|
|
4
4
|
//#region src/client/store/AuthProvider.tsx
|
|
5
|
-
var s =
|
|
5
|
+
var s = /*#__PURE__*/ t.createContext(null), c = 3600 * 1e3;
|
|
6
6
|
function l({ children: l }) {
|
|
7
7
|
let u = o(), [d, f] = t.useState(null), [p, m] = t.useState(void 0), [h, g] = t.useState(void 0), [_, v] = a(!1), [y, b] = a(void 0), x = i(null), S = i(null), C = !!d, w = n(() => {
|
|
8
8
|
x.current &&= (clearTimeout(x.current), null);
|
|
@@ -74,7 +74,7 @@ function l({ children: l }) {
|
|
|
74
74
|
C,
|
|
75
75
|
O,
|
|
76
76
|
T
|
|
77
|
-
]),
|
|
77
|
+
]), /*#__PURE__*/ e(s.Provider, {
|
|
78
78
|
value: {
|
|
79
79
|
isAuthenticated: C,
|
|
80
80
|
user: d,
|
|
@@ -97,4 +97,4 @@ function u() {
|
|
|
97
97
|
//#endregion
|
|
98
98
|
export { u as n, l as t };
|
|
99
99
|
|
|
100
|
-
//# sourceMappingURL=AuthProvider-
|
|
100
|
+
//# sourceMappingURL=AuthProvider-Co4d0WzB.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthProvider-
|
|
1
|
+
{"version":3,"file":"AuthProvider-Co4d0WzB.mjs","names":["React","useEffect","useRef","useCallback","useState","useRouter","AuthContext","createContext","INACTIVITY_TIMEOUT","AuthProvider","children","router","user","setUser","expiresAt","setExpiresAt","undefined","logoutReason","setLogoutReason","showInactivityModal","setShowInactivityModal","redirectAfterModal","setRedirectAfterModal","logoutTimerRef","inactivityTimerRef","isAuthenticated","clearLogoutTimer","current","clearTimeout","clearInactivityTimer","closeInactivityModal","navigate","to","search","redirect","logout","reason","currentPath","window","location","pathname","startsWith","invalidate","resetInactivityTimer","setTimeout","login","expires_at","expiration","Date","timeUntilExpiry","getTime","now","events","handleActivity","forEach","event","document","addEventListener","removeEventListener","Provider","value","useAuth","context","useContext","Error"],"sources":["../../src/client/store/AuthProvider.tsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback, useState } from \"react\"\nimport { TokenData } from \"../../server/Authentication/types/models\"\nimport { useRouter } from \"@tanstack/react-router\"\n\nexport type User = TokenData[\"user\"] | null\n\nexport interface AuthContext {\n isAuthenticated: boolean\n login: (user: User, expires_at?: string) => Promise<void>\n logout: (reason?: \"inactive\" | \"expired\" | \"manual\") => Promise<void>\n user?: User\n expiresAt?: Date\n logoutReason?: \"inactive\" | \"expired\" | \"manual\"\n showInactivityModal: boolean\n closeInactivityModal: () => void\n redirectAfterModal?: string\n}\n\nconst AuthContext = React.createContext<AuthContext | null>(null)\n\nconst INACTIVITY_TIMEOUT = 60 * 60 * 1000 // 60 minutes\n\nexport function AuthProvider({ children }: { children: React.ReactNode }) {\n const router = useRouter()\n const [user, setUser] = React.useState<User | null>(null)\n const [expiresAt, setExpiresAt] = React.useState<Date | undefined>(undefined)\n const [logoutReason, setLogoutReason] = React.useState<\"inactive\" | \"expired\" | \"manual\" | undefined>(undefined)\n const [showInactivityModal, setShowInactivityModal] = useState(false)\n const [redirectAfterModal, setRedirectAfterModal] = useState<string | undefined>(undefined)\n\n const logoutTimerRef = useRef<NodeJS.Timeout | null>(null)\n const inactivityTimerRef = useRef<NodeJS.Timeout | null>(null)\n\n const isAuthenticated = !!user\n\n const clearLogoutTimer = useCallback(() => {\n if (logoutTimerRef.current) {\n clearTimeout(logoutTimerRef.current)\n logoutTimerRef.current = null\n }\n }, [])\n\n const clearInactivityTimer = useCallback(() => {\n if (inactivityTimerRef.current) {\n clearTimeout(inactivityTimerRef.current)\n inactivityTimerRef.current = null\n }\n }, [])\n\n const closeInactivityModal = useCallback(() => {\n setShowInactivityModal(false)\n\n router.navigate({\n to: \"/\",\n search: redirectAfterModal ? { redirect: redirectAfterModal } : undefined,\n })\n }, [redirectAfterModal])\n\n const logout = useCallback(\n async (reason: \"inactive\" | \"expired\" | \"manual\" = \"manual\") => {\n clearLogoutTimer()\n clearInactivityTimer()\n\n setUser(null)\n setExpiresAt(undefined)\n setLogoutReason(reason)\n\n // For inactive/expired: Show modal instead of direct navigation\n if (reason === \"inactive\" || reason === \"expired\") {\n const currentPath = window.location.pathname + window.location.search\n if (currentPath && currentPath.startsWith(\"/\")) {\n setRedirectAfterModal(currentPath)\n }\n\n setShowInactivityModal(true)\n } else {\n // Manual logout: direct navigation\n router.invalidate()\n }\n },\n [clearLogoutTimer, clearInactivityTimer]\n )\n\n const resetInactivityTimer = useCallback(() => {\n if (!isAuthenticated) return\n\n clearInactivityTimer()\n\n inactivityTimerRef.current = setTimeout(() => {\n logout(\"inactive\")\n }, INACTIVITY_TIMEOUT)\n }, [isAuthenticated, clearInactivityTimer, logout])\n\n const login = useCallback(\n async (user: User, expires_at?: string) => {\n setUser(user)\n setLogoutReason(undefined)\n setShowInactivityModal(false)\n setRedirectAfterModal(undefined)\n\n if (expires_at) {\n const expiration = new Date(expires_at)\n setExpiresAt(expiration)\n } else {\n setExpiresAt(undefined)\n }\n\n resetInactivityTimer()\n },\n [resetInactivityTimer]\n )\n\n useEffect(() => {\n clearLogoutTimer()\n\n if (user && expiresAt) {\n const timeUntilExpiry = expiresAt.getTime() - Date.now()\n\n if (timeUntilExpiry <= 0) {\n logout(\"expired\")\n return\n }\n\n logoutTimerRef.current = setTimeout(() => {\n logout(\"expired\")\n }, timeUntilExpiry)\n }\n\n return () => {\n clearLogoutTimer()\n }\n }, [user, expiresAt, logout, clearLogoutTimer])\n\n useEffect(() => {\n if (!isAuthenticated) {\n clearInactivityTimer()\n return\n }\n\n const events = [\"mousedown\", \"mousemove\", \"keypress\", \"scroll\", \"touchstart\", \"click\"]\n\n const handleActivity = () => {\n resetInactivityTimer()\n }\n\n resetInactivityTimer()\n\n events.forEach((event) => {\n document.addEventListener(event, handleActivity, true)\n })\n\n return () => {\n clearInactivityTimer()\n events.forEach((event) => {\n document.removeEventListener(event, handleActivity, true)\n })\n }\n }, [isAuthenticated, resetInactivityTimer, clearInactivityTimer])\n\n return (\n <AuthContext.Provider\n value={{\n isAuthenticated,\n user,\n login,\n logout,\n expiresAt,\n logoutReason,\n showInactivityModal,\n closeInactivityModal,\n redirectAfterModal,\n }}\n >\n {children}\n </AuthContext.Provider>\n )\n}\n\nexport function useAuth() {\n const context = React.useContext(AuthContext)\n if (!context) {\n throw new Error(\"useAuth must be used within an AuthProvider\")\n }\n return context\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as e, P as t, Z as n, i as r, j as i, nt as a, rt as o } from "./build-
|
|
1
|
+
import { A as e, P as t, Z as n, i as r, j as i, nt as a, rt as o } from "./build-DracvfrJ.mjs";
|
|
2
2
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
3
3
|
import { useState as l } from "react";
|
|
4
4
|
import { Trans as u, useLingui as d } from "@lingui/react";
|
|
@@ -12,12 +12,12 @@ var f = ({ text: i, tooltipContent: o, className: u, truncateAt: f, showTooltip:
|
|
|
12
12
|
console.error("Failed to copy text:", e);
|
|
13
13
|
}
|
|
14
14
|
}, C = f && i.length > f ? `${i.slice(0, f)}...` : i, w = () => _ ? o || h._({ id: "u+VWhB" }) : h._({ id: "he3ygx" }), T = _ && p || y && p;
|
|
15
|
-
return
|
|
15
|
+
return /*#__PURE__*/ s("div", {
|
|
16
16
|
...m,
|
|
17
17
|
className: x,
|
|
18
|
-
children:
|
|
18
|
+
children: /*#__PURE__*/ c(n, {
|
|
19
19
|
open: T,
|
|
20
|
-
children: [
|
|
20
|
+
children: [/*#__PURE__*/ s(t, {
|
|
21
21
|
onClick: S,
|
|
22
22
|
onMouseEnter: () => !_ && b(!0),
|
|
23
23
|
onMouseLeave: () => b(!1),
|
|
@@ -28,54 +28,54 @@ var f = ({ text: i, tooltipContent: o, className: u, truncateAt: f, showTooltip:
|
|
|
28
28
|
className: "cursor-pointer",
|
|
29
29
|
asChild: !0,
|
|
30
30
|
"data-testid": "clipboard-copy-trigger",
|
|
31
|
-
children:
|
|
31
|
+
children: /*#__PURE__*/ s("div", {
|
|
32
32
|
className: "group",
|
|
33
|
-
children:
|
|
33
|
+
children: /*#__PURE__*/ c(a, {
|
|
34
34
|
direction: "horizontal",
|
|
35
35
|
gap: "1",
|
|
36
36
|
className: "items-center hover:underline",
|
|
37
|
-
children: [
|
|
37
|
+
children: [/*#__PURE__*/ s("span", {
|
|
38
38
|
className: "select-none",
|
|
39
39
|
children: C
|
|
40
|
-
}),
|
|
40
|
+
}), /*#__PURE__*/ s(r, {
|
|
41
41
|
icon: _ ? "check" : "contentCopy",
|
|
42
42
|
size: "18"
|
|
43
43
|
})]
|
|
44
44
|
})
|
|
45
45
|
})
|
|
46
|
-
}),
|
|
46
|
+
}), /*#__PURE__*/ s(e, { children: w() })]
|
|
47
47
|
})
|
|
48
48
|
});
|
|
49
49
|
};
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region src/client/components/ContentHeader/ContentHeader.tsx
|
|
52
52
|
function p({ title: e, projectId: t, actions: n }) {
|
|
53
|
-
return
|
|
54
|
-
|
|
53
|
+
return /*#__PURE__*/ c("header", { children: [
|
|
54
|
+
/*#__PURE__*/ c("div", {
|
|
55
55
|
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between",
|
|
56
|
-
children: [
|
|
56
|
+
children: [/*#__PURE__*/ s(i, { children: e }), /*#__PURE__*/ c("div", {
|
|
57
57
|
className: "text-theme-light flex items-center gap-1 text-sm",
|
|
58
|
-
children: [
|
|
58
|
+
children: [/*#__PURE__*/ c("span", {
|
|
59
59
|
className: "font-semibold",
|
|
60
60
|
children: [
|
|
61
|
-
|
|
61
|
+
/*#__PURE__*/ s(u, { id: "mSfwLL" }),
|
|
62
62
|
":",
|
|
63
63
|
" "
|
|
64
64
|
]
|
|
65
|
-
}),
|
|
65
|
+
}), /*#__PURE__*/ s(f, {
|
|
66
66
|
text: t,
|
|
67
67
|
truncateAt: 15
|
|
68
68
|
})]
|
|
69
69
|
})]
|
|
70
70
|
}),
|
|
71
|
-
|
|
72
|
-
n &&
|
|
73
|
-
className: "mt-
|
|
71
|
+
/*#__PURE__*/ s(o, { className: "mt-4" }),
|
|
72
|
+
n && /*#__PURE__*/ s("div", {
|
|
73
|
+
className: "mt-3 flex justify-end",
|
|
74
74
|
children: n
|
|
75
75
|
})
|
|
76
76
|
] });
|
|
77
77
|
}
|
|
78
78
|
//#endregion
|
|
79
|
-
export { p as t };
|
|
79
|
+
export { f as n, p as t };
|
|
80
80
|
|
|
81
|
-
//# sourceMappingURL=ContentHeader-
|
|
81
|
+
//# sourceMappingURL=ContentHeader-xQVhO2yT.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentHeader-
|
|
1
|
+
{"version":3,"file":"ContentHeader-xQVhO2yT.mjs","names":["React","useState","Tooltip","TooltipTrigger","TooltipContent","Icon","Stack","ClipboardText","text","tooltipContent","className","truncateAt","showTooltip","props","useLingui","copied","setCopied","isHovering","setIsHovering","combinedClassName","handleCopy","e","preventDefault","stopPropagation","navigator","clipboard","writeText","setTimeout","err","console","error","displayText","length","slice","getTooltipContent","t","tooltipIsOpen","div","open","onClick","onMouseEnter","onMouseLeave","aria-label","asChild","data-testid","direction","gap","span","icon","size","Divider","ContentHeading","ClipboardText","ContentHeader","title","projectId","actions","header","div","className","span","text","truncateAt"],"sources":["../../src/client/components/ClipboardText.tsx","../../src/client/components/ContentHeader/ContentHeader.tsx"],"sourcesContent":["import React, { useState } from \"react\"\nimport { Tooltip, TooltipTrigger, TooltipContent, Icon, Stack } from \"@cloudoperators/juno-ui-components\"\nimport { useLingui } from \"@lingui/react/macro\"\n\nexport interface ClipboardTextProps extends React.HTMLAttributes<HTMLDivElement> {\n tooltipContent?: string\n text: string\n className?: string\n truncateAt?: number\n showTooltip?: boolean\n}\n\nconst ClipboardText: React.FC<ClipboardTextProps> = ({\n text,\n tooltipContent,\n className,\n truncateAt,\n showTooltip = true,\n ...props\n}) => {\n const { t } = useLingui()\n const [copied, setCopied] = useState(false)\n const [isHovering, setIsHovering] = useState(false)\n\n const combinedClassName = `copyableTooltip inline-flex items-center ${className || \"\"}`\n\n const handleCopy = async (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setIsHovering(false)\n setTimeout(() => setCopied(false), 2000)\n } catch (err) {\n console.error(\"Failed to copy text:\", err)\n }\n }\n\n const displayText = truncateAt && text.length > truncateAt ? `${text.slice(0, truncateAt)}...` : text\n\n // Determine tooltip content based on state\n const getTooltipContent = () => {\n if (copied) {\n return tooltipContent || t`Copied to clipboard!`\n }\n return t`Copy`\n }\n\n const tooltipIsOpen = (copied && showTooltip) || (isHovering && showTooltip)\n\n return (\n <div {...props} className={combinedClassName}>\n <Tooltip open={tooltipIsOpen}>\n <TooltipTrigger\n onClick={handleCopy}\n onMouseEnter={() => !copied && setIsHovering(true)}\n onMouseLeave={() => setIsHovering(false)}\n aria-label={t`Copy ${text} to clipboard`}\n className=\"cursor-pointer\"\n asChild\n data-testid=\"clipboard-copy-trigger\"\n >\n <div className=\"group\">\n <Stack direction=\"horizontal\" gap=\"1\" className=\"items-center hover:underline\">\n <span className=\"select-none\">{displayText}</span>\n <Icon icon={copied ? \"check\" : \"contentCopy\"} size=\"18\" />\n </Stack>\n </div>\n </TooltipTrigger>\n <TooltipContent>{getTooltipContent()}</TooltipContent>\n </Tooltip>\n </div>\n )\n}\n\nexport default ClipboardText\n","import type { ReactNode } from \"react\"\nimport { Divider, ContentHeading } from \"@cloudoperators/juno-ui-components\"\nimport { Trans } from \"@lingui/react/macro\"\nimport ClipboardText from \"../ClipboardText\"\n\ninterface ContentHeaderProps {\n title: string\n projectId: string\n actions?: ReactNode\n}\n\nexport function ContentHeader({ title, projectId, actions }: ContentHeaderProps) {\n return (\n <header>\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n <ContentHeading>{title}</ContentHeading>\n <div className=\"text-theme-light flex items-center gap-1 text-sm\">\n <span className=\"font-semibold\">\n <Trans>Project ID</Trans>:{\" \"}\n </span>\n <ClipboardText text={projectId} truncateAt={15} />\n </div>\n </div>\n <Divider className=\"mt-4\" />\n {actions && <div className=\"mt-3 flex justify-end\">{actions}</div>}\n </header>\n )\n}\n"],"mappings":";;;;;AAYA,IAAMO,KAA+C,EACnDC,SACAC,mBACAC,cACAC,eACAC,iBAAc,IACd,GAAGC,QACJ;CACC,IAAM,EAAA,MAAA,GAAA,GAAA,MAAQC,EAAAA,GACR,CAACC,GAAQC,KAAaf,EAAS,EAAA,GAC/B,CAACgB,GAAYC,KAAiBjB,EAAS,EAAA,GAEvCkB,IAAoB,6CAA6CT,KAAa,MAE9EU,IAAa,OAAOC,MAAAA;EAExBA,AADAA,EAAEC,eAAc,GAChBD,EAAEE,gBAAe;EAEjB,IAAI;GAIFI,AAHA,MAAMH,UAAUC,UAAUC,UAAUlB,CAAAA,GACpCQ,EAAU,EAAA,GACVE,EAAc,EAAA,GACdS,iBAAiBX,EAAU,EAAA,GAAQ,GAAA;EACrC,SAASY,GAAK;GACZC,QAAQC,MAAM,wBAAwBF,CAAAA;EACxC;CACF,GAEMG,IAAcpB,KAAcH,EAAKwB,SAASrB,IAAa,GAAGH,EAAKyB,MAAM,GAAGtB,CAAAA,EAAY,OAAOH,GAG3F0B,UACAnB,IACKN,KAAkB0B,EAAAA,EAAC,EAAA,IAAA,SAAqB,CAAA,IAE1CA,EAAAA,EAAC,EAAA,IAAA,SAAK,CAAA,GAGTC,IAAgB,KAAWxB,KAAiBK,KAAcL;CAEhE,OACE,gBAACyB,OAAAA;EAAK,GAAGxB;EAAOH,WAAWS;YACzB,gBAACjB,GAAAA;GAAQoC,MAAMF;cACb,gBAACjC,GAAAA;IACCoC,SAASnB;IACToB,oBAAoB,CAACzB,KAAUG,EAAc,EAAA;IAC7CuB,oBAAoBvB,EAAc,EAAA;IAClCwB,cAAYP,EAAAA,EAAC;;eAAQ3B,QAAAA;IAAkB,CAAA;IACvCE,WAAU;IACViC,SAAO;IACPC,eAAY;cAEZ,gBAACP,OAAAA;KAAI3B,WAAU;eACb,gBAACJ,GAAAA;MAAMuC,WAAU;MAAaC,KAAI;MAAIpC,WAAU;iBAC9C,gBAACqC,QAAAA;OAAKrC,WAAU;iBAAeqB;UAC/B,gBAAC1B,GAAAA;OAAK2C,MAAMjC,IAAS,UAAU;OAAekC,MAAK;;;;OAIzD,gBAAC7C,GAAAA,EAAAA,UAAgB8B,EAAAA,EAAAA,CAAAA,CAAAA;;;AAIzB;;;AChEA,SAAgBmB,EAAc,EAAEC,UAAOC,cAAWC,cAA6B;CAC7E,OACE,gBAACC,UAAAA,EAAAA,UAAAA;EACC,gBAACC,OAAAA;GAAIC,WAAU;cACb,gBAACR,GAAAA,EAAAA,UAAgBG,EAAAA,CAAAA,GACjB,gBAACI,OAAAA;IAAIC,WAAU;eACb,gBAACC,QAAAA;KAAKD,WAAU;;MACd,gBAAA,GAAA,EAAA,IAAA,SAAA,CAAA;MAAyB;MAAE;;QAE7B,gBAACP,GAAAA;KAAcS,MAAMN;KAAWO,YAAY;;;;EAGhD,gBAACZ,GAAAA,EAAQS,WAAU,OAAA,CAAA;EAClBH,KAAW,gBAACE,OAAAA;GAAIC,WAAU;aAAyBH;;;AAG1D"}
|