@braidlabs/console 0.3.0 → 0.4.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 +34 -10
- package/package.json +10 -4
- package/src/app/auth.d.ts +46 -0
- package/src/app/auth.js +80 -0
- package/src/app/auth.js.map +1 -0
- package/src/app/console-app.d.ts +8 -6
- package/src/app/console-app.js +91 -20
- package/src/app/console-app.js.map +1 -1
- package/src/app/main.js +25 -2
- package/src/app/main.js.map +1 -1
- package/src/app/routes.d.ts +14 -0
- package/src/app/routes.js +23 -0
- package/src/app/routes.js.map +1 -0
- package/src/index.d.ts +15 -2
- package/src/index.js +10 -2
- package/src/index.js.map +1 -1
- package/src/lib/client.d.ts +52 -1
- package/src/lib/client.js +48 -0
- package/src/lib/client.js.map +1 -1
- package/src/lib/draft.d.ts +1 -1
- package/src/lib/draft.js +2 -2
- package/src/lib/draft.js.map +1 -1
- package/src/lib/empty-state.d.ts +15 -0
- package/src/lib/empty-state.js +38 -0
- package/src/lib/empty-state.js.map +1 -0
- package/src/lib/history-panel.d.ts +19 -0
- package/src/lib/history-panel.js +85 -0
- package/src/lib/history-panel.js.map +1 -0
- package/src/lib/ownership.d.ts +15 -0
- package/src/lib/ownership.js +21 -0
- package/src/lib/ownership.js.map +1 -0
- package/src/lib/query.d.ts +47 -0
- package/src/lib/query.js +121 -0
- package/src/lib/query.js.map +1 -0
- package/src/lib/registry-console.d.ts +13 -2
- package/src/lib/registry-console.js +15 -11
- package/src/lib/registry-console.js.map +1 -1
- package/src/lib/registry-editor.js +20 -7
- package/src/lib/registry-editor.js.map +1 -1
- package/src/lib/shell-codegen.d.ts +28 -0
- package/src/lib/shell-codegen.js +316 -0
- package/src/lib/shell-codegen.js.map +1 -0
- package/src/lib/shells-panel.d.ts +43 -0
- package/src/lib/shells-panel.js +307 -0
- package/src/lib/shells-panel.js.map +1 -0
- package/src/lib/styles.d.ts +1 -1
- package/src/lib/styles.js +72 -4
- package/src/lib/styles.js.map +1 -1
- package/src/lib/tag-chip.d.ts +8 -0
- package/src/lib/tag-chip.js +12 -0
- package/src/lib/tag-chip.js.map +1 -0
- package/src/lib/tags.d.ts +10 -0
- package/src/lib/tags.js +53 -0
- package/src/lib/tags.js.map +1 -0
- package/src/lib/topology-graph.d.ts +5 -2
- package/src/lib/topology-graph.js +17 -8
- package/src/lib/topology-graph.js.map +1 -1
- package/src/lib/topology.d.ts +18 -3
- package/src/lib/topology.js +42 -3
- package/src/lib/topology.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# @braidlabs/console
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
3
|
+
A console for a [Braid](../braid-gateway) gateway's registry: fragments, the composition map,
|
|
4
|
+
**shells** designed as data, and snapshot history with rollback. One package, two shapes: mountable
|
|
5
|
+
React components, and a standalone deployable app with optional OIDC (Okta) sign-in.
|
|
5
6
|
|
|
6
|
-
**
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
**Viewing needs nothing deployed.** The fragment list and map read the `/__braid/registry`
|
|
8
|
+
discovery endpoint the gateway already serves. Shells, history and editing need the registry write
|
|
9
|
+
API from [`@braidlabs/registry`](../braid-registry); without it those views say what to mount.
|
|
10
|
+
|
|
11
|
+
The full guide — the layout designer, query syntax, Okta setup, and how an enterprise runs it — is
|
|
12
|
+
[docs/packages/console.md](../../docs/packages/console.md).
|
|
9
13
|
|
|
10
14
|
## As a library
|
|
11
15
|
|
|
@@ -67,7 +71,7 @@ directions, because an admin shell may be dark inside a light OS.
|
|
|
67
71
|
viewport's. In a 420px sidebar it stacks — on a 1280px screen.
|
|
68
72
|
|
|
69
73
|
**Slim is a number.** 140 kB gzipped for the app bundle including React and the inlined
|
|
70
|
-
stylesheet, enforced by `nx size braid-console`. Currently
|
|
74
|
+
stylesheet, enforced by `nx size braid-console`. Currently 105 kB, with the OIDC client in a separate chunk loaded only when sign-in is configured. React is a peer dependency in
|
|
71
75
|
library form, so a host never ships two copies.
|
|
72
76
|
|
|
73
77
|
## Editing
|
|
@@ -123,9 +127,29 @@ but not load is a legitimate state — a launcher should render it, not hide it.
|
|
|
123
127
|
is in development mode the listing skips access filtering entirely, which the console says out
|
|
124
128
|
loud rather than letting you mistake a dev listing for a production one.
|
|
125
129
|
|
|
130
|
+
## Shells, search, and sign-in
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { ShellsPanel, HistoryPanel } from '@braidlabs/console';
|
|
134
|
+
|
|
135
|
+
<ShellsPanel api={api} selected={shellId} onSelect={setShellId} />
|
|
136
|
+
<HistoryPanel api={api} />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- **`ShellsPanel`** lists shells and opens a designer: routes, a layout typed as ASCII art that *is*
|
|
140
|
+
CSS `grid-template-areas` with a live grid preview, a fragment per area, the document head as
|
|
141
|
+
data (never loaded into this page), and generated host code for React, Angular, Angular SSR and
|
|
142
|
+
plain HTML. Publishing sends `baseId`, so a stale draft is refused rather than overwriting.
|
|
143
|
+
- **`HistoryPanel`** lists snapshots with their server-recorded publisher. Rollback is pinning one.
|
|
144
|
+
- **Query syntax** in every filter: `tag:` `type:` `framework:` `route:` `adapter:` `is:gated`
|
|
145
|
+
`is:unrouted`, `-` to negate, quotes for spaces. Tags are colored from their text, the same
|
|
146
|
+
everywhere.
|
|
147
|
+
- **Sign-in** is the standalone app's alone: add `"auth": { "issuer", "clientId" }` to the page
|
|
148
|
+
config and it signs in with Authorization Code + PKCE, loading the OIDC client only then. The
|
|
149
|
+
library still never logs in; `GET /permissions` only decides which buttons to draw.
|
|
150
|
+
|
|
126
151
|
## Related
|
|
127
152
|
|
|
128
|
-
- [`@braidlabs/registry`](../braid-registry) — snapshots
|
|
129
|
-
|
|
130
|
-
- [the
|
|
131
|
-
deliberately optional, and the line it must not cross
|
|
153
|
+
- [`@braidlabs/registry`](../braid-registry) — snapshots, shells, analysis, the write API, and
|
|
154
|
+
`@braidlabs/registry/oidc`
|
|
155
|
+
- [the guide](../../docs/packages/console.md) — including how an enterprise deploys and governs it
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@braidlabs/console",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "A console for a Braid gateway: fragments, shells as data, a composition map, and snapshot history. Mountable React components, or a standalone app with OIDC sign-in.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"braid",
|
|
7
7
|
"micro-frontends",
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@braidlabs/gateway": "^0.
|
|
25
|
+
"@braidlabs/gateway": "^0.4.0",
|
|
26
26
|
"react": "^18.0.0 || ^19.0.0",
|
|
27
27
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
28
|
-
"@braidlabs/registry": "^0.
|
|
28
|
+
"@braidlabs/registry": "^0.4.0",
|
|
29
|
+
"oidc-client-ts": "^3.5.0"
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
31
32
|
"access": "public"
|
|
@@ -39,5 +40,10 @@
|
|
|
39
40
|
"bugs": {
|
|
40
41
|
"url": "https://github.com/braidjs/braid/issues"
|
|
41
42
|
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"oidc-client-ts": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
42
48
|
"module": "./src/index.js"
|
|
43
49
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign-in for the standalone console: OIDC Authorization Code with PKCE — Okta, or any issuer.
|
|
3
|
+
*
|
|
4
|
+
* This lives in `app/`, not `lib/`, for the same reason the URL does: the *library* never performs
|
|
5
|
+
* a login. Mounted inside a portal it inherits that portal's session through `headers()`; only the
|
|
6
|
+
* deployable app owns a session, and only when its config names an issuer.
|
|
7
|
+
*
|
|
8
|
+
* This module is itself loaded only when `auth` is configured, so a console deployed without it
|
|
9
|
+
* downloads none of `oidc-client-ts`. Tokens are kept in `sessionStorage` (the library's default): per tab, gone when it closes.
|
|
10
|
+
* Anything script-readable is exposed to XSS on this origin, which is why the console never
|
|
11
|
+
* renders a shell's own scripts or styles and why the deployment docs ask for a strict CSP.
|
|
12
|
+
*
|
|
13
|
+
* The identity shown here is the ID token's. What the server *decides* with is the access token,
|
|
14
|
+
* verified on every request; see `createOidcAuthorizer` in `@braidlabs/registry/oidc`.
|
|
15
|
+
*/
|
|
16
|
+
export interface AuthConfig {
|
|
17
|
+
/** e.g. `https://example.okta.com/oauth2/default` — a custom authorization server for Okta. */
|
|
18
|
+
issuer: string;
|
|
19
|
+
/** The console's SPA application id. */
|
|
20
|
+
clientId: string;
|
|
21
|
+
/**
|
|
22
|
+
* Defaults to `openid profile email offline_access`. `offline_access` asks for a refresh token,
|
|
23
|
+
* which is how the session renews without a hidden iframe; enable the Refresh Token grant on the
|
|
24
|
+
* Okta app. Okta needs `groups` here only if the claim is scope-gated.
|
|
25
|
+
*/
|
|
26
|
+
scopes?: string;
|
|
27
|
+
/** Sent as `audience` for issuers that select the API by it (Auth0); Okta sets it per server. */
|
|
28
|
+
audience?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Session {
|
|
31
|
+
headers: () => Promise<Record<string, string>>;
|
|
32
|
+
/** Email, else preferred_username, else subject. */
|
|
33
|
+
user: string;
|
|
34
|
+
signOut: () => Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* For a token the server would not accept although it has not expired (the issuer rotated its
|
|
37
|
+
* keys; the API expects another audience). Signs in again, at most once a minute, so a
|
|
38
|
+
* misconfiguration produces a message rather than a redirect loop. Returns false when it held back.
|
|
39
|
+
*/
|
|
40
|
+
signInAgain: () => boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolves to a signed-in session, or never resolves because the page is navigating to the
|
|
44
|
+
* issuer. Call once, before rendering anything that makes requests.
|
|
45
|
+
*/
|
|
46
|
+
export declare function signIn(config: AuthConfig): Promise<Session>;
|
package/src/app/auth.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { UserManager, WebStorageStateStore } from 'oidc-client-ts';
|
|
2
|
+
const RETRY_KEY = 'braid-console:sign-in-again';
|
|
3
|
+
const RETRY_WINDOW_MS = 60_000;
|
|
4
|
+
/**
|
|
5
|
+
* Resolves to a signed-in session, or never resolves because the page is navigating to the
|
|
6
|
+
* issuer. Call once, before rendering anything that makes requests.
|
|
7
|
+
*/
|
|
8
|
+
export async function signIn(config) {
|
|
9
|
+
// The callback lands on the console's own URL without its hash, so the view a user was on is
|
|
10
|
+
// carried through the round trip in the request state and restored afterwards.
|
|
11
|
+
const here = `${location.origin}${location.pathname}`;
|
|
12
|
+
const manager = new UserManager({
|
|
13
|
+
authority: config.issuer,
|
|
14
|
+
client_id: config.clientId,
|
|
15
|
+
redirect_uri: here,
|
|
16
|
+
post_logout_redirect_uri: here,
|
|
17
|
+
response_type: 'code',
|
|
18
|
+
scope: config.scopes ?? 'openid profile email offline_access',
|
|
19
|
+
automaticSilentRenew: true,
|
|
20
|
+
userStore: new WebStorageStateStore({ store: sessionStorage }),
|
|
21
|
+
...(config.audience ? { extraQueryParams: { audience: config.audience } } : {}),
|
|
22
|
+
});
|
|
23
|
+
const params = new URLSearchParams(location.search);
|
|
24
|
+
let user = null;
|
|
25
|
+
if (params.has('code') && params.has('state')) {
|
|
26
|
+
user = await manager.signinRedirectCallback();
|
|
27
|
+
const hash = typeof user.state === 'object' && user.state && 'hash' in user.state ? String(user.state.hash) : '';
|
|
28
|
+
// Strip `code` and `state` so a reload or a copied link does not replay a spent grant.
|
|
29
|
+
history.replaceState(null, '', `${location.pathname}${hash}`);
|
|
30
|
+
}
|
|
31
|
+
else if (params.has('error')) {
|
|
32
|
+
// The issuer refused (a user not assigned to the app, say). Retrying would loop, so stop and
|
|
33
|
+
// say so — by error code only: the description is free text anyone can put in a link.
|
|
34
|
+
const code = (params.get('error') ?? '').replace(/[^a-z_]/gi, '').slice(0, 40);
|
|
35
|
+
throw new Error(`the identity provider refused sign-in (${code || 'unknown error'})`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
user = await manager.getUser();
|
|
39
|
+
}
|
|
40
|
+
if (!user || user.expired) {
|
|
41
|
+
await manager.signinRedirect({ state: { hash: location.hash } });
|
|
42
|
+
return new Promise(() => undefined);
|
|
43
|
+
}
|
|
44
|
+
const profile = user.profile;
|
|
45
|
+
return {
|
|
46
|
+
user: String(profile.email ?? profile.preferred_username ?? profile.sub),
|
|
47
|
+
headers: async () => {
|
|
48
|
+
let current = await manager.getUser();
|
|
49
|
+
if (!current || current.expired) {
|
|
50
|
+
// Background renewal missed (a sleeping laptop, an issuer that issued no refresh token).
|
|
51
|
+
// Try once more quietly; failing that, sign in again and come back to this view.
|
|
52
|
+
current = await manager.signinSilent().catch(() => null);
|
|
53
|
+
if (!current) {
|
|
54
|
+
await manager.signinRedirect({ state: { hash: location.hash } });
|
|
55
|
+
return new Promise(() => undefined);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { authorization: `Bearer ${current.access_token}` };
|
|
59
|
+
},
|
|
60
|
+
signInAgain: () => {
|
|
61
|
+
const last = Number(sessionStorage.getItem(RETRY_KEY) ?? 0);
|
|
62
|
+
if (Date.now() - last < RETRY_WINDOW_MS)
|
|
63
|
+
return false;
|
|
64
|
+
sessionStorage.setItem(RETRY_KEY, String(Date.now()));
|
|
65
|
+
void manager.removeUser().then(() => manager.signinRedirect({ state: { hash: location.hash } }));
|
|
66
|
+
return true;
|
|
67
|
+
},
|
|
68
|
+
signOut: async () => {
|
|
69
|
+
try {
|
|
70
|
+
await manager.signoutRedirect();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// No end_session_endpoint: forget the tokens locally and start over.
|
|
74
|
+
await manager.removeUser();
|
|
75
|
+
location.reload();
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/auth.ts"],"names":[],"mappings":"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"}
|
package/src/app/console-app.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ConsoleApi } from '../lib/client.js';
|
|
2
|
+
import type { Session } from './auth.js';
|
|
2
3
|
/**
|
|
3
4
|
* The standalone deployment's shell.
|
|
4
5
|
*
|
|
5
|
-
* This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, and
|
|
6
|
-
*
|
|
7
|
-
* someone else's admin app. Keeping the page-level concerns here is what lets
|
|
8
|
-
* stay embeddable.
|
|
6
|
+
* This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, the URL, and
|
|
7
|
+
* when configured a sign-in — and every one of those is something the library must *not* own when
|
|
8
|
+
* it mounts inside someone else's admin app. Keeping the page-level concerns here is what lets the
|
|
9
|
+
* panels stay embeddable.
|
|
9
10
|
*
|
|
10
11
|
* The view is in the URL hash rather than in state alone, so a topology someone is looking at is
|
|
11
12
|
* a link they can paste into a ticket. That is the difference between a console an operator uses
|
|
12
13
|
* and one they screenshot.
|
|
13
14
|
*/
|
|
14
|
-
export declare function ConsoleApp({ api, edit }: {
|
|
15
|
+
export declare function ConsoleApp({ api, edit, session }: {
|
|
15
16
|
api: ConsoleApi;
|
|
16
17
|
edit: boolean;
|
|
18
|
+
session?: Session;
|
|
17
19
|
}): import("react").JSX.Element;
|
package/src/app/console-app.js
CHANGED
|
@@ -1,48 +1,119 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { lazy, Suspense, useEffect, useState } from 'react';
|
|
3
3
|
import { RegistryConsole } from '../lib/registry-console.js';
|
|
4
|
-
import { RegistryEditor } from '../lib/registry-editor.js';
|
|
5
4
|
import { ensureStyles } from '../lib/styles.js';
|
|
5
|
+
import { fetchHead, fetchPermissions, RegistryApiError } from '../lib/client.js';
|
|
6
|
+
import { readRoute, routeHash } from './routes.js';
|
|
7
|
+
// Loaded when first opened: most visits are the fragment list, and these are most of the bundle.
|
|
8
|
+
const RegistryEditor = lazy(() => import('../lib/registry-editor.js').then((m) => ({ default: m.RegistryEditor })));
|
|
9
|
+
const ShellsPanel = lazy(() => import('../lib/shells-panel.js').then((m) => ({ default: m.ShellsPanel })));
|
|
10
|
+
const HistoryPanel = lazy(() => import('../lib/history-panel.js').then((m) => ({ default: m.HistoryPanel })));
|
|
6
11
|
/**
|
|
7
12
|
* The standalone deployment's shell.
|
|
8
13
|
*
|
|
9
|
-
* This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, and
|
|
10
|
-
*
|
|
11
|
-
* someone else's admin app. Keeping the page-level concerns here is what lets
|
|
12
|
-
* stay embeddable.
|
|
14
|
+
* This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, the URL, and
|
|
15
|
+
* when configured a sign-in — and every one of those is something the library must *not* own when
|
|
16
|
+
* it mounts inside someone else's admin app. Keeping the page-level concerns here is what lets the
|
|
17
|
+
* panels stay embeddable.
|
|
13
18
|
*
|
|
14
19
|
* The view is in the URL hash rather than in state alone, so a topology someone is looking at is
|
|
15
20
|
* a link they can paste into a ticket. That is the difference between a console an operator uses
|
|
16
21
|
* and one they screenshot.
|
|
17
22
|
*/
|
|
18
|
-
export function ConsoleApp({ api, edit }) {
|
|
19
|
-
const [
|
|
23
|
+
export function ConsoleApp({ api, edit, session }) {
|
|
24
|
+
const [route, setRoute] = useState(() => readRoute(window.location.hash, edit));
|
|
25
|
+
const [permissions, setPermissions] = useState(null);
|
|
26
|
+
const [shells, setShells] = useState(undefined);
|
|
27
|
+
const [pinToken, setPinToken] = useState(0);
|
|
28
|
+
// Bumped by a rollback in History only: the Shells panel reloads on it, but not on its own
|
|
29
|
+
// publishes, which it already reflects.
|
|
30
|
+
const [rollbackToken, setRollbackToken] = useState(0);
|
|
31
|
+
// Views with a draft stay mounted once opened, hidden when not shown, so switching tabs or going
|
|
32
|
+
// Back never throws away unpublished edits.
|
|
33
|
+
const [visited, setVisited] = useState(() => new Set([route.view]));
|
|
34
|
+
const [shellsDirty, setShellsDirty] = useState(false);
|
|
35
|
+
// The Shells tab returns to the shell that was open, the way the panel kept its draft.
|
|
36
|
+
const [lastShell, setLastShell] = useState(route.shell);
|
|
20
37
|
useEffect(() => {
|
|
21
38
|
ensureStyles();
|
|
22
39
|
}, []);
|
|
23
40
|
// Back and forward should move between views, since the tabs put entries in history.
|
|
24
41
|
useEffect(() => {
|
|
25
|
-
const onHashChange = () =>
|
|
42
|
+
const onHashChange = () => {
|
|
43
|
+
const next = readRoute(window.location.hash, edit);
|
|
44
|
+
setRoute(next);
|
|
45
|
+
if (next.view === 'shells')
|
|
46
|
+
setLastShell(next.shell);
|
|
47
|
+
};
|
|
26
48
|
window.addEventListener('hashchange', onHashChange);
|
|
27
49
|
return () => window.removeEventListener('hashchange', onHashChange);
|
|
28
50
|
}, [edit]);
|
|
51
|
+
// Both are advisory and optional: a gateway without the write API has neither, and the console
|
|
52
|
+
// still lists fragments. Failures are therefore silent here; the panels that need the API say
|
|
53
|
+
// why when they are opened.
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
let current = true;
|
|
56
|
+
fetchPermissions(api).then((result) => current && setPermissions(result), () => current && setPermissions(null));
|
|
57
|
+
fetchHead(api).then((head) => current && setShells(head.snapshot?.shells ?? []), (error) => {
|
|
58
|
+
if (!current)
|
|
59
|
+
return;
|
|
60
|
+
// Signed in here, yet the server refused the token outright (a 401, not a 403 for a
|
|
61
|
+
// known user who lacks a role): sign in again rather than show a console that cannot read.
|
|
62
|
+
if (session && error instanceof RegistryApiError && error.status === 401 && session.signInAgain())
|
|
63
|
+
return;
|
|
64
|
+
setShells(undefined);
|
|
65
|
+
});
|
|
66
|
+
return () => {
|
|
67
|
+
current = false;
|
|
68
|
+
};
|
|
69
|
+
// `api` and `session` are built once by main.tsx; pinToken refreshes after a rollback.
|
|
70
|
+
}, [api, session, pinToken]);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
setVisited((current) => (current.has(route.view) ? current : new Set([...current, route.view])));
|
|
73
|
+
}, [route.view]);
|
|
74
|
+
// A reload or a closed tab is the one way left to lose a draft; the browser asks first.
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!shellsDirty)
|
|
77
|
+
return;
|
|
78
|
+
const warn = (event) => event.preventDefault();
|
|
79
|
+
window.addEventListener('beforeunload', warn);
|
|
80
|
+
return () => window.removeEventListener('beforeunload', warn);
|
|
81
|
+
}, [shellsDirty]);
|
|
29
82
|
function go(next) {
|
|
30
|
-
|
|
31
|
-
|
|
83
|
+
// Renaming the open shell rewrites its link in place, rather than leaving one history entry
|
|
84
|
+
// per keystroke for Back to step through.
|
|
85
|
+
const rename = next.view === 'shells' && route.view === 'shells' && Boolean(next.shell && route.shell);
|
|
86
|
+
if (rename)
|
|
87
|
+
history.replaceState(null, '', `#${routeHash(next)}`);
|
|
88
|
+
else
|
|
89
|
+
window.location.hash = routeHash(next);
|
|
90
|
+
setRoute(next);
|
|
91
|
+
if (next.view === 'shells')
|
|
92
|
+
setLastShell(next.shell);
|
|
32
93
|
}
|
|
94
|
+
// Edit is offered only to a caller who could save. The server enforces that regardless; hiding
|
|
95
|
+
// the tab avoids an editor whose every publish fails.
|
|
96
|
+
// Unknown until /permissions answers, and unknown means hidden: a read-only user should not see
|
|
97
|
+
// an editor flash up and vanish.
|
|
98
|
+
const canEdit = edit && permissions?.publish === true;
|
|
33
99
|
const tabs = [
|
|
34
100
|
{ id: 'fragments', label: 'Fragments' },
|
|
35
101
|
{ id: 'topology', label: 'Topology' },
|
|
36
|
-
|
|
102
|
+
{ id: 'shells', label: 'Shells' },
|
|
103
|
+
{ id: 'history', label: 'History' },
|
|
104
|
+
...(canEdit ? [{ id: 'edit', label: 'Edit fragments' }] : []),
|
|
37
105
|
];
|
|
38
|
-
|
|
106
|
+
const view = route.view === 'edit' && !canEdit ? 'fragments' : route.view;
|
|
107
|
+
return (_jsxs("div", { className: "braid-console", children: [_jsxs("div", { className: "braid-console__shell", children: [_jsxs("div", { className: "braid-console__titlebar", children: [_jsx("h1", { className: "braid-console__producttitle", children: "Braid gateway" }), _jsxs("span", { className: "braid-console__breadcrumb", children: [_jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("code", { children: api.baseUrl || window.location.host })] }), _jsx("span", { className: "braid-console__spacer" }), session && (_jsxs("span", { className: "braid-console__identity", children: [_jsx("span", { children: session.user }), permissions && _jsx("span", { className: "braid-console__rolebadge", children: roleLabel(permissions) }), _jsx("button", { type: "button", className: "braid-console__ghost", onClick: () => void session.signOut(), children: "Sign out" })] }))] }), _jsx("div", { className: "braid-console__commandbar", children: _jsx("div", { className: "braid-console__tabs", role: "tablist", "aria-label": "Console views", children: tabs.map((entry) => (_jsx("button", { type: "button", role: "tab", className: "braid-console__tab", "aria-selected": view === entry.id, onClick: () => go(entry.id === 'shells' && lastShell ? { view: 'shells', shell: lastShell } : { view: entry.id }), children: entry.label }, entry.id))) }) })] }), _jsxs(Suspense, { fallback: _jsx("p", { className: "braid-console__empty", children: "Loading\u2026" }), children: [view === 'edit' && _jsx(RegistryEditor, { api: api }), visited.has('shells') && (_jsx("div", { hidden: view !== 'shells', children: _jsx(ShellsPanel, { api: api, selected: route.shell ?? null, onSelect: (id) => go(id ? { view: 'shells', shell: id } : { view: 'shells' }), onPublished: (outcome) => outcome.pinned && setPinToken((token) => token + 1), onDirtyChange: setShellsDirty, refreshKey: rollbackToken }) })), view === 'history' && (_jsx(HistoryPanel, { api: api, onPinned: () => {
|
|
108
|
+
setPinToken((token) => token + 1);
|
|
109
|
+
setRollbackToken((token) => token + 1);
|
|
110
|
+
} }))] }), (view === 'fragments' || view === 'topology') && (_jsx(RegistryConsole, { api: api, chrome: false, view: view, ...(shells ? { shells } : {}) }))] }));
|
|
39
111
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return 'fragments';
|
|
112
|
+
function roleLabel({ publish, pin }) {
|
|
113
|
+
if (publish && pin)
|
|
114
|
+
return 'can publish';
|
|
115
|
+
if (publish)
|
|
116
|
+
return 'can publish candidates';
|
|
117
|
+
return 'read-only';
|
|
47
118
|
}
|
|
48
119
|
//# sourceMappingURL=console-app.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-app.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/console-app.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"console-app.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/console-app.tsx"],"names":[],"mappings":"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"}
|
package/src/app/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
3
|
import { ConsoleApp } from './console-app.js';
|
|
4
|
+
import { ensureStyles } from '../lib/styles.js';
|
|
4
5
|
/**
|
|
5
6
|
* Standalone entry — the deployable form.
|
|
6
7
|
*
|
|
@@ -13,10 +14,32 @@ const mount = document.getElementById('root');
|
|
|
13
14
|
if (!mount)
|
|
14
15
|
throw new Error('braid-console: no #root element to mount into');
|
|
15
16
|
const config = readConfig();
|
|
17
|
+
const root = createRoot(mount);
|
|
18
|
+
const { auth, edit, ...api } = config;
|
|
16
19
|
// Read-only unless the deployment says otherwise. Editing needs a write API the gateway may not
|
|
17
20
|
// have mounted, and defaulting to an editor that cannot save is a worse first impression than a
|
|
18
21
|
// listing that works — so `edit` adds a tab rather than replacing the console with one.
|
|
19
|
-
|
|
22
|
+
//
|
|
23
|
+
// With `auth`, nothing renders until there is a session: every request would otherwise go out
|
|
24
|
+
// anonymous and come back 401, which is noise, not information. The sign-in code is loaded only
|
|
25
|
+
// in this branch.
|
|
26
|
+
if (auth) {
|
|
27
|
+
// Something to see while the sign-in code loads and the issuer answers, instead of a blank page.
|
|
28
|
+
ensureStyles();
|
|
29
|
+
root.render(_jsx("div", { className: "braid-console", children: _jsx("p", { className: "braid-console__empty", role: "status", children: "Signing in\u2026" }) }));
|
|
30
|
+
import('./auth.js')
|
|
31
|
+
.then(({ signIn }) => signIn(auth))
|
|
32
|
+
.then((session) => root.render(_jsx(ConsoleApp, { api: { ...api, headers: session.headers }, edit: edit === true, session: session })), (error) => {
|
|
33
|
+
ensureStyles();
|
|
34
|
+
root.render(_jsx(SignInFailed, { error: error }));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
root.render(_jsx(ConsoleApp, { api: api, edit: edit === true }));
|
|
39
|
+
}
|
|
40
|
+
function SignInFailed({ error }) {
|
|
41
|
+
return (_jsx("div", { className: "braid-console", children: _jsxs("div", { className: "braid-console__error", role: "alert", children: [_jsx("h3", { children: "Could not sign in" }), _jsx("p", { children: error instanceof Error ? error.message : String(error) }), _jsx("button", { className: "braid-console__retry", type: "button", onClick: () => location.assign(location.pathname), children: "Try again" })] }) }));
|
|
42
|
+
}
|
|
20
43
|
function readConfig() {
|
|
21
44
|
const element = document.getElementById('braid-console-config');
|
|
22
45
|
if (!element?.textContent)
|
package/src/app/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AAC9C,IAAI,CAAC,KAAK;IAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AAE7E,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,gGAAgG;AAChG,gGAAgG;AAChG,wFAAwF;AACxF,
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AAC9C,IAAI,CAAC,KAAK;IAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AAE7E,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;AAEtC,gGAAgG;AAChG,gGAAgG;AAChG,wFAAwF;AACxF,EAAE;AACF,8FAA8F;AAC9F,gGAAgG;AAChG,kBAAkB;AAClB,IAAI,IAAI,EAAE,CAAC;IACT,iGAAiG;IACjG,YAAY,EAAE,CAAC;IACf,IAAI,CAAC,MAAM,CACT,cAAK,SAAS,EAAC,eAAe,YAC5B,YAAG,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,QAAQ,iCAE7C,GACA,CACP,CAAC;IACF,MAAM,CAAC,WAAW,CAAC;SAChB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SAClC,IAAI,CACH,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAC,UAAU,IAAC,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,OAAO,EAAE,OAAO,GAAI,CAAC,EAC1H,CAAC,KAAc,EAAE,EAAE;QACjB,YAAY,EAAE,CAAC;QACf,IAAI,CAAC,MAAM,CAAC,KAAC,YAAY,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAC;IAC9C,CAAC,CACF,CAAC;AACN,CAAC;KAAM,CAAC;IACN,IAAI,CAAC,MAAM,CAAC,KAAC,UAAU,IAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,GAAI,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,YAAY,CAAC,EAAE,KAAK,EAAsB;IACjD,OAAO,CACL,cAAK,SAAS,EAAC,eAAe,YAC5B,eAAK,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,OAAO,aAChD,6CAA0B,EAC1B,sBAAI,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAK,EAC/D,iBAAQ,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,0BAE/F,IACL,GACF,CACP,CAAC;AACJ,CAAC;AAID,SAAS,UAAU;IACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,EAAE,WAAW;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAW,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The standalone app's views, in the URL hash so a view is a link someone can paste into a ticket.
|
|
3
|
+
*
|
|
4
|
+
* Old links keep working: `#fragments`, `#topology` and `#edit` mean what they always did, and
|
|
5
|
+
* anything unrecognized lands on the fragment list rather than a blank page.
|
|
6
|
+
*/
|
|
7
|
+
export type View = 'fragments' | 'topology' | 'shells' | 'history' | 'edit';
|
|
8
|
+
export interface Route {
|
|
9
|
+
view: View;
|
|
10
|
+
/** `#shells/<id>`: the shell open in the designer. */
|
|
11
|
+
shell?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function readRoute(hash: string, edit: boolean): Route;
|
|
14
|
+
export declare function routeHash(route: Route): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function readRoute(hash, edit) {
|
|
2
|
+
const [view = '', ...rest] = hash.replace(/^#\/?/, '').split('/');
|
|
3
|
+
if (view === 'topology' || view === 'history')
|
|
4
|
+
return { view };
|
|
5
|
+
if (view === 'edit' && edit)
|
|
6
|
+
return { view };
|
|
7
|
+
if (view === 'shells') {
|
|
8
|
+
const id = rest.join('/');
|
|
9
|
+
if (!id)
|
|
10
|
+
return { view };
|
|
11
|
+
try {
|
|
12
|
+
return { view, shell: decodeURIComponent(id) };
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return { view };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { view: 'fragments' };
|
|
19
|
+
}
|
|
20
|
+
export function routeHash(route) {
|
|
21
|
+
return route.view === 'shells' && route.shell ? `shells/${encodeURIComponent(route.shell)}` : route.view;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/routes.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAa;IACnD,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClE,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC/D,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3G,CAAC"}
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @braidlabs/console — a
|
|
2
|
+
* @braidlabs/console — a console for a Braid gateway's registry: fragments, shells, and history.
|
|
3
3
|
*
|
|
4
4
|
* Two ways to use it, from one package:
|
|
5
5
|
*
|
|
@@ -33,6 +33,19 @@ export { AccessPanel } from './lib/access-panel.js';
|
|
|
33
33
|
export type { AccessPanelProps } from './lib/access-panel.js';
|
|
34
34
|
export { createDraft, draftStatus, addFragment, removeFragment, updateFragment, resetDraft, parseList, formatList, } from './lib/draft.js';
|
|
35
35
|
export type { Draft, DraftStatus } from './lib/draft.js';
|
|
36
|
-
export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
|
|
36
|
+
export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, fetchPermissions, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
|
|
37
37
|
export type { ConsoleApi, RegistryListing, HeadState, PublishOutcome } from './lib/client.js';
|
|
38
38
|
export { CONSOLE_STYLES, ensureStyles } from './lib/styles.js';
|
|
39
|
+
export { ShellsPanel, newShell } from './lib/shells-panel.js';
|
|
40
|
+
export type { ShellsPanelProps } from './lib/shells-panel.js';
|
|
41
|
+
export { HistoryPanel } from './lib/history-panel.js';
|
|
42
|
+
export type { HistoryPanelProps } from './lib/history-panel.js';
|
|
43
|
+
export { EmptyState, emptyKindOf } from './lib/empty-state.js';
|
|
44
|
+
export type { EmptyKind } from './lib/empty-state.js';
|
|
45
|
+
export { shellCode, SHELL_TARGETS, angularPath } from './lib/shell-codegen.js';
|
|
46
|
+
export type { GeneratedFile } from './lib/shell-codegen.js';
|
|
47
|
+
export { parseQuery, matchQuery, filterBy, fragmentItem, shellItem, QUERY_KEYS } from './lib/query.js';
|
|
48
|
+
export type { ParsedQuery, QueryTerm, QueryKey, SearchItem } from './lib/query.js';
|
|
49
|
+
export { tagColor, tagClass, TAG_COLOR_COUNT } from './lib/tags.js';
|
|
50
|
+
export { TagChip } from './lib/tag-chip.js';
|
|
51
|
+
export { tagQuery } from './lib/registry-console.js';
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @braidlabs/console — a
|
|
2
|
+
* @braidlabs/console — a console for a Braid gateway's registry: fragments, shells, and history.
|
|
3
3
|
*
|
|
4
4
|
* Two ways to use it, from one package:
|
|
5
5
|
*
|
|
@@ -25,6 +25,14 @@ export { buildTopology, neighborhood, coTenants, edgeKey } from './lib/topology.
|
|
|
25
25
|
export { RegistryEditor } from './lib/registry-editor.js';
|
|
26
26
|
export { AccessPanel } from './lib/access-panel.js';
|
|
27
27
|
export { createDraft, draftStatus, addFragment, removeFragment, updateFragment, resetDraft, parseList, formatList, } from './lib/draft.js';
|
|
28
|
-
export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
|
|
28
|
+
export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, fetchPermissions, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
|
|
29
29
|
export { CONSOLE_STYLES, ensureStyles } from './lib/styles.js';
|
|
30
|
+
export { ShellsPanel, newShell } from './lib/shells-panel.js';
|
|
31
|
+
export { HistoryPanel } from './lib/history-panel.js';
|
|
32
|
+
export { EmptyState, emptyKindOf } from './lib/empty-state.js';
|
|
33
|
+
export { shellCode, SHELL_TARGETS, angularPath } from './lib/shell-codegen.js';
|
|
34
|
+
export { parseQuery, matchQuery, filterBy, fragmentItem, shellItem, QUERY_KEYS } from './lib/query.js';
|
|
35
|
+
export { tagColor, tagClass, TAG_COLOR_COUNT } from './lib/tags.js';
|
|
36
|
+
export { TagChip } from './lib/tag-chip.js';
|
|
37
|
+
export { tagQuery } from './lib/registry-console.js';
|
|
30
38
|
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-console/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG5H,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-console/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG5H,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEvG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC"}
|