@rebasepro/app 0.23.0 → 0.24.1-canary.g19596ef
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 +2 -2
- package/dist/auth/api.d.ts +2 -2
- package/dist/auth/types.d.ts +57 -4
- package/dist/collections/filter-operator-resolution.d.ts +18 -0
- package/dist/collections/navigation_utils.d.ts +8 -2
- package/dist/collections/property_presentation.d.ts +12 -15
- package/dist/components/ConnectionLostBanner.d.ts +31 -0
- package/dist/components/LoginView/email-link.d.ts +14 -5
- package/dist/components/LoginView/index.d.ts +2 -0
- package/dist/components/UserSelectPopover.d.ts +14 -1
- package/dist/components/common/useColumnsIds.d.ts +2 -2
- package/dist/components/common/useDataTableController.d.ts +15 -1
- package/dist/components/common/useScrollRestoration.d.ts +16 -7
- package/dist/components/email-change-message.d.ts +6 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/contexts/CollectionResolverContext.d.ts +18 -1
- package/dist/contexts/StorageSourcesContext.d.ts +6 -0
- package/dist/core/RebaseProps.d.ts +21 -0
- package/dist/core/deprecated_plugin_keys.d.ts +10 -0
- package/dist/de-BcBo287O.js +1434 -0
- package/dist/de-BcBo287O.js.map +1 -0
- package/dist/debug/ui-reference/ComponentSections.d.ts +16 -0
- package/dist/debug.js +909 -519
- package/dist/es-D-JXBvsW.js +1442 -0
- package/dist/es-D-JXBvsW.js.map +1 -0
- package/dist/fr-BKGBSaZM.js +1434 -0
- package/dist/fr-BKGBSaZM.js.map +1 -0
- package/dist/hi-D1jEYlQ1.js +1434 -0
- package/dist/hi-D1jEYlQ1.js.map +1 -0
- package/dist/hooks/data/collectionWindow.d.ts +266 -0
- package/dist/hooks/data/save.d.ts +11 -2
- package/dist/hooks/data/useBatchedFetch.d.ts +21 -0
- package/dist/hooks/data/useDataOrder.d.ts +6 -0
- package/dist/hooks/data/useFetch.d.ts +12 -4
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/useBuildModeController.d.ts +22 -2
- package/dist/hooks/useComponentOverride.d.ts +10 -7
- package/dist/hooks/useNavigationBlocker.d.ts +17 -9
- package/dist/index.d.ts +0 -1
- package/dist/index.es.js +2998 -7046
- package/dist/index.es.js.map +1 -1
- package/dist/it-DLXLsP1j.js +1434 -0
- package/dist/it-DLXLsP1j.js.map +1 -0
- package/dist/pt-Dd3JWvUZ.js +1439 -0
- package/dist/pt-Dd3JWvUZ.js.map +1 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/previews.d.ts +22 -5
- package/dist/util/realtime.d.ts +18 -0
- package/dist/util/useStorageUploadController.d.ts +6 -2
- package/dist/vitePlugin.js +123 -12
- package/package.json +11 -7
- package/dist/hooks/useBackendStorageSource.d.ts +0 -35
package/README.md
CHANGED
|
@@ -67,8 +67,8 @@ This package is **framework-agnostic** in the sense that it doesn't depend on an
|
|
|
67
67
|
| `useRebaseContext` | Access the top-level Rebase context |
|
|
68
68
|
| `useDialogsController` | Programmatic dialog management |
|
|
69
69
|
| `useSnackbarController` | Show snackbar notifications |
|
|
70
|
-
| `useModeController` / `useBuildModeController` | Light/dark mode |
|
|
71
|
-
| `useStorageSource`
|
|
70
|
+
| `useModeController` / `useBuildModeController` | Light/dark mode: `mode` and `setMode("light" \| "dark" \| "system")`. To let your app own the theme, pass its own controller as `<Rebase modeController>`; `useBuildModeController({ enabled: false })` builds one that touches nothing outside React |
|
|
71
|
+
| `useStorageSource` | Storage source from context |
|
|
72
72
|
| `useRebaseClient` | Access the `RebaseClient` instance |
|
|
73
73
|
| `useLargeLayout` | Responsive layout breakpoint hook |
|
|
74
74
|
| `useClipboard` | Copy-to-clipboard |
|
package/dist/auth/api.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* here is the unauthenticated `/api/auth/config` probe used to detect
|
|
9
9
|
* bootstrap mode and enabled providers before a session exists.
|
|
10
10
|
*/
|
|
11
|
-
import type {
|
|
11
|
+
import type { AuthConfigDocument } from "@rebasepro/types";
|
|
12
12
|
/**
|
|
13
13
|
* What `GET /api/auth/config` answers.
|
|
14
14
|
*
|
|
@@ -17,7 +17,7 @@ import type { AuthAdapterCapabilities } from "@rebasepro/types";
|
|
|
17
17
|
* this one listed an `emailServiceEnabled` flag no backend sends, and marked as
|
|
18
18
|
* optional fields every backend always returns.
|
|
19
19
|
*/
|
|
20
|
-
export type AuthConfigResponse =
|
|
20
|
+
export type AuthConfigResponse = AuthConfigDocument;
|
|
21
21
|
/**
|
|
22
22
|
* Cache container for `fetchAuthConfig` — holds both the inflight promise
|
|
23
23
|
* (to deduplicate concurrent calls) and the cached result.
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -21,7 +21,14 @@ export type RebaseAuthController = AuthController & {
|
|
|
21
21
|
/** Login with email and password */
|
|
22
22
|
emailPasswordLogin: (email: string, password: string) => Promise<void>;
|
|
23
23
|
/** Register a new user */
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Create an account. `confirmationRequired` when the backend registers
|
|
26
|
+
* confirm-first (`requireEmailVerification`): nobody is signed in until
|
|
27
|
+
* the address is confirmed.
|
|
28
|
+
*/
|
|
29
|
+
register: (email: string, password: string, displayName?: string) => Promise<{
|
|
30
|
+
confirmationRequired: boolean;
|
|
31
|
+
}>;
|
|
25
32
|
/** Skip login (for anonymous access if enabled) */
|
|
26
33
|
skipLogin: () => void;
|
|
27
34
|
/** Whether login was skipped */
|
|
@@ -36,10 +43,33 @@ export type RebaseAuthController = AuthController & {
|
|
|
36
43
|
forgotPassword: (email: string) => Promise<void>;
|
|
37
44
|
/** Reset password using token from email */
|
|
38
45
|
resetPassword: (token: string, password: string) => Promise<void>;
|
|
39
|
-
/**
|
|
40
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Confirm an email address using the token from a verification email.
|
|
48
|
+
* Refused with `PROOF_REQUIRED` when the account holds a password this
|
|
49
|
+
* call does not prove: pass `password` to keep it (and sign in), or
|
|
50
|
+
* `removeUnproven` to verify without it.
|
|
51
|
+
*/
|
|
52
|
+
verifyEmail: (token: string, options?: {
|
|
53
|
+
password?: string;
|
|
54
|
+
removeUnproven?: boolean;
|
|
55
|
+
}) => Promise<{
|
|
56
|
+
passwordRemoved: boolean;
|
|
57
|
+
signedIn: boolean;
|
|
58
|
+
}>;
|
|
59
|
+
/** Sign in with a magic link's token. Absent when the client cannot. */
|
|
60
|
+
magicLinkLogin?: (token: string) => Promise<void>;
|
|
41
61
|
/** Change password for authenticated user */
|
|
42
62
|
changePassword: (oldPassword: string, newPassword: string) => Promise<void>;
|
|
63
|
+
/** Ask to move the signed-in account to another address. Absent when the client cannot. */
|
|
64
|
+
changeEmail?: (newEmail: string) => Promise<{
|
|
65
|
+
pendingEmail: string;
|
|
66
|
+
expiresAt: string;
|
|
67
|
+
}>;
|
|
68
|
+
/** Follow an address-change link. Absent when the client cannot. */
|
|
69
|
+
confirmEmailChange?: (token: string) => Promise<{
|
|
70
|
+
email: string;
|
|
71
|
+
removedProviders: string[];
|
|
72
|
+
}>;
|
|
43
73
|
/** Update user profile */
|
|
44
74
|
updateProfile: (displayName?: string, photoURL?: string) => Promise<User>;
|
|
45
75
|
/** Fetch active sessions */
|
|
@@ -64,6 +94,8 @@ export type RebaseAuthController = AuthController & {
|
|
|
64
94
|
* the client has no MFA support.
|
|
65
95
|
*/
|
|
66
96
|
verifyMfaChallenge?: (mfaToken: string, challengeId: string, code: string) => Promise<void>;
|
|
97
|
+
/** The scopes the signed-in user holds; `undefined` until known. */
|
|
98
|
+
heldScopes?: string[];
|
|
67
99
|
};
|
|
68
100
|
/**
|
|
69
101
|
* Structural type for the subset of `client.auth` (from `@rebasepro/client`)
|
|
@@ -91,8 +123,23 @@ export interface ClientAuth {
|
|
|
91
123
|
resetPasswordForEmail(email: string): Promise<unknown>;
|
|
92
124
|
resetPassword(token: string, password: string): Promise<unknown>;
|
|
93
125
|
/** Optional so a hand-built auth client need not implement it. */
|
|
94
|
-
verifyEmail?(token: string
|
|
126
|
+
verifyEmail?(token: string, options?: {
|
|
127
|
+
password?: string;
|
|
128
|
+
removeUnproven?: boolean;
|
|
129
|
+
}): Promise<unknown>;
|
|
95
130
|
changePassword(oldPassword: string, newPassword: string): Promise<unknown>;
|
|
131
|
+
/** Optional so a hand-built auth client need not implement it. */
|
|
132
|
+
verifyMagicLink?(token: string): Promise<unknown>;
|
|
133
|
+
/** Optional so a hand-built auth client need not implement it. */
|
|
134
|
+
changeEmail?(newEmail: string): Promise<{
|
|
135
|
+
pendingEmail: string;
|
|
136
|
+
expiresAt: string;
|
|
137
|
+
}>;
|
|
138
|
+
/** Optional so a hand-built auth client need not implement it. */
|
|
139
|
+
confirmEmailChange?(token: string): Promise<{
|
|
140
|
+
email: string;
|
|
141
|
+
removedProviders: string[];
|
|
142
|
+
}>;
|
|
96
143
|
updateUser(updates: {
|
|
97
144
|
displayName?: string;
|
|
98
145
|
photoURL?: string;
|
|
@@ -131,6 +178,12 @@ export interface RebaseAuthControllerProps {
|
|
|
131
178
|
setAuthTokenGetter: (getter: () => Promise<string | null>) => void;
|
|
132
179
|
};
|
|
133
180
|
auth?: ClientAuth;
|
|
181
|
+
/** Read for the scopes the signed-in user holds (`GET /auth/scopes`). */
|
|
182
|
+
personalKeys?: {
|
|
183
|
+
listScopes(): Promise<{
|
|
184
|
+
held: string[];
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
134
187
|
};
|
|
135
188
|
/** Google OAuth client ID (optional, enables Google login) */
|
|
136
189
|
googleClientId?: string;
|
|
@@ -55,3 +55,21 @@ export interface ResolveFilterOperatorsParams {
|
|
|
55
55
|
* @group Models
|
|
56
56
|
*/
|
|
57
57
|
export declare function resolveFilterOperators({ property, isArray, engine }: ResolveFilterOperatorsParams): WhereFilterOp[];
|
|
58
|
+
/**
|
|
59
|
+
* Whether a property can be filtered at all — the one answer the table header
|
|
60
|
+
* and the filters dialog both give.
|
|
61
|
+
*
|
|
62
|
+
* They used to answer it with a predicate each, and disagreed: the header
|
|
63
|
+
* allowed an array only of strings, numbers, dates, references and relations;
|
|
64
|
+
* the dialog allowed an array of anything, and listed an array of maps with an
|
|
65
|
+
* empty control. The header, for its part, ignored both the developer's
|
|
66
|
+
* `filterOperators: []` and a custom `admin.Filter`.
|
|
67
|
+
*
|
|
68
|
+
* A property with a custom filter field is filterable: the developer owns that
|
|
69
|
+
* field. Otherwise it is filterable when at least one operator survives
|
|
70
|
+
* {@link resolveFilterOperators} — for an array, on its item type. A tuple
|
|
71
|
+
* array (`of: [a, b]`) has no single item type to filter by.
|
|
72
|
+
*
|
|
73
|
+
* @group Models
|
|
74
|
+
*/
|
|
75
|
+
export declare function isPropertyFilterable(property: Property, engine?: string): boolean;
|
|
@@ -13,8 +13,14 @@ export declare function resolveCollectionPathIds(path: string, allCollections: A
|
|
|
13
13
|
*/
|
|
14
14
|
export declare function getCollectionBySlugWithin(slugOrPath: string, collections: AdminCollection[]): AdminCollection | undefined;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Every leading run of whole segments of a path, longest first: the
|
|
17
|
+
* candidates for the collection the path starts with.
|
|
18
|
+
* "sites/es/locales" => ["sites/es/locales", "sites/es", "sites"]
|
|
19
|
+
*
|
|
20
|
+
* Every length, not only the odd ones. A slug may contain slashes, so
|
|
21
|
+
* `content/podcasts/abc123/episodes` starts with the two-segment collection
|
|
22
|
+
* `content/podcasts`, and a path's own segment count says nothing about where
|
|
23
|
+
* its first collection ends.
|
|
18
24
|
* @param subpaths
|
|
19
25
|
*/
|
|
20
26
|
export declare function getCollectionPathsCombinations(subpaths: string[]): string[];
|
|
@@ -3,23 +3,20 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These read a property's admin block — `readOnly`, `disabled.hidden`, the
|
|
5
5
|
* declarative `conditions` — and lived in `@rebasepro/common`, which is on the
|
|
6
|
-
* backend's dependency path. Nothing in core ever called them: `isReadOnly
|
|
7
|
-
* `isHidden`
|
|
8
|
-
* production caller at all.
|
|
6
|
+
* backend's dependency path. Nothing in core ever called them: `isReadOnly`,
|
|
7
|
+
* `isHidden` and `applyPropertyConditions` are the panel's alone.
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* `applyPropertyConditions` is called by the record form, through
|
|
10
|
+
* `resolveFormProperty`, both where a field is laid out and where the form is
|
|
11
|
+
* judged on save — so a rule the collection editor writes hides, disables and
|
|
12
|
+
* requires what it says it does, and a field it hides is not held against the
|
|
13
|
+
* save. Until that was wired, the evaluator was reached only from its own tests.
|
|
15
14
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* deliberate, not an oversight: it is the difference between a condition that
|
|
22
|
-
* needs an entity to be evaluated against and one that does not.
|
|
15
|
+
* A condition may also be a literal: `hidden`/`readOnly`/`disabled` stated as a
|
|
16
|
+
* plain boolean rather than as a rule. A literal needs no context, so
|
|
17
|
+
* `isHidden`/`isReadOnly`/`isDisabled` answer it directly, and those three
|
|
18
|
+
* gates are consulted everywhere a field is laid out — including places with
|
|
19
|
+
* no entity to evaluate a rule against.
|
|
23
20
|
*/
|
|
24
21
|
import type { ConditionContext, Property } from "@rebasepro/types";
|
|
25
22
|
export declare function isReadOnly(property: Property): boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { RealtimeConnectionState } from "@rebasepro/types";
|
|
3
|
+
/**
|
|
4
|
+
* The realtime connection's state, re-rendering on every change.
|
|
5
|
+
*
|
|
6
|
+
* `undefined` when there is no client, or it was built without realtime —
|
|
7
|
+
* there is no connection to describe.
|
|
8
|
+
*
|
|
9
|
+
* @group Hooks and utilities
|
|
10
|
+
*/
|
|
11
|
+
export declare function useRealtimeConnectionState(): RealtimeConnectionState | undefined;
|
|
12
|
+
export interface ConnectionLostBannerProps {
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Says that live updates have stopped, while they have.
|
|
17
|
+
*
|
|
18
|
+
* Shown once the realtime client reports the connection `disconnected`: the
|
|
19
|
+
* socket has been down for longer than a blip, so tables, boards and open
|
|
20
|
+
* records are showing what they last received and nothing else will arrive
|
|
21
|
+
* until it is back. They keep their data rather than turning into errors — this
|
|
22
|
+
* banner is how the user learns it may be out of date. It disappears by itself
|
|
23
|
+
* when the connection returns, and every live view then refreshes.
|
|
24
|
+
*
|
|
25
|
+
* A brief drop (`reconnecting`) shows nothing: a deploy blips every socket for
|
|
26
|
+
* a second or two, and a banner that flashes on each one teaches people to
|
|
27
|
+
* ignore it.
|
|
28
|
+
*
|
|
29
|
+
* @group Components
|
|
30
|
+
*/
|
|
31
|
+
export declare function ConnectionLostBanner({ className }: ConnectionLostBannerProps): React.JSX.Element | null;
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The server builds them from the configured frontend URL:
|
|
5
5
|
* `<frontend>/reset-password?token=…` for a forgotten password, an admin's
|
|
6
|
-
* "send reset email" and every invitation,
|
|
7
|
-
* to confirm an address
|
|
8
|
-
*
|
|
6
|
+
* "send reset email" and every invitation, `<frontend>/verify-email?token=…`
|
|
7
|
+
* to confirm an address, `<frontend>/confirm-email-change?token=…` to move an
|
|
8
|
+
* account to a new one, and `<frontend>/auth/magic-link?token=…` to sign in.
|
|
9
|
+
* The frontend URL may carry a base path (`/admin`), so the action is read off
|
|
10
|
+
* the *end* of the path, not the whole path.
|
|
9
11
|
*/
|
|
10
12
|
export type EmailLinkAction = {
|
|
11
13
|
kind: "reset-password";
|
|
@@ -13,14 +15,21 @@ export type EmailLinkAction = {
|
|
|
13
15
|
} | {
|
|
14
16
|
kind: "verify-email";
|
|
15
17
|
token: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "confirm-email-change";
|
|
20
|
+
token: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "magic-link";
|
|
23
|
+
token: string;
|
|
16
24
|
};
|
|
17
25
|
export declare function readEmailLinkAction(location: {
|
|
18
26
|
pathname: string;
|
|
19
27
|
search: string;
|
|
20
28
|
}): EmailLinkAction | null;
|
|
21
29
|
/**
|
|
22
|
-
* Where the app lives: the link's own address without the action
|
|
23
|
-
* its token. `/admin/reset-password?token=…` becomes `/admin
|
|
30
|
+
* Where the app lives: the link's own address without the action's path and
|
|
31
|
+
* its token. `/admin/reset-password?token=…` becomes `/admin/`, and
|
|
32
|
+
* `/admin/auth/magic-link?token=…` too.
|
|
24
33
|
*/
|
|
25
34
|
export declare function appAddressOfEmailLink(location: {
|
|
26
35
|
origin: string;
|
|
@@ -28,6 +28,19 @@ export interface UserSelectPopoverProps {
|
|
|
28
28
|
* Whether users are currently loading.
|
|
29
29
|
*/
|
|
30
30
|
loading?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Called with the search text each time it changes (debounced), for a
|
|
33
|
+
* parent that searches its users on a server rather than passing them all
|
|
34
|
+
* in `users`. The list is still filtered here by the same text.
|
|
35
|
+
*/
|
|
36
|
+
onSearchTextChange?: (searchText: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* For a parent that lists only the first page of a server search: how many
|
|
39
|
+
* users that search matched in all. Leave it out when `users` holds every
|
|
40
|
+
* match. When set, the header counts the listed users against it and a
|
|
41
|
+
* notice says the others are not listed.
|
|
42
|
+
*/
|
|
43
|
+
totalCount?: number;
|
|
31
44
|
/**
|
|
32
45
|
* The current user (displayed as the "self" option at the top).
|
|
33
46
|
*/
|
|
@@ -60,4 +73,4 @@ export interface UserSelectPopoverProps {
|
|
|
60
73
|
*
|
|
61
74
|
* @group Components
|
|
62
75
|
*/
|
|
63
|
-
export declare function UserSelectPopover({ selectedUser, onUserSelected, users, loading, currentUser, defaultLabel, renderLimit, className, size }: UserSelectPopoverProps): React.JSX.Element;
|
|
76
|
+
export declare function UserSelectPopover({ selectedUser, onUserSelected, users, loading, onSearchTextChange, totalCount, currentUser, defaultLabel, renderLimit, className, size }: UserSelectPopoverProps): React.JSX.Element;
|
|
@@ -12,8 +12,8 @@ export declare function getSubcollectionColumnId(collection: AdminCollection<any
|
|
|
12
12
|
* Every child view gets a 200px button column that opens its tab. For a relation
|
|
13
13
|
* declared in `relations` that button is the relation's only presence in the
|
|
14
14
|
* table. For one declared as a property it is the second: the property's own
|
|
15
|
-
* column is already there, hydrated by the list fetch's `include
|
|
16
|
-
* the child rows themselves — and carrying the *same heading*, because the tab
|
|
15
|
+
* column is already there, hydrated by the list fetch's `include`
|
|
16
|
+
* (`getRelationIncludeParams`), showing the child rows themselves — and carrying the *same heading*, because the tab
|
|
17
17
|
* takes its name from the declaring property. Two columns called "Applications",
|
|
18
18
|
* one of them a button, and nothing in the header to tell them apart.
|
|
19
19
|
*
|
|
@@ -2,6 +2,12 @@ import { Entity, FilterValues, User } from "@rebasepro/types";
|
|
|
2
2
|
import { EntityTableController, AdminCollection } from "@rebasepro/cms-types";
|
|
3
3
|
import { ScrollRestorationController } from "./useScrollRestoration.js";
|
|
4
4
|
export declare const DEFAULT_PAGE_SIZE = 50;
|
|
5
|
+
/**
|
|
6
|
+
* Rows held with `pagination: false` past which development builds warn. The
|
|
7
|
+
* docs promise every row, so they are all loaded; but tens of thousands of
|
|
8
|
+
* them sit in memory and re-render on every change, and nothing said so.
|
|
9
|
+
*/
|
|
10
|
+
export declare const UNPAGINATED_WARNING_ROWS = 10000;
|
|
5
11
|
export type DataTableControllerProps<M extends Record<string, any> = any> = {
|
|
6
12
|
/**
|
|
7
13
|
* Full path where the data of this table is located
|
|
@@ -26,6 +32,14 @@ export type DataTableControllerProps<M extends Record<string, any> = any> = {
|
|
|
26
32
|
* When set to true the filters and sort will be updated in the URL
|
|
27
33
|
*/
|
|
28
34
|
updateUrl?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Read rows at all. Defaults to `true`. `false` closes the subscription and
|
|
37
|
+
* reads nothing — for a view that keeps the controller for its search and
|
|
38
|
+
* filters but draws its rows some other way, like the board, whose columns
|
|
39
|
+
* each read their own. The rows already held stay until it is enabled
|
|
40
|
+
* again, which reads afresh.
|
|
41
|
+
*/
|
|
42
|
+
enabled?: boolean;
|
|
29
43
|
};
|
|
30
44
|
/**
|
|
31
45
|
* Use this hook to build a controller for the {@link DataCollectionTable}.
|
|
@@ -42,4 +56,4 @@ export type DataTableControllerProps<M extends Record<string, any> = any> = {
|
|
|
42
56
|
* @param fixedFilterFromProps
|
|
43
57
|
* @param updateUrl
|
|
44
58
|
*/
|
|
45
|
-
export declare function useDataTableController<M extends Record<string, any> = any, USER extends User = User>({ path, collection, scrollRestoration, entitiesDisplayedFirst, lastDeleteTimestamp, fixedFilter: fixedFilterFromProps, updateUrl }: DataTableControllerProps<M>): EntityTableController<M>;
|
|
59
|
+
export declare function useDataTableController<M extends Record<string, any> = any, USER extends User = User>({ path, collection, scrollRestoration, entitiesDisplayedFirst, lastDeleteTimestamp, fixedFilter: fixedFilterFromProps, updateUrl, enabled }: DataTableControllerProps<M>): EntityTableController<M>;
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
import { Entity, FilterValues } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* Where a collection view was, and the rows to show when it comes back.
|
|
4
|
+
*
|
|
5
|
+
* `data` is the rows around what was on screen — a page either side, when the
|
|
6
|
+
* view reports what it draws — starting at row `dataOffset` (0 when absent:
|
|
7
|
+
* `data` then starts at the first row). It used to be every row the view held,
|
|
8
|
+
* which a table scrolled to 100,000 rows kept for the rest of the session and
|
|
9
|
+
* read again in full on the way back.
|
|
10
|
+
*/
|
|
11
|
+
export type CollectionScrollEntry = {
|
|
12
|
+
scrollOffset: number;
|
|
13
|
+
data: Entity<any>[];
|
|
14
|
+
dataOffset?: number;
|
|
15
|
+
};
|
|
2
16
|
/**
|
|
3
17
|
* Forget every collection's scroll position and the rows kept with it.
|
|
4
18
|
*
|
|
@@ -7,15 +21,10 @@ import { Entity, FilterValues } from "@rebasepro/types";
|
|
|
7
21
|
*/
|
|
8
22
|
export declare function clearCollectionScrollCache(): void;
|
|
9
23
|
export type ScrollRestorationController = {
|
|
10
|
-
getCollectionScroll: (path: string, filters?: FilterValues<any>) =>
|
|
11
|
-
|
|
12
|
-
data: Entity<any>[];
|
|
13
|
-
} | undefined;
|
|
14
|
-
updateCollectionScroll: (props: {
|
|
24
|
+
getCollectionScroll: (path: string, filters?: FilterValues<any>) => CollectionScrollEntry | undefined;
|
|
25
|
+
updateCollectionScroll: (props: CollectionScrollEntry & {
|
|
15
26
|
path: string;
|
|
16
|
-
scrollOffset: number;
|
|
17
27
|
filters?: FilterValues<any>;
|
|
18
|
-
data: Entity<any>[];
|
|
19
28
|
}) => void;
|
|
20
29
|
};
|
|
21
30
|
export declare function useScrollRestoration(): ScrollRestorationController;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the settings screen and the link's screen say about a refused address
|
|
3
|
+
* change: the codes a person can act on get the panel's own, translated words,
|
|
4
|
+
* and anything else keeps the server's message.
|
|
5
|
+
*/
|
|
6
|
+
export declare function emailChangeErrorMessage(error: unknown, t: (key: string) => string): string;
|
|
@@ -5,6 +5,12 @@ import React from "react";
|
|
|
5
5
|
export type CollectionResolver = (slug: string) => {
|
|
6
6
|
properties?: Record<string, unknown>;
|
|
7
7
|
} | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Translate the path a collection is addressed by into the path its driver
|
|
10
|
+
* stores it under — `fs_diagnosis` into `diagnosis`, for a Firestore collection
|
|
11
|
+
* that declares `path: "diagnosis"`. See `EntityDataOptions.resolveDataPath`.
|
|
12
|
+
*/
|
|
13
|
+
export type DataPathResolver = (path: string) => string | undefined;
|
|
8
14
|
/**
|
|
9
15
|
* Lets the layer that owns the collections hand a resolver *up* to the data
|
|
10
16
|
* layer, which needs a collection's primary keys to give its rows an address.
|
|
@@ -15,9 +21,20 @@ export type CollectionResolver = (slug: string) => {
|
|
|
15
21
|
* prop without giving every headless BaaS app a collections argument it has no
|
|
16
22
|
* use for.
|
|
17
23
|
*
|
|
24
|
+
* The same layer knows where each collection is stored, so it hands up the
|
|
25
|
+
* data-path translation alongside: a direct driver has to be given a
|
|
26
|
+
* collection's declared `path`, and only the registry knows it.
|
|
27
|
+
*
|
|
18
28
|
* Registration is a ref write, so it is safe to call during render — and it has
|
|
19
29
|
* to be. The views that fetch rows are *below* the registrar, and child effects
|
|
20
30
|
* run before parent effects, so registering in an effect would bind after the
|
|
21
31
|
* first page of rows had already been converted.
|
|
32
|
+
*
|
|
33
|
+
* Several layers may own collections at once — the CMS navigation, and each
|
|
34
|
+
* standalone `CollectionsProvider` on a page — so each registers under its own
|
|
35
|
+
* `owner` (`"default"` when omitted). A lookup asks every owner and takes the
|
|
36
|
+
* first that knows the collection. Registering nothing (`undefined` for both)
|
|
37
|
+
* removes that owner's registration.
|
|
22
38
|
*/
|
|
23
|
-
export
|
|
39
|
+
export type CollectionResolverRegistration = (resolver: CollectionResolver | undefined, resolveDataPath?: DataPathResolver, owner?: string) => void;
|
|
40
|
+
export declare const CollectionResolverRegistrationContext: React.Context<CollectionResolverRegistration>;
|
|
@@ -14,6 +14,12 @@ export interface StorageSourcesContextValue {
|
|
|
14
14
|
registry: Record<string, StorageSourceDefinition>;
|
|
15
15
|
/** Built {@link StorageSource} for direct sources, keyed by key. */
|
|
16
16
|
sources: Record<string, StorageSource>;
|
|
17
|
+
/**
|
|
18
|
+
* A server-routed source for a key not (yet) in `sources` — requests carry
|
|
19
|
+
* `?storageId=<key>`, so the server serves it or refuses naming it, rather
|
|
20
|
+
* than the panel guessing the default. Absent without a client.
|
|
21
|
+
*/
|
|
22
|
+
createSource?: (key: string) => StorageSource;
|
|
17
23
|
}
|
|
18
24
|
/** @internal */
|
|
19
25
|
export declare const StorageSourcesContext: React.Context<StorageSourcesContextValue>;
|
|
@@ -45,6 +45,7 @@ type DeepPartial<T> = T extends object ? {
|
|
|
45
45
|
*/
|
|
46
46
|
export type { EffectiveRoleController } from "@rebasepro/types";
|
|
47
47
|
import type { EffectiveRoleController } from "@rebasepro/types";
|
|
48
|
+
import type { ModeController } from "../hooks/useModeController.js";
|
|
48
49
|
/**
|
|
49
50
|
* Props for the main {@link Rebase} component.
|
|
50
51
|
*
|
|
@@ -265,6 +266,26 @@ export type RebaseProps<USER extends User, DB = unknown> = {
|
|
|
265
266
|
* Controller to simulate different roles when dev mode is active.
|
|
266
267
|
*/
|
|
267
268
|
effectiveRoleController?: EffectiveRoleController;
|
|
269
|
+
/**
|
|
270
|
+
* The light/dark mode, owned by the host app.
|
|
271
|
+
*
|
|
272
|
+
* Without it, `<Rebase>` owns the page's theme: it puts the `dark` class on
|
|
273
|
+
* `<html>`, follows `prefers-color-scheme`, remembers the user's pick in
|
|
274
|
+
* localStorage, and takes its class away when it unmounts. Pass one when
|
|
275
|
+
* your app already has a theme — Rebase then reads `mode` from it, calls
|
|
276
|
+
* its `setMode` from its own theme toggle, and touches none of the above.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```tsx
|
|
280
|
+
* const [mode, setMode] = useState<"light" | "dark">("light");
|
|
281
|
+
* const modeController = useMemo(() => ({
|
|
282
|
+
* mode,
|
|
283
|
+
* setMode: (next: "light" | "dark" | "system") => setMode(next === "dark" ? "dark" : "light")
|
|
284
|
+
* }), [mode]);
|
|
285
|
+
* <Rebase client={client} modeController={modeController}>…</Rebase>
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
modeController?: ModeController;
|
|
268
289
|
/**
|
|
269
290
|
* Override or extend any Rebase UI string, keyed by locale.
|
|
270
291
|
*/
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RebasePlugin } from "@rebasepro/cms-types";
|
|
2
|
+
/**
|
|
3
|
+
* Warn, once per plugin and key, about plugin keys that are declared on
|
|
4
|
+
* `RebasePlugin` but that nothing has ever called.
|
|
5
|
+
*
|
|
6
|
+
* A plugin that set one of these did nothing and said nothing about it. The
|
|
7
|
+
* types mark them deprecated; this names them at runtime too, which also
|
|
8
|
+
* reaches a plugin written in JavaScript.
|
|
9
|
+
*/
|
|
10
|
+
export declare function warnDeprecatedPluginKeys(plugins: readonly RebasePlugin[]): void;
|