@adminide-stack/yantra-mobile 12.0.108-alpha.0 → 12.0.109-alpha.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/lib/compute.js +57 -1
- package/lib/compute.js.map +1 -1
- package/lib/config/env-config.js +8 -0
- package/lib/config/env-config.js.map +1 -1
- package/lib/features/apps/AppsCatalog.js +10 -0
- package/lib/features/apps/AppsCatalog.js.map +1 -1
- package/lib/features/apps/appArt.js +2 -1
- package/lib/features/apps/appArt.js.map +1 -1
- package/lib/features/apps/mobileAppCatalog.js +11 -0
- package/lib/features/apps/mobileAppCatalog.js.map +1 -1
- package/lib/features/apps/nativeAppHandoff.js +2 -1
- package/lib/features/apps/nativeAppHandoff.js.map +1 -1
- package/lib/features/health/healthSyncStore.js +7 -1
- package/lib/features/health/healthSyncStore.js.map +1 -1
- package/lib/features/messaging/NewGroupScreen.js.map +1 -1
- package/lib/features/messaging/useChatViewer.js +3 -2
- package/lib/features/messaging/useChatViewer.js.map +1 -1
- package/lib/features/webbuilder/WebBuilderExperience.js +474 -0
- package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -0
- package/lib/features/webbuilder/brandKitStorage.js +69 -0
- package/lib/features/webbuilder/brandKitStorage.js.map +1 -0
- package/lib/features/webbuilder/buildFragments.js +360 -0
- package/lib/features/webbuilder/buildFragments.js.map +1 -0
- package/lib/features/webbuilder/components/BottomTabs.js +65 -0
- package/lib/features/webbuilder/components/BottomTabs.js.map +1 -0
- package/lib/features/webbuilder/components/BrandKitSheet.js +197 -0
- package/lib/features/webbuilder/components/BrandKitSheet.js.map +1 -0
- package/lib/features/webbuilder/components/CodeView.js +99 -0
- package/lib/features/webbuilder/components/CodeView.js.map +1 -0
- package/lib/features/webbuilder/components/Composer.js +217 -0
- package/lib/features/webbuilder/components/Composer.js.map +1 -0
- package/lib/features/webbuilder/components/PreviewFrame.js +72 -0
- package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -0
- package/lib/features/webbuilder/components/PreviewPlaceholder.js +107 -0
- package/lib/features/webbuilder/components/PreviewPlaceholder.js.map +1 -0
- package/lib/features/webbuilder/components/PreviewScreen.js +200 -0
- package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -0
- package/lib/features/webbuilder/components/ProjectChat.js +580 -0
- package/lib/features/webbuilder/components/ProjectChat.js.map +1 -0
- package/lib/features/webbuilder/components/ProjectsScreen.js +339 -0
- package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -0
- package/lib/features/webbuilder/components/PublishSheet.js +143 -0
- package/lib/features/webbuilder/components/PublishSheet.js.map +1 -0
- package/lib/features/webbuilder/components/SiteScoreSheet.js +73 -0
- package/lib/features/webbuilder/components/SiteScoreSheet.js.map +1 -0
- package/lib/features/webbuilder/components/StudioHome.js +367 -0
- package/lib/features/webbuilder/components/StudioHome.js.map +1 -0
- package/lib/features/webbuilder/components/TemplateCard.js +73 -0
- package/lib/features/webbuilder/components/TemplateCard.js.map +1 -0
- package/lib/features/webbuilder/components/TemplatesSheet.js +178 -0
- package/lib/features/webbuilder/components/TemplatesSheet.js.map +1 -0
- package/lib/features/webbuilder/components/VersionsSheet.js +57 -0
- package/lib/features/webbuilder/components/VersionsSheet.js.map +1 -0
- package/lib/features/webbuilder/components/ui.js +291 -0
- package/lib/features/webbuilder/components/ui.js.map +1 -0
- package/lib/features/webbuilder/nativeWebBuilderRegistry.js +15 -0
- package/lib/features/webbuilder/nativeWebBuilderRegistry.js.map +1 -0
- package/lib/features/webbuilder/studioCatalog.js +147 -0
- package/lib/features/webbuilder/studioCatalog.js.map +1 -0
- package/lib/features/webbuilder/webbuilderPrompts.js +42 -0
- package/lib/features/webbuilder/webbuilderPrompts.js.map +1 -0
- package/lib/features/webbuilder/webbuilderTheme.js +63 -0
- package/lib/features/webbuilder/webbuilderTheme.js.map +1 -0
- package/lib/features/webbuilder/workflow.js +540 -0
- package/lib/features/webbuilder/workflow.js.map +1 -0
- package/lib/hooks/useChatApi.js +7 -2
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +1 -1
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/routes.json +106 -0
- package/lib/screens/WebBuilderNative/index.js +71 -0
- package/lib/screens/WebBuilderNative/index.js.map +1 -0
- package/lib/screens/WebBuilderNative/useCodeAssistantCatalog.js +45 -0
- package/lib/screens/WebBuilderNative/useCodeAssistantCatalog.js.map +1 -0
- package/lib/screens/WebBuilderNative/useWebBuilderGallery.js +125 -0
- package/lib/screens/WebBuilderNative/useWebBuilderGallery.js.map +1 -0
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js +408 -0
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -0
- package/lib/screens/WebBuilderNative/webbuilderTransport.js +88 -0
- package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {useMemo}from'react';import {useSettings}from'@adminide-stack/platform-client';import {ConfigurationTarget,ContributionSchemaId}from'common';import {settingsUriForOrg}from'../../utils/cdecodeUri.js';import {CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,APP_SETTINGS_AIEDITOR_KEY,templatesFromSettings,workflowDefaultsFromSettings,FALLBACK_TEMPLATES}from'../../features/webbuilder/workflow.js';function useCodeAssistantCatalog(orgName) {
|
|
2
|
+
const slug = orgName.trim();
|
|
3
|
+
const resourceUri = useMemo(() => slug ? settingsUriForOrg(slug) : void 0, [slug]);
|
|
4
|
+
const ui = useSettings({
|
|
5
|
+
resourceUri,
|
|
6
|
+
skip: !resourceUri,
|
|
7
|
+
options: {
|
|
8
|
+
schemaId: ContributionSchemaId.UiLayout,
|
|
9
|
+
configKey: CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,
|
|
10
|
+
includeMarketplace: true,
|
|
11
|
+
target: ConfigurationTarget.ORGANIZATION
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
const app = useSettings({
|
|
15
|
+
resourceUri,
|
|
16
|
+
skip: !resourceUri,
|
|
17
|
+
options: {
|
|
18
|
+
schemaId: ContributionSchemaId.Configuration,
|
|
19
|
+
configKey: APP_SETTINGS_AIEDITOR_KEY,
|
|
20
|
+
includeMarketplace: true,
|
|
21
|
+
target: ConfigurationTarget.ORGANIZATION
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const uiPayload = ui.settings;
|
|
25
|
+
const appPayload = app.settings;
|
|
26
|
+
const loading = Boolean(resourceUri) && (ui.loading || app.loading);
|
|
27
|
+
const loaded = Boolean(resourceUri) && !ui.loading && !app.loading;
|
|
28
|
+
const error = ui.error ? "Check your connection and try again." : null;
|
|
29
|
+
return useMemo(() => {
|
|
30
|
+
const remote = loaded ? templatesFromSettings(uiPayload, appPayload) : [];
|
|
31
|
+
return {
|
|
32
|
+
// The web falls back to its bundled starters only when the workspace has none.
|
|
33
|
+
templates: loaded && !error && remote.length === 0 ? FALLBACK_TEMPLATES : remote,
|
|
34
|
+
defaults: loaded ? workflowDefaultsFromSettings(uiPayload, appPayload) : null,
|
|
35
|
+
loading,
|
|
36
|
+
loaded,
|
|
37
|
+
error,
|
|
38
|
+
reload: () => {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
(_a = ui.observable) == null ? void 0 : _a.refetch().catch(() => void 0);
|
|
41
|
+
(_b = app.observable) == null ? void 0 : _b.refetch().catch(() => void 0);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}, [uiPayload, appPayload, loaded, loading, error]);
|
|
45
|
+
}export{useCodeAssistantCatalog};//# sourceMappingURL=useCodeAssistantCatalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCodeAssistantCatalog.js","sources":["../../../src/screens/WebBuilderNative/useCodeAssistantCatalog.ts"],"sourcesContent":["/**\n * The workspace's starter templates and its build workflow model - the web\n * surface's `listCodeAssistantTemplatesViaGraphql`, read from the backend the\n * app is signed in to (the same `pageSettings` Home's Build mode reads), so the\n * phone shows what the web shows for the workspace: in local development both\n * read the local backend, in production both read the plane's.\n */\nimport { useMemo } from 'react';\nimport { useSettings } from '@adminide-stack/platform-client';\nimport { ConfigurationTarget, ContributionSchemaId } from 'common';\nimport { settingsUriForOrg, type SettingsUriInput } from '../../utils/cdecodeUri';\nimport {\n APP_SETTINGS_AIEDITOR_KEY,\n CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,\n FALLBACK_TEMPLATES,\n templatesFromSettings,\n workflowDefaultsFromSettings,\n type WebBuilderTemplate,\n} from '../../features/webbuilder/workflow';\n\nexport interface CodeAssistantCatalog {\n templates: WebBuilderTemplate[];\n /** The org's workflow model (form extension, E2B template ids) for builds without a template. */\n defaults: WebBuilderTemplate | null;\n loading: boolean;\n loaded: boolean;\n error: string | null;\n reload: () => void;\n}\n\nexport function useCodeAssistantCatalog(orgName: string): CodeAssistantCatalog {\n const slug = orgName.trim();\n const resourceUri: SettingsUriInput | undefined = useMemo(\n () => (slug ? settingsUriForOrg(slug) : undefined),\n [slug],\n );\n const ui = useSettings({\n resourceUri: resourceUri as never,\n skip: !resourceUri,\n options: {\n schemaId: ContributionSchemaId.UiLayout,\n configKey: CODE_ASSISTANT_TEMPLATE_CONFIG_KEY,\n includeMarketplace: true,\n target: ConfigurationTarget.ORGANIZATION,\n },\n });\n const app = useSettings({\n resourceUri: resourceUri as never,\n skip: !resourceUri,\n options: {\n schemaId: ContributionSchemaId.Configuration,\n configKey: APP_SETTINGS_AIEDITOR_KEY,\n includeMarketplace: true,\n target: ConfigurationTarget.ORGANIZATION,\n },\n });\n\n // `settings` is the raw `pageSettings.settings` payload - what the web parses.\n const uiPayload = ui.settings;\n const appPayload = app.settings;\n const loading = Boolean(resourceUri) && (ui.loading || app.loading);\n const loaded = Boolean(resourceUri) && !ui.loading && !app.loading;\n const error = ui.error ? 'Check your connection and try again.' : null;\n\n return useMemo(() => {\n const remote = loaded ? templatesFromSettings(uiPayload, appPayload) : [];\n return {\n // The web falls back to its bundled starters only when the workspace has none.\n templates: loaded && !error && remote.length === 0 ? FALLBACK_TEMPLATES : remote,\n defaults: loaded ? workflowDefaultsFromSettings(uiPayload, appPayload) : null,\n loading,\n loaded,\n error,\n reload: () => {\n ui.observable?.refetch().catch(() => undefined);\n app.observable?.refetch().catch(() => undefined);\n },\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [uiPayload, appPayload, loaded, loading, error]);\n}\n"],"names":[],"mappings":"qYAqBO,SAAS,wBAAwB,OAAuC,EAAA;AAC7E,EAAM,MAAA,IAAA,GAAO,QAAQ,IAAK,EAAA;AAC1B,EAAM,MAAA,WAAA,GAA4C,OAAQ,CAAA,MAAM,IAAO,GAAA,iBAAA,CAAkB,IAAI,CAAI,GAAA,MAAA,EAAW,CAAC,IAAI,CAAC,CAAA;AAClH,EAAA,MAAM,KAAK,WAAY,CAAA;AAAA,IACrB,WAAA;AAAA,IACA,MAAM,CAAC,WAAA;AAAA,IACP,OAAS,EAAA;AAAA,MACP,UAAU,oBAAqB,CAAA,QAAA;AAAA,MAC/B,SAAW,EAAA,kCAAA;AAAA,MACX,kBAAoB,EAAA,IAAA;AAAA,MACpB,QAAQ,mBAAoB,CAAA;AAAA;AAC9B,GACD,CAAA;AACD,EAAA,MAAM,MAAM,WAAY,CAAA;AAAA,IACtB,WAAA;AAAA,IACA,MAAM,CAAC,WAAA;AAAA,IACP,OAAS,EAAA;AAAA,MACP,UAAU,oBAAqB,CAAA,aAAA;AAAA,MAC/B,SAAW,EAAA,yBAAA;AAAA,MACX,kBAAoB,EAAA,IAAA;AAAA,MACpB,QAAQ,mBAAoB,CAAA;AAAA;AAC9B,GACD,CAAA;AAGD,EAAA,MAAM,YAAY,EAAG,CAAA,QAAA;AACrB,EAAA,MAAM,aAAa,GAAI,CAAA,QAAA;AACvB,EAAA,MAAM,UAAU,OAAQ,CAAA,WAAW,CAAM,KAAA,EAAA,CAAG,WAAW,GAAI,CAAA,OAAA,CAAA;AAC3D,EAAM,MAAA,MAAA,GAAS,QAAQ,WAAW,CAAA,IAAK,CAAC,EAAG,CAAA,OAAA,IAAW,CAAC,GAAI,CAAA,OAAA;AAC3D,EAAM,MAAA,KAAA,GAAQ,EAAG,CAAA,KAAA,GAAQ,sCAAyC,GAAA,IAAA;AAClE,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,MAAM,SAAS,MAAS,GAAA,qBAAA,CAAsB,SAAW,EAAA,UAAU,IAAI,EAAC;AACxE,IAAO,OAAA;AAAA;AAAA,MAEL,WAAW,MAAU,IAAA,CAAC,SAAS,MAAO,CAAA,MAAA,KAAW,IAAI,kBAAqB,GAAA,MAAA;AAAA,MAC1E,QAAU,EAAA,MAAA,GAAS,4BAA6B,CAAA,SAAA,EAAW,UAAU,CAAI,GAAA,IAAA;AAAA,MACzE,OAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAQ,MAAM;AA5DpB,QAAA,IAAA,EAAA,EAAA,EAAA;AA6DQ,QAAA,CAAA,EAAA,GAAA,EAAA,CAAG,UAAH,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAe,OAAU,EAAA,CAAA,KAAA,CAAM,MAAM,MAAA,CAAA;AACrC,QAAA,CAAA,EAAA,GAAA,GAAA,CAAI,UAAJ,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgB,OAAU,EAAA,CAAA,KAAA,CAAM,MAAM,MAAA,CAAA;AAAA;AACxC,KACF;AAAA,KAEC,CAAC,SAAA,EAAW,YAAY,MAAQ,EAAA,OAAA,EAAS,KAAK,CAAC,CAAA;AACpD"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {useState,useRef,useCallback,useEffect}from'react';import {useApolloClient}from'@apollo/client/index.js';import {MessagesDocument,GetChannelsByUserWithLastMessageDocument}from'common/graphql';import {getThreadMessagesQueryVariables,getHistoryChannelsQueryVariables}from'../../hooks/useChatApi.js';import {lastMessageHasCover,projectFromPosts}from'../../features/webbuilder/buildFragments.js';const GALLERY_PAGE_SIZE = 10;
|
|
2
|
+
const MIN_FILL = 6;
|
|
3
|
+
const MAX_PAGES_PER_LOAD = 4;
|
|
4
|
+
function useWebBuilderGallery(orgName, cdnOrigin) {
|
|
5
|
+
const client = useApolloClient();
|
|
6
|
+
const [projects, setProjects] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(false);
|
|
8
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
9
|
+
const [hasMore, setHasMore] = useState(false);
|
|
10
|
+
const [error, setError] = useState(null);
|
|
11
|
+
const skipRef = useRef(0);
|
|
12
|
+
const busyRef = useRef(false);
|
|
13
|
+
const runRef = useRef(0);
|
|
14
|
+
const projectFor = useCallback(async (channel) => {
|
|
15
|
+
var _a, _b, _c, _d;
|
|
16
|
+
const id = (_a = channel.id) != null ? _a : "";
|
|
17
|
+
if (!id) return null;
|
|
18
|
+
if (lastMessageHasCover(channel)) {
|
|
19
|
+
const fromLast = projectFromPosts(channel, [channel.lastMessage], cdnOrigin);
|
|
20
|
+
if (fromLast) return fromLast;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const result = await client.query({
|
|
24
|
+
query: MessagesDocument,
|
|
25
|
+
variables: getThreadMessagesQueryVariables(id),
|
|
26
|
+
fetchPolicy: "network-only",
|
|
27
|
+
errorPolicy: "all",
|
|
28
|
+
context: {
|
|
29
|
+
cacheKey: `messages-list:${id}`
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const posts = (_d = (_c = (_b = result.data) == null ? void 0 : _b.messages) == null ? void 0 : _c.data) != null ? _d : [];
|
|
33
|
+
const withLast = channel.lastMessage ? [...posts, channel.lastMessage] : posts;
|
|
34
|
+
return projectFromPosts(channel, withLast, cdnOrigin);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.warn("[WebBuilderNative] could not read builds of", id, err);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}, [client, cdnOrigin]);
|
|
40
|
+
const load = useCallback(async (mode) => {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
if (!orgName || busyRef.current) return;
|
|
43
|
+
busyRef.current = true;
|
|
44
|
+
const run = runRef.current + 1;
|
|
45
|
+
runRef.current = run;
|
|
46
|
+
if (mode === "reset") {
|
|
47
|
+
skipRef.current = 0;
|
|
48
|
+
setLoading(true);
|
|
49
|
+
} else {
|
|
50
|
+
setLoadingMore(true);
|
|
51
|
+
}
|
|
52
|
+
setError(null);
|
|
53
|
+
const found = [];
|
|
54
|
+
let more = false;
|
|
55
|
+
try {
|
|
56
|
+
for (let page = 0; page < MAX_PAGES_PER_LOAD; page += 1) {
|
|
57
|
+
const result = await client.query({
|
|
58
|
+
query: GetChannelsByUserWithLastMessageDocument,
|
|
59
|
+
variables: getHistoryChannelsQueryVariables(orgName, {
|
|
60
|
+
limit: GALLERY_PAGE_SIZE,
|
|
61
|
+
skip: skipRef.current
|
|
62
|
+
}),
|
|
63
|
+
// cache-first served a stale first page on the web; always ask.
|
|
64
|
+
fetchPolicy: "network-only",
|
|
65
|
+
context: {
|
|
66
|
+
cacheKey: "webbuilder-gallery"
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
const channels = ((_b = (_a = result.data) == null ? void 0 : _a.channelsByUser) != null ? _b : []).filter((c) => c == null ? void 0 : c.id);
|
|
70
|
+
skipRef.current += channels.length;
|
|
71
|
+
more = channels.length >= GALLERY_PAGE_SIZE;
|
|
72
|
+
const rows = await Promise.all(channels.map((channel) => projectFor(channel)));
|
|
73
|
+
found.push(...rows.filter((row) => row !== null));
|
|
74
|
+
if (!more || found.length >= MIN_FILL) break;
|
|
75
|
+
}
|
|
76
|
+
if (runRef.current !== run) return;
|
|
77
|
+
setProjects((prev) => {
|
|
78
|
+
const base = mode === "reset" ? [] : prev;
|
|
79
|
+
const byId = new Map(base.map((p) => [p.channelId, p]));
|
|
80
|
+
for (const row of found) byId.set(row.channelId, row);
|
|
81
|
+
return [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
82
|
+
});
|
|
83
|
+
setHasMore(more);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.warn("[WebBuilderNative] could not load builds:", err);
|
|
86
|
+
if (runRef.current === run) setError("Check your connection and try again.");
|
|
87
|
+
} finally {
|
|
88
|
+
busyRef.current = false;
|
|
89
|
+
if (runRef.current === run) {
|
|
90
|
+
setLoading(false);
|
|
91
|
+
setLoadingMore(false);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}, [client, orgName, projectFor]);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
void load("reset");
|
|
97
|
+
}, [load]);
|
|
98
|
+
const refresh = useCallback(() => {
|
|
99
|
+
busyRef.current = false;
|
|
100
|
+
void load("reset");
|
|
101
|
+
}, [load]);
|
|
102
|
+
const loadMore = useCallback(() => {
|
|
103
|
+
if (hasMore) void load("more");
|
|
104
|
+
}, [hasMore, load]);
|
|
105
|
+
const upsert = useCallback((project) => {
|
|
106
|
+
setProjects((prev) => {
|
|
107
|
+
const existing = prev.find((p) => p.channelId === project.channelId);
|
|
108
|
+
if (existing && existing.title === project.title && existing.coverUrl === project.coverUrl && existing.liveUrl === project.liveUrl && existing.updatedAt === project.updatedAt) {
|
|
109
|
+
return prev;
|
|
110
|
+
}
|
|
111
|
+
const rest = prev.filter((p) => p.channelId !== project.channelId);
|
|
112
|
+
return [project, ...rest].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
113
|
+
});
|
|
114
|
+
}, []);
|
|
115
|
+
return {
|
|
116
|
+
projects,
|
|
117
|
+
loading,
|
|
118
|
+
loadingMore,
|
|
119
|
+
hasMore,
|
|
120
|
+
error,
|
|
121
|
+
refresh,
|
|
122
|
+
loadMore,
|
|
123
|
+
upsert
|
|
124
|
+
};
|
|
125
|
+
}export{GALLERY_PAGE_SIZE,useWebBuilderGallery};//# sourceMappingURL=useWebBuilderGallery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWebBuilderGallery.js","sources":["../../../src/screens/WebBuilderNative/useWebBuilderGallery.ts"],"sourcesContent":["/**\n * \"Recent builds\" - the web surface's gallery hydrate, on the host.\n *\n * Same steps as the web (`realServices` gallery load): page the person's AI\n * assistant chats 10 at a time, newest first; for each, read its posts (unless\n * the last post already carries the build's screenshot) and keep the chat only\n * if it holds a build. A chat that never built anything is not a site, which\n * is why history's \"build\" label alone is not used.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useApolloClient } from '@apollo/client';\nimport { GetChannelsByUserWithLastMessageDocument, MessagesDocument } from 'common/graphql';\nimport { getHistoryChannelsQueryVariables, getThreadMessagesQueryVariables } from '../../hooks/useChatApi';\nimport { lastMessageHasCover, projectFromPosts, type ChannelLike } from '../../features/webbuilder/buildFragments';\nimport type { WebBuilderProject } from '../../features/webbuilder/types';\n\n/** The web gallery's page size (`GALLERY_PAGE_SIZE`). */\nexport const GALLERY_PAGE_SIZE = 10;\n/** Keep paging (up to this many pages per call) while a page yields too few builds to fill the screen. */\nconst MIN_FILL = 6;\nconst MAX_PAGES_PER_LOAD = 4;\n\ntype Loose = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any\n\nexport interface WebBuilderGallery {\n projects: WebBuilderProject[];\n loading: boolean;\n loadingMore: boolean;\n hasMore: boolean;\n error: string | null;\n refresh: () => void;\n loadMore: () => void;\n /** Put (or update) one site - the open one, as its posts change. */\n upsert: (project: WebBuilderProject) => void;\n}\n\nexport function useWebBuilderGallery(orgName: string, cdnOrigin: string): WebBuilderGallery {\n const client = useApolloClient();\n const [projects, setProjects] = useState<WebBuilderProject[]>([]);\n const [loading, setLoading] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const skipRef = useRef(0);\n const busyRef = useRef(false);\n const runRef = useRef(0);\n\n const projectFor = useCallback(\n async (channel: ChannelLike): Promise<WebBuilderProject | null> => {\n const id = channel.id ?? '';\n if (!id) return null;\n // The web skips the thread read only when the last post already has a cover.\n if (lastMessageHasCover(channel)) {\n const fromLast = projectFromPosts(channel, [channel.lastMessage], cdnOrigin);\n if (fromLast) return fromLast;\n }\n try {\n const result = await client.query({\n query: MessagesDocument,\n variables: getThreadMessagesQueryVariables(id),\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n context: { cacheKey: `messages-list:${id}` },\n });\n const posts = ((result.data as Loose)?.messages?.data ?? []) as unknown[];\n const withLast = channel.lastMessage ? [...posts, channel.lastMessage] : posts;\n return projectFromPosts(channel, withLast, cdnOrigin);\n } catch (err) {\n console.warn('[WebBuilderNative] could not read builds of', id, err);\n return null;\n }\n },\n [client, cdnOrigin],\n );\n\n const load = useCallback(\n async (mode: 'reset' | 'more') => {\n if (!orgName || busyRef.current) return;\n busyRef.current = true;\n const run = runRef.current + 1;\n runRef.current = run;\n if (mode === 'reset') {\n skipRef.current = 0;\n setLoading(true);\n } else {\n setLoadingMore(true);\n }\n setError(null);\n const found: WebBuilderProject[] = [];\n let more = false;\n try {\n for (let page = 0; page < MAX_PAGES_PER_LOAD; page += 1) {\n // eslint-disable-next-line no-await-in-loop -- pages are sequential by design\n const result = await client.query({\n query: GetChannelsByUserWithLastMessageDocument,\n variables: getHistoryChannelsQueryVariables(orgName, {\n limit: GALLERY_PAGE_SIZE,\n skip: skipRef.current,\n }),\n // cache-first served a stale first page on the web; always ask.\n fetchPolicy: 'network-only',\n context: { cacheKey: 'webbuilder-gallery' },\n });\n const channels = (((result.data as Loose)?.channelsByUser ?? []) as ChannelLike[]).filter(\n (c) => c?.id,\n );\n skipRef.current += channels.length;\n more = channels.length >= GALLERY_PAGE_SIZE;\n // eslint-disable-next-line no-await-in-loop\n const rows = await Promise.all(channels.map((channel) => projectFor(channel)));\n found.push(...rows.filter((row): row is WebBuilderProject => row !== null));\n if (!more || found.length >= MIN_FILL) break;\n }\n if (runRef.current !== run) return;\n setProjects((prev) => {\n const base = mode === 'reset' ? [] : prev;\n const byId = new Map(base.map((p) => [p.channelId, p]));\n for (const row of found) byId.set(row.channelId, row);\n return [...byId.values()].sort((a, b) => b.updatedAt - a.updatedAt);\n });\n setHasMore(more);\n } catch (err) {\n console.warn('[WebBuilderNative] could not load builds:', err);\n if (runRef.current === run) setError('Check your connection and try again.');\n } finally {\n busyRef.current = false;\n if (runRef.current === run) {\n setLoading(false);\n setLoadingMore(false);\n }\n }\n },\n [client, orgName, projectFor],\n );\n\n useEffect(() => {\n void load('reset');\n }, [load]);\n\n const refresh = useCallback(() => {\n busyRef.current = false;\n void load('reset');\n }, [load]);\n const loadMore = useCallback(() => {\n if (hasMore) void load('more');\n }, [hasMore, load]);\n\n const upsert = useCallback((project: WebBuilderProject) => {\n setProjects((prev) => {\n const existing = prev.find((p) => p.channelId === project.channelId);\n if (\n existing &&\n existing.title === project.title &&\n existing.coverUrl === project.coverUrl &&\n existing.liveUrl === project.liveUrl &&\n existing.updatedAt === project.updatedAt\n ) {\n return prev;\n }\n const rest = prev.filter((p) => p.channelId !== project.channelId);\n return [project, ...rest].sort((a, b) => b.updatedAt - a.updatedAt);\n });\n }, []);\n\n return { projects, loading, loadingMore, hasMore, error, refresh, loadMore, upsert };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import {useRef,useState,useMemo,useEffect,useCallback}from'react';import {useAiCodeDeployToCloudflareMutation}from'common/graphql';import {v4}from'uuid';import {useCdecliConnection}from'../../contexts/CdecliConnectionContext.js';import {useChatStream}from'../../hooks/useChatStream.js';import {useHostChatChannel}from'../../hooks/useHostChatChannel.js';import {config}from'../../config/env-config.js';import {useChatMessages}from'../../hooks/useChatApi.js';import {usePrerequisiteIds}from'../../hooks/usePrerequisiteIds.js';import {useCanvasSession}from'../../features/canvas/useCanvasSession.js';import {tokenClaims}from'../../features/canvas/sessionIdentity.js';import {buildsFromPosts,hasWorkflowPosts,projectFromPosts,turnState,pendingWork,transcriptFromPosts,stripAgentNote}from'../../features/webbuilder/buildFragments.js';import {WEBBUILDER_CHAT_SKILL,buildTriggerParams,templateRemixNote,newObjectId}from'../../features/webbuilder/workflow.js';import {useWebBuilderGallery}from'./useWebBuilderGallery.js';import {useCodeAssistantCatalog}from'./useCodeAssistantCatalog.js';import {uploadAttachment,triggerBuild,resumeSandbox}from'./webbuilderTransport.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
const POLL_MS = 2500;
|
|
21
|
+
const TURN_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
22
|
+
function notSetUp(org) {
|
|
23
|
+
return `Builds are not set up for ${org || "this workspace"} yet. Ask an admin to configure the Code Assistant templates.`;
|
|
24
|
+
}
|
|
25
|
+
function failureText(error) {
|
|
26
|
+
if (/\b401\b|unauthori[sz]ed/i.test(error)) return "Your sign-in was not accepted. Try again in a moment.";
|
|
27
|
+
if (/network|fetch|timed out/i.test(error)) return "Couldn't reach the build service. Check your connection and try again.";
|
|
28
|
+
return "The build didn't start. Try again.";
|
|
29
|
+
}
|
|
30
|
+
function useWebBuilderHost(routeOrg) {
|
|
31
|
+
var _a, _b, _c;
|
|
32
|
+
const {
|
|
33
|
+
orgName,
|
|
34
|
+
projectId: appProjectId
|
|
35
|
+
} = usePrerequisiteIds();
|
|
36
|
+
const session = useCanvasSession();
|
|
37
|
+
const {
|
|
38
|
+
token,
|
|
39
|
+
indexUrl,
|
|
40
|
+
graphqlUrl
|
|
41
|
+
} = session;
|
|
42
|
+
const sessionOrg = String((_a = tokenClaims(token).orgName) != null ? _a : "");
|
|
43
|
+
const effectiveOrg = routeOrg || orgName || sessionOrg || "";
|
|
44
|
+
const tokenRef = useRef(token);
|
|
45
|
+
tokenRef.current = token;
|
|
46
|
+
const catalog = useCodeAssistantCatalog(effectiveOrg);
|
|
47
|
+
const reloadTemplates = catalog.reload;
|
|
48
|
+
const cdnOrigin = config.AWS_CDN_URL;
|
|
49
|
+
const gallery = useWebBuilderGallery(effectiveOrg, cdnOrigin);
|
|
50
|
+
const {
|
|
51
|
+
projects,
|
|
52
|
+
refresh: refreshProjects,
|
|
53
|
+
upsert: upsertProject
|
|
54
|
+
} = gallery;
|
|
55
|
+
const [activeChannelId, setActiveChannelId] = useState(null);
|
|
56
|
+
const projectIds = useRef(/* @__PURE__ */ new Map());
|
|
57
|
+
const {
|
|
58
|
+
posts: rawPosts,
|
|
59
|
+
refetch
|
|
60
|
+
} = useChatMessages(activeChannelId);
|
|
61
|
+
const posts = useMemo(() => activeChannelId ? rawPosts : [], [activeChannelId, rawPosts]);
|
|
62
|
+
const activeProject = projects.find((p) => p.channelId === activeChannelId);
|
|
63
|
+
const postBuilds = useMemo(() => buildsFromPosts(posts, activeProject == null ? void 0 : activeProject.title, cdnOrigin), [posts, activeProject == null ? void 0 : activeProject.title, cdnOrigin]);
|
|
64
|
+
const cdecli = useCdecliConnection();
|
|
65
|
+
const {
|
|
66
|
+
setActiveChannelId: setCdecliChannel
|
|
67
|
+
} = cdecli;
|
|
68
|
+
const [agentChannelId, setAgentChannelId] = useState(() => v4());
|
|
69
|
+
const agentChannels = useRef(/* @__PURE__ */ new Set());
|
|
70
|
+
const unsavedAgentChannels = useRef(/* @__PURE__ */ new Set());
|
|
71
|
+
const pendingAgentTurn = useRef(null);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
setCdecliChannel(agentChannelId);
|
|
74
|
+
return void 0;
|
|
75
|
+
}, [agentChannelId, setCdecliChannel]);
|
|
76
|
+
const {
|
|
77
|
+
ensureChannel
|
|
78
|
+
} = useHostChatChannel({
|
|
79
|
+
channelId: agentChannelId,
|
|
80
|
+
orgName: effectiveOrg,
|
|
81
|
+
projectId: appProjectId != null ? appProjectId : "",
|
|
82
|
+
label: "WebBuilderNative"
|
|
83
|
+
});
|
|
84
|
+
const chatRouting = useMemo(() => {
|
|
85
|
+
var _a2;
|
|
86
|
+
return {
|
|
87
|
+
channelConnected: cdecli.channelConnected,
|
|
88
|
+
accountId: cdecli.accountId,
|
|
89
|
+
persistenceMode: (_a2 = cdecli.persistenceMode) != null ? _a2 : "backend",
|
|
90
|
+
recoverAgentAuth: cdecli.recoverAgentAuth,
|
|
91
|
+
skill: WEBBUILDER_CHAT_SKILL
|
|
92
|
+
};
|
|
93
|
+
}, [cdecli.channelConnected, cdecli.accountId, cdecli.persistenceMode, cdecli.recoverAgentAuth]);
|
|
94
|
+
const chat = useChatStream(agentChannelId, chatRouting);
|
|
95
|
+
const agentLane = activeChannelId !== null && (agentChannels.current.has(activeChannelId) || posts.length > 0 && !hasWorkflowPosts(posts));
|
|
96
|
+
const agentBusy = agentLane && (chat.isLoading || chat.isStreaming);
|
|
97
|
+
const sendAgentTurn = useCallback((channelId, text, files) => {
|
|
98
|
+
const ready = unsavedAgentChannels.current.has(channelId) ? ensureChannel() : Promise.resolve();
|
|
99
|
+
ready.then(() => {
|
|
100
|
+
unsavedAgentChannels.current.delete(channelId);
|
|
101
|
+
return chat.sendMessage(text, files, channelId);
|
|
102
|
+
}).catch(() => void 0);
|
|
103
|
+
}, [chat, ensureChannel]);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
const pending = pendingAgentTurn.current;
|
|
106
|
+
if (!pending || pending.channelId !== agentChannelId) return;
|
|
107
|
+
pendingAgentTurn.current = null;
|
|
108
|
+
sendAgentTurn(pending.channelId, pending.text, pending.files);
|
|
109
|
+
}, [agentChannelId, sendAgentTurn]);
|
|
110
|
+
const wasAgentBusy = useRef(false);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (wasAgentBusy.current && !agentBusy) refetch().catch(() => void 0);
|
|
113
|
+
wasAgentBusy.current = agentBusy;
|
|
114
|
+
}, [agentBusy, refetch]);
|
|
115
|
+
const builds = useMemo(() => {
|
|
116
|
+
if (postBuilds.length || !agentLane) return postBuilds;
|
|
117
|
+
const now = Date.now();
|
|
118
|
+
return buildsFromPosts(chat.messages.map((m, index) => ({
|
|
119
|
+
id: `live-${index}`,
|
|
120
|
+
message: m.content,
|
|
121
|
+
props: {
|
|
122
|
+
role: m.role === "user" ? "USER" : "ASSISTANT"
|
|
123
|
+
},
|
|
124
|
+
createdAt: new Date(now + index).toISOString()
|
|
125
|
+
})), activeProject == null ? void 0 : activeProject.title, cdnOrigin);
|
|
126
|
+
}, [postBuilds, agentLane, chat.messages, activeProject == null ? void 0 : activeProject.title, cdnOrigin]);
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!activeChannelId || posts.length === 0) return;
|
|
129
|
+
const row = projectFromPosts({
|
|
130
|
+
id: activeChannelId,
|
|
131
|
+
title: activeProject == null ? void 0 : activeProject.title
|
|
132
|
+
}, posts, cdnOrigin);
|
|
133
|
+
if (row) upsertProject(row);
|
|
134
|
+
}, [activeChannelId, posts, cdnOrigin, upsertProject, activeProject == null ? void 0 : activeProject.title]);
|
|
135
|
+
const [turn, setTurn] = useState(null);
|
|
136
|
+
const [turnError, setTurnError] = useState(null);
|
|
137
|
+
const state = useMemo(() => turn && turn.channelId === activeChannelId ? turnState(posts, turn.startedAt) : null, [turn, activeChannelId, posts]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (!turn || !state) return;
|
|
140
|
+
if (state.status === "done") setTurn(null);
|
|
141
|
+
if (state.status === "failed") {
|
|
142
|
+
setTurn(null);
|
|
143
|
+
setTurnError(state.error);
|
|
144
|
+
}
|
|
145
|
+
}, [turn, state]);
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (!turn) return void 0;
|
|
148
|
+
const timer = setInterval(() => {
|
|
149
|
+
if (Date.now() - turn.startedAt > TURN_TIMEOUT_MS) {
|
|
150
|
+
setTurn(null);
|
|
151
|
+
setTurnError("The build is taking too long. It may still finish; reopen the site later to check.");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
refetch().catch(() => void 0);
|
|
155
|
+
}, POLL_MS);
|
|
156
|
+
return () => clearInterval(timer);
|
|
157
|
+
}, [turn, refetch]);
|
|
158
|
+
const runTurn = useCallback(async (opts) => {
|
|
159
|
+
var _a2, _b2, _c2, _d;
|
|
160
|
+
const {
|
|
161
|
+
current
|
|
162
|
+
} = tokenRef;
|
|
163
|
+
if (!current || !indexUrl) return "Web Builder is still signing in. Try again in a moment.";
|
|
164
|
+
let mode = "new";
|
|
165
|
+
if (opts.edit) mode = "edit";
|
|
166
|
+
else if ((_a2 = opts.template) == null ? void 0 : _a2.snapshotId) mode = "remix";
|
|
167
|
+
const uploaded = (await Promise.all(((_b2 = opts.attachments) != null ? _b2 : []).map((file) => uploadAttachment(current, indexUrl, {
|
|
168
|
+
name: file.name,
|
|
169
|
+
url: file.url,
|
|
170
|
+
dataUrl: file.dataUrl,
|
|
171
|
+
mimeType: file.mimeType
|
|
172
|
+
})))).filter((f) => f !== null);
|
|
173
|
+
const built = buildTriggerParams(__spreadProps(__spreadValues(__spreadValues(__spreadValues({
|
|
174
|
+
channelId: opts.channelId,
|
|
175
|
+
projectId: opts.projectId,
|
|
176
|
+
text: opts.text,
|
|
177
|
+
template: (_c2 = opts.template) != null ? _c2 : void 0,
|
|
178
|
+
defaults: catalog.defaults,
|
|
179
|
+
mode
|
|
180
|
+
}, opts.edit ? {
|
|
181
|
+
edit: {
|
|
182
|
+
sandboxId: opts.edit.sandboxId,
|
|
183
|
+
sandboxUrl: opts.edit.previewUrl,
|
|
184
|
+
title: opts.edit.title
|
|
185
|
+
},
|
|
186
|
+
// An edit keeps the build's stack (web `lastSandbox.templateId`).
|
|
187
|
+
stackHint: opts.edit.templateId
|
|
188
|
+
} : {}), opts.referenceUrl ? {
|
|
189
|
+
referenceUrl: opts.referenceUrl
|
|
190
|
+
} : {}), uploaded.length ? {
|
|
191
|
+
attachments: uploaded
|
|
192
|
+
} : {}), {
|
|
193
|
+
graphqlUrl,
|
|
194
|
+
token: current
|
|
195
|
+
}));
|
|
196
|
+
if (!built.ok) return notSetUp(effectiveOrg);
|
|
197
|
+
setTurnError(null);
|
|
198
|
+
setTurn({
|
|
199
|
+
channelId: opts.channelId,
|
|
200
|
+
text: opts.text,
|
|
201
|
+
startedAt: Date.now(),
|
|
202
|
+
mode
|
|
203
|
+
});
|
|
204
|
+
const outcome = await triggerBuild(current, indexUrl, built.params);
|
|
205
|
+
if (!outcome.ok) {
|
|
206
|
+
const reason = (_d = outcome.error) != null ? _d : "";
|
|
207
|
+
console.warn("[WebBuilderNative] trigger failed:", reason);
|
|
208
|
+
if (outcome.auth) session.retry();
|
|
209
|
+
setTurn(null);
|
|
210
|
+
setTurnError(failureText(reason));
|
|
211
|
+
return failureText(reason);
|
|
212
|
+
}
|
|
213
|
+
refetch().catch(() => void 0);
|
|
214
|
+
return null;
|
|
215
|
+
}, [indexUrl, graphqlUrl, catalog.defaults, effectiveOrg, refetch, session]);
|
|
216
|
+
const [startError, setStartError] = useState(null);
|
|
217
|
+
const startProject = useCallback((request) => {
|
|
218
|
+
var _a2;
|
|
219
|
+
setStartError(null);
|
|
220
|
+
const workflowReady = Boolean((_a2 = catalog.defaults) == null ? void 0 : _a2.formExtensionId);
|
|
221
|
+
if (request.template || request.agent || !workflowReady) {
|
|
222
|
+
const id = v4();
|
|
223
|
+
agentChannels.current.add(id);
|
|
224
|
+
unsavedAgentChannels.current.add(id);
|
|
225
|
+
pendingAgentTurn.current = {
|
|
226
|
+
channelId: id,
|
|
227
|
+
text: request.template ? `${request.text}
|
|
228
|
+
|
|
229
|
+
${templateRemixNote(request.template)}` : request.text,
|
|
230
|
+
files: request.attachments
|
|
231
|
+
};
|
|
232
|
+
setTurnError(null);
|
|
233
|
+
setActiveChannelId(id);
|
|
234
|
+
setAgentChannelId(id);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const channelId = newObjectId();
|
|
238
|
+
const projectId = newObjectId();
|
|
239
|
+
projectIds.current.set(channelId, projectId);
|
|
240
|
+
setStartError(null);
|
|
241
|
+
setActiveChannelId(channelId);
|
|
242
|
+
runTurn({
|
|
243
|
+
channelId,
|
|
244
|
+
projectId,
|
|
245
|
+
text: request.text,
|
|
246
|
+
template: request.template,
|
|
247
|
+
edit: null,
|
|
248
|
+
referenceUrl: request.referenceUrl,
|
|
249
|
+
attachments: request.attachments
|
|
250
|
+
}).then((error) => {
|
|
251
|
+
if (error && /not set up|signing in/i.test(error)) {
|
|
252
|
+
setActiveChannelId(null);
|
|
253
|
+
setStartError(error);
|
|
254
|
+
}
|
|
255
|
+
}).catch(() => void 0);
|
|
256
|
+
}, [runTurn, catalog.defaults]);
|
|
257
|
+
const openProject = useCallback((channelId) => {
|
|
258
|
+
setTurnError(null);
|
|
259
|
+
setActiveChannelId(channelId);
|
|
260
|
+
setAgentChannelId(channelId);
|
|
261
|
+
}, []);
|
|
262
|
+
const closeProject = useCallback(() => setActiveChannelId(null), []);
|
|
263
|
+
const work = useMemo(() => pendingWork(posts), [posts]);
|
|
264
|
+
const running = Boolean(turn && turn.channelId === activeChannelId);
|
|
265
|
+
const startedAt = (_b = turn == null ? void 0 : turn.startedAt) != null ? _b : 0;
|
|
266
|
+
const progress = (_c = state == null ? void 0 : state.progress) != null ? _c : null;
|
|
267
|
+
const building = useMemo(() => {
|
|
268
|
+
if (agentBusy) return {
|
|
269
|
+
statusText: "Building with the agent\u2026",
|
|
270
|
+
startedAt: startedAt || Date.now()
|
|
271
|
+
};
|
|
272
|
+
if (!running && work !== "creating") return null;
|
|
273
|
+
let fallback = "Starting your build\u2026";
|
|
274
|
+
if ((turn == null ? void 0 : turn.mode) === "edit") fallback = "Updating your app\u2026";
|
|
275
|
+
if (work === "creating") fallback = "Starting the preview\u2026";
|
|
276
|
+
return {
|
|
277
|
+
statusText: progress || fallback,
|
|
278
|
+
startedAt: startedAt || Date.now()
|
|
279
|
+
};
|
|
280
|
+
}, [agentBusy, running, work, turn == null ? void 0 : turn.mode, progress, startedAt]);
|
|
281
|
+
const messages = useMemo(() => {
|
|
282
|
+
const rows = transcriptFromPosts(posts).map((m) => ({
|
|
283
|
+
id: m.id,
|
|
284
|
+
role: m.role,
|
|
285
|
+
content: m.content
|
|
286
|
+
}));
|
|
287
|
+
const pending = running && (turn == null ? void 0 : turn.text) ? turn.text.replace(/^build\s*me\s*:\s*/i, "") : "";
|
|
288
|
+
if (pending && !rows.some((m) => m.role === "user" && pending.startsWith(m.content))) {
|
|
289
|
+
rows.push({
|
|
290
|
+
id: `pending-${turn == null ? void 0 : turn.startedAt}`,
|
|
291
|
+
role: "user",
|
|
292
|
+
content: pending
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return rows;
|
|
296
|
+
}, [posts, running, turn]);
|
|
297
|
+
const send = useCallback((text, attachments, target) => {
|
|
298
|
+
var _a2;
|
|
299
|
+
const channelId = activeChannelId;
|
|
300
|
+
if (!channelId) return;
|
|
301
|
+
if (agentLane) {
|
|
302
|
+
sendAgentTurn(channelId, text, attachments);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const projectId = projectIds.current.get(channelId) || (target == null ? void 0 : target.projectId) || ((_a2 = builds[0]) == null ? void 0 : _a2.projectId) || newObjectId();
|
|
306
|
+
projectIds.current.set(channelId, projectId);
|
|
307
|
+
runTurn({
|
|
308
|
+
channelId,
|
|
309
|
+
projectId,
|
|
310
|
+
text,
|
|
311
|
+
template: null,
|
|
312
|
+
edit: target != null ? target : null,
|
|
313
|
+
attachments
|
|
314
|
+
}).catch(() => void 0);
|
|
315
|
+
}, [activeChannelId, agentLane, builds, runTurn, sendAgentTurn]);
|
|
316
|
+
const agentMessages = useMemo(() => chat.messages.map((m, index) => ({
|
|
317
|
+
id: `${m.role}-${index}`,
|
|
318
|
+
role: m.role,
|
|
319
|
+
// The template note is for the agent; the person sees what they typed.
|
|
320
|
+
content: m.role === "user" ? stripAgentNote(m.content).replace(/^build\s*me\s*:\s*/i, "") : m.content,
|
|
321
|
+
attachments: m.attachments
|
|
322
|
+
})), [chat.messages]);
|
|
323
|
+
const hostChat = useMemo(() => agentLane ? {
|
|
324
|
+
messages: agentMessages,
|
|
325
|
+
streaming: chat.response || null,
|
|
326
|
+
busy: agentBusy,
|
|
327
|
+
error: chat.error,
|
|
328
|
+
connected: cdecli.channelConnected,
|
|
329
|
+
send
|
|
330
|
+
} : {
|
|
331
|
+
messages,
|
|
332
|
+
streaming: running ? progress || (building == null ? void 0 : building.statusText) || "Working on it\u2026" : null,
|
|
333
|
+
busy: running,
|
|
334
|
+
error: turnError || (session.ready ? session.error : null),
|
|
335
|
+
connected: Boolean(token),
|
|
336
|
+
send
|
|
337
|
+
}, [agentLane, agentMessages, chat.response, agentBusy, chat.error, cdecli.channelConnected, messages, running, progress, building == null ? void 0 : building.statusText, turnError, session.ready, session.error, token, send]);
|
|
338
|
+
const resumePreview = useCallback(async (build) => {
|
|
339
|
+
const {
|
|
340
|
+
current
|
|
341
|
+
} = tokenRef;
|
|
342
|
+
if (!current || !indexUrl || !build.sandboxId) return "failed";
|
|
343
|
+
return resumeSandbox(current, indexUrl, build.sandboxId);
|
|
344
|
+
}, [indexUrl]);
|
|
345
|
+
const [deployToCloudflare] = useAiCodeDeployToCloudflareMutation({});
|
|
346
|
+
const publish = useCallback(async (build, projectName) => {
|
|
347
|
+
var _a2;
|
|
348
|
+
if (!build.sandboxId || !activeChannelId) {
|
|
349
|
+
return {
|
|
350
|
+
ok: false,
|
|
351
|
+
message: "There is nothing to publish yet."
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
const result = await deployToCloudflare({
|
|
356
|
+
variables: {
|
|
357
|
+
sandboxId: build.sandboxId,
|
|
358
|
+
projectName,
|
|
359
|
+
channelId: activeChannelId
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
const payload = (_a2 = result.data) == null ? void 0 : _a2.aiCodeDeployToCloudflare;
|
|
363
|
+
if (payload == null ? void 0 : payload.success) return {
|
|
364
|
+
ok: true
|
|
365
|
+
};
|
|
366
|
+
console.warn("[WebBuilderNative] publish refused:", payload == null ? void 0 : payload.message);
|
|
367
|
+
return {
|
|
368
|
+
ok: false,
|
|
369
|
+
message: "Publishing didn't start. Try again in a moment."
|
|
370
|
+
};
|
|
371
|
+
} catch (err) {
|
|
372
|
+
console.warn("[WebBuilderNative] publish failed:", err);
|
|
373
|
+
return {
|
|
374
|
+
ok: false,
|
|
375
|
+
message: "Publishing didn't start. Check your connection and try again."
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}, [deployToCloudflare, activeChannelId]);
|
|
379
|
+
let startBlocked = null;
|
|
380
|
+
if (!token && !cdecli.channelConnected) {
|
|
381
|
+
startBlocked = session.ready && session.error ? session.error : "Connecting to Web Builder\u2026";
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
projects,
|
|
385
|
+
projectsLoading: gallery.loading,
|
|
386
|
+
projectsError: gallery.error,
|
|
387
|
+
projectsHasMore: gallery.hasMore,
|
|
388
|
+
refreshProjects,
|
|
389
|
+
loadMoreProjects: gallery.loadMore,
|
|
390
|
+
templates: catalog.templates,
|
|
391
|
+
templatesLoading: catalog.loading,
|
|
392
|
+
templatesError: catalog.error,
|
|
393
|
+
reloadTemplates,
|
|
394
|
+
startBlocked,
|
|
395
|
+
startNotice: startError,
|
|
396
|
+
activeChannelId,
|
|
397
|
+
openProject,
|
|
398
|
+
closeProject,
|
|
399
|
+
startProject,
|
|
400
|
+
builds,
|
|
401
|
+
buildsLoading: activeChannelId !== null && posts.length === 0 && !running,
|
|
402
|
+
building,
|
|
403
|
+
publishing: work === "publishing",
|
|
404
|
+
hostChat,
|
|
405
|
+
publish,
|
|
406
|
+
resumePreview
|
|
407
|
+
};
|
|
408
|
+
}export{useWebBuilderHost};//# sourceMappingURL=useWebBuilderHost.js.map
|