@rebasepro/app 0.22.0 → 0.24.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/dist/auth/api.d.ts +2 -2
- package/dist/auth/session_caches.d.ts +26 -0
- package/dist/auth/types.d.ts +84 -1
- package/dist/collections/entity-display-cache.d.ts +1 -0
- 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 +37 -0
- package/dist/components/LoginView/index.d.ts +2 -0
- package/dist/components/LoginView/mfa-required.d.ts +33 -0
- package/dist/components/UserSelectPopover.d.ts +14 -1
- package/dist/components/common/useDataTableController.d.ts +1 -1
- package/dist/components/common/useScrollRestoration.d.ts +7 -0
- package/dist/components/email-change-message.d.ts +6 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/contexts/CollectionResolverContext.d.ts +11 -1
- package/dist/core/PluginLifecycleManager.d.ts +12 -4
- package/dist/debug.js +47 -40
- package/dist/hooks/data/collectionWindow.d.ts +133 -0
- package/dist/hooks/data/useStableFilterValues.d.ts +9 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.es.js +7008 -2951
- package/dist/index.es.js.map +1 -1
- package/dist/util/entity_cache.d.ts +11 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/realtime.d.ts +18 -0
- package/dist/vitePlugin.d.ts +6 -0
- package/dist/vitePlugin.js +138 -15
- package/package.json +7 -7
package/dist/debug.js
CHANGED
|
@@ -77,11 +77,11 @@ var UIStyleGuide = () => {
|
|
|
77
77
|
/* @__PURE__ */ jsx(Typography, { variant: "h4", gutterBottom: true, className: "border-b pb-2 mb-6", children: "Icon Buttons" }),
|
|
78
78
|
/* @__PURE__ */ jsx(Paper, { className: "p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-8 items-center", children: [
|
|
79
79
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
80
|
-
/* @__PURE__ */ jsx(IconButton, {
|
|
80
|
+
/* @__PURE__ */ jsx(IconButton, { children: /* @__PURE__ */ jsx(IconExample, {}) }),
|
|
81
81
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-text-disabled font-mono", children: "primary" })
|
|
82
82
|
] }),
|
|
83
83
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
84
|
-
/* @__PURE__ */ jsx(IconButton, {
|
|
84
|
+
/* @__PURE__ */ jsx(IconButton, { children: /* @__PURE__ */ jsx(IconExample, {}) }),
|
|
85
85
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-text-disabled font-mono", children: "secondary" })
|
|
86
86
|
] }),
|
|
87
87
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
@@ -93,7 +93,7 @@ var UIStyleGuide = () => {
|
|
|
93
93
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-text-disabled font-mono", children: "disabled" })
|
|
94
94
|
] }),
|
|
95
95
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
96
|
-
/* @__PURE__ */ jsx(IconButton, { size: "small",
|
|
96
|
+
/* @__PURE__ */ jsx(IconButton, { size: "small", children: /* @__PURE__ */ jsx(Trash2Icon, {}) }),
|
|
97
97
|
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-text-disabled font-mono", children: "delete" })
|
|
98
98
|
] })
|
|
99
99
|
] }) })
|
|
@@ -397,7 +397,7 @@ function PipelineOverview({
|
|
|
397
397
|
}
|
|
398
398
|
)
|
|
399
399
|
] }),
|
|
400
|
-
/* @__PURE__ */
|
|
400
|
+
/* @__PURE__ */ jsxs4(
|
|
401
401
|
Button2,
|
|
402
402
|
{
|
|
403
403
|
variant: "text",
|
|
@@ -405,8 +405,10 @@ function PipelineOverview({
|
|
|
405
405
|
onClick: () => {
|
|
406
406
|
onNavigate("/c/engagements");
|
|
407
407
|
},
|
|
408
|
-
|
|
409
|
-
|
|
408
|
+
children: [
|
|
409
|
+
"View All",
|
|
410
|
+
/* @__PURE__ */ jsx4(ChevronRightIcon, { className: "h-4 w-4" })
|
|
411
|
+
]
|
|
410
412
|
}
|
|
411
413
|
)
|
|
412
414
|
] }),
|
|
@@ -1131,7 +1133,7 @@ function CompletedSection({
|
|
|
1131
1133
|
if (willExpand) onExpand();
|
|
1132
1134
|
};
|
|
1133
1135
|
return /* @__PURE__ */ jsxs7("div", { children: [
|
|
1134
|
-
/* @__PURE__ */
|
|
1136
|
+
/* @__PURE__ */ jsxs7(
|
|
1135
1137
|
Button5,
|
|
1136
1138
|
{
|
|
1137
1139
|
variant: "text",
|
|
@@ -1139,34 +1141,36 @@ function CompletedSection({
|
|
|
1139
1141
|
color: "neutral",
|
|
1140
1142
|
className: "w-full justify-between hover:bg-surface-hover px-3 py-1.5 h-auto text-left",
|
|
1141
1143
|
onClick: handleToggle,
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1144
|
+
children: [
|
|
1145
|
+
/* @__PURE__ */ jsxs7(
|
|
1146
|
+
Typography6,
|
|
1147
|
+
{
|
|
1148
|
+
variant: "caption",
|
|
1149
|
+
color: "secondary",
|
|
1150
|
+
className: "font-semibold uppercase tracking-wider text-[10px]",
|
|
1151
|
+
children: [
|
|
1152
|
+
"Completed",
|
|
1153
|
+
tasks.length > 0 ? ` (${tasks.length}${hasMore ? "+" : ""})` : ""
|
|
1154
|
+
]
|
|
1155
|
+
}
|
|
1156
|
+
),
|
|
1157
|
+
/* @__PURE__ */ jsx7(
|
|
1158
|
+
"svg",
|
|
1159
|
+
{
|
|
1160
|
+
className: cls4(
|
|
1161
|
+
"h-3 w-3 text-text-secondary dark:text-text-secondary-dark transition-transform duration-150",
|
|
1162
|
+
expanded && "rotate-90"
|
|
1163
|
+
),
|
|
1164
|
+
viewBox: "0 0 24 24",
|
|
1165
|
+
fill: "none",
|
|
1166
|
+
stroke: "currentColor",
|
|
1167
|
+
strokeWidth: 2,
|
|
1168
|
+
strokeLinecap: "round",
|
|
1169
|
+
strokeLinejoin: "round",
|
|
1170
|
+
children: /* @__PURE__ */ jsx7("polyline", { points: "9 18 15 12 9 6" })
|
|
1171
|
+
}
|
|
1172
|
+
)
|
|
1173
|
+
]
|
|
1170
1174
|
}
|
|
1171
1175
|
),
|
|
1172
1176
|
expanded && /* @__PURE__ */ jsx7("div", { className: "mt-1 space-y-0.5", children: loading && tasks.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 px-3 py-3", children: [
|
|
@@ -1537,7 +1541,10 @@ function CalendarWidget({ loading, tasks, onOpenTask }) {
|
|
|
1537
1541
|
{
|
|
1538
1542
|
onClick: () => setSelectedDay(isSelected ? null : day.dateKey),
|
|
1539
1543
|
className: cls5(
|
|
1540
|
-
|
|
1544
|
+
// The today and selected rings are utilities, which outrank the kit's
|
|
1545
|
+
// base :focus-visible ring — so the focus ring is said here too, or a
|
|
1546
|
+
// keyboard user on today's cell sees nothing change.
|
|
1547
|
+
"flex flex-col items-center justify-center py-1.5 rounded-md transition-colors duration-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary",
|
|
1541
1548
|
day.isCurrentMonth ? "text-text-primary dark:text-text-primary-dark" : "text-surface-300 dark:text-surface-600",
|
|
1542
1549
|
day.isToday && !isSelected && "ring-1 ring-primary/50",
|
|
1543
1550
|
isSelected ? "bg-primary/10 dark:bg-primary/15 ring-1 ring-primary/60" : "hover:bg-surface-hover",
|
|
@@ -2661,8 +2668,8 @@ function CollectionTableDemo() {
|
|
|
2661
2668
|
/* @__PURE__ */ jsx11(TableCell, { children: /* @__PURE__ */ jsx11("div", { className: "flex flex-wrap gap-1", children: project.tags.map((tag) => /* @__PURE__ */ jsx11(Chip4, { size: "smallest", colorScheme: "cyan", children: tag }, tag)) }) }),
|
|
2662
2669
|
/* @__PURE__ */ jsx11(TableCell, { children: /* @__PURE__ */ jsx11(Typography9, { variant: "body2", className: "font-mono text-xs", children: project.dueDate }) }),
|
|
2663
2670
|
/* @__PURE__ */ jsx11(TableCell, { style: { width: "80px" }, children: /* @__PURE__ */ jsxs11("div", { className: "flex gap-1", children: [
|
|
2664
|
-
/* @__PURE__ */ jsx11(Tooltip2, { title: "Edit", asChild: true, children: /* @__PURE__ */ jsx11(IconButton3, { size: "smallest", children: /* @__PURE__ */ jsx11(PencilIcon, { size: iconSize.smallest }) }) }),
|
|
2665
|
-
/* @__PURE__ */ jsx11(Tooltip2, { title: "Delete", asChild: true, children: /* @__PURE__ */ jsx11(IconButton3, { size: "smallest", children: /* @__PURE__ */ jsx11(Trash2Icon2, { size: iconSize.smallest }) }) })
|
|
2671
|
+
/* @__PURE__ */ jsx11(Tooltip2, { title: "Edit", asChild: true, children: /* @__PURE__ */ jsx11(IconButton3, { "aria-label": "Edit", size: "smallest", children: /* @__PURE__ */ jsx11(PencilIcon, { size: iconSize.smallest }) }) }),
|
|
2672
|
+
/* @__PURE__ */ jsx11(Tooltip2, { title: "Delete", asChild: true, children: /* @__PURE__ */ jsx11(IconButton3, { "aria-label": "Delete", size: "smallest", children: /* @__PURE__ */ jsx11(Trash2Icon2, { size: iconSize.smallest }) }) })
|
|
2666
2673
|
] }) })
|
|
2667
2674
|
] }, project.id)) })
|
|
2668
2675
|
] }),
|
|
@@ -3569,7 +3576,7 @@ function UIReferenceView() {
|
|
|
3569
3576
|
/* @__PURE__ */ jsx16("button", { className: cls12("px-3 py-1 text-xs font-medium rounded-md transition-all", "bg-surface-lifted shadow-sm text-text-primary dark:text-text-primary-dark"), children: "Content" }),
|
|
3570
3577
|
/* @__PURE__ */ jsx16("button", { className: cls12("px-3 py-1 text-xs font-medium rounded-md transition-all", "text-surface-500 hover:text-surface-900 dark:hover:text-white"), children: "Studio" })
|
|
3571
3578
|
] }),
|
|
3572
|
-
/* @__PURE__ */ jsxs16(Menu, { trigger: /* @__PURE__ */ jsx16(IconButton5, {
|
|
3579
|
+
/* @__PURE__ */ jsxs16(Menu, { trigger: /* @__PURE__ */ jsx16(IconButton5, { children: /* @__PURE__ */ jsx16(MoonIcon, {}) }), children: [
|
|
3573
3580
|
/* @__PURE__ */ jsxs16(MenuItem, { children: [
|
|
3574
3581
|
/* @__PURE__ */ jsx16(MoonIcon, { size: iconSize3.smallest }),
|
|
3575
3582
|
" Dark"
|
|
@@ -4092,7 +4099,7 @@ function UIReferenceView() {
|
|
|
4092
4099
|
roles: []
|
|
4093
4100
|
}
|
|
4094
4101
|
].map((user) => /* @__PURE__ */ jsxs16(TableRow2, { children: [
|
|
4095
|
-
/* @__PURE__ */ jsx16(TableCell2, { style: { width: "64px" }, children: /* @__PURE__ */ jsx16(Tooltip3, { asChild: true, title: "Delete this user", children: /* @__PURE__ */ jsx16(IconButton5, { size: "small", children: /* @__PURE__ */ jsx16(Trash2Icon3, {}) }) }) }),
|
|
4102
|
+
/* @__PURE__ */ jsx16(TableCell2, { style: { width: "64px" }, children: /* @__PURE__ */ jsx16(Tooltip3, { asChild: true, title: "Delete this user", children: /* @__PURE__ */ jsx16(IconButton5, { "aria-label": "Delete this user", size: "small", children: /* @__PURE__ */ jsx16(Trash2Icon3, {}) }) }) }),
|
|
4096
4103
|
/* @__PURE__ */ jsx16(TableCell2, { children: user.email }),
|
|
4097
4104
|
/* @__PURE__ */ jsx16(TableCell2, { className: "font-medium", children: user.displayName }),
|
|
4098
4105
|
/* @__PURE__ */ jsx16(TableCell2, { children: /* @__PURE__ */ jsx16("div", { className: "flex flex-wrap gap-2", children: user.roles.map((role) => /* @__PURE__ */ jsx16(Chip8, { colorScheme: role.isAdmin ? "purple" : "blue", size: "small", children: role.name }, role.id)) }) })
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { CollectionAccessor, Entity, FindParams } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The part of a read that says *which* rows, without saying how many or from
|
|
4
|
+
* where. The window adds `limit` and `offset` itself, page by page.
|
|
5
|
+
*/
|
|
6
|
+
export type CollectionWindowQuery<M extends Record<string, unknown>> = Omit<FindParams<M>, "limit" | "offset" | "page" | "after">;
|
|
7
|
+
/**
|
|
8
|
+
* What a {@link CollectionWindow} reports on every change.
|
|
9
|
+
*/
|
|
10
|
+
export interface CollectionWindowState<M extends Record<string, unknown> = Record<string, unknown>> {
|
|
11
|
+
/**
|
|
12
|
+
* The rows in the window, in order, without duplicates.
|
|
13
|
+
*
|
|
14
|
+
* `undefined` until the window first covers what it was opened for — the
|
|
15
|
+
* first page, or every row a restored scroll position had on screen — so a
|
|
16
|
+
* view that is still showing its previous rows keeps them instead of
|
|
17
|
+
* flashing a partial list.
|
|
18
|
+
*/
|
|
19
|
+
rows: Entity<M>[] | undefined;
|
|
20
|
+
/** Rows not yet on screen are being read: the first page, or the next one. */
|
|
21
|
+
loading: boolean;
|
|
22
|
+
error: Error | undefined;
|
|
23
|
+
/** A page came back short, so there is nothing past `rows`. */
|
|
24
|
+
complete: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface CollectionWindowOptions<M extends Record<string, unknown>> {
|
|
27
|
+
accessor: Pick<CollectionAccessor<M>, "find" | "listen">;
|
|
28
|
+
query: CollectionWindowQuery<M>;
|
|
29
|
+
/** Rows in the first page, which is the one kept live. */
|
|
30
|
+
pageSize: number;
|
|
31
|
+
/** How many rows the window should hold. `Infinity` reads them all. */
|
|
32
|
+
target: number;
|
|
33
|
+
/** Subscribe to the first page when the accessor can. Defaults to `true`. */
|
|
34
|
+
live?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Applied to every page as it arrives, before it is merged — the panel's
|
|
37
|
+
* own `afterRead`, for instance.
|
|
38
|
+
*/
|
|
39
|
+
process?: (rows: Entity<M>[]) => Promise<Entity<M>[]> | Entity<M>[];
|
|
40
|
+
/**
|
|
41
|
+
* When the subscription fails, read the first page once instead of
|
|
42
|
+
* reporting the failure (which is only reported if that read fails too).
|
|
43
|
+
*/
|
|
44
|
+
fallbackToFind?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Read the first page once if the subscription has not answered by then.
|
|
47
|
+
* The subscription still wins whenever it does answer.
|
|
48
|
+
*/
|
|
49
|
+
firstPaintTimeoutMs?: number;
|
|
50
|
+
onChange: (state: CollectionWindowState<M>) => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A scrolled collection view's rows, read one page at a time.
|
|
54
|
+
*
|
|
55
|
+
* ## Why this exists
|
|
56
|
+
*
|
|
57
|
+
* The table, list, card and board views used to grow a single read: the next
|
|
58
|
+
* page was the same query with `limit` raised by a page, so page *k* re-read
|
|
59
|
+
* the *k − 1* pages before it, and the read that reached row 1,001 asked for a
|
|
60
|
+
* `limit` the API refuses (`MAX_LIST_LIMIT`). Every row past 1,000 was out of
|
|
61
|
+
* reach, behind a developer error. The board clamped at the ceiling instead,
|
|
62
|
+
* and its columns then said they were finished while their own header counted
|
|
63
|
+
* thousands more.
|
|
64
|
+
*
|
|
65
|
+
* ## How it reads
|
|
66
|
+
*
|
|
67
|
+
* - The **first page** is a subscription when the accessor can listen, else a
|
|
68
|
+
* one-shot read. It is the only live query the window holds.
|
|
69
|
+
* - Every **later page** is a one-shot read by `offset`, of only the rows past
|
|
70
|
+
* the ones already held, never more than `MAX_LIST_LIMIT` at a time. Offset
|
|
71
|
+
* rather than the keyset cursor because it is the one paging every sort a
|
|
72
|
+
* view offers can express — a relevance-ordered search has no cursor — and
|
|
73
|
+
* because the server breaks ties on the id, so pages neither repeat nor skip
|
|
74
|
+
* rows under a sort with duplicates.
|
|
75
|
+
* - **Realtime** covers every row held, not only the first page. The server
|
|
76
|
+
* re-runs a subscription on every write to its collection, so each push after
|
|
77
|
+
* the first says "something changed". The rows past the first page are then
|
|
78
|
+
* read again, in reads of at most `MAX_LIST_LIMIT`, and replaced in one step.
|
|
79
|
+
* Pushes that arrive while that re-read runs are folded into one more.
|
|
80
|
+
*
|
|
81
|
+
* Rows are de-duplicated by id: between a push moving the first page and the
|
|
82
|
+
* re-read of the rest, a row can briefly belong to both.
|
|
83
|
+
*/
|
|
84
|
+
export declare class CollectionWindow<M extends Record<string, unknown>> {
|
|
85
|
+
private readonly accessor;
|
|
86
|
+
private readonly query;
|
|
87
|
+
private readonly pageSize;
|
|
88
|
+
private readonly options;
|
|
89
|
+
/** Rows the window must hold before it first shows any. */
|
|
90
|
+
private readonly holdUntil;
|
|
91
|
+
private target;
|
|
92
|
+
private head;
|
|
93
|
+
/** The first page came back full, so there may be more past it. */
|
|
94
|
+
private headFull;
|
|
95
|
+
/** Rows past the first page, from offset `pageSize` on. */
|
|
96
|
+
private tail;
|
|
97
|
+
/** The last read past the first page came back short. */
|
|
98
|
+
private tailEnded;
|
|
99
|
+
/** The first page changed after it first arrived: re-read the rest. */
|
|
100
|
+
private stale;
|
|
101
|
+
private pumping;
|
|
102
|
+
private loadingMore;
|
|
103
|
+
private headError;
|
|
104
|
+
private tailError;
|
|
105
|
+
private settled;
|
|
106
|
+
private disposed;
|
|
107
|
+
private headSequence;
|
|
108
|
+
private liveAnswered;
|
|
109
|
+
private unsubscribe;
|
|
110
|
+
private firstPaintTimer;
|
|
111
|
+
constructor(options: CollectionWindowOptions<M>);
|
|
112
|
+
start(): void;
|
|
113
|
+
/** Hold this many rows. Fewer than are held drops the rows past it. */
|
|
114
|
+
setTarget(target: number): void;
|
|
115
|
+
dispose(): void;
|
|
116
|
+
private readHeadOnce;
|
|
117
|
+
private receiveLiveError;
|
|
118
|
+
private receiveHead;
|
|
119
|
+
/** Rows still wanted past the ones held. */
|
|
120
|
+
private wanted;
|
|
121
|
+
/**
|
|
122
|
+
* The one loop that reads past the first page, so a re-read and a next page
|
|
123
|
+
* never run at the same time and interleave their offsets.
|
|
124
|
+
*/
|
|
125
|
+
private pump;
|
|
126
|
+
private readNext;
|
|
127
|
+
/** Read every held row past the first page again, and swap them in at once. */
|
|
128
|
+
private reread;
|
|
129
|
+
private process;
|
|
130
|
+
private complete;
|
|
131
|
+
private emit;
|
|
132
|
+
private rows;
|
|
133
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The same filter object for as long as its contents stay the same.
|
|
3
|
+
*
|
|
4
|
+
* Callers write filters inline — the hooks guide does — so every render hands
|
|
5
|
+
* a data hook a new object. Used as an effect dependency by identity, that
|
|
6
|
+
* re-subscribed on every render, and every delivery rendered again: a
|
|
7
|
+
* subscribe loop against the server for as long as the component was mounted.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useStableFilterValues<T>(filterValues: T): T;
|
package/dist/hooks/index.d.ts
CHANGED