@odla-ai/chapter 0.20.2 → 0.22.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 +147 -32
- package/dist/{chunk-LME2IHY5.js → chunk-ILGUJXSB.js} +1 -1
- package/dist/chunk-ILGUJXSB.js.map +1 -0
- package/dist/chunk-IWW5VAAC.js +1666 -0
- package/dist/chunk-IWW5VAAC.js.map +1 -0
- package/dist/chunk-VZPBTTO3.js +91 -0
- package/dist/chunk-VZPBTTO3.js.map +1 -0
- package/dist/index.cjs +72 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -19
- package/dist/index.d.ts +78 -19
- package/dist/index.js +72 -6
- package/dist/index.js.map +1 -1
- package/dist/{types-D2fGiNG8.d.ts → types-CgWUQ2MH.d.ts} +50 -8
- package/dist/ui/admin/index.d.ts +150 -83
- package/dist/ui/admin/index.js +14 -2
- package/dist/ui/index.d.ts +3 -2
- package/dist/ui/index.js +15 -3
- package/dist/ui/member/index.d.ts +3 -1
- package/dist/ui/member/index.js +2 -2
- package/dist/worker/index.cjs +28 -16
- package/dist/worker/index.cjs.map +1 -1
- package/dist/worker/index.d.cts +50 -8
- package/dist/worker/index.d.ts +50 -8
- package/dist/worker/index.js +28 -16
- package/dist/worker/index.js.map +1 -1
- package/package.json +3 -3
- package/runbooks/adopt-existing.md +22 -4
- package/runbooks/greenfield.md +19 -9
- package/dist/chunk-LME2IHY5.js.map +0 -1
- package/dist/chunk-MKXHZMAP.js +0 -51
- package/dist/chunk-MKXHZMAP.js.map +0 -1
- package/dist/chunk-UIWFEESI.js +0 -922
- package/dist/chunk-UIWFEESI.js.map +0 -1
|
@@ -31,8 +31,50 @@ interface Rule {
|
|
|
31
31
|
}
|
|
32
32
|
/** Namespace → rule set. */
|
|
33
33
|
type DbRules = Record<string, Rule>;
|
|
34
|
-
/**
|
|
34
|
+
/** Typed semantic roles shared by the public site and application surfaces. */
|
|
35
|
+
interface ChapterBrandTokens {
|
|
36
|
+
background?: string;
|
|
37
|
+
surface?: string;
|
|
38
|
+
surface2?: string;
|
|
39
|
+
text?: string;
|
|
40
|
+
textMuted?: string;
|
|
41
|
+
textFaint?: string;
|
|
42
|
+
border?: string;
|
|
43
|
+
borderStrong?: string;
|
|
44
|
+
accent?: string;
|
|
45
|
+
accentStrong?: string;
|
|
46
|
+
accentSoft?: string;
|
|
47
|
+
onAccent?: string;
|
|
48
|
+
good?: string;
|
|
49
|
+
warn?: string;
|
|
50
|
+
danger?: string;
|
|
51
|
+
chart1?: string;
|
|
52
|
+
chart2?: string;
|
|
53
|
+
chart3?: string;
|
|
54
|
+
chart4?: string;
|
|
55
|
+
chart5?: string;
|
|
56
|
+
chart6?: string;
|
|
57
|
+
chartPositive?: string;
|
|
58
|
+
chartNegative?: string;
|
|
59
|
+
/** Admin/application content width, e.g. `"960px"`. */
|
|
60
|
+
contentWidth?: string;
|
|
61
|
+
panelRadius?: string;
|
|
62
|
+
panelShadow?: string;
|
|
63
|
+
masterDetailColumns?: string;
|
|
64
|
+
masterDetailMinHeight?: string;
|
|
65
|
+
/** Chapter-admin page padding shorthand. */
|
|
66
|
+
pagePadding?: string;
|
|
67
|
+
/** Chapter-admin workspace-tab padding shorthand. */
|
|
68
|
+
workspacePadding?: string;
|
|
69
|
+
}
|
|
70
|
+
/** Brand tokens that theme the site: theme, semantic roles, fonts, and logos. */
|
|
35
71
|
interface ChapterBrand {
|
|
72
|
+
/** Preloaded @odla-ai/ui theme name used by ThemeScope. */
|
|
73
|
+
theme?: string;
|
|
74
|
+
/** Admin/application color mode. Explicit light is the safe default. */
|
|
75
|
+
colorScheme?: "light" | "dark" | "system";
|
|
76
|
+
tokens?: ChapterBrandTokens;
|
|
77
|
+
tokensDark?: ChapterBrandTokens;
|
|
36
78
|
/** Palette overrides written into styles.css :root (e.g. `{ moss: "#2F3E34" }`
|
|
37
79
|
* or `--ui-*` token names). Applies in BOTH light and dark unless overridden
|
|
38
80
|
* by {@link paletteDark}. */
|
|
@@ -66,7 +108,7 @@ interface ChapterNetworkTarget {
|
|
|
66
108
|
id: string;
|
|
67
109
|
/** Human-facing site name. Defaults to `id`. */
|
|
68
110
|
name?: string;
|
|
69
|
-
/** Absolute follower origin, e.g. `https://
|
|
111
|
+
/** Absolute follower origin, e.g. `https://chapter.example.com`. */
|
|
70
112
|
url: string;
|
|
71
113
|
/** Leader-vault key holding this follower's share secret. Defaults to
|
|
72
114
|
* `network_share_<id-with-underscores>`. */
|
|
@@ -137,10 +179,10 @@ interface ChapterScheduling {
|
|
|
137
179
|
}
|
|
138
180
|
/** How a signed-in user's role is determined.
|
|
139
181
|
*
|
|
140
|
-
* - `"claim"` reads a role ladder from a JWT claim (
|
|
182
|
+
* - `"claim"` reads a role ladder from a JWT claim (the member-site model:
|
|
141
183
|
* `provisional → member → admin`). Admin is the last (highest) rung; the
|
|
142
184
|
* read-only `superAdmins` tier sits above it.
|
|
143
|
-
* - `"table"` gates on the deny-all `admins` allowlist (
|
|
185
|
+
* - `"table"` gates on the deny-all `admins` allowlist (the hub model):
|
|
144
186
|
* a binary "email is an admin or isn't", set only in odla Studio.
|
|
145
187
|
*
|
|
146
188
|
* Defaults: `"claim"` in `chapter` mode, `"table"` in `hub` mode. */
|
|
@@ -167,7 +209,7 @@ interface ResolvedAuth {
|
|
|
167
209
|
}
|
|
168
210
|
/** The application status pipeline. Which statuses exist, and the subsets a site
|
|
169
211
|
* allows a call to be booked from / an application approved from. Defaults to
|
|
170
|
-
*
|
|
212
|
+
* the reference pipeline. Status never moves backwards (package-enforced). */
|
|
171
213
|
interface ChapterPipeline {
|
|
172
214
|
stages?: readonly string[];
|
|
173
215
|
bookableFrom?: readonly string[];
|
|
@@ -184,8 +226,8 @@ interface ResolvedPipeline {
|
|
|
184
226
|
}
|
|
185
227
|
/** The application (join form) validation surface — which string fields are
|
|
186
228
|
* required vs accepted, their max lengths, and the request body cap. Drives
|
|
187
|
-
* submit validation + the CRM slot projection; defaults to
|
|
188
|
-
* The `applications` schema attrs stay fixed
|
|
229
|
+
* submit validation + the CRM slot projection; defaults to the reference form.
|
|
230
|
+
* The `applications` schema attrs stay fixed; this is
|
|
189
231
|
* validation config, not schema generation. */
|
|
190
232
|
interface ChapterApplication {
|
|
191
233
|
required?: readonly string[];
|
|
@@ -257,7 +299,7 @@ interface ChapterConfig {
|
|
|
257
299
|
/** `notificationEmail` required in `chapter` mode. */
|
|
258
300
|
emails?: ChapterEmails;
|
|
259
301
|
scheduling?: ChapterScheduling;
|
|
260
|
-
/** Application status pipeline (stages + bookable/approvable subsets).
|
|
302
|
+
/** Application status pipeline (stages + bookable/approvable subsets). */
|
|
261
303
|
pipeline?: ChapterPipeline;
|
|
262
304
|
/** Join-form validation (required/optional fields, max lengths, body cap). */
|
|
263
305
|
application?: ChapterApplication;
|
package/dist/ui/admin/index.d.ts
CHANGED
|
@@ -1,133 +1,201 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { CrmClient, Crm, CrmRecord } from '@odla-ai/crm';
|
|
4
|
-
import { C as Chapter } from '../../types-
|
|
4
|
+
import { C as Chapter } from '../../types-CgWUQ2MH.js';
|
|
5
|
+
import { CrmLifecycleAdapter, CrmWorkspaceMasterContext, CrmWorkspaceRecordContext, RecordPanelTab } from '@odla-ai/crm/ui';
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
client: CrmClient;
|
|
10
|
-
getToken: () => Promise<string | null>;
|
|
11
|
-
/** Switch to another section by id (e.g. Overview "jump in" buttons). */
|
|
12
|
-
navigate: (sectionId: string) => void;
|
|
7
|
+
/** Normalized public auth configuration consumed by the Clerk gate. */
|
|
8
|
+
interface ChapterAdminAuthConfig {
|
|
9
|
+
publishableKey: string | null;
|
|
13
10
|
}
|
|
14
|
-
/**
|
|
15
|
-
interface
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
/** Normalized current-user data retained for workspace visibility decisions. */
|
|
12
|
+
interface ChapterAdminUser extends Record<string, unknown> {
|
|
13
|
+
authorized?: boolean;
|
|
14
|
+
email?: string | null;
|
|
15
|
+
}
|
|
16
|
+
/** Inputs supplied to custom admin configuration and current-user loaders. */
|
|
17
|
+
interface ChapterAdminAuthLoadContext {
|
|
18
|
+
apiBase: string;
|
|
19
|
+
getToken?: () => Promise<string | null>;
|
|
20
|
+
}
|
|
21
|
+
/** Existing-site adapter for auth endpoint names and response shapes. */
|
|
22
|
+
interface ChapterAdminAuthAdapter {
|
|
23
|
+
configPath?: string;
|
|
24
|
+
currentUserPath?: string;
|
|
25
|
+
loadConfig?: (context: ChapterAdminAuthLoadContext) => Promise<ChapterAdminAuthConfig>;
|
|
26
|
+
loadCurrentUser?: (context: Required<ChapterAdminAuthLoadContext>) => Promise<ChapterAdminUser>;
|
|
27
|
+
mapConfig?: (body: Record<string, unknown>) => ChapterAdminAuthConfig;
|
|
28
|
+
mapCurrentUser?: (body: Record<string, unknown>) => ChapterAdminUser;
|
|
29
|
+
isAuthorized?: (user: ChapterAdminUser) => boolean;
|
|
19
30
|
}
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/** Wordmark shown in the gate and top bar. `name` is the plain-text identity (and
|
|
26
|
-
* the badge fallback); `wordmark` is an optional rich display node for brands
|
|
27
|
-
* whose typography can't be a plain string (e.g. an ampersand wrapped to render
|
|
28
|
-
* upright), and `badge` overrides the glyph. */
|
|
31
|
+
/** Load and normalize the public authentication configuration. */
|
|
32
|
+
declare function loadChapterAdminConfig(adapter: ChapterAdminAuthAdapter, apiBase: string): Promise<ChapterAdminAuthConfig>;
|
|
33
|
+
/** Load and normalize the authenticated user used by admin workspaces. */
|
|
34
|
+
declare function loadChapterAdminUser(adapter: ChapterAdminAuthAdapter, apiBase: string, getToken: () => Promise<string | null>): Promise<ChapterAdminUser>;
|
|
35
|
+
|
|
29
36
|
type Brand = {
|
|
30
37
|
name: string;
|
|
31
38
|
badge?: string;
|
|
32
39
|
wordmark?: ReactNode;
|
|
33
40
|
};
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
/** Typed URL state for the admin's nested in-page workspaces. */
|
|
43
|
+
interface AdminRouteState {
|
|
44
|
+
workspaceId: string;
|
|
45
|
+
viewId?: string;
|
|
46
|
+
recordId?: string;
|
|
47
|
+
detailTab?: string;
|
|
48
|
+
}
|
|
49
|
+
/** URL encoding used for admin workspace state. */
|
|
50
|
+
type AdminRouting = "fragment" | "query" | "path";
|
|
51
|
+
type AdminRouteAliases = Readonly<Record<string, AdminRouteState>>;
|
|
52
|
+
/** Read canonical fragments first, then inbound query and legacy path links. */
|
|
53
|
+
declare function adminRouteFromUrl(url: URL, basePath: string, workspaceIds: readonly string[], aliases?: AdminRouteAliases): AdminRouteState;
|
|
54
|
+
/** Build a stable URL for one admin state. Fragment routing is the default. */
|
|
55
|
+
declare function adminRouteHref(current: URL, basePath: string, route: AdminRouteState, routing?: AdminRouting): string;
|
|
56
|
+
/** Backwards-compatible section helpers over the workspace router. */
|
|
36
57
|
declare function adminSectionFromUrl(url: URL, basePath: string, sectionIds: readonly string[]): string;
|
|
37
|
-
/** Build
|
|
38
|
-
* policy. Query mode collapses a legacy path route back to the admin mount. */
|
|
58
|
+
/** Build a compatibility URL for a top-level admin section. */
|
|
39
59
|
declare function adminSectionHref(current: URL, basePath: string, id: string, routing?: AdminRouting): string;
|
|
40
60
|
|
|
41
|
-
/**
|
|
61
|
+
/** A workspace id or partial nested route passed to navigation helpers. */
|
|
62
|
+
type AdminRouteTarget = string | {
|
|
63
|
+
workspaceId?: string;
|
|
64
|
+
viewId?: string | null;
|
|
65
|
+
recordId?: string | null;
|
|
66
|
+
detailTab?: string | null;
|
|
67
|
+
};
|
|
68
|
+
/** Context shared by every admin workspace and its nested views. */
|
|
69
|
+
interface AdminSectionContext {
|
|
70
|
+
client: CrmClient;
|
|
71
|
+
getToken: () => Promise<string | null>;
|
|
72
|
+
currentUser?: Record<string, unknown>;
|
|
73
|
+
route: AdminRouteState;
|
|
74
|
+
navigate: (target: AdminRouteTarget) => void;
|
|
75
|
+
href: (target: AdminRouteTarget) => string;
|
|
76
|
+
}
|
|
77
|
+
/** One top-level admin workspace rendered inside the signed-in shell. */
|
|
78
|
+
interface AdminWorkspace {
|
|
79
|
+
id: string;
|
|
80
|
+
label: string;
|
|
81
|
+
/** Canonical nested view used when a workspace is opened without one. */
|
|
82
|
+
defaultViewId?: string;
|
|
83
|
+
render: (ctx: AdminSectionContext) => ReactNode;
|
|
84
|
+
}
|
|
85
|
+
/** Legacy name for a top-level workspace. @deprecated Use AdminWorkspace. */
|
|
86
|
+
type AdminSection = AdminWorkspace;
|
|
87
|
+
/** Built-in shell presentation; embedded preserves site-owned chrome. */
|
|
88
|
+
type AdminChrome = "embedded" | "standalone" | "editorial" | "topbar" | "none";
|
|
89
|
+
/** Identity and sign-out services supplied to host-owned account controls. */
|
|
90
|
+
interface AdminAccountMenuProps {
|
|
91
|
+
brand: Brand;
|
|
92
|
+
email: string | null;
|
|
93
|
+
currentUser?: Record<string, unknown>;
|
|
94
|
+
signOut: () => void;
|
|
95
|
+
}
|
|
96
|
+
/** Workspace route and navigation services supplied to host-owned navigation. */
|
|
97
|
+
interface AdminWorkspaceNavProps {
|
|
98
|
+
workspaces: readonly AdminWorkspace[];
|
|
99
|
+
route: AdminRouteState;
|
|
100
|
+
navigate: (target: AdminRouteTarget) => void;
|
|
101
|
+
href: (target: AdminRouteTarget) => string;
|
|
102
|
+
}
|
|
103
|
+
interface AdminShellProps {
|
|
104
|
+
workspaces: AdminWorkspace[];
|
|
105
|
+
basePath: string;
|
|
106
|
+
brand: Brand;
|
|
107
|
+
client: CrmClient;
|
|
108
|
+
getToken: () => Promise<string | null>;
|
|
109
|
+
signOut: () => void;
|
|
110
|
+
email: string | null;
|
|
111
|
+
currentUser?: Record<string, unknown>;
|
|
112
|
+
routing?: AdminRouting;
|
|
113
|
+
chrome?: AdminChrome;
|
|
114
|
+
renderHeader?: (props: AdminAccountMenuProps) => ReactNode;
|
|
115
|
+
renderAccountMenu?: (props: AdminAccountMenuProps) => ReactNode;
|
|
116
|
+
renderWorkspaceNav?: (props: AdminWorkspaceNavProps) => ReactNode;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Configuration for the Clerk-gated, brand-scoped Chapter admin console. */
|
|
42
120
|
interface ChapterAdminProps {
|
|
43
|
-
/** The resolved site config. When present it supplies the brand and, unless
|
|
44
|
-
* `sections` is passed, the complete standard section catalog. */
|
|
45
121
|
chapter?: Chapter;
|
|
46
|
-
/**
|
|
122
|
+
/** Replace or transform the standard workspace set. */
|
|
123
|
+
workspaces?: AdminWorkspace[] | ((defaults: readonly AdminWorkspace[]) => AdminWorkspace[]);
|
|
124
|
+
/** @deprecated Use workspaces. */
|
|
47
125
|
sections?: AdminSection[];
|
|
48
|
-
/** Admin mount path. The sign-in redirect + section routing derive from it,
|
|
49
|
-
* so the "bounce to home after sign-in" bug is impossible. Default "/admin". */
|
|
50
126
|
basePath?: string;
|
|
51
|
-
/** Wordmark shown in the gate + top bar. */
|
|
52
127
|
brand?: Brand;
|
|
53
|
-
/** CRM route mount. Default "/api/crm". */
|
|
54
128
|
crmBasePath?: string;
|
|
55
|
-
/** Origin for /api/config and /api/me. Default same origin. */
|
|
56
129
|
apiBase?: string;
|
|
57
|
-
/**
|
|
58
|
-
* works with both SPA and ordinary static hosting. `"path"` requires the host
|
|
59
|
-
* to serve the admin entry for every `/admin/<section>` URL. */
|
|
130
|
+
/** Default fragment: `/admin/#people/person/record-id/profile`. */
|
|
60
131
|
routing?: AdminRouting;
|
|
132
|
+
/** Default embedded. Standalone adds packaged global chrome. */
|
|
133
|
+
chrome?: AdminChrome;
|
|
134
|
+
renderHeader?: AdminShellProps["renderHeader"];
|
|
135
|
+
renderAccountMenu?: (props: AdminAccountMenuProps) => ReactNode;
|
|
136
|
+
renderWorkspaceNav?: (props: AdminWorkspaceNavProps) => ReactNode;
|
|
137
|
+
/** Adapt existing config/current-user endpoints without rewriting auth. */
|
|
138
|
+
auth?: ChapterAdminAuthAdapter;
|
|
61
139
|
}
|
|
62
|
-
/**
|
|
63
|
-
* The whole admin console for a chapter/hub: fetches the Clerk publishable key
|
|
64
|
-
* (/api/config), gates on sign-in with the post-sign-in redirect derived from
|
|
65
|
-
* `basePath`, checks the odla-db admins allowlist (/api/me), and renders a
|
|
66
|
-
* TopBar shell over the caller's `sections`. The gate/shell/redirect are owned
|
|
67
|
-
* here so no site re-wires (or re-bugs) them.
|
|
68
|
-
*/
|
|
140
|
+
/** Render the complete authenticated admin application from one Chapter config. */
|
|
69
141
|
declare function ChapterAdmin(props: ChapterAdminProps): react.JSX.Element;
|
|
70
142
|
|
|
71
|
-
/**
|
|
72
|
-
|
|
73
|
-
|
|
143
|
+
/** Default follower grammar: three workspaces with nested operational views. */
|
|
144
|
+
declare function defaultAdminWorkspaces(chapter: Chapter): AdminWorkspace[];
|
|
145
|
+
|
|
146
|
+
/** Legacy default catalog. @deprecated Use defaultAdminWorkspaces. */
|
|
74
147
|
declare function defaultAdminSections(chapter: Chapter): AdminSection[];
|
|
75
148
|
|
|
76
|
-
/**
|
|
149
|
+
/** Application-authoritative stage transitions used by Chapter collections. */
|
|
150
|
+
declare function applicationLifecycleAdapter(ctx: Pick<AdminSectionContext, "getToken">): CrmLifecycleAdapter;
|
|
151
|
+
|
|
152
|
+
/** Configuration for the person-collection compatibility preset. */
|
|
77
153
|
interface PeopleSectionOptions {
|
|
78
|
-
/** The chapter's resolved CRM engine — `chapter.crm` from defineChapter. */
|
|
79
154
|
crm: Crm;
|
|
80
|
-
/** Section id / route segment. Default "people". */
|
|
81
155
|
id?: string;
|
|
82
|
-
/** Nav label. Default "People". */
|
|
83
156
|
label?: string;
|
|
84
|
-
/** The record type to list. Default "person". */
|
|
85
157
|
type?: string;
|
|
86
158
|
}
|
|
87
|
-
/**
|
|
159
|
+
/** Configuration for one CRM collection and its application-specific tabs. */
|
|
88
160
|
interface CollectionSectionOptions {
|
|
89
|
-
/** The chapter's resolved CRM engine — `chapter.crm` from defineChapter. */
|
|
90
161
|
crm: Crm;
|
|
91
|
-
/** The CRM record type to list (e.g. `"person"`, `"deal"`, `"investment"`). */
|
|
92
162
|
type: string;
|
|
93
|
-
/** Section id / route segment. Defaults to `type`. */
|
|
94
163
|
id?: string;
|
|
95
|
-
/** Nav label. Defaults to the type's plural label from the CRM config. */
|
|
96
164
|
label?: string;
|
|
97
|
-
/** Show the lifecycle action panel (role change / approve / refund) on an open
|
|
98
|
-
* record — for application-backed people. Default `true` for `type: "person"`,
|
|
99
|
-
* `false` otherwise (a `deal`/`investment` has no approve/refund). */
|
|
100
165
|
lifecycle?: boolean;
|
|
101
|
-
/** Role ladder for the role selector. Default `["provisional","member","admin"]`
|
|
102
|
-
* — pass your `chapter.auth.ladder` if you use a custom ladder. */
|
|
103
166
|
roles?: readonly string[];
|
|
167
|
+
networkSharing?: boolean;
|
|
168
|
+
lifecycleAdapter?: (CrmLifecycleAdapter | ((ctx: AdminSectionContext) => CrmLifecycleAdapter));
|
|
169
|
+
requireLifecycleAdapter?: boolean;
|
|
170
|
+
renderSummary?: (context: CrmWorkspaceMasterContext, ctx: AdminSectionContext) => ReactNode;
|
|
171
|
+
renderMaster?: (context: CrmWorkspaceMasterContext, ctx: AdminSectionContext) => ReactNode;
|
|
172
|
+
renderDetailHeader?: (context: CrmWorkspaceRecordContext, ctx: AdminSectionContext) => ReactNode;
|
|
173
|
+
renderEmptyDetail?: (context: CrmWorkspaceMasterContext, ctx: AdminSectionContext) => ReactNode;
|
|
174
|
+
hrefForRecord?: (record: CrmRecord, ctx: AdminSectionContext) => string;
|
|
175
|
+
extendRecordTabs?: (tabs: readonly RecordPanelTab[], context: CrmWorkspaceRecordContext) => readonly RecordPanelTab[];
|
|
104
176
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Build a CRM collection admin section for ANY declared record type: a
|
|
107
|
-
* server-driven records table plus a facet-composed detail drawer (fields,
|
|
108
|
-
* pipeline stage, tags) over the token-bound CrmClient, and — for people — a
|
|
109
|
-
* lifecycle action panel (role change, approve, refund) wired to the
|
|
110
|
-
* `/api/admin/*` routes. This is the generic kit — call it once per collection a
|
|
111
|
-
* site runs (members, deals, investments), and each renders with the same UX.
|
|
112
|
-
* CRM edits go through `/api/crm/*` and lifecycle actions through `/api/admin/*`,
|
|
113
|
-
* never a direct db write, so the invariants hold.
|
|
114
|
-
*/
|
|
177
|
+
/** Build one CRM collection as an admin workspace. */
|
|
115
178
|
declare function collectionSection(options: CollectionSectionOptions): AdminSection;
|
|
116
|
-
/**
|
|
117
|
-
* Build the People/CRM admin section — {@link collectionSection} preset to the
|
|
118
|
-
* `person` type (so the lifecycle actions are on). New collections use
|
|
119
|
-
* `collectionSection`.
|
|
120
|
-
*/
|
|
179
|
+
/** Person-collection preset. */
|
|
121
180
|
declare function peopleSection(options: PeopleSectionOptions & {
|
|
122
181
|
roles?: readonly string[];
|
|
182
|
+
networkSharing?: boolean;
|
|
183
|
+
lifecycleAdapter?: CollectionSectionOptions["lifecycleAdapter"];
|
|
184
|
+
requireLifecycleAdapter?: boolean;
|
|
185
|
+
renderSummary?: CollectionSectionOptions["renderSummary"];
|
|
186
|
+
renderMaster?: CollectionSectionOptions["renderMaster"];
|
|
187
|
+
renderDetailHeader?: CollectionSectionOptions["renderDetailHeader"];
|
|
188
|
+
renderEmptyDetail?: CollectionSectionOptions["renderEmptyDetail"];
|
|
189
|
+
hrefForRecord?: CollectionSectionOptions["hrefForRecord"];
|
|
190
|
+
extendRecordTabs?: CollectionSectionOptions["extendRecordTabs"];
|
|
123
191
|
}): AdminSection;
|
|
124
192
|
|
|
125
|
-
/**
|
|
193
|
+
/** Labels and ids for a composed dashboard workspace entry. */
|
|
126
194
|
interface DashboardSectionOptions {
|
|
127
195
|
id?: string;
|
|
128
196
|
label?: string;
|
|
129
197
|
}
|
|
130
|
-
/** Build the
|
|
198
|
+
/** Build the operational dashboard workspace over `/api/admin/dashboard`. */
|
|
131
199
|
declare function dashboardSection(options?: DashboardSectionOptions): AdminSection;
|
|
132
200
|
|
|
133
201
|
/** Options for {@link billingSection}. */
|
|
@@ -214,12 +282,11 @@ declare function Panel({ title, actions, children }: {
|
|
|
214
282
|
actions?: ReactNode;
|
|
215
283
|
children: ReactNode;
|
|
216
284
|
}): react.JSX.Element;
|
|
217
|
-
/** A loud banner when the odla-ui theme token layer is missing
|
|
218
|
-
* total failure S&S flagged. Renders nothing when the theme is present. */
|
|
285
|
+
/** A loud banner when the odla-ui theme token layer is missing. */
|
|
219
286
|
declare function ThemeWarning(): react.JSX.Element | null;
|
|
220
287
|
/** A centered status line for loading / empty / error states. */
|
|
221
288
|
declare function AdminNote({ children }: {
|
|
222
289
|
children: ReactNode;
|
|
223
290
|
}): react.JSX.Element;
|
|
224
291
|
|
|
225
|
-
export { AdminNote, AdminPage, type AdminResource, type AdminRouting, type AdminSection, type AdminSectionContext, type AvailabilitySectionOptions, type BillingSectionOptions, ChapterAdmin, type ChapterAdminProps, type CollectionSectionOptions, type DashboardSectionOptions, type EmailSectionOptions, type MeetingsSectionOptions, NetworkShareActions, type NetworkShareActionsProps, Panel, type PeopleSectionOptions, RecordActions, type RecordActionsProps, ThemeWarning, adminFetch, adminSectionFromUrl, adminSectionHref, availabilitySection, billingSection, collectionSection, dashboardSection, defaultAdminSections, emailSection, meetingsSection, peopleSection, useAdminResource };
|
|
292
|
+
export { type AdminAccountMenuProps, type AdminChrome, AdminNote, AdminPage, type AdminResource, type AdminRouteState, type AdminRouteTarget, type AdminRouting, type AdminSection, type AdminSectionContext, type AdminWorkspace, type AdminWorkspaceNavProps, type AvailabilitySectionOptions, type BillingSectionOptions, ChapterAdmin, type ChapterAdminAuthAdapter, type ChapterAdminAuthConfig, type ChapterAdminAuthLoadContext, type ChapterAdminProps, type ChapterAdminUser, type CollectionSectionOptions, type DashboardSectionOptions, type EmailSectionOptions, type MeetingsSectionOptions, NetworkShareActions, type NetworkShareActionsProps, Panel, type PeopleSectionOptions, RecordActions, type RecordActionsProps, ThemeWarning, adminFetch, adminRouteFromUrl, adminRouteHref, adminSectionFromUrl, adminSectionHref, applicationLifecycleAdapter, availabilitySection, billingSection, collectionSection, dashboardSection, defaultAdminSections, defaultAdminWorkspaces, emailSection, loadChapterAdminConfig, loadChapterAdminUser, meetingsSection, peopleSection, useAdminResource };
|
package/dist/ui/admin/index.js
CHANGED
|
@@ -7,19 +7,25 @@ import {
|
|
|
7
7
|
RecordActions,
|
|
8
8
|
ThemeWarning,
|
|
9
9
|
adminFetch,
|
|
10
|
+
adminRouteFromUrl,
|
|
11
|
+
adminRouteHref,
|
|
10
12
|
adminSectionFromUrl,
|
|
11
13
|
adminSectionHref,
|
|
14
|
+
applicationLifecycleAdapter,
|
|
12
15
|
availabilitySection,
|
|
13
16
|
billingSection,
|
|
14
17
|
collectionSection,
|
|
15
18
|
dashboardSection,
|
|
16
19
|
defaultAdminSections,
|
|
20
|
+
defaultAdminWorkspaces,
|
|
17
21
|
emailSection,
|
|
22
|
+
loadChapterAdminConfig,
|
|
23
|
+
loadChapterAdminUser,
|
|
18
24
|
meetingsSection,
|
|
19
25
|
peopleSection,
|
|
20
26
|
useAdminResource
|
|
21
|
-
} from "../../chunk-
|
|
22
|
-
import "../../chunk-
|
|
27
|
+
} from "../../chunk-IWW5VAAC.js";
|
|
28
|
+
import "../../chunk-VZPBTTO3.js";
|
|
23
29
|
export {
|
|
24
30
|
AdminNote,
|
|
25
31
|
AdminPage,
|
|
@@ -29,14 +35,20 @@ export {
|
|
|
29
35
|
RecordActions,
|
|
30
36
|
ThemeWarning,
|
|
31
37
|
adminFetch,
|
|
38
|
+
adminRouteFromUrl,
|
|
39
|
+
adminRouteHref,
|
|
32
40
|
adminSectionFromUrl,
|
|
33
41
|
adminSectionHref,
|
|
42
|
+
applicationLifecycleAdapter,
|
|
34
43
|
availabilitySection,
|
|
35
44
|
billingSection,
|
|
36
45
|
collectionSection,
|
|
37
46
|
dashboardSection,
|
|
38
47
|
defaultAdminSections,
|
|
48
|
+
defaultAdminWorkspaces,
|
|
39
49
|
emailSection,
|
|
50
|
+
loadChapterAdminConfig,
|
|
51
|
+
loadChapterAdminUser,
|
|
40
52
|
meetingsSection,
|
|
41
53
|
peopleSection,
|
|
42
54
|
useAdminResource
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { AdminNote, AdminPage, AdminResource, AdminRouting, AdminSection, AdminSectionContext, AvailabilitySectionOptions, BillingSectionOptions, ChapterAdmin, ChapterAdminProps, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, MeetingsSectionOptions, NetworkShareActions, NetworkShareActionsProps, Panel, PeopleSectionOptions, RecordActions, RecordActionsProps, ThemeWarning, adminFetch, adminSectionFromUrl, adminSectionHref, availabilitySection, billingSection, collectionSection, dashboardSection, defaultAdminSections, emailSection, meetingsSection, peopleSection, useAdminResource } from './admin/index.js';
|
|
1
|
+
export { AdminAccountMenuProps, AdminChrome, AdminNote, AdminPage, AdminResource, AdminRouteState, AdminRouteTarget, AdminRouting, AdminSection, AdminSectionContext, AdminWorkspace, AdminWorkspaceNavProps, AvailabilitySectionOptions, BillingSectionOptions, ChapterAdmin, ChapterAdminAuthAdapter, ChapterAdminAuthConfig, ChapterAdminAuthLoadContext, ChapterAdminProps, ChapterAdminUser, CollectionSectionOptions, DashboardSectionOptions, EmailSectionOptions, MeetingsSectionOptions, NetworkShareActions, NetworkShareActionsProps, Panel, PeopleSectionOptions, RecordActions, RecordActionsProps, ThemeWarning, adminFetch, adminRouteFromUrl, adminRouteHref, adminSectionFromUrl, adminSectionHref, applicationLifecycleAdapter, availabilitySection, billingSection, collectionSection, dashboardSection, defaultAdminSections, defaultAdminWorkspaces, emailSection, loadChapterAdminConfig, loadChapterAdminUser, meetingsSection, peopleSection, useAdminResource } from './admin/index.js';
|
|
2
2
|
export { ApiFn, BrandStyle, BrandStyleProps, JoinConfig, JoinIsland, JoinIslandProps, MembersArea, MembersAreaProps, PaymentStep, PaymentStepProps, RescheduleProps, Rescheduler, Slot, SlotPicker, SlotPickerClasses, SlotPickerProps, dayKey, dayLabel, fmtDate, fmtMoney, fullLabel, groupSlotsByDay, timeLabel, tzShort } from './member/index.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
import '@odla-ai/crm';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-CgWUQ2MH.js';
|
|
6
|
+
import '@odla-ai/crm/ui';
|
package/dist/ui/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
groupSlotsByDay,
|
|
13
13
|
timeLabel,
|
|
14
14
|
tzShort
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-ILGUJXSB.js";
|
|
16
16
|
import {
|
|
17
17
|
AdminNote,
|
|
18
18
|
AdminPage,
|
|
@@ -22,21 +22,27 @@ import {
|
|
|
22
22
|
RecordActions,
|
|
23
23
|
ThemeWarning,
|
|
24
24
|
adminFetch,
|
|
25
|
+
adminRouteFromUrl,
|
|
26
|
+
adminRouteHref,
|
|
25
27
|
adminSectionFromUrl,
|
|
26
28
|
adminSectionHref,
|
|
29
|
+
applicationLifecycleAdapter,
|
|
27
30
|
availabilitySection,
|
|
28
31
|
billingSection,
|
|
29
32
|
collectionSection,
|
|
30
33
|
dashboardSection,
|
|
31
34
|
defaultAdminSections,
|
|
35
|
+
defaultAdminWorkspaces,
|
|
32
36
|
emailSection,
|
|
37
|
+
loadChapterAdminConfig,
|
|
38
|
+
loadChapterAdminUser,
|
|
33
39
|
meetingsSection,
|
|
34
40
|
peopleSection,
|
|
35
41
|
useAdminResource
|
|
36
|
-
} from "../chunk-
|
|
42
|
+
} from "../chunk-IWW5VAAC.js";
|
|
37
43
|
import {
|
|
38
44
|
BrandStyle
|
|
39
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-VZPBTTO3.js";
|
|
40
46
|
export {
|
|
41
47
|
AdminNote,
|
|
42
48
|
AdminPage,
|
|
@@ -52,8 +58,11 @@ export {
|
|
|
52
58
|
SlotPicker,
|
|
53
59
|
ThemeWarning,
|
|
54
60
|
adminFetch,
|
|
61
|
+
adminRouteFromUrl,
|
|
62
|
+
adminRouteHref,
|
|
55
63
|
adminSectionFromUrl,
|
|
56
64
|
adminSectionHref,
|
|
65
|
+
applicationLifecycleAdapter,
|
|
57
66
|
availabilitySection,
|
|
58
67
|
billingSection,
|
|
59
68
|
collectionSection,
|
|
@@ -61,11 +70,14 @@ export {
|
|
|
61
70
|
dayKey,
|
|
62
71
|
dayLabel,
|
|
63
72
|
defaultAdminSections,
|
|
73
|
+
defaultAdminWorkspaces,
|
|
64
74
|
emailSection,
|
|
65
75
|
fmtDate,
|
|
66
76
|
fmtMoney,
|
|
67
77
|
fullLabel,
|
|
68
78
|
groupSlotsByDay,
|
|
79
|
+
loadChapterAdminConfig,
|
|
80
|
+
loadChapterAdminUser,
|
|
69
81
|
meetingsSection,
|
|
70
82
|
peopleSection,
|
|
71
83
|
timeLabel,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { a as ChapterBrand } from '../../types-
|
|
3
|
+
import { a as ChapterBrand } from '../../types-CgWUQ2MH.js';
|
|
4
4
|
import '@odla-ai/crm';
|
|
5
5
|
|
|
6
6
|
/** A bookable slot: a start instant in epoch milliseconds. */
|
|
@@ -126,6 +126,8 @@ declare function PaymentStep(props: PaymentStepProps): react.JSX.Element;
|
|
|
126
126
|
/** Props for {@link BrandStyle}. */
|
|
127
127
|
interface BrandStyleProps {
|
|
128
128
|
brand: ChapterBrand | undefined;
|
|
129
|
+
/** CSS selector receiving the variables. Default `:root`. */
|
|
130
|
+
selector?: string;
|
|
129
131
|
}
|
|
130
132
|
/** Render a chapter's brand tokens as an inline <style> block (or nothing when
|
|
131
133
|
* there is no brand to theme). */
|
package/dist/ui/member/index.js
CHANGED
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
groupSlotsByDay,
|
|
13
13
|
timeLabel,
|
|
14
14
|
tzShort
|
|
15
|
-
} from "../../chunk-
|
|
15
|
+
} from "../../chunk-ILGUJXSB.js";
|
|
16
16
|
import {
|
|
17
17
|
BrandStyle
|
|
18
|
-
} from "../../chunk-
|
|
18
|
+
} from "../../chunk-VZPBTTO3.js";
|
|
19
19
|
export {
|
|
20
20
|
BrandStyle,
|
|
21
21
|
JoinIsland,
|
package/dist/worker/index.cjs
CHANGED
|
@@ -1165,7 +1165,7 @@ function createStripeProvider(config) {
|
|
|
1165
1165
|
"expand[0]": "latest_invoice.confirmation_secret",
|
|
1166
1166
|
metadata: meta
|
|
1167
1167
|
},
|
|
1168
|
-
//
|
|
1168
|
+
// Hardening: one subscription per application, so a client
|
|
1169
1169
|
// retry between create and the db write can't orphan a second one.
|
|
1170
1170
|
`sub:${input.applicationId}`
|
|
1171
1171
|
);
|
|
@@ -1736,18 +1736,30 @@ var handleAdminPeopleRole = async (req, url, env, ctx) => {
|
|
|
1736
1736
|
};
|
|
1737
1737
|
|
|
1738
1738
|
// src/series.ts
|
|
1739
|
-
function
|
|
1740
|
-
const
|
|
1741
|
-
const
|
|
1742
|
-
const
|
|
1743
|
-
const
|
|
1744
|
-
for (const
|
|
1745
|
-
if (!Number.isFinite(
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1739
|
+
function periodSeries(points, now, count, periodMs) {
|
|
1740
|
+
const start = now - count * periodMs;
|
|
1741
|
+
const previousStart = start - count * periodMs;
|
|
1742
|
+
const current = Array.from({ length: count }, () => 0);
|
|
1743
|
+
const previous = Array.from({ length: count }, () => 0);
|
|
1744
|
+
for (const point of points) {
|
|
1745
|
+
if (!Number.isFinite(point.t) || !Number.isFinite(point.v)) continue;
|
|
1746
|
+
if (point.t >= start && point.t <= now) {
|
|
1747
|
+
const index = Math.min(count - 1, Math.floor((point.t - start) / periodMs));
|
|
1748
|
+
current[index] = (current[index] ?? 0) + point.v;
|
|
1749
|
+
} else if (point.t >= previousStart && point.t < start) {
|
|
1750
|
+
const index = Math.min(count - 1, Math.floor((point.t - previousStart) / periodMs));
|
|
1751
|
+
previous[index] = (previous[index] ?? 0) + point.v;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
const labels = current.map((_, index) => new Date(start + index * periodMs).toISOString().slice(5, 10));
|
|
1755
|
+
return { labels, current, previous };
|
|
1756
|
+
}
|
|
1757
|
+
function dashboardMetricData(points, now) {
|
|
1758
|
+
const DAY = 864e5;
|
|
1759
|
+
return {
|
|
1760
|
+
wow: periodSeries(points, now, 7, DAY),
|
|
1761
|
+
mom: periodSeries(points, now, 4, 7 * DAY)
|
|
1762
|
+
};
|
|
1751
1763
|
}
|
|
1752
1764
|
function subAnnualCents(sub) {
|
|
1753
1765
|
const items = sub.items?.data ?? [];
|
|
@@ -1830,8 +1842,8 @@ var handleAdminDashboard = async (req, url, env, ctx) => {
|
|
|
1830
1842
|
if (subsRes.ok) {
|
|
1831
1843
|
const subs = rows(subsRes.body.data);
|
|
1832
1844
|
const subMs = (s) => (s.created ?? 0) * 1e3;
|
|
1833
|
-
membersSeries =
|
|
1834
|
-
revenueSeries =
|
|
1845
|
+
membersSeries = dashboardMetricData(subs.map((s) => ({ t: subMs(s), v: 1 })), now);
|
|
1846
|
+
revenueSeries = dashboardMetricData(subs.map((s) => ({ t: subMs(s), v: subAnnualCents(s) })), now);
|
|
1835
1847
|
const active = subs.filter((s) => s.status === "active");
|
|
1836
1848
|
revenue = {
|
|
1837
1849
|
billingReady: true,
|
|
@@ -1843,7 +1855,7 @@ var handleAdminDashboard = async (req, url, env, ctx) => {
|
|
|
1843
1855
|
};
|
|
1844
1856
|
}
|
|
1845
1857
|
}
|
|
1846
|
-
const applicationsSeries =
|
|
1858
|
+
const applicationsSeries = dashboardMetricData(apps.map((a) => ({ t: a.createdAt || 0, v: 1 })), now);
|
|
1847
1859
|
return json({ applications, applicationsSeries, pipeline, pipelineDelta, calls, agenda, timezone, revenue, revenueSeries, membersSeries });
|
|
1848
1860
|
};
|
|
1849
1861
|
var handleAdminBilling = async (req, url, env, ctx) => {
|