camox 0.68.0 → 0.71.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/core/createBlock.js +14 -7
- package/dist/core/hooks/useArtifactHost.js +56 -46
- package/dist/core/lib/artifact.d.ts +4 -0
- package/dist/core/lib/artifactHost.js +40 -0
- package/dist/core/lib/artifactRuntime.js +20 -1
- package/dist/features/canvas/canvasFrameDocument.js +25 -2
- package/dist/features/canvas/useCanvasFrame.js +6 -2
- package/dist/features/preview/components/previewStyles.js +11 -2
- package/dist/features/provider/AuthenticatedCamoxProvider.js +33 -28
- package/dist/features/renderer/RendererApp.js +202 -154
- package/dist/features/renderer/RendererFrames.js +87 -55
- package/dist/features/renderer/definitionAnswers.js +1 -0
- package/dist/features/renderer/rendererHost.js +4 -0
- package/dist/features/renderer/studioConnection.js +9 -1
- package/dist/features/runtime/pageApp.js +7 -3
- package/dist/features/runtime/pageNavigation.js +93 -17
- package/dist/features/runtime/rendererClient.js +13 -6
- package/dist/features/studio/agentRunToast.js +71 -0
- package/dist/features/studio/components/ChatWidget.js +2 -0
- package/dist/features/studio/components/DraftBar.js +2 -3
- package/dist/features/studio/components/DraftsControl.js +181 -198
- package/dist/features/studio/components/LocalePicker.js +22 -4
- package/dist/features/studio/components/ReviewDraftSheet.js +345 -568
- package/dist/features/studio/draftLabel.js +1 -1
- package/dist/features/studio/studioStore.js +5 -17
- package/dist/features/studio/viewSwitch.js +62 -0
- package/dist/lib/auth.js +5 -1
- package/dist/lib/draft-scope.js +28 -15
- package/dist/lib/studio-reads.js +46 -13
- package/dist/lib/view-switch.js +64 -0
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +6 -4
- package/skills/camox/references/artifacts.md +85 -1
|
@@ -26,7 +26,7 @@ const mirror = (message) => mirrors[message.store]?.send({
|
|
|
26
26
|
* its cache follows the studio's (see `protocol.ts`). The studio's questions are answered from
|
|
27
27
|
* `camoxApp`, the draft's code; without it, none can be.
|
|
28
28
|
*/
|
|
29
|
-
function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxApp }) {
|
|
29
|
+
function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxApp, prepareFrame }) {
|
|
30
30
|
let welcomed = false;
|
|
31
31
|
let frames = [];
|
|
32
32
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -109,6 +109,14 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
|
|
|
109
109
|
return;
|
|
110
110
|
case "ask": {
|
|
111
111
|
const { askId, question } = message;
|
|
112
|
+
if (question.type === "prepareFrame") {
|
|
113
|
+
(prepareFrame?.(question) ?? Promise.resolve()).catch(() => {}).then(() => studio({
|
|
114
|
+
type: "answer",
|
|
115
|
+
askId,
|
|
116
|
+
value: null
|
|
117
|
+
}));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
112
120
|
if (!camoxApp) {
|
|
113
121
|
studio({
|
|
114
122
|
type: "answer",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DraftScopeContext } from "../../lib/draft-scope.js";
|
|
2
2
|
import { useAuthState, useSignInRedirect } from "../../lib/auth.js";
|
|
3
|
+
import { ArtifactCaptureContext } from "../../core/hooks/useArtifactHost.js";
|
|
3
4
|
import { useSignInShortcut } from "../provider/signInShortcut.js";
|
|
4
5
|
import { PreviewDocumentContext } from "./PreviewDocumentContext.js";
|
|
5
6
|
import { PreviewActivation } from "../preview/components/PreviewActivation.js";
|
|
@@ -36,9 +37,12 @@ function PageApp(t0) {
|
|
|
36
37
|
sessionless: input.look,
|
|
37
38
|
children: /* @__PURE__ */ jsx(PreviewDocumentContext.Provider, {
|
|
38
39
|
value: currentInput.previewDocument,
|
|
39
|
-
children: input.previewHandoff ? /* @__PURE__ */ jsx(PreviewSignInPage, {}) : input.look ? /* @__PURE__ */ jsx(
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
children: input.previewHandoff ? /* @__PURE__ */ jsx(PreviewSignInPage, {}) : input.look ? /* @__PURE__ */ jsx(ArtifactCaptureContext, {
|
|
41
|
+
value: true,
|
|
42
|
+
children: /* @__PURE__ */ jsx(PageContent, {
|
|
43
|
+
camoxApp,
|
|
44
|
+
input: currentInput
|
|
45
|
+
})
|
|
42
46
|
}) : /* @__PURE__ */ jsx(PageExperience, {
|
|
43
47
|
camoxApp,
|
|
44
48
|
input: currentInput,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { DraftScopeContext, draftNamedBy } from "../../lib/draft-scope.js";
|
|
1
|
+
import { DraftScopeContext, ShownDraftContext, draftNamedBy } from "../../lib/draft-scope.js";
|
|
2
2
|
import { PageAlternatesContext, ViewLocaleContext } from "../../lib/view-locale-context.js";
|
|
3
3
|
import { NavigationProvider } from "../navigation/navigation.js";
|
|
4
4
|
import { fetchRuntimeJson, getNavigationTarget } from "./navigationTarget.js";
|
|
5
|
+
import { SWITCH_WAIT_MS, ViewSwitchDeadlineContext, ViewSwitchesContext } from "../../lib/view-switch.js";
|
|
5
6
|
import { reads } from "../../lib/studio-reads.js";
|
|
6
7
|
import { createPrefetchCache, listenForLinkIntent } from "./linkPrefetch.js";
|
|
7
8
|
import { PageViewportContext } from "./pageViewport.js";
|
|
@@ -13,7 +14,7 @@ import { createNavigationRequestTracker } from "./navigationRequest.js";
|
|
|
13
14
|
import { createScrollRestoration } from "./scrollRestoration.js";
|
|
14
15
|
import { c } from "react/compiler-runtime";
|
|
15
16
|
import * as React from "react";
|
|
16
|
-
import { jsx } from "react/jsx-runtime";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
18
|
import { hydrate } from "@tanstack/react-query";
|
|
18
19
|
import { createHead, renderDOMHead } from "@unhead/react/client";
|
|
19
20
|
|
|
@@ -63,13 +64,24 @@ function prefetchKey(pathname, draft) {
|
|
|
63
64
|
function PageNavigationProvider({ camoxApp, children, initialInput, queryClient }) {
|
|
64
65
|
const draftScope = React.useContext(DraftScopeContext);
|
|
65
66
|
if (!draftScope) throw new Error("PageNavigationProvider needs a DraftScopeContext provider");
|
|
66
|
-
const [{ input, source,
|
|
67
|
+
const [{ input, source, switched, navigation }, setLocation] = React.useState(() => {
|
|
67
68
|
draftScope.adopt(initialInput);
|
|
68
69
|
return {
|
|
69
70
|
input: initialInput,
|
|
70
|
-
|
|
71
|
+
navigation: 0
|
|
71
72
|
};
|
|
72
73
|
});
|
|
74
|
+
const [preparers] = React.useState(() => /* @__PURE__ */ new Set());
|
|
75
|
+
const [commits] = React.useState(() => /* @__PURE__ */ new Map());
|
|
76
|
+
const navigations = React.useRef(0);
|
|
77
|
+
const lastShown = React.useRef(Promise.resolve());
|
|
78
|
+
const switches = React.useMemo(() => ({
|
|
79
|
+
prepare(preparer) {
|
|
80
|
+
preparers.add(preparer);
|
|
81
|
+
return () => void preparers.delete(preparer);
|
|
82
|
+
},
|
|
83
|
+
shown: () => lastShown.current
|
|
84
|
+
}), [preparers]);
|
|
73
85
|
const current = React.useRef(initialInput);
|
|
74
86
|
const [requests] = React.useState(createNavigationRequestTracker);
|
|
75
87
|
const ownsWindow = initialInput.presentation !== "studio";
|
|
@@ -88,6 +100,20 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
88
100
|
}, [restoration]);
|
|
89
101
|
const pendingAnnouncement = React.useRef(null);
|
|
90
102
|
const announcer = React.useRef(null);
|
|
103
|
+
const prepareSwitch = React.useCallback((next) => {
|
|
104
|
+
const view = {
|
|
105
|
+
pathname: next.pathname,
|
|
106
|
+
...next.derived && { derivedLayoutId: next.derived.layoutId },
|
|
107
|
+
draftId: next.draftId ?? null,
|
|
108
|
+
locale: next.locale
|
|
109
|
+
};
|
|
110
|
+
const deadline = Date.now() + SWITCH_WAIT_MS;
|
|
111
|
+
const prepared = Promise.all([...preparers].map((prepare) => Promise.resolve(prepare(view)).catch(() => {})));
|
|
112
|
+
return {
|
|
113
|
+
deadline,
|
|
114
|
+
ready: Promise.race([prepared.then(() => {}), new Promise((resolve) => setTimeout(resolve, SWITCH_WAIT_MS))])
|
|
115
|
+
};
|
|
116
|
+
}, [preparers]);
|
|
91
117
|
const loadPage = React.useCallback(async (pathname, draft, signal) => {
|
|
92
118
|
const response = await fetchRuntimeJson(draftScope, "/_camox/data", initialInput.runtimeBasePath, { path: pathname }, draft, signal);
|
|
93
119
|
if (!response.ok) throw new Error(`Navigation failed: ${response.status}`);
|
|
@@ -106,6 +132,7 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
106
132
|
const { analytics } = initialInput;
|
|
107
133
|
const navigate = React.useCallback(async ({ to, replace, source, draft, pop = false, refresh = false }) => {
|
|
108
134
|
const request = requests.begin();
|
|
135
|
+
const id = ++navigations.current;
|
|
109
136
|
const href = pop ? to : draftScope.hrefFor(to, {
|
|
110
137
|
from: window.location.href,
|
|
111
138
|
draft
|
|
@@ -122,12 +149,20 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
122
149
|
if (target.url.hash && viewport) position(viewport, "fragment", target.url.href);
|
|
123
150
|
return;
|
|
124
151
|
}
|
|
152
|
+
lastShown.current = new Promise((resolve) => commits.set(id, resolve));
|
|
153
|
+
const settle = () => {
|
|
154
|
+
for (const [waiting, resolve] of commits) {
|
|
155
|
+
if (waiting > id) continue;
|
|
156
|
+
commits.delete(waiting);
|
|
157
|
+
resolve();
|
|
158
|
+
}
|
|
159
|
+
};
|
|
125
160
|
try {
|
|
126
161
|
let next = current.current;
|
|
127
162
|
const targetDraft = draftNamedBy(target.url.href);
|
|
128
163
|
const fetched = target.pathname !== next.pathname || refresh || targetDraft !== draftNamedBy(next.href);
|
|
129
164
|
if (fetched) next = await (!refresh && prefetched.take(prefetchKey(target.pathname, targetDraft)) || loadPage(target.pathname, targetDraft, request.signal));
|
|
130
|
-
if (!request.isCurrent()) return;
|
|
165
|
+
if (!request.isCurrent()) return settle();
|
|
131
166
|
const switching = (next.draftId ?? null) !== (current.current.draftId ?? null) || !sameLocale(next.locale, current.current.locale);
|
|
132
167
|
const positions = restoration();
|
|
133
168
|
if (!pop) {
|
|
@@ -145,6 +180,7 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
145
180
|
};
|
|
146
181
|
pendingAnnouncement.current = fetched && !refresh ? next.pathname : null;
|
|
147
182
|
if (fetched) draftScope.adopt(next);
|
|
183
|
+
const switched = switching ? prepareSwitch(next) : void 0;
|
|
148
184
|
hydrate(queryClient, switching ? next.dehydratedState : preserveStableLayoutBlockCaches(next.dehydratedState, current.current.layoutIdentity, next.layoutIdentity));
|
|
149
185
|
next = {
|
|
150
186
|
...next,
|
|
@@ -162,12 +198,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
162
198
|
renderDOMHead(manager.head);
|
|
163
199
|
if (ownsWindow && analytics && next.pathname !== previous.pathname) sendPageView(analytics, window);
|
|
164
200
|
if (ownsWindow) document.documentElement.lang = next.locale.tag;
|
|
165
|
-
React.startTransition(() => setLocation(
|
|
201
|
+
React.startTransition(() => setLocation({
|
|
166
202
|
input: next,
|
|
167
203
|
source: pop ? void 0 : source,
|
|
168
|
-
|
|
169
|
-
|
|
204
|
+
switched,
|
|
205
|
+
navigation: id
|
|
206
|
+
}));
|
|
170
207
|
} catch {
|
|
208
|
+
settle();
|
|
171
209
|
if (!request.isCurrent()) return;
|
|
172
210
|
if (pop) window.location.reload();
|
|
173
211
|
else if (replace) window.location.replace(target.url.href);
|
|
@@ -175,12 +213,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
175
213
|
}
|
|
176
214
|
}, [
|
|
177
215
|
analytics,
|
|
216
|
+
commits,
|
|
178
217
|
draftScope,
|
|
179
218
|
initialInput.runtimeBasePath,
|
|
180
219
|
loadPage,
|
|
181
220
|
ownsWindow,
|
|
182
221
|
position,
|
|
183
222
|
prefetched,
|
|
223
|
+
prepareSwitch,
|
|
184
224
|
queryClient,
|
|
185
225
|
requests,
|
|
186
226
|
restoration
|
|
@@ -250,6 +290,21 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
250
290
|
prefetched.clear();
|
|
251
291
|
};
|
|
252
292
|
}, [draftScope, prefetched]);
|
|
293
|
+
React.useLayoutEffect(() => {
|
|
294
|
+
for (const [waiting, resolve] of commits) {
|
|
295
|
+
if (waiting > navigation) continue;
|
|
296
|
+
commits.delete(waiting);
|
|
297
|
+
resolve();
|
|
298
|
+
}
|
|
299
|
+
if (switched) setLocation((location) => ({
|
|
300
|
+
...location,
|
|
301
|
+
switched: void 0
|
|
302
|
+
}));
|
|
303
|
+
}, [
|
|
304
|
+
commits,
|
|
305
|
+
navigation,
|
|
306
|
+
switched
|
|
307
|
+
]);
|
|
253
308
|
React.useLayoutEffect(() => {
|
|
254
309
|
const intent = takeScroll(input.href);
|
|
255
310
|
const viewport = scroll.current?.viewport();
|
|
@@ -310,13 +365,14 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
310
365
|
initialInput.runtimeBasePath,
|
|
311
366
|
requests
|
|
312
367
|
]);
|
|
368
|
+
const hydrated = React.useSyncExternalStore(noSubscription, isClient, isServer);
|
|
313
369
|
const url = new URL(input.href);
|
|
314
370
|
const viewLocale = useSameJson({
|
|
315
371
|
locale: input.locale,
|
|
316
372
|
locales: input.locales
|
|
317
373
|
});
|
|
318
374
|
const alternates = useSameJson(input.alternates ?? null);
|
|
319
|
-
return /* @__PURE__ */
|
|
375
|
+
return /* @__PURE__ */ jsxs(NavigationProvider, {
|
|
320
376
|
location: {
|
|
321
377
|
href: input.href,
|
|
322
378
|
pathname: input.pathname,
|
|
@@ -325,18 +381,38 @@ function PageNavigationProvider({ camoxApp, children, initialInput, queryClient
|
|
|
325
381
|
source
|
|
326
382
|
},
|
|
327
383
|
navigate,
|
|
328
|
-
children: /* @__PURE__ */ jsx(
|
|
329
|
-
value:
|
|
330
|
-
children: /* @__PURE__ */ jsx(
|
|
331
|
-
value:
|
|
332
|
-
children: /* @__PURE__ */ jsx(
|
|
333
|
-
value:
|
|
334
|
-
children: /* @__PURE__ */ jsx(
|
|
384
|
+
children: [/* @__PURE__ */ jsx(ViewSwitchesContext, {
|
|
385
|
+
value: switches,
|
|
386
|
+
children: /* @__PURE__ */ jsx(ViewSwitchDeadlineContext, {
|
|
387
|
+
value: switched?.deadline ?? null,
|
|
388
|
+
children: /* @__PURE__ */ jsx(ShownDraftContext, {
|
|
389
|
+
value: input.draftId ?? null,
|
|
390
|
+
children: /* @__PURE__ */ jsx(ViewLocaleContext, {
|
|
391
|
+
value: viewLocale,
|
|
392
|
+
children: /* @__PURE__ */ jsx(PageAlternatesContext, {
|
|
393
|
+
value: alternates,
|
|
394
|
+
children: /* @__PURE__ */ jsx(PageViewportContext, {
|
|
395
|
+
value: pageViewport,
|
|
396
|
+
children: children(input)
|
|
397
|
+
})
|
|
398
|
+
})
|
|
399
|
+
})
|
|
335
400
|
})
|
|
336
401
|
})
|
|
337
|
-
})
|
|
402
|
+
}), hydrated && /* @__PURE__ */ jsx(React.Suspense, {
|
|
403
|
+
fallback: null,
|
|
404
|
+
children: /* @__PURE__ */ jsx(SwitchGate, { ready: switched?.ready })
|
|
405
|
+
})]
|
|
338
406
|
});
|
|
339
407
|
}
|
|
408
|
+
const noSubscription = () => () => {};
|
|
409
|
+
const isClient = () => true;
|
|
410
|
+
const isServer = () => false;
|
|
411
|
+
/** Suspends the switch's render until the next view is ready. */
|
|
412
|
+
function SwitchGate({ ready }) {
|
|
413
|
+
if (ready) React.use(ready);
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
340
416
|
|
|
341
417
|
//#endregion
|
|
342
418
|
export { PageNavigationProvider };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DraftScopeContext, createDraftScope, followUrl } from "../../lib/draft-scope.js";
|
|
2
|
-
import { StudioCacheContext, createStudioCache } from "../../lib/studio-reads.js";
|
|
2
|
+
import { StudioCacheContext, createStudioCache, reads } from "../../lib/studio-reads.js";
|
|
3
3
|
import { getDraftReadClient } from "../../lib/api-client.js";
|
|
4
4
|
import { STUDIO_HANDLE_KEY } from "../renderer/protocol.js";
|
|
5
5
|
import { CoreCamoxProvider } from "../provider/CoreCamoxProvider.js";
|
|
@@ -23,7 +23,8 @@ async function startRendererWithApp(camoxApp) {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
const input = readHydrationData();
|
|
26
|
-
|
|
26
|
+
const { projectUuid, runtimeBasePath } = input;
|
|
27
|
+
if (!input.apiUrl || !input.authenticationUrl || !projectUuid) {
|
|
27
28
|
console.error("Camox: the renderer document is missing its API or project.");
|
|
28
29
|
return;
|
|
29
30
|
}
|
|
@@ -44,7 +45,13 @@ async function startRendererWithApp(camoxApp) {
|
|
|
44
45
|
queryClient,
|
|
45
46
|
studioCache,
|
|
46
47
|
draftScope,
|
|
47
|
-
camoxApp
|
|
48
|
+
camoxApp,
|
|
49
|
+
prepareFrame: ({ pathname, derivedLayoutId, locale }) => Promise.all([studioCache.ensure(reads.canvasFrame({
|
|
50
|
+
projectUuid,
|
|
51
|
+
runtimeBasePath,
|
|
52
|
+
pathname,
|
|
53
|
+
...derivedLayoutId && { derivedLayoutId }
|
|
54
|
+
}), { locale }), codeLoaded])
|
|
48
55
|
});
|
|
49
56
|
const container = document.createElement("div");
|
|
50
57
|
document.body.append(container);
|
|
@@ -58,14 +65,14 @@ async function startRendererWithApp(camoxApp) {
|
|
|
58
65
|
apiUrl: input.apiUrl,
|
|
59
66
|
authenticationUrl: input.authenticationUrl,
|
|
60
67
|
camoxApp,
|
|
61
|
-
projectUuid
|
|
68
|
+
projectUuid,
|
|
62
69
|
initialAuthenticated: true,
|
|
63
70
|
children: /* @__PURE__ */ jsx(CompleteBlockEditingRuntimeProvider, { children: /* @__PURE__ */ jsx(RendererApp, {
|
|
64
71
|
connection,
|
|
65
72
|
camoxApp,
|
|
66
73
|
codeLoaded,
|
|
67
|
-
projectUuid
|
|
68
|
-
runtimeBasePath
|
|
74
|
+
projectUuid,
|
|
75
|
+
runtimeBasePath
|
|
69
76
|
}) })
|
|
70
77
|
})
|
|
71
78
|
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { toast } from "@camox/ui/toaster";
|
|
4
|
+
|
|
5
|
+
//#region src/features/studio/agentRunToast.ts
|
|
6
|
+
/**
|
|
7
|
+
* Says the agent is working in a toast while a run goes in the draft's thread, anyone's, so the
|
|
8
|
+
* editor knows wherever they are in the studio, then how it ended. Live's runs are too quick to
|
|
9
|
+
* need one. Leaving the thread takes the toast away.
|
|
10
|
+
*/
|
|
11
|
+
function useAgentRunToast(view, draftId) {
|
|
12
|
+
const $ = c(13);
|
|
13
|
+
const id = React.useId();
|
|
14
|
+
const running = draftId !== null && view.running;
|
|
15
|
+
const ran = React.useRef(false);
|
|
16
|
+
let t0;
|
|
17
|
+
if ($[0] !== id || $[1] !== view) {
|
|
18
|
+
t0 = () => {
|
|
19
|
+
const last = view.messages.at(-1)?.from;
|
|
20
|
+
if (last === "failed") toast.error("Agent couldn't finish", { id });
|
|
21
|
+
else if (last === "stopped") toast.dismiss(id);
|
|
22
|
+
else toast.success("Agent is done", { id });
|
|
23
|
+
};
|
|
24
|
+
$[0] = id;
|
|
25
|
+
$[1] = view;
|
|
26
|
+
$[2] = t0;
|
|
27
|
+
} else t0 = $[2];
|
|
28
|
+
const ended = React.useEffectEvent(t0);
|
|
29
|
+
let t1;
|
|
30
|
+
if ($[3] !== ended || $[4] !== id || $[5] !== running) {
|
|
31
|
+
t1 = () => {
|
|
32
|
+
if (running) {
|
|
33
|
+
ran.current = true;
|
|
34
|
+
toast.loading("Agent is working…", { id });
|
|
35
|
+
} else if (ran.current) {
|
|
36
|
+
ran.current = false;
|
|
37
|
+
ended();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
$[3] = ended;
|
|
41
|
+
$[4] = id;
|
|
42
|
+
$[5] = running;
|
|
43
|
+
$[6] = t1;
|
|
44
|
+
} else t1 = $[6];
|
|
45
|
+
let t2;
|
|
46
|
+
if ($[7] !== id || $[8] !== running) {
|
|
47
|
+
t2 = [running, id];
|
|
48
|
+
$[7] = id;
|
|
49
|
+
$[8] = running;
|
|
50
|
+
$[9] = t2;
|
|
51
|
+
} else t2 = $[9];
|
|
52
|
+
React.useEffect(t1, t2);
|
|
53
|
+
let t3;
|
|
54
|
+
let t4;
|
|
55
|
+
if ($[10] !== id) {
|
|
56
|
+
t3 = () => () => {
|
|
57
|
+
if (ran.current) toast.dismiss(id);
|
|
58
|
+
};
|
|
59
|
+
t4 = [id];
|
|
60
|
+
$[10] = id;
|
|
61
|
+
$[11] = t3;
|
|
62
|
+
$[12] = t4;
|
|
63
|
+
} else {
|
|
64
|
+
t3 = $[11];
|
|
65
|
+
t4 = $[12];
|
|
66
|
+
}
|
|
67
|
+
React.useEffect(t3, t4);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { useAgentRunToast };
|
|
@@ -7,6 +7,7 @@ import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES } from "../../preview/components/Sid
|
|
|
7
7
|
import { studioStore } from "../studioStore.js";
|
|
8
8
|
import { FollowAgentContext } from "../followAgentContext.js";
|
|
9
9
|
import { useThread } from "../../../lib/use-thread.js";
|
|
10
|
+
import { useAgentRunToast } from "../agentRunToast.js";
|
|
10
11
|
import { EditorWhereContext } from "../editorWhereContext.js";
|
|
11
12
|
import { useEditorSelection } from "../useEditorSelection.js";
|
|
12
13
|
import { ThreadComposer, useComposerCarrier } from "./ThreadComposer.js";
|
|
@@ -141,6 +142,7 @@ function Thread(t0) {
|
|
|
141
142
|
$[1] = t1;
|
|
142
143
|
} else t1 = $[1];
|
|
143
144
|
const { view, sending, send, stop, error, touched } = useThread(apiUrl, projectId, draftId, t1);
|
|
145
|
+
useAgentRunToast(view, draftId);
|
|
144
146
|
const follow = React.use(FollowAgentContext);
|
|
145
147
|
let t2;
|
|
146
148
|
if ($[2] !== follow) {
|
|
@@ -14,8 +14,7 @@ import { FloatingToolbar } from "@camox/ui/floating-toolbar";
|
|
|
14
14
|
*/
|
|
15
15
|
const SETTLE_MS = 1500;
|
|
16
16
|
/**
|
|
17
|
-
* Asks what to do with the draft being viewed, once its edits settle:
|
|
18
|
-
* publish them. `stacked` places it in the Preview toolbar's column, just above the toolbar;
|
|
17
|
+
* Asks what to do with the draft being viewed, once its edits settle: delete it or publish it. `stacked` places it in the Preview toolbar's column, just above the toolbar;
|
|
19
18
|
* otherwise it floats at the bottom of the screen on its own.
|
|
20
19
|
*/
|
|
21
20
|
function DraftBar(t0) {
|
|
@@ -63,7 +62,7 @@ function DraftBar(t0) {
|
|
|
63
62
|
type: "button",
|
|
64
63
|
variant: "outline",
|
|
65
64
|
onClick: _temp,
|
|
66
|
-
children: "
|
|
65
|
+
children: "Delete"
|
|
67
66
|
});
|
|
68
67
|
$[8] = t7;
|
|
69
68
|
} else t7 = $[8];
|