@agent-native/toolkit 0.211.0 → 0.212.0-nightly-20261021010049
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/agent-native.eject.json +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +23 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +23 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +23 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +23 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +23 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +23 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +23 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +23 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +23 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +23 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +23 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +23 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/sharing/OwnershipFilter.d.ts +8 -0
- package/dist/app/sharing/OwnershipFilter.d.ts.map +1 -0
- package/dist/app/sharing/OwnershipFilter.js +20 -0
- package/dist/app/sharing/OwnershipFilter.js.map +1 -0
- package/dist/app/sharing/ShareButton.d.ts +43 -1
- package/dist/app/sharing/ShareButton.d.ts.map +1 -1
- package/dist/app/sharing/ShareButton.js +102 -63
- package/dist/app/sharing/ShareButton.js.map +1 -1
- package/dist/app/sharing/ShareDialog.d.ts +3 -1
- package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/app/sharing/ShareDialog.js +18 -12
- package/dist/app/sharing/ShareDialog.js.map +1 -1
- package/dist/app/sharing/ShareVisibilityConfirmDialog.d.ts +20 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.d.ts.map +1 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.js +57 -0
- package/dist/app/sharing/ShareVisibilityConfirmDialog.js.map +1 -0
- package/dist/app/sharing/VisibilityBadge.d.ts +8 -1
- package/dist/app/sharing/VisibilityBadge.d.ts.map +1 -1
- package/dist/app/sharing/VisibilityBadge.js +16 -1
- package/dist/app/sharing/VisibilityBadge.js.map +1 -1
- package/dist/app/sharing/index.d.ts +2 -0
- package/dist/app/sharing/index.d.ts.map +1 -1
- package/dist/app/sharing/index.js +2 -0
- package/dist/app/sharing/index.js.map +1 -1
- package/dist/chat-history/ChatHistoryList.d.ts +19 -0
- package/dist/chat-history/ChatHistoryList.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryList.js +19 -7
- package/dist/chat-history/ChatHistoryList.js.map +1 -1
- package/dist/chat-history/ChatHistoryRail.d.ts +55 -8
- package/dist/chat-history/ChatHistoryRail.d.ts.map +1 -1
- package/dist/chat-history/ChatHistoryRail.js +33 -7
- package/dist/chat-history/ChatHistoryRail.js.map +1 -1
- package/dist/chat-history/index.d.ts +3 -3
- package/dist/chat-history/index.d.ts.map +1 -1
- package/dist/chat-history/index.js +1 -1
- package/dist/chat-history/index.js.map +1 -1
- package/dist/chat-history/useChatHistoryRailController.d.ts +44 -0
- package/dist/chat-history/useChatHistoryRailController.d.ts.map +1 -1
- package/dist/chat-history/useChatHistoryRailController.js +46 -0
- package/dist/chat-history/useChatHistoryRailController.js.map +1 -1
- package/dist/chat-history.css +29 -0
- package/dist/composer/TiptapComposer.d.ts +7 -0
- package/dist/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/composer/TiptapComposer.js +15 -2
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/dist/sharing/OwnershipFilter.d.ts +21 -0
- package/dist/sharing/OwnershipFilter.d.ts.map +1 -0
- package/dist/sharing/OwnershipFilter.js +30 -0
- package/dist/sharing/OwnershipFilter.js.map +1 -0
- package/dist/sharing/VisibilityBadge.d.ts +12 -2
- package/dist/sharing/VisibilityBadge.d.ts.map +1 -1
- package/dist/sharing/VisibilityBadge.js +13 -4
- package/dist/sharing/VisibilityBadge.js.map +1 -1
- package/dist/sharing/index.d.ts +2 -1
- package/dist/sharing/index.d.ts.map +1 -1
- package/dist/sharing/index.js +2 -1
- package/dist/sharing/index.js.map +1 -1
- package/dist/ui/alert-dialog.d.ts +2 -0
- package/dist/ui/alert-dialog.d.ts.map +1 -1
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/tooltip.d.ts +6 -1
- package/dist/ui/tooltip.d.ts.map +1 -1
- package/dist/ui/tooltip.js +13 -1
- package/dist/ui/tooltip.js.map +1 -1
- package/package.json +4 -4
- package/src/app/i18n/catalogs/ar-SA.ts +26 -0
- package/src/app/i18n/catalogs/de-DE.ts +25 -0
- package/src/app/i18n/catalogs/en-US.ts +25 -0
- package/src/app/i18n/catalogs/es-ES.ts +25 -0
- package/src/app/i18n/catalogs/fr-FR.ts +25 -0
- package/src/app/i18n/catalogs/hi-IN.ts +25 -0
- package/src/app/i18n/catalogs/ja-JP.ts +25 -0
- package/src/app/i18n/catalogs/ko-KR.ts +25 -0
- package/src/app/i18n/catalogs/pt-BR.ts +25 -0
- package/src/app/i18n/catalogs/zh-CN.ts +25 -0
- package/src/app/i18n/catalogs/zh-TW.ts +25 -0
- package/src/app/sharing/OwnershipFilter.tsx +35 -0
- package/src/app/sharing/ShareButton.tsx +384 -259
- package/src/app/sharing/ShareDialog.spec.tsx +50 -0
- package/src/app/sharing/ShareDialog.tsx +51 -15
- package/src/app/sharing/ShareVisibilityConfirmDialog.spec.tsx +138 -0
- package/src/app/sharing/ShareVisibilityConfirmDialog.tsx +124 -0
- package/src/app/sharing/ShareVisibilityKeyboard.spec.tsx +244 -0
- package/src/app/sharing/VisibilityBadge.spec.tsx +65 -0
- package/src/app/sharing/VisibilityBadge.tsx +31 -3
- package/src/app/sharing/index.ts +2 -0
- package/src/app/sharing/share-visibility-mutation-lifecycle.spec.tsx +1107 -0
- package/src/app/sharing/useShareButtonController.spec.tsx +226 -37
- package/src/app/sharing/useShareDialogController.spec.tsx +357 -9
- package/src/chat-history/ChatHistoryList.spec.tsx +157 -0
- package/src/chat-history/ChatHistoryList.tsx +104 -10
- package/src/chat-history/ChatHistoryRail.spec.tsx +50 -1
- package/src/chat-history/ChatHistoryRail.tsx +177 -26
- package/src/chat-history/ChatHistoryRailSections.spec.tsx +410 -0
- package/src/chat-history/index.ts +8 -0
- package/src/chat-history/useChatHistoryRailController.ts +94 -0
- package/src/chat-history/useChatHistoryRailSectionsController.spec.tsx +133 -0
- package/src/chat-history.css +29 -0
- package/src/composer/TiptapComposer.spec.ts +19 -0
- package/src/composer/TiptapComposer.tsx +26 -5
- package/src/sharing/OwnershipFilter.spec.tsx +108 -0
- package/src/sharing/OwnershipFilter.tsx +103 -0
- package/src/sharing/VisibilityBadge.spec.ts +53 -35
- package/src/sharing/VisibilityBadge.tsx +23 -3
- package/src/sharing/index.ts +11 -0
- package/src/ui/alert-dialog.tsx +7 -2
- package/src/ui/tooltip.tsx +22 -1
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
type ShareButtonController,
|
|
6
6
|
type ShareButtonControllerOptions,
|
|
7
7
|
type ShareButtonSharesResponse,
|
|
8
|
+
type ShareButtonVisibility,
|
|
8
9
|
} from "@agent-native/core/client/sharing/useShareButtonController";
|
|
10
|
+
import { ShareVisibilityNotSavedError } from "@agent-native/core/client/sharing/useShareVisibilityTransition";
|
|
9
11
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
10
12
|
import React, { act } from "react";
|
|
11
13
|
import { createRoot, type Root } from "react-dom/client";
|
|
@@ -17,11 +19,23 @@ const mocks = vi.hoisted(() => ({
|
|
|
17
19
|
data: undefined as ShareButtonSharesResponse | undefined,
|
|
18
20
|
refetch: vi.fn(async () => undefined),
|
|
19
21
|
},
|
|
20
|
-
setVisibility: { mutate: vi.fn() },
|
|
22
|
+
setVisibility: { mutate: vi.fn(), mutateAsync: vi.fn() },
|
|
21
23
|
share: { mutate: vi.fn() },
|
|
22
24
|
unshare: { mutate: vi.fn() },
|
|
23
25
|
}));
|
|
24
26
|
|
|
27
|
+
// The controllers settle each save through mutateAsync; the tests drive it
|
|
28
|
+
// through the callbacks recorded on `mutate`.
|
|
29
|
+
mocks.setVisibility.mutateAsync.mockImplementation(
|
|
30
|
+
(variables: unknown) =>
|
|
31
|
+
new Promise((resolve, reject) => {
|
|
32
|
+
mocks.setVisibility.mutate(variables, {
|
|
33
|
+
onSuccess: resolve,
|
|
34
|
+
onError: reject,
|
|
35
|
+
});
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
|
|
25
39
|
vi.mock("@agent-native/core/client/use-action", () => ({
|
|
26
40
|
useActionQuery: mocks.useActionQuery,
|
|
27
41
|
useActionMutation: vi.fn((name: string) => {
|
|
@@ -61,6 +75,25 @@ describe("useShareButtonController", () => {
|
|
|
61
75
|
return controller as ShareButtonController;
|
|
62
76
|
}
|
|
63
77
|
|
|
78
|
+
async function renderOpen(
|
|
79
|
+
nextOptions: ShareButtonControllerOptions = options,
|
|
80
|
+
): Promise<ShareButtonController> {
|
|
81
|
+
const result = await render(nextOptions);
|
|
82
|
+
act(() => result.handleOpenChange(true));
|
|
83
|
+
return controller as ShareButtonController;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function chooseVisibility(next: ShareButtonVisibility) {
|
|
87
|
+
act(() => (controller as ShareButtonController).handleVisibility(next));
|
|
88
|
+
if ((controller as ShareButtonController).visibilityTransition.pending) {
|
|
89
|
+
act(() => {
|
|
90
|
+
void (
|
|
91
|
+
controller as ShareButtonController
|
|
92
|
+
).visibilityTransition.confirm();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
64
97
|
beforeEach(() => {
|
|
65
98
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
66
99
|
vi.stubGlobal(
|
|
@@ -100,7 +133,13 @@ describe("useShareButtonController", () => {
|
|
|
100
133
|
root = createRoot(container);
|
|
101
134
|
});
|
|
102
135
|
|
|
103
|
-
afterEach(() => {
|
|
136
|
+
afterEach(async () => {
|
|
137
|
+
await act(async () => {
|
|
138
|
+
for (const [variables, callbacks] of mocks.setVisibility.mutate.mock
|
|
139
|
+
.calls) {
|
|
140
|
+
callbacks?.onSuccess?.({ visibility: variables.visibility });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
104
143
|
act(() => root.unmount());
|
|
105
144
|
queryClient.clear();
|
|
106
145
|
container.remove();
|
|
@@ -208,8 +247,8 @@ describe("useShareButtonController", () => {
|
|
|
208
247
|
|
|
209
248
|
it("reports a private plan becoming shared to its host", async () => {
|
|
210
249
|
const onShareSuccess = vi.fn();
|
|
211
|
-
|
|
212
|
-
|
|
250
|
+
await renderOpen({ ...options, onShareSuccess });
|
|
251
|
+
chooseVisibility("org");
|
|
213
252
|
|
|
214
253
|
const mutation = mocks.setVisibility.mutate.mock.calls[0]?.[1];
|
|
215
254
|
await act(async () => {
|
|
@@ -220,34 +259,34 @@ describe("useShareButtonController", () => {
|
|
|
220
259
|
expect(onShareSuccess).toHaveBeenCalledOnce();
|
|
221
260
|
});
|
|
222
261
|
|
|
223
|
-
it("reports
|
|
262
|
+
it("reports the actual private-to-shared save once after refusing a different target", async () => {
|
|
224
263
|
const onShareSuccess = vi.fn();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
264
|
+
await renderOpen({ ...options, onShareSuccess });
|
|
265
|
+
chooseVisibility("public");
|
|
266
|
+
const mutation = mocks.setVisibility.mutate.mock.calls[0]?.[1];
|
|
267
|
+
chooseVisibility("org");
|
|
268
|
+
expect(mocks.setVisibility.mutate).toHaveBeenCalledOnce();
|
|
269
|
+
expect((controller as ShareButtonController).visibility).toBe("public");
|
|
270
|
+
expect(onShareSuccess).not.toHaveBeenCalled();
|
|
230
271
|
|
|
231
272
|
await act(async () => {
|
|
232
|
-
|
|
233
|
-
latestMutation?.onSuccess?.({ visibility: "public" });
|
|
273
|
+
mutation?.onSuccess?.({ visibility: "public" });
|
|
234
274
|
await Promise.resolve();
|
|
235
275
|
});
|
|
236
276
|
|
|
237
277
|
expect(onShareSuccess).toHaveBeenCalledOnce();
|
|
238
278
|
});
|
|
239
279
|
|
|
240
|
-
it("
|
|
280
|
+
it("requires an authoritative shared result after refusing a different target", async () => {
|
|
241
281
|
const onShareSuccess = vi.fn();
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
282
|
+
await renderOpen({ ...options, onShareSuccess });
|
|
283
|
+
chooseVisibility("public");
|
|
284
|
+
const mutation = mocks.setVisibility.mutate.mock.calls[0]?.[1];
|
|
285
|
+
chooseVisibility("org");
|
|
286
|
+
expect(mocks.setVisibility.mutate).toHaveBeenCalledOnce();
|
|
247
287
|
|
|
248
288
|
await act(async () => {
|
|
249
|
-
|
|
250
|
-
latestMutation?.onSuccess?.({ visibility: "private" });
|
|
289
|
+
mutation?.onSuccess?.({ visibility: "private" });
|
|
251
290
|
await Promise.resolve();
|
|
252
291
|
});
|
|
253
292
|
|
|
@@ -267,8 +306,8 @@ describe("useShareButtonController", () => {
|
|
|
267
306
|
],
|
|
268
307
|
initial,
|
|
269
308
|
);
|
|
270
|
-
|
|
271
|
-
|
|
309
|
+
await renderOpen();
|
|
310
|
+
chooseVisibility("org");
|
|
272
311
|
const callback = mocks.setVisibility.mutate.mock.calls[0]?.[1];
|
|
273
312
|
await act(async () => {
|
|
274
313
|
callback?.onError(new Error("visibility failed"));
|
|
@@ -283,9 +322,12 @@ describe("useShareButtonController", () => {
|
|
|
283
322
|
]);
|
|
284
323
|
expect(restored).toEqual(initial);
|
|
285
324
|
expect((controller as ShareButtonController).visibilityOverride).toBeNull();
|
|
286
|
-
expect(
|
|
287
|
-
|
|
288
|
-
);
|
|
325
|
+
expect(
|
|
326
|
+
(controller as ShareButtonController).visibilityTransition.error,
|
|
327
|
+
).toBe("visibility failed");
|
|
328
|
+
expect(
|
|
329
|
+
(controller as ShareButtonController).visibilityTransition.pending,
|
|
330
|
+
).toEqual({ from: "private", to: "org" });
|
|
289
331
|
});
|
|
290
332
|
|
|
291
333
|
it("restores the sequence snapshot and refetches when the latest visibility update fails", async () => {
|
|
@@ -299,24 +341,17 @@ describe("useShareButtonController", () => {
|
|
|
299
341
|
{ resourceType: "document", resourceId: "doc-1" },
|
|
300
342
|
] as const;
|
|
301
343
|
queryClient.setQueryData(shareQueryKey, initial);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
act(() => {
|
|
305
|
-
firstPromise = result.handleVisibilityChange("org");
|
|
306
|
-
});
|
|
344
|
+
await renderOpen();
|
|
345
|
+
chooseVisibility("public");
|
|
307
346
|
const firstMutation = mocks.setVisibility.mutate.mock.calls[0]?.[1];
|
|
308
|
-
|
|
309
|
-
act(() => {
|
|
310
|
-
latestPromise = (
|
|
311
|
-
controller as ShareButtonController
|
|
312
|
-
).handleVisibilityChange("public");
|
|
313
|
-
});
|
|
347
|
+
chooseVisibility("org");
|
|
314
348
|
const latestMutation = mocks.setVisibility.mutate.mock.calls[1]?.[1];
|
|
315
349
|
|
|
316
350
|
await act(async () => {
|
|
317
351
|
firstMutation?.onError(new Error("stale visibility failure"));
|
|
318
352
|
latestMutation?.onError(new Error("latest visibility failure"));
|
|
319
|
-
await Promise.
|
|
353
|
+
await Promise.resolve();
|
|
354
|
+
await Promise.resolve();
|
|
320
355
|
});
|
|
321
356
|
|
|
322
357
|
expect(queryClient.getQueryData(shareQueryKey)).toEqual(initial);
|
|
@@ -325,6 +360,160 @@ describe("useShareButtonController", () => {
|
|
|
325
360
|
expect((controller as ShareButtonController).visibility).toBe("private");
|
|
326
361
|
});
|
|
327
362
|
|
|
363
|
+
it("keeps the deprecated handleVisibilityChange behind the confirmation", async () => {
|
|
364
|
+
await renderOpen();
|
|
365
|
+
|
|
366
|
+
act(() => {
|
|
367
|
+
void (controller as ShareButtonController).handleVisibilityChange("org");
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
expect(mocks.setVisibility.mutate).not.toHaveBeenCalled();
|
|
371
|
+
expect(
|
|
372
|
+
(controller as ShareButtonController).visibilityTransition.pending,
|
|
373
|
+
).toEqual({ from: "private", to: "org" });
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("resolves the deprecated alias only once a direct change is persisted", async () => {
|
|
377
|
+
await renderOpen();
|
|
378
|
+
let settled = false;
|
|
379
|
+
let alias!: Promise<void>;
|
|
380
|
+
act(() => {
|
|
381
|
+
alias = (controller as ShareButtonController)
|
|
382
|
+
.handleVisibilityChange("public")
|
|
383
|
+
.then(() => {
|
|
384
|
+
settled = true;
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
await act(async () => {
|
|
388
|
+
await Promise.resolve();
|
|
389
|
+
});
|
|
390
|
+
expect(settled).toBe(false);
|
|
391
|
+
|
|
392
|
+
await act(async () => {
|
|
393
|
+
mocks.setVisibility.mutate.mock.calls[0]?.[1]?.onSuccess({
|
|
394
|
+
visibility: "public",
|
|
395
|
+
});
|
|
396
|
+
await alias;
|
|
397
|
+
});
|
|
398
|
+
expect(settled).toBe(true);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("rejects the deprecated alias when a direct change fails", async () => {
|
|
402
|
+
await renderOpen();
|
|
403
|
+
let alias!: Promise<void>;
|
|
404
|
+
act(() => {
|
|
405
|
+
alias = (controller as ShareButtonController).handleVisibilityChange(
|
|
406
|
+
"public",
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
await act(async () => {
|
|
411
|
+
mocks.setVisibility.mutate.mock.calls[0]?.[1]?.onError(
|
|
412
|
+
new Error("visibility failed"),
|
|
413
|
+
);
|
|
414
|
+
await expect(alias).rejects.toThrow("visibility failed");
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it("keeps a held alias change unresolved until confirmed and rejects it when cancelled", async () => {
|
|
419
|
+
await renderOpen();
|
|
420
|
+
const transition = () =>
|
|
421
|
+
(controller as ShareButtonController).visibilityTransition;
|
|
422
|
+
let confirmed = false;
|
|
423
|
+
let alias!: Promise<void>;
|
|
424
|
+
act(() => {
|
|
425
|
+
alias = (controller as ShareButtonController)
|
|
426
|
+
.handleVisibilityChange("org")
|
|
427
|
+
.then(() => {
|
|
428
|
+
confirmed = true;
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
await act(async () => {
|
|
432
|
+
await Promise.resolve();
|
|
433
|
+
});
|
|
434
|
+
expect(confirmed).toBe(false);
|
|
435
|
+
|
|
436
|
+
await act(async () => {
|
|
437
|
+
void transition().confirm();
|
|
438
|
+
});
|
|
439
|
+
await act(async () => {
|
|
440
|
+
mocks.setVisibility.mutate.mock.calls[0]?.[1]?.onSuccess({
|
|
441
|
+
visibility: "org",
|
|
442
|
+
});
|
|
443
|
+
await alias;
|
|
444
|
+
});
|
|
445
|
+
expect(confirmed).toBe(true);
|
|
446
|
+
|
|
447
|
+
mocks.setVisibility.mutate.mockReset();
|
|
448
|
+
mocks.query.data = { ...mocks.query.data!, visibility: "private" };
|
|
449
|
+
await render();
|
|
450
|
+
let cancelled!: Promise<void>;
|
|
451
|
+
act(() => {
|
|
452
|
+
cancelled = (controller as ShareButtonController).handleVisibilityChange(
|
|
453
|
+
"org",
|
|
454
|
+
);
|
|
455
|
+
});
|
|
456
|
+
act(() => transition().cancel());
|
|
457
|
+
await expect(cancelled).rejects.toBeInstanceOf(
|
|
458
|
+
ShareVisibilityNotSavedError,
|
|
459
|
+
);
|
|
460
|
+
expect(mocks.setVisibility.mutate).not.toHaveBeenCalled();
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it("does not carry a pending change from one resource into the next", async () => {
|
|
464
|
+
mocks.query.data = { ...mocks.query.data!, visibility: "private" };
|
|
465
|
+
await renderOpen();
|
|
466
|
+
act(() => (controller as ShareButtonController).handleVisibility("public"));
|
|
467
|
+
expect(mocks.setVisibility.mutate).toHaveBeenCalledTimes(1);
|
|
468
|
+
expect((controller as ShareButtonController).visibility).toBe("public");
|
|
469
|
+
|
|
470
|
+
// The mounted controller moves to another resource while the first write
|
|
471
|
+
// is still in flight.
|
|
472
|
+
await render({ ...options, resourceId: "doc-2" });
|
|
473
|
+
expect((controller as ShareButtonController).visibility).toBe("private");
|
|
474
|
+
expect((controller as ShareButtonController).visibilityOverride).toBeNull();
|
|
475
|
+
|
|
476
|
+
act(() => (controller as ShareButtonController).handleVisibility("org"));
|
|
477
|
+
expect(
|
|
478
|
+
(controller as ShareButtonController).visibilityTransition.pending,
|
|
479
|
+
).toEqual({ from: "private", to: "org" });
|
|
480
|
+
expect(mocks.setVisibility.mutate).toHaveBeenCalledTimes(1);
|
|
481
|
+
|
|
482
|
+
// The first resource's write finishes late: it neither clears nor
|
|
483
|
+
// confirms anything for the second one.
|
|
484
|
+
await act(async () => {
|
|
485
|
+
mocks.setVisibility.mutate.mock.calls[0]?.[1]?.onSuccess({
|
|
486
|
+
visibility: "public",
|
|
487
|
+
});
|
|
488
|
+
await Promise.resolve();
|
|
489
|
+
});
|
|
490
|
+
expect(
|
|
491
|
+
(controller as ShareButtonController).visibilityTransition.pending,
|
|
492
|
+
).toEqual({ from: "private", to: "org" });
|
|
493
|
+
expect((controller as ShareButtonController).visibility).toBe("private");
|
|
494
|
+
|
|
495
|
+
await act(async () => {
|
|
496
|
+
void (controller as ShareButtonController).visibilityTransition.confirm();
|
|
497
|
+
});
|
|
498
|
+
expect(mocks.setVisibility.mutate).toHaveBeenCalledTimes(2);
|
|
499
|
+
expect(mocks.setVisibility.mutate.mock.calls[1]?.[0]).toMatchObject({
|
|
500
|
+
resourceId: "doc-2",
|
|
501
|
+
visibility: "org",
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it("ignores visibility requests while the surface is closed", async () => {
|
|
506
|
+
const result = await render();
|
|
507
|
+
|
|
508
|
+
act(() => result.handleVisibility("public"));
|
|
509
|
+
act(() => result.handleVisibility("org"));
|
|
510
|
+
|
|
511
|
+
expect(mocks.setVisibility.mutate).not.toHaveBeenCalled();
|
|
512
|
+
expect(
|
|
513
|
+
(controller as ShareButtonController).visibilityTransition.pending,
|
|
514
|
+
).toBeNull();
|
|
515
|
+
});
|
|
516
|
+
|
|
328
517
|
it("gates every sharing mutation for non-managers", async () => {
|
|
329
518
|
mocks.query.data = { ...mocks.query.data!, role: "viewer" };
|
|
330
519
|
const result = await render();
|