@cosmoops/connect-sdk 0.7.0 → 0.15.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/CHANGELOG.md +662 -0
- package/README.md +376 -124
- package/dist/cjs/cli/doctor.js +3 -3
- package/dist/cjs/cli/init.js +3 -3
- package/dist/cjs/client/components/access-gate.js +59 -5
- package/dist/cjs/client/components/ai-format.js +135 -0
- package/dist/cjs/client/components/ai-widgets.js +232 -0
- package/dist/cjs/client/components/app-shell.js +80 -45
- package/dist/cjs/client/components/apps-grid.js +3 -2
- package/dist/cjs/client/components/ask-ai.js +353 -0
- package/dist/cjs/client/components/confirm-dialog.js +40 -0
- package/dist/cjs/client/components/cursor-pagination.js +22 -0
- package/dist/cjs/client/components/filter-tabs.js +24 -0
- package/dist/cjs/client/components/grievance-notice.js +30 -0
- package/dist/cjs/client/components/link-button.js +17 -10
- package/dist/cjs/client/components/logo.js +4 -3
- package/dist/cjs/client/components/nav.js +42 -1
- package/dist/cjs/client/components/plan-pricing.js +27 -0
- package/dist/cjs/client/components/plans.js +1 -1
- package/dist/cjs/client/components/platform-gate.js +48 -0
- package/dist/cjs/client/components/shell-context.js +149 -0
- package/dist/cjs/client/components/side-nav.js +50 -24
- package/dist/cjs/client/components/sidebar.js +127 -0
- package/dist/cjs/client/components/subscribe-dialog.js +2 -2
- package/dist/cjs/client/components/subscription.js +1 -1
- package/dist/cjs/client/components/user-menu.js +122 -40
- package/dist/cjs/client/components/workspace-switcher.js +100 -0
- package/dist/cjs/client/components/workspace-type-gate.js +48 -0
- package/dist/cjs/client/index.js +98 -3
- package/dist/cjs/client/provider.js +100 -2
- package/dist/cjs/client/use-checkout.js +9 -5
- package/dist/cjs/errors.js +1 -1
- package/dist/cjs/index.js +11 -1
- package/dist/cjs/next/index.js +2 -2
- package/dist/cjs/server/client.js +25 -2
- package/dist/cjs/server/handler.js +237 -16
- package/dist/cjs/server/http.js +52 -26
- package/dist/cjs/server/resources/acting-as.js +16 -0
- package/dist/cjs/server/resources/ai.js +15 -2
- package/dist/cjs/server/resources/data.js +374 -0
- package/dist/cjs/server/resources/entitlements.js +41 -0
- package/dist/cjs/server/resources/identity.js +9 -3
- package/dist/cjs/server/resources/kv.js +84 -0
- package/dist/cjs/server/resources/platform.js +43 -0
- package/dist/cjs/server/resources/sessions.js +1 -1
- package/dist/cjs/server/resources/workspaces.js +74 -0
- package/dist/cjs/store.js +152 -0
- package/dist/cjs/ui/empty-state.js +28 -0
- package/dist/cjs/ui/index.js +44 -0
- package/dist/cjs/ui/page-header.js +27 -0
- package/dist/cjs/ui/page-shell.js +44 -0
- package/dist/cjs/ui/section.js +20 -0
- package/dist/cjs/ui/setting-row.js +14 -0
- package/dist/cjs/ui/status-chip.js +17 -0
- package/dist/esm/cli/doctor.js +3 -3
- package/dist/esm/cli/init.js +3 -3
- package/dist/esm/client/components/access-gate.js +60 -6
- package/dist/esm/client/components/ai-format.js +129 -0
- package/dist/esm/client/components/ai-widgets.js +223 -0
- package/dist/esm/client/components/app-shell.js +85 -50
- package/dist/esm/client/components/apps-grid.js +3 -2
- package/dist/esm/client/components/ask-ai.js +350 -0
- package/dist/esm/client/components/confirm-dialog.js +37 -0
- package/dist/esm/client/components/cursor-pagination.js +19 -0
- package/dist/esm/client/components/filter-tabs.js +21 -0
- package/dist/esm/client/components/grievance-notice.js +27 -0
- package/dist/esm/client/components/link-button.js +17 -10
- package/dist/esm/client/components/logo.js +4 -3
- package/dist/esm/client/components/nav.js +41 -1
- package/dist/esm/client/components/plan-pricing.js +25 -0
- package/dist/esm/client/components/plans.js +2 -2
- package/dist/esm/client/components/platform-gate.js +45 -0
- package/dist/esm/client/components/shell-context.js +141 -0
- package/dist/esm/client/components/side-nav.js +49 -22
- package/dist/esm/client/components/sidebar.js +120 -0
- package/dist/esm/client/components/subscribe-dialog.js +3 -3
- package/dist/esm/client/components/subscription.js +2 -2
- package/dist/esm/client/components/user-menu.js +121 -41
- package/dist/esm/client/components/workspace-switcher.js +97 -0
- package/dist/esm/client/components/workspace-type-gate.js +45 -0
- package/dist/esm/client/index.js +58 -5
- package/dist/esm/client/provider.js +94 -2
- package/dist/esm/client/use-checkout.js +9 -5
- package/dist/esm/errors.js +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/next/index.js +2 -2
- package/dist/esm/server/client.js +25 -2
- package/dist/esm/server/handler.js +237 -16
- package/dist/esm/server/http.js +52 -26
- package/dist/esm/server/resources/acting-as.js +13 -0
- package/dist/esm/server/resources/ai.js +15 -2
- package/dist/esm/server/resources/data.js +369 -0
- package/dist/esm/server/resources/entitlements.js +41 -0
- package/dist/esm/server/resources/identity.js +9 -3
- package/dist/esm/server/resources/kv.js +80 -0
- package/dist/esm/server/resources/platform.js +39 -0
- package/dist/esm/server/resources/sessions.js +1 -1
- package/dist/esm/server/resources/workspaces.js +70 -0
- package/dist/esm/store.js +141 -0
- package/dist/esm/ui/empty-state.js +25 -0
- package/dist/esm/ui/index.js +34 -0
- package/dist/esm/ui/page-header.js +24 -0
- package/dist/esm/ui/page-shell.js +41 -0
- package/dist/esm/ui/section.js +17 -0
- package/dist/esm/ui/setting-row.js +11 -0
- package/dist/esm/ui/status-chip.js +14 -0
- package/dist/theme.css +87 -0
- package/dist/types/client/components/access-gate.d.ts +17 -3
- package/dist/types/client/components/ai-format.d.ts +24 -0
- package/dist/types/client/components/ai-widgets.d.ts +42 -0
- package/dist/types/client/components/app-shell.d.ts +85 -31
- package/dist/types/client/components/apps-grid.d.ts +11 -2
- package/dist/types/client/components/ask-ai.d.ts +73 -0
- package/dist/types/client/components/confirm-dialog.d.ts +34 -0
- package/dist/types/client/components/cursor-pagination.d.ts +27 -0
- package/dist/types/client/components/filter-tabs.d.ts +26 -0
- package/dist/types/client/components/grievance-notice.d.ts +31 -0
- package/dist/types/client/components/link-button.d.ts +32 -9
- package/dist/types/client/components/logo.d.ts +18 -2
- package/dist/types/client/components/nav.d.ts +27 -3
- package/dist/types/client/components/plan-pricing.d.ts +10 -0
- package/dist/types/client/components/platform-gate.d.ts +53 -0
- package/dist/types/client/components/shell-context.d.ts +116 -0
- package/dist/types/client/components/side-nav.d.ts +28 -14
- package/dist/types/client/components/sidebar.d.ts +95 -0
- package/dist/types/client/components/user-menu.d.ts +70 -23
- package/dist/types/client/components/workspace-switcher.d.ts +49 -0
- package/dist/types/client/components/workspace-type-gate.d.ts +48 -0
- package/dist/types/client/index.d.ts +36 -7
- package/dist/types/client/provider.d.ts +149 -3
- package/dist/types/client/use-checkout.d.ts +8 -4
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/next/index.d.ts +1 -1
- package/dist/types/server/client.d.ts +25 -2
- package/dist/types/server/http.d.ts +14 -3
- package/dist/types/server/index.d.ts +4 -0
- package/dist/types/server/resources/acting-as.d.ts +11 -0
- package/dist/types/server/resources/ai.d.ts +9 -1
- package/dist/types/server/resources/data.d.ts +258 -0
- package/dist/types/server/resources/entitlements.d.ts +33 -1
- package/dist/types/server/resources/kv.d.ts +63 -0
- package/dist/types/server/resources/platform.d.ts +32 -0
- package/dist/types/server/resources/workspaces.d.ts +55 -0
- package/dist/types/store.d.ts +96 -0
- package/dist/types/types.d.ts +491 -13
- package/dist/types/ui/empty-state.d.ts +34 -0
- package/dist/types/ui/index.d.ts +40 -0
- package/dist/types/ui/page-header.d.ts +34 -0
- package/dist/types/ui/page-shell.d.ts +39 -0
- package/dist/types/ui/section.d.ts +26 -0
- package/dist/types/ui/setting-row.d.ts +18 -0
- package/dist/types/ui/status-chip.d.ts +36 -0
- package/package.json +13 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
+
import { type ConnectAskAiProps } from "./ask-ai.js";
|
|
2
3
|
import { type ConnectLinkRenderer, type ConnectNav } from "./nav.js";
|
|
3
4
|
import type { ThemeMode } from "../../types.js";
|
|
4
|
-
export interface
|
|
5
|
+
export interface AppShellProps {
|
|
5
6
|
/** This application's name, in the `cosmo·ops VOICE` lockup. See `ConnectLogo`. */
|
|
6
7
|
name: string;
|
|
7
8
|
/** This application's glyph, drawn on the CosmoOps badge. Falls back to the Connect rings. */
|
|
@@ -10,34 +11,51 @@ export interface ConnectAppShellProps {
|
|
|
10
11
|
homeHref?: string;
|
|
11
12
|
/** The sidebar's destinations - items, sections, or a mix. See `ConnectNav`. */
|
|
12
13
|
nav: ConnectNav;
|
|
13
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* A second nav group, pinned to the foot of the rail above the account row.
|
|
16
|
+
*
|
|
17
|
+
* For the routes a product has but does not want competing with its own:
|
|
18
|
+
* settings, help, changelog, status. They are the same `ConnectNav` shape
|
|
19
|
+
* and get the same active resolution and audience filtering - the only
|
|
20
|
+
* difference is where they sit, which is the difference between "what this
|
|
21
|
+
* product is for" and "everything else".
|
|
22
|
+
*
|
|
23
|
+
* A route belongs up top if a user goes there to *do the job*, and down here
|
|
24
|
+
* if they go there to change how the job works. Putting Settings in the
|
|
25
|
+
* primary list is what makes a nine-item rail out of a five-item product.
|
|
26
|
+
*/
|
|
27
|
+
secondaryNav?: ConnectNav;
|
|
28
|
+
/** Current path. Pass `usePathname()` in Next; see `ConnectSidebarNavProps.activePath`. */
|
|
14
29
|
activePath?: string;
|
|
15
30
|
/** See `ConnectLinkRenderer` - how this app renders a link. Defaults to a plain `<a>`. */
|
|
16
31
|
renderLink?: ConnectLinkRenderer;
|
|
32
|
+
/** Extra rows pinned to the bottom of the sidebar, above the account row. See `ConnectSidebarRow`. */
|
|
33
|
+
sidebarFooter?: ReactNode;
|
|
17
34
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
35
|
+
* The workspace switcher under the brand. On by default, and it hides itself
|
|
36
|
+
* for an account with only one workspace - so the reason to pass `false` is
|
|
37
|
+
* not "most users have one" (already handled) but "this application renders
|
|
38
|
+
* its own".
|
|
21
39
|
*/
|
|
22
|
-
|
|
23
|
-
/** Your own controls in the top bar, left of the Connect ones. */
|
|
24
|
-
headerActions?: ReactNode;
|
|
25
|
-
/** Extra content pinned to the bottom of the sidebar, above the fold-away. */
|
|
26
|
-
sidebarFooter?: ReactNode;
|
|
40
|
+
workspaceSwitcher?: false;
|
|
27
41
|
/** Rendered below `children`, inside the scrolling content pane. */
|
|
28
42
|
footer?: ReactNode;
|
|
29
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Start the rail collapsed. **Defaults to `true`** - see the component's
|
|
45
|
+
* own doc comment. Ignored when `collapsed` is supplied, and overridden by
|
|
46
|
+
* a stored preference from the user's last visit.
|
|
47
|
+
*/
|
|
30
48
|
defaultCollapsed?: boolean;
|
|
31
49
|
/** Drive the rail yourself. Supply `onCollapsedChange` with it. */
|
|
32
50
|
collapsed?: boolean;
|
|
33
51
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
34
52
|
/** Remove the collapse control and pin the rail expanded. */
|
|
35
53
|
collapsible?: boolean;
|
|
36
|
-
/** The app launcher in the
|
|
54
|
+
/** The app launcher, in the sidebar footer. On by default. */
|
|
37
55
|
showAppsGrid?: boolean;
|
|
38
|
-
/** "Continue with Connect" / "Create account" in the
|
|
56
|
+
/** "Continue with Connect" / "Create account" in the sidebar footer when signed out. On by default. */
|
|
39
57
|
showAuthButtons?: boolean;
|
|
40
|
-
/** Passed to `
|
|
58
|
+
/** Passed to `ConnectUserButton` - the SDK has no theme provider, so this is host-controlled. */
|
|
41
59
|
theme?: ThemeMode;
|
|
42
60
|
onThemeChange?: (theme: ThemeMode) => void;
|
|
43
61
|
/**
|
|
@@ -47,7 +65,7 @@ export interface ConnectAppShellProps {
|
|
|
47
65
|
* gate asks for, and an app that mounts a shell and forgets the gate is an
|
|
48
66
|
* app that lets a suspended workspace keep working.
|
|
49
67
|
*
|
|
50
|
-
* The chrome is never gated: the sidebar, the lockup, the
|
|
68
|
+
* The chrome is never gated: the sidebar, the lockup, the account row and
|
|
51
69
|
* sign-out stay reachable in every blocked state, so a blocked customer can
|
|
52
70
|
* always get to the page that unblocks them.
|
|
53
71
|
*
|
|
@@ -61,55 +79,91 @@ export interface ConnectAppShellProps {
|
|
|
61
79
|
* say. Prefix-matched, same as the nav's active resolution.
|
|
62
80
|
*/
|
|
63
81
|
gateExemptRoutes?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Mount `ConnectAskAi` - a chat panel grounded in the signed-in workspace's
|
|
84
|
+
* Context Index, streamed through your own bridge. Pass an object to
|
|
85
|
+
* override its heading, copy or markdown plugins.
|
|
86
|
+
*
|
|
87
|
+
* **On by default**, like `gate`, and for the same reason: a family of
|
|
88
|
+
* application platforms should answer questions the same way, and a feature
|
|
89
|
+
* every partner has to remember to switch on is a feature most of them do
|
|
90
|
+
* not have. It stays inert until it can actually work - the trigger renders
|
|
91
|
+
* nothing for a signed-out visitor, and a workspace whose Context Index is
|
|
92
|
+
* off gets a message in the panel rather than a broken answer.
|
|
93
|
+
*
|
|
94
|
+
* Set `false` for an application that should not offer it at all.
|
|
95
|
+
*/
|
|
96
|
+
askAi?: boolean | ConnectAskAiProps;
|
|
64
97
|
className?: string;
|
|
65
98
|
/** Classes on the scrolling content pane - override the default max-width and padding here. */
|
|
66
99
|
contentClassName?: string;
|
|
67
100
|
children: ReactNode;
|
|
68
101
|
}
|
|
69
102
|
/**
|
|
70
|
-
* The application frame every CosmoOps application platform runs inside:
|
|
71
|
-
*
|
|
72
|
-
*
|
|
103
|
+
* The application frame every CosmoOps application platform runs inside: one
|
|
104
|
+
* rail down the side holding the brand, the workspace, the navigation and the
|
|
105
|
+
* account, and your pages in the rest.
|
|
73
106
|
*
|
|
74
107
|
* This is the piece each partner was otherwise writing by hand, and writing
|
|
75
|
-
* slightly differently - which is how a family of applications stops looking
|
|
76
|
-
* one product. Everything that should be identical across platforms
|
|
77
|
-
*
|
|
78
|
-
* account menu, the access gate) lives here; everything that genuinely
|
|
79
|
-
* differs is a prop:
|
|
108
|
+
* slightly differently - which is how a family of applications stops looking
|
|
109
|
+
* like one product. Everything that should be identical across platforms
|
|
110
|
+
* lives here; everything that genuinely differs is a prop:
|
|
80
111
|
*
|
|
81
112
|
* ```tsx
|
|
82
113
|
* "use client";
|
|
83
114
|
* import Link from "next/link";
|
|
84
115
|
* import { usePathname } from "next/navigation";
|
|
85
|
-
* import {
|
|
86
|
-
* import { LayoutDashboard, Truck } from "lucide-react";
|
|
116
|
+
* import { AppShell } from "@cosmoops/connect-sdk/client";
|
|
117
|
+
* import { LayoutDashboard, Settings, Truck } from "lucide-react";
|
|
87
118
|
*
|
|
88
119
|
* export function Shell({ children }: { children: React.ReactNode }) {
|
|
89
120
|
* return (
|
|
90
|
-
* <
|
|
121
|
+
* <AppShell
|
|
91
122
|
* name="Dispatch"
|
|
92
123
|
* icon={<Truck />}
|
|
93
124
|
* activePath={usePathname()}
|
|
94
125
|
* renderLink={(props) => <Link {...props} />}
|
|
95
126
|
* nav={[
|
|
96
127
|
* { label: "Overview", href: "/", icon: <LayoutDashboard className="size-5" /> },
|
|
97
|
-
* { label: "
|
|
128
|
+
* { label: "Shipments", href: "/shipments", icon: <Truck className="size-5" /> },
|
|
129
|
+
* ]}
|
|
130
|
+
* secondaryNav={[
|
|
131
|
+
* { label: "Settings", href: "/settings", icon: <Settings className="size-5" /> },
|
|
98
132
|
* ]}
|
|
99
133
|
* >
|
|
100
134
|
* {children}
|
|
101
|
-
* </
|
|
135
|
+
* </AppShell>
|
|
102
136
|
* );
|
|
103
137
|
* }
|
|
104
138
|
* ```
|
|
105
139
|
*
|
|
140
|
+
* **There is no top bar.** There used to be one, carrying a page title, the
|
|
141
|
+
* launcher and the account menu - and it was a second, half-width strip of
|
|
142
|
+
* chrome saying things the rail was better placed to say. The launcher and
|
|
143
|
+
* the account row moved into the rail's footer, where they are one press from
|
|
144
|
+
* wherever the pointer already is; the page title moved into the page, where
|
|
145
|
+
* `ConnectPageShell` renders it next to that page's own actions and
|
|
146
|
+
* breadcrumbs. What is left is a single column of chrome and a full-height
|
|
147
|
+
* content pane, which is what every application this shell is modelled on
|
|
148
|
+
* settled at.
|
|
149
|
+
*
|
|
150
|
+
* The one exception is below `md`, where a slim bar carries the drawer
|
|
151
|
+
* trigger. A phone has no rail to put it in, and a navigation you cannot open
|
|
152
|
+
* is not a smaller navigation.
|
|
153
|
+
*
|
|
154
|
+
* **The rail starts collapsed.** `defaultCollapsed` is `true`: the icon rail
|
|
155
|
+
* is the resting state, and expanding is the deliberate act. That is the right
|
|
156
|
+
* default because the rail's job is to be *there*, not to be read - a person
|
|
157
|
+
* learns five glyphs in a day and then wants the 200px back for their data.
|
|
158
|
+
* A stored preference from the user's last visit always wins over it.
|
|
159
|
+
*
|
|
106
160
|
* There is no `isSignedIn` branch anywhere in here, and there should be none
|
|
107
|
-
* in yours: the auth buttons render nothing once a session exists, the
|
|
108
|
-
*
|
|
161
|
+
* in yours: the auth buttons render nothing once a session exists, the account
|
|
162
|
+
* row renders nothing without one, and the launcher renders nothing when
|
|
109
163
|
* signed out. The swap happens inside the components.
|
|
110
164
|
*
|
|
111
165
|
* It renders no provider of its own - mount `ConnectProvider` above it, once,
|
|
112
166
|
* so a page with a shell, a plan table and a usage meter still makes one
|
|
113
167
|
* session read.
|
|
114
168
|
*/
|
|
115
|
-
export declare function
|
|
169
|
+
export declare function AppShell({ name, icon, homeHref, nav, secondaryNav, activePath, renderLink, sidebarFooter, workspaceSwitcher, footer, defaultCollapsed, collapsed: controlledCollapsed, onCollapsedChange, collapsible, showAppsGrid, showAuthButtons, theme, onThemeChange, gate, gateExemptRoutes, askAi, className, contentClassName, children, }: AppShellProps): import("react").JSX.Element;
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
export interface ConnectAppsGridProps {
|
|
2
2
|
/** Extra classes on the trigger button. */
|
|
3
3
|
className?: string;
|
|
4
|
-
/** Trigger label for screen readers. */
|
|
4
|
+
/** Trigger label for screen readers, and the collapsed rail's tooltip. */
|
|
5
5
|
label?: string;
|
|
6
|
+
/**
|
|
7
|
+
* How the trigger is drawn.
|
|
8
|
+
*
|
|
9
|
+
* - `"row"` - a full-width sidebar row, glyph on the rail's shared 32px
|
|
10
|
+
* centre. The default, since the launcher lives in the sidebar footer now
|
|
11
|
+
* that there is no top bar to hold it.
|
|
12
|
+
* - `"icon"` - the square accent button, for a bar of your own.
|
|
13
|
+
*/
|
|
14
|
+
variant?: "row" | "icon";
|
|
6
15
|
}
|
|
7
16
|
/**
|
|
8
17
|
* The Google-style app launcher: a grid icon in your top bar that opens a
|
|
@@ -17,4 +26,4 @@ export interface ConnectAppsGridProps {
|
|
|
17
26
|
* Renders nothing when signed out: a launcher with nothing to launch is just a
|
|
18
27
|
* button that opens an empty box.
|
|
19
28
|
*/
|
|
20
|
-
export declare function ConnectAppsGrid({ className, label }: ConnectAppsGridProps): import("react").JSX.Element | null;
|
|
29
|
+
export declare function ConnectAppsGrid({ className, label, variant }: ConnectAppsGridProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type StreamdownProps } from "streamdown";
|
|
2
|
+
export interface ConnectAskAiProps {
|
|
3
|
+
/** Panel heading. Defaults to `"Ask AI"`. */
|
|
4
|
+
title?: string;
|
|
5
|
+
/** Byline over each assistant turn. Defaults to `"Assistant"`. */
|
|
6
|
+
assistantName?: string;
|
|
7
|
+
/** Composer placeholder. */
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
/** Shown once, above an empty conversation. */
|
|
10
|
+
hint?: string;
|
|
11
|
+
/** Start open. The panel owns its state after that. */
|
|
12
|
+
defaultOpen?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Streamdown plugins - syntax highlighting, KaTeX, Mermaid, CJK.
|
|
15
|
+
*
|
|
16
|
+
* Off unless you pass them, because each is a package of its own and several
|
|
17
|
+
* are large (Mermaid alone dwarfs this SDK). Prose, GFM tables, task lists
|
|
18
|
+
* and plain code fences all render without any of them.
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { code } from "@streamdown/code";
|
|
22
|
+
* import { mermaid } from "@streamdown/mermaid";
|
|
23
|
+
*
|
|
24
|
+
* <ConnectAskAi markdownPlugins={{ code, mermaid }} />
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Hoist the object to module scope: Streamdown compares this prop by
|
|
28
|
+
* reference, so an inline literal defeats its block memoisation.
|
|
29
|
+
*/
|
|
30
|
+
markdownPlugins?: StreamdownProps["plugins"];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Ask AI - a chat panel grounded in the signed-in workspace's Context Index,
|
|
34
|
+
* streamed through your own bridge.
|
|
35
|
+
*
|
|
36
|
+
* Answers are not only prose. Connect's model can call a small set of
|
|
37
|
+
* presentation tools - `showTable`, `showChart`, `showMetrics`, `showTimeline`,
|
|
38
|
+
* `showDetails`, `showSteps`, `showSources` - and this panel renders each one
|
|
39
|
+
* natively: a sortable table with a CSV download, a chart, a row of metric
|
|
40
|
+
* tiles. Values arrive raw with a format tag, so they are formatted here rather
|
|
41
|
+
* than by the model, which is what lets a column sort numerically.
|
|
42
|
+
*
|
|
43
|
+
* Nothing here holds a credential: it POSTs to `${basePath}/ai/chat` on your
|
|
44
|
+
* own origin, and `createConnectHandler` is what reaches Connect. The workspace
|
|
45
|
+
* is resolved from the caller's session there, never sent from the browser - so
|
|
46
|
+
* a user can only ever ask about the workspace they are signed into.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <AppShell name="Dispatch" nav={nav}>
|
|
50
|
+
* {children}
|
|
51
|
+
* </AppShell>
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* `AppShell` mounts it by default. Mount it directly only when you are not
|
|
55
|
+
* using the shell: it renders a fixed corner trigger plus a panel that is an
|
|
56
|
+
* *in-flow flex sibling* at `lg` and up, so opening it pushes your content
|
|
57
|
+
* aside rather than covering it. That requires it to be the last child of a
|
|
58
|
+
* `flex` row owning the viewport height - which is exactly what `AppShell` is.
|
|
59
|
+
* Below `lg` it is a full-screen sheet with a backdrop instead; there is no
|
|
60
|
+
* room to push anything on a phone.
|
|
61
|
+
*
|
|
62
|
+
* **Host setup:** markdown rendering needs `streamdown` installed, one Tailwind
|
|
63
|
+
* `@source "…/node_modules/streamdown/dist/*.js"` line so its utility classes
|
|
64
|
+
* are generated, and `import "streamdown/styles.css"` for the streaming
|
|
65
|
+
* animation. The colour tokens Streamdown expects are already mapped in this
|
|
66
|
+
* SDK's `theme.css`.
|
|
67
|
+
*
|
|
68
|
+
* Answers require the workspace's Context Index to be turned on (a workspace
|
|
69
|
+
* admin toggle in Connect) and your API key to carry the `ai:chat` scope.
|
|
70
|
+
* Neither is something the browser can discover, so both surface as a message
|
|
71
|
+
* in the panel rather than as a hidden button.
|
|
72
|
+
*/
|
|
73
|
+
export declare function ConnectAskAi({ title, assistantName, placeholder, hint, defaultOpen, markdownPlugins, }: ConnectAskAiProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export interface ConnectConfirmDialogProps {
|
|
3
|
+
/** The control that opens it. Rendered inside `Modal.Trigger`. */
|
|
4
|
+
trigger: ReactNode;
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
/** What will happen, in the user's words. Name the thing being acted on. */
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
confirmLabel?: string;
|
|
9
|
+
cancelLabel?: string;
|
|
10
|
+
/** `danger` for anything that destroys data. */
|
|
11
|
+
tone?: "danger" | "primary";
|
|
12
|
+
onConfirm: () => void | Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The confirmation in front of a destructive action.
|
|
16
|
+
*
|
|
17
|
+
* **It closes on confirm, not on response.** Holding the modal open until the
|
|
18
|
+
* server answers makes every delete feel like a form submission, and the error
|
|
19
|
+
* path already has somewhere to go - a toast, or the row reappearing. A dialog
|
|
20
|
+
* that stays open to report failure is right only where the failure is
|
|
21
|
+
* *expected* and correctable in place (a seat cap, a last-admin invariant),
|
|
22
|
+
* and that is a blocking form, not this.
|
|
23
|
+
*
|
|
24
|
+
* `onConfirm` may return a promise. It is not awaited before closing, but a
|
|
25
|
+
* rejection is caught here rather than escaping - an error thrown out of an
|
|
26
|
+
* async transition reaches the nearest error boundary and takes the page down.
|
|
27
|
+
*
|
|
28
|
+
* The anatomy is HeroUI's: `Modal.Backdrop` owns the open state,
|
|
29
|
+
* `Modal.Container` the sizing, `Modal.Dialog` the focus trap. The trigger
|
|
30
|
+
* goes inside `Modal.Trigger`, which *is* a React Aria button - so pass a
|
|
31
|
+
* plain element, never a `<Button>`, or the nested button swallows the press
|
|
32
|
+
* and the dialog silently never opens.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ConnectConfirmDialog({ trigger, title, description, confirmLabel, cancelLabel, tone, onConfirm, }: Readonly<ConnectConfirmDialogProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ConnectCursorPaginationProps {
|
|
2
|
+
/** How many rows the current page is showing. Used for the live-region count. */
|
|
3
|
+
shown: number;
|
|
4
|
+
/** The cursor for the next page, or `null` when this is the last one. */
|
|
5
|
+
nextCursor: string | null;
|
|
6
|
+
/** Whether a previous page exists - the caller owns the cursor history. */
|
|
7
|
+
hasPrevious: boolean;
|
|
8
|
+
onNext: (cursor: string) => void;
|
|
9
|
+
onPrevious: () => void;
|
|
10
|
+
isPending?: boolean;
|
|
11
|
+
/** Singular/plural noun for the count, e.g. `["contact", "contacts"]`. */
|
|
12
|
+
noun?: readonly [string, string];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Next / previous for a cursor-paginated list.
|
|
16
|
+
*
|
|
17
|
+
* Cursor rather than page numbers, and the component shape follows from that:
|
|
18
|
+
* there is no "page 7 of 42" because a keyset-paginated list does not know how
|
|
19
|
+
* many pages there are without a second count query over the same filter -
|
|
20
|
+
* which is a billed index scan for a number nobody acts on. What a user does
|
|
21
|
+
* act on is "more" and "back", and those are exact.
|
|
22
|
+
*
|
|
23
|
+
* The count is announced in a live region so a screen-reader user learns that
|
|
24
|
+
* filtering or paging changed the result set. Without it the table silently
|
|
25
|
+
* swaps its contents.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ConnectCursorPagination({ shown, nextCursor, hasPrevious, onNext, onPrevious, isPending, noun, }: Readonly<ConnectCursorPaginationProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ConnectFilterTabsOption<TValue extends string> {
|
|
2
|
+
value: TValue | null;
|
|
3
|
+
label: string;
|
|
4
|
+
/** Shown as a count beside the label. Omit where a count would need its own query. */
|
|
5
|
+
count?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ConnectFilterTabsProps<TValue extends string> {
|
|
8
|
+
options: ReadonlyArray<ConnectFilterTabsOption<TValue>>;
|
|
9
|
+
value: TValue | null;
|
|
10
|
+
onChange: (value: TValue | null) => void;
|
|
11
|
+
/** Names the group for assistive technology - "Filter contacts by lifecycle". */
|
|
12
|
+
label: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A single-select filter strip - the "All / Open / Won / Lost" row above a
|
|
16
|
+
* list.
|
|
17
|
+
*
|
|
18
|
+
* Real radio semantics rather than a row of buttons: it is a single choice
|
|
19
|
+
* from a closed set, so arrow keys should move between options and the
|
|
20
|
+
* selected one should be announced as selected. A group of `<button>`s gets
|
|
21
|
+
* neither, and that is the usual hand-rolled shape.
|
|
22
|
+
*
|
|
23
|
+
* Scrolls horizontally rather than wrapping on a narrow viewport - a filter
|
|
24
|
+
* strip that wraps to three lines pushes the list itself off the screen.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ConnectFilterTabs<TValue extends string>({ options, value, onChange, label, }: Readonly<ConnectFilterTabsProps<TValue>>): import("react").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConnectGrievanceNoticeProps {
|
|
3
|
+
/**
|
|
4
|
+
* Heading text. `null` renders none, for embedding inside a page that
|
|
5
|
+
* already has one.
|
|
6
|
+
*/
|
|
7
|
+
title?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* What this application calls itself in the sentence naming the processor
|
|
10
|
+
* relationship. Omit to leave that sentence out entirely.
|
|
11
|
+
*/
|
|
12
|
+
applicationName?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The DPDP s.13 grievance channel, rendered.
|
|
17
|
+
*
|
|
18
|
+
* Every application on the platform is a Data Processor under one notice, so
|
|
19
|
+
* the wording lives here rather than being retyped per application - a user
|
|
20
|
+
* comparing two applications' privacy pages should not find two different
|
|
21
|
+
* accounts of who their Data Fiduciary is.
|
|
22
|
+
*
|
|
23
|
+
* Renders nothing at all while loading and nothing on failure, rather than a
|
|
24
|
+
* skeleton or an error. That is unusual here and deliberate: this component
|
|
25
|
+
* is almost always inside a larger privacy page that has its own content, and
|
|
26
|
+
* a red error box in the middle of a legal notice reads as the notice itself
|
|
27
|
+
* being broken. The address is also on the public web either way. Pass
|
|
28
|
+
* `useConnectCompanyProfile()` directly to your own layout if you want to
|
|
29
|
+
* handle those states yourself.
|
|
30
|
+
*/
|
|
31
|
+
export declare function ConnectGrievanceNotice({ title, applicationName, className, }: Readonly<ConnectGrievanceNoticeProps>): import("react").JSX.Element | null;
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import { type ButtonProps } from "@heroui/react";
|
|
2
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
3
|
export type ConnectLinkButtonProps = Omit<ButtonProps, "render"> & {
|
|
3
4
|
href: string;
|
|
5
|
+
/**
|
|
6
|
+
* The host's router link, if it has one.
|
|
7
|
+
*
|
|
8
|
+
* Without it this renders a plain `<a href>`, which navigates under every
|
|
9
|
+
* router but costs a **full document load** - in an App Router app that
|
|
10
|
+
* throws away the client cache and re-runs the whole tree, which is very
|
|
11
|
+
* visible on a button sitting inside a page the user is working in.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <ConnectLinkButton href="/deals" renderLink={(props) => <Link {...props} />}>
|
|
15
|
+
* Open board
|
|
16
|
+
* </ConnectLinkButton>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Same shape as `AppShell`'s `renderLink`, so a host declares its router
|
|
20
|
+
* once and passes the same function to both. This package imports nothing
|
|
21
|
+
* from `next` - see the `./next` entry's doc comment for why that is a hard
|
|
22
|
+
* rule - so handing the link component in is the only way it can be a client
|
|
23
|
+
* transition.
|
|
24
|
+
*/
|
|
25
|
+
renderLink?: (props: {
|
|
26
|
+
href: string;
|
|
27
|
+
className?: string;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}) => ReactElement;
|
|
4
30
|
};
|
|
5
31
|
/**
|
|
6
|
-
* A HeroUI `Button` that renders a
|
|
32
|
+
* A HeroUI `Button` that renders a link.
|
|
7
33
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* rule), so it cannot know which router - if any - the host app uses. An
|
|
11
|
-
* `<a href>` navigates under all of them, and a host that wants client-side
|
|
12
|
-
* routing can pass its own element via `render` on the underlying `Button`.
|
|
34
|
+
* HeroUI v3's `Button` has no `as` prop, so `<Button as={Link}>` does not type
|
|
35
|
+
* check and does not work - this is the supported route, via `render`.
|
|
13
36
|
*
|
|
14
37
|
* The cast is the same one HeroUI's own "Render Function" example needs:
|
|
15
38
|
* `render` types its argument as the props of the element `Button` would have
|
|
16
|
-
* emitted, which is a `<button
|
|
39
|
+
* emitted, which is a `<button>`, including a `ref` typed to
|
|
17
40
|
* `HTMLButtonElement`. Spreading that onto an anchor is sound at runtime and
|
|
18
|
-
* unrepresentable in the type, which is
|
|
41
|
+
* unrepresentable in the type, which is what the cast is for.
|
|
19
42
|
*/
|
|
20
|
-
export declare function ConnectLinkButton({ href, ...props }: Readonly<ConnectLinkButtonProps>): import("react").JSX.Element;
|
|
43
|
+
export declare function ConnectLinkButton({ href, renderLink, ...props }: Readonly<ConnectLinkButtonProps>): import("react").JSX.Element;
|
|
@@ -14,7 +14,23 @@ export interface ConnectLogoProps {
|
|
|
14
14
|
* Falls back to the Connect rings when omitted.
|
|
15
15
|
*/
|
|
16
16
|
icon?: ReactNode;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Which halves of the lockup to draw.
|
|
19
|
+
*
|
|
20
|
+
* - `"full"` - badge and wordmark, the default.
|
|
21
|
+
* - `"mark"` - the badge alone, for a collapsed rail or a favicon-sized slot.
|
|
22
|
+
* - `"wordmark"` - the words alone, for a layout that already draws the
|
|
23
|
+
* badge somewhere fixed. The sidebar header uses this: the badge stays put
|
|
24
|
+
* while the words fade, and rendering a second badge only to hide it with
|
|
25
|
+
* a CSS child selector is how that kind of layout quietly rots.
|
|
26
|
+
*/
|
|
27
|
+
variant?: "full" | "mark" | "wordmark";
|
|
28
|
+
/**
|
|
29
|
+
* Mark only, no wordmark.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated Pass `variant="mark"`. Kept because it is the published 0.11
|
|
32
|
+
* API; `variant` wins when both are given.
|
|
33
|
+
*/
|
|
18
34
|
collapsed?: boolean;
|
|
19
35
|
className?: string;
|
|
20
36
|
}
|
|
@@ -32,4 +48,4 @@ export interface ConnectLogoProps {
|
|
|
32
48
|
* as `text-sm`, with the badge, gap and tracking all in proportion. That is
|
|
33
49
|
* why there is no `size` prop.
|
|
34
50
|
*/
|
|
35
|
-
export declare function ConnectLogo({ name, icon, collapsed, className }: ConnectLogoProps): import("react").JSX.Element;
|
|
51
|
+
export declare function ConnectLogo({ name, icon, variant, collapsed, className }: ConnectLogoProps): import("react").JSX.Element;
|
|
@@ -28,11 +28,26 @@ export interface ConnectNavItem {
|
|
|
28
28
|
items?: ConnectNavItem[];
|
|
29
29
|
/**
|
|
30
30
|
* Leave this route *outside* `ConnectAccessGate` - see
|
|
31
|
-
* `
|
|
31
|
+
* `AppShellProps.gate`. Declared here, next to the route it applies
|
|
32
32
|
* to, rather than as a second list somewhere else that has to be kept in
|
|
33
33
|
* step with this one.
|
|
34
34
|
*/
|
|
35
35
|
gateExempt?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Who this route is for. Omit - the default - and it renders for everyone,
|
|
38
|
+
* which is what every route on an ordinary application is.
|
|
39
|
+
*
|
|
40
|
+
* - `"staff"` shows it only to a Connect platform staff session; your
|
|
41
|
+
* operator console goes here.
|
|
42
|
+
* - `"member"` hides it *from* staff. Reach for it on anything that reads
|
|
43
|
+
* the workspace - billing, plans, usage, team - since a staff session has
|
|
44
|
+
* no workspace and those routes can only fail for it.
|
|
45
|
+
*
|
|
46
|
+
* Filtering here is presentation, not access: it decides which links a
|
|
47
|
+
* person sees, and a link is not a permission. The route itself must still
|
|
48
|
+
* check `staff` on your server - see `<ConnectPlatformGate>`.
|
|
49
|
+
*/
|
|
50
|
+
audience?: "staff" | "member";
|
|
36
51
|
}
|
|
37
52
|
/** A titled group of items. Untitled groups render as a plain divider-free block. */
|
|
38
53
|
export interface ConnectNavSection {
|
|
@@ -40,7 +55,7 @@ export interface ConnectNavSection {
|
|
|
40
55
|
items: ConnectNavItem[];
|
|
41
56
|
}
|
|
42
57
|
/**
|
|
43
|
-
* What `
|
|
58
|
+
* What `AppShell`/`ConnectSideNav` accept for `nav`: a flat list of
|
|
44
59
|
* items, a list of sections, or a mix. Consecutive bare items fold into one
|
|
45
60
|
* untitled section, so the common case is just an array of items.
|
|
46
61
|
*/
|
|
@@ -106,5 +121,14 @@ export declare function resolveActivePath(pathname: string, nav: ConnectNav): st
|
|
|
106
121
|
* lights up on every app's home route. External items are never active.
|
|
107
122
|
*/
|
|
108
123
|
export declare function isNavItemActive(item: ConnectNavItem, activeHref: string | null): boolean;
|
|
109
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* `nav` with every item the current session should not see removed - see
|
|
126
|
+
* `ConnectNavItem.audience`.
|
|
127
|
+
*
|
|
128
|
+
* Applied to nested `items` too, and a parent whose children all disappear is
|
|
129
|
+
* dropped along with them: a section header pointing at nothing reads as a
|
|
130
|
+
* broken link rather than as a hidden one.
|
|
131
|
+
*/
|
|
132
|
+
export declare function filterNavForAudience(nav: ConnectNav, isStaff: boolean): ConnectNav;
|
|
133
|
+
/** Hrefs declared `gateExempt` - the routes `AppShell` renders outside its `ConnectAccessGate`. */
|
|
110
134
|
export declare function gateExemptPaths(nav: ConnectNav): string[];
|
|
@@ -24,6 +24,16 @@ export declare function formatPrice(paise: number): string;
|
|
|
24
24
|
* plan reads as an upgrade over every monthly one.
|
|
25
25
|
*/
|
|
26
26
|
export declare function monthlyOf(price: number, billingInterval: Plan["billingInterval"]): number;
|
|
27
|
+
export declare function intervalLabel(billingInterval: Plan["billingInterval"]): {
|
|
28
|
+
per: string;
|
|
29
|
+
short: string;
|
|
30
|
+
adverb: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* `/month`, `/year` - and nothing at all for a one-time plan, where a price
|
|
34
|
+
* with no slash is the honest rendering.
|
|
35
|
+
*/
|
|
36
|
+
export declare function pricePerLabel(billingInterval: Plan["billingInterval"]): string;
|
|
27
37
|
export declare function discountLabel(discount: AppliedDiscount): string;
|
|
28
38
|
/**
|
|
29
39
|
* The minimum a plan-like object has to expose to be grouped or compared -
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConnectPlatformGateProps {
|
|
3
|
+
/**
|
|
4
|
+
* Restrict to these platform roles. Omit to accept any staff session, which
|
|
5
|
+
* is the common case - your application already chose which roles it accepts
|
|
6
|
+
* when a platform admin turned staff access on for it, and repeating that
|
|
7
|
+
* list here is a second copy to keep in sync.
|
|
8
|
+
*
|
|
9
|
+
* Pass one only when your own console has tiers: a `developer` seeing the
|
|
10
|
+
* read-only half of what a `platform_admin` can edit.
|
|
11
|
+
*/
|
|
12
|
+
roles?: string[];
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Rendered for an ordinary member session. Defaults to `null` - hiding the
|
|
16
|
+
* subtree, which is what this gate is normally for. An operator console is
|
|
17
|
+
* usually better hidden than explained.
|
|
18
|
+
*/
|
|
19
|
+
fallback?: ReactNode;
|
|
20
|
+
/** Shown until the session read settles. Defaults to nothing. */
|
|
21
|
+
loading?: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Renders `children` only for a Connect platform staff session.
|
|
25
|
+
*
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <ConnectPlatformGate>
|
|
28
|
+
* <LinkMasterConsole />
|
|
29
|
+
* </ConnectPlatformGate>
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* Staff are Connect's own operators - `platform_admin`, `platform_manager`,
|
|
33
|
+
* `developer` - signing into *your* application. They belong to no workspace,
|
|
34
|
+
* so a staff session carries no `workspaceId`, no subscription and no member
|
|
35
|
+
* role; see `SessionAccess.staff`. Staff access is off by default and turned on
|
|
36
|
+
* per application by a Connect platform admin, so this gate renders nothing
|
|
37
|
+
* until that happens.
|
|
38
|
+
*
|
|
39
|
+
* **This is a UX gate, not a security boundary** - the same caveat every gate
|
|
40
|
+
* in this package carries, and it matters more here than anywhere else,
|
|
41
|
+
* because what is behind this one is usually an operator console. The browser
|
|
42
|
+
* can ignore this component entirely. Every route it reveals must re-check
|
|
43
|
+
* `staff` on your own server:
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const { staff, role } = await client.identity.getUser(sessionToken);
|
|
47
|
+
* if (!staff) return forbidden();
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Renders `loading` - not `fallback` - while the session is unknown, so an
|
|
51
|
+
* operator never flickers through the customer layout on the way in.
|
|
52
|
+
*/
|
|
53
|
+
export declare function ConnectPlatformGate({ roles, children, fallback, loading, }: ConnectPlatformGateProps): import("react").JSX.Element;
|