@aglyn/plugins-ai 1.0.0-beta.227 → 1.0.0-beta.229

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.
Files changed (109) hide show
  1. package/README.md +1 -1
  2. package/package.json +17 -17
  3. package/src/lib/components/ai-brief-dialog.component.js +1 -1
  4. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  5. package/src/lib/components/ai-describe-automation.component.js +7 -2
  6. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  7. package/src/lib/components/ai-describe-button.component.js +6 -1
  8. package/src/lib/components/ai-describe-button.component.js.map +1 -1
  9. package/src/lib/components/ai-describe-page.component.d.ts +1 -1
  10. package/src/lib/components/ai-describe-page.component.js +1 -1
  11. package/src/lib/components/ai-describe-page.component.js.map +1 -1
  12. package/src/lib/components/ai-job-events.d.ts +7 -1
  13. package/src/lib/components/ai-job-events.js +4 -2
  14. package/src/lib/components/ai-job-events.js.map +1 -1
  15. package/src/lib/components/ai-job-site.d.ts +22 -0
  16. package/src/lib/components/ai-job-site.js +73 -0
  17. package/src/lib/components/ai-job-site.js.map +1 -0
  18. package/src/lib/components/ai-jobs-list-page.component.d.ts +23 -0
  19. package/src/lib/components/ai-jobs-list-page.component.js +314 -0
  20. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -0
  21. package/src/lib/components/ai-jobs-page.component.d.ts +7 -0
  22. package/src/lib/components/ai-jobs-page.component.js +30 -0
  23. package/src/lib/components/ai-jobs-page.component.js.map +1 -0
  24. package/src/lib/components/ai-page-brief-dialog.component.d.ts +1 -1
  25. package/src/lib/components/ai-page-brief-dialog.component.js.map +1 -1
  26. package/src/lib/components/ai-site-build-page.component.d.ts +31 -3
  27. package/src/lib/components/ai-site-build-page.component.js +394 -243
  28. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  29. package/src/lib/components/ai-site-start-card.component.d.ts +18 -1
  30. package/src/lib/components/ai-site-start-card.component.js +27 -15
  31. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  32. package/src/lib/components/assist-jobs-drawer.component.d.ts +11 -0
  33. package/src/lib/components/assist-jobs-drawer.component.js +37 -1
  34. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  35. package/src/lib/components/assist-panel.component.js +9 -4
  36. package/src/lib/components/assist-panel.component.js.map +1 -1
  37. package/src/lib/jobs/ai-job-draft-ids.d.ts +6 -0
  38. package/src/lib/jobs/ai-job-draft-ids.js +9 -0
  39. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  40. package/src/lib/jobs/ai-job-drafts.d.ts +7 -0
  41. package/src/lib/jobs/ai-job-drafts.js +16 -7
  42. package/src/lib/jobs/ai-job-drafts.js.map +1 -1
  43. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +70 -0
  44. package/src/lib/jobs/ai-job-layout-site-pages.js +216 -0
  45. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -0
  46. package/src/lib/jobs/ai-job-layout-step.d.ts +2 -2
  47. package/src/lib/jobs/ai-job-layout-step.js +21 -2
  48. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  49. package/src/lib/jobs/ai-job-page-sections.d.ts +6 -5
  50. package/src/lib/jobs/ai-job-page-sections.js +3 -3
  51. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  52. package/src/lib/jobs/ai-job-page-step.d.ts +19 -1
  53. package/src/lib/jobs/ai-job-page-step.js +50 -8
  54. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  55. package/src/lib/jobs/ai-job-plan-step.js +7 -2
  56. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  57. package/src/lib/jobs/ai-job-site-step.d.ts +21 -0
  58. package/src/lib/jobs/ai-job-site-step.js +103 -17
  59. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  60. package/src/lib/jobs/ai-job-text-step.d.ts +7 -1
  61. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  62. package/src/lib/jobs/ai-jobs.d.ts +19 -1
  63. package/src/lib/jobs/ai-jobs.js +130 -53
  64. package/src/lib/jobs/ai-jobs.js.map +1 -1
  65. package/src/lib/jobs/ai-site-publish.d.ts +98 -0
  66. package/src/lib/jobs/ai-site-publish.js +372 -0
  67. package/src/lib/jobs/ai-site-publish.js.map +1 -0
  68. package/src/lib/jobs/fixtures/ai-page-briefs.d.ts +7 -6
  69. package/src/lib/jobs/fixtures/ai-page-briefs.js +23 -56
  70. package/src/lib/jobs/fixtures/ai-page-briefs.js.map +1 -1
  71. package/src/lib/model/ai-job-failure-copy.d.ts +20 -1
  72. package/src/lib/model/ai-job-failure-copy.js +28 -1
  73. package/src/lib/model/ai-job-failure-copy.js.map +1 -1
  74. package/src/lib/model/ai-job-notice.d.ts +6 -1
  75. package/src/lib/model/ai-job-notice.js +29 -3
  76. package/src/lib/model/ai-job-notice.js.map +1 -1
  77. package/src/lib/model/ai-jobs.types.d.ts +34 -0
  78. package/src/lib/model/ai-jobs.types.js.map +1 -1
  79. package/src/lib/model/ai-plan-capabilities.d.ts +25 -10
  80. package/src/lib/model/ai-plan-capabilities.js +15 -2
  81. package/src/lib/model/ai-plan-capabilities.js.map +1 -1
  82. package/src/lib/model/ai-site-build-progress.d.ts +25 -1
  83. package/src/lib/model/ai-site-build-progress.js +129 -15
  84. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  85. package/src/lib/model/ai-site-start-seo.d.ts +35 -0
  86. package/src/lib/model/ai-site-start-seo.js +145 -7
  87. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  88. package/src/lib/model/ai-site-start.d.ts +14 -0
  89. package/src/lib/model/ai-site-start.js +43 -0
  90. package/src/lib/model/ai-site-start.js.map +1 -1
  91. package/src/lib/plugin.js +18 -10
  92. package/src/lib/plugin.js.map +1 -1
  93. package/src/lib/runtime/ai-doctrine-validators.d.ts +16 -12
  94. package/src/lib/runtime/ai-doctrine-validators.js +19 -36
  95. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  96. package/src/lib/runtime/ai-doctrine.d.ts +6 -0
  97. package/src/lib/runtime/ai-doctrine.js +6 -2
  98. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  99. package/src/lib/runtime/ai-eval-live.d.ts +1 -1
  100. package/src/lib/runtime/ai-eval-live.js +1 -1
  101. package/src/lib/runtime/ai-eval-live.js.map +1 -1
  102. package/src/lib/server/ai-jobs-live-sites.d.ts +26 -0
  103. package/src/lib/server/ai-jobs-live-sites.js +58 -0
  104. package/src/lib/server/ai-jobs-live-sites.js.map +1 -0
  105. package/src/lib/server/ai-jobs-route.js +22 -3
  106. package/src/lib/server/ai-jobs-route.js.map +1 -1
  107. package/src/lib/usage/assist-job-refund.d.ts +3 -2
  108. package/src/lib/usage/assist-job-refund.js +2 -1
  109. package/src/lib/usage/assist-job-refund.js.map +1 -1
@@ -14,45 +14,88 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */ 'use client';
17
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
18
  import { PLATFORM_BRAND_NAME } from "@aglyn/aglyn";
19
+ import { PageHeaderRecord } from "@aglyn/aglyn/app-utils/page-header-record-context";
19
20
  import { mdiAlertCircle, mdiCheckCircle, mdiChevronDown, mdiClockOutline } from "@aglyn/shared-data-mdi";
20
21
  import { AppLink, MdiIcon } from "@aglyn/shared-ui-jsx";
21
- import { useFirestore, useUser } from "@aglyn/tenant-feature-instance";
22
+ import { useUser } from "@aglyn/tenant-feature-instance";
22
23
  import { Accordion, AccordionDetails, AccordionSummary, Alert, Box, Button, Card, CircularProgress, Container, LinearProgress, Stack, Typography } from "@mui/material";
23
- import { doc, getDoc } from "firebase/firestore";
24
24
  import { useCallback, useEffect, useRef, useState } from "react";
25
- import { aiSiteBuildCreditsLine, aiSiteBuildPhase, aiSiteBuildRows } from "../model/ai-site-build-progress.js";
26
- import { aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
25
+ import { aiJobPageCopy, aiSiteBuildCreditsLine, aiSiteBuildPhase, aiSiteBuildRows } from "../model/ai-site-build-progress.js";
26
+ import { aiJobRefundCopy, aiSiteStarterFallbackOffered } from "../model/ai-job-failure-copy.js";
27
+ import { aiSiteStartAnswersFromInputs } from "../model/ai-site-start.js";
28
+ import { AiSiteStartCard } from "./ai-site-start-card.component.js";
29
+ import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
27
30
  import { followAiJobEvents } from "./ai-job-events.js";
28
31
  import { aiSiteBuildDoneLinks } from "./ai-job-links.js";
29
32
  import { resumeAiJobRequest } from "./ai-job-requests.js";
33
+ import { useAiJobSite } from "./ai-job-site.js";
30
34
  import { AiSiteStarterFallback } from "./ai-site-starter-fallback.component.js";
31
- /** Follows one job by id: its latest summary, `null` while the first state is out, `'missing'` when the route had none. */ export function useAiJobById(user, orgId, jobId) {
35
+ /**
36
+ * "Building your site" (AGL-3594): one job's page, at `/ai-jobs/{jobId}`
37
+ * under its site — where the guided start sends a person the moment they
38
+ * plan a site, and where a notification about that job opens.
39
+ *
40
+ * A guided site start confirms its own plan (`autoConfirm`), so there is no
41
+ * approval to make here: the page says what is happening, step by step, live
42
+ * from the job's events route; shows what is being built; and, when the job
43
+ * ends, leads with the next thing to do — the live site and the pages to
44
+ * edit, or, where it stopped, the plain sentence for why and what to do
45
+ * about it. It is linkable and survives a reload, because it reads the job by
46
+ * the id in its own address under the site's own route.
47
+ *
48
+ * Every wait ends (AGL-3596): a site that cannot be read, a job the route
49
+ * does not know, a route that fails, and a first state that never arrives
50
+ * each end on a sentence instead of a spinner.
51
+ *
52
+ * Mounted by `AiJobsPage`, the plugin's unlisted `/ai-jobs` route: no tab on
53
+ * the site's strip, an address under it.
54
+ */ /** How long the job's first state may take before the page says it could not be loaded. */ export const AI_JOB_FIRST_STATE_TIMEOUT_MS = 20000;
55
+ /** Follows one job by id. `retry` follows it again after a `'missing'` or `'error'`. */ export function useAiJobById(user, orgId, jobId) {
32
56
  const userRef = useRef(user);
33
57
  userRef.current = user;
34
58
  const [job, setJob] = useState(null);
35
- const status = job && job !== 'missing' ? job.status : null;
36
- const moving = status === null || status === 'queued' || status === 'running';
59
+ const [attempt, setAttempt] = useState(0);
60
+ const status = job && typeof job === 'object' ? job.status : null;
61
+ // Followed until the job ENDS (AGL-3596), not until it first stops: a guided
62
+ // start parks on its plan for the instant it takes to confirm it, and a page
63
+ // that stopped following there showed that park — the plan's 13 credits and
64
+ // "the plan is ready" — after the job had built, spent and failed.
65
+ const moving = status === null || !AI_JOB_TERMINAL_STATUSES.includes(status);
37
66
  useEffect(()=>{
38
67
  if (!orgId || !jobId || !moving) return undefined;
39
68
  const controller = new AbortController();
40
69
  let heard = false;
70
+ const timer = setTimeout(()=>{
71
+ if (!heard) setJob((current)=>current != null ? current : 'error');
72
+ }, AI_JOB_FIRST_STATE_TIMEOUT_MS);
41
73
  void followAiJobEvents(()=>userRef.current, orgId, jobId, controller.signal, (next)=>{
42
74
  heard = true;
43
75
  setJob(next);
44
- }).then(()=>{
45
- if (!heard && !controller.signal.aborted) setJob((current)=>current != null ? current : 'missing');
76
+ }).then((end)=>{
77
+ if (heard || controller.signal.aborted) return;
78
+ const unheard = end === 'not-found' ? 'missing' : 'error';
79
+ setJob((current)=>current && typeof current === 'object' ? current : unheard);
46
80
  });
47
- return ()=>controller.abort();
81
+ return ()=>{
82
+ clearTimeout(timer);
83
+ controller.abort();
84
+ };
48
85
  }, [
49
86
  orgId,
50
87
  jobId,
51
- moving
88
+ moving,
89
+ attempt
52
90
  ]);
91
+ const retry = useCallback(()=>{
92
+ setJob(null);
93
+ setAttempt((count)=>count + 1);
94
+ }, []);
53
95
  return [
54
96
  job,
55
- setJob
97
+ setJob,
98
+ retry
56
99
  ];
57
100
  }
58
101
  const ROW_ICON = {
@@ -95,67 +138,7 @@ function RowIcon({ state }) {
95
138
  })
96
139
  });
97
140
  }
98
- export function AiSiteBuildPage({ hostId, segments, basePath }) {
99
- var _split_, _ref, _ref1;
100
- var _ready_review, _ready_review1, _ready_review2;
101
- const firestore = useFirestore();
102
- const { data: user } = useUser();
103
- const jobId = (segments == null ? void 0 : segments[0]) ? decodeURIComponent(String(segments[0])) : null;
104
- const orgSlug = (_split_ = (basePath != null ? basePath : '').split('/')[1]) != null ? _split_ : '';
105
- const [site, setSite] = useState(null);
106
- useEffect(()=>{
107
- if (!hostId) return;
108
- let active = true;
109
- void getDoc(doc(firestore, 'hosts', hostId)).then((snapshot)=>{
110
- var _snapshot_data, _data_orgId, _data_displayName;
111
- if (!active) return;
112
- const data = (_snapshot_data = snapshot.data()) != null ? _snapshot_data : {};
113
- setSite({
114
- orgId: String((_data_orgId = data.orgId) != null ? _data_orgId : ''),
115
- name: String((_data_displayName = data.displayName) != null ? _data_displayName : '')
116
- });
117
- }).catch(()=>{
118
- if (active) setSite({
119
- orgId: '',
120
- name: ''
121
- });
122
- });
123
- return ()=>{
124
- active = false;
125
- };
126
- }, [
127
- firestore,
128
- hostId
129
- ]);
130
- const [job, setJob] = useAiJobById(user, (site == null ? void 0 : site.orgId) || null, jobId);
131
- const [busy, setBusy] = useState(false);
132
- const [notice, setNotice] = useState(null);
133
- const tryAgain = useCallback(async ()=>{
134
- if (!(site == null ? void 0 : site.orgId) || !job || job === 'missing') return;
135
- setBusy(true);
136
- setNotice(null);
137
- const decision = await resumeAiJobRequest(user, site.orgId, job);
138
- if (decision.job) setJob(decision.job);
139
- if (decision.error) setNotice(decision.error);
140
- setBusy(false);
141
- }, [
142
- site,
143
- job,
144
- user,
145
- setJob
146
- ]);
147
- const ready = job && job !== 'missing' ? job : null;
148
- const phase = ready ? aiSiteBuildPhase(ready) : 'working';
149
- const heading = phase === 'done' ? 'Your site is ready' : phase === 'working' ? 'Building your site' : 'Your site was not built';
150
- const lede = phase === 'done' ? 'Your new pages are drafts. Publish them when you’re happy.' : phase === 'working' ? `${PLATFORM_BRAND_NAME} AI is planning your pages and writing each one. You can leave this page; it keeps going.` : phase === 'canceled' ? 'The job was canceled.' : (_ref = (_ref1 = ready == null ? void 0 : (_ready_review = ready.review) == null ? void 0 : _ready_review.message) != null ? _ref1 : ready == null ? void 0 : ready.error) != null ? _ref : 'Something went wrong building your site.';
151
- const rows = ready ? aiSiteBuildRows(ready) : [];
152
- const credits = ready ? aiSiteBuildCreditsLine(ready) : null;
153
- const links = ready && phase === 'done' ? aiSiteBuildDoneLinks(ready, orgSlug) : {
154
- view: null,
155
- pages: null
156
- };
157
- const retryRefusal = ready == null ? void 0 : (_ready_review1 = ready.review) == null ? void 0 : _ready_review1.retryRefusal;
158
- const canRetry = phase === 'stopped' && (ready == null ? void 0 : (_ready_review2 = ready.review) == null ? void 0 : _ready_review2.reason) === 'doctrine';
141
+ /** The page's frame: the site's name over the heading and its sentence. */ function Frame({ siteName, heading, lede, children }) {
159
142
  return /*#__PURE__*/ _jsx(Container, {
160
143
  maxWidth: "sm",
161
144
  sx: {
@@ -174,202 +157,370 @@ export function AiSiteBuildPage({ hostId, segments, basePath }) {
174
157
  /*#__PURE__*/ _jsxs(Stack, {
175
158
  spacing: 1,
176
159
  children: [
177
- (site == null ? void 0 : site.name) ? /*#__PURE__*/ _jsx(Typography, {
160
+ siteName ? /*#__PURE__*/ _jsx(Typography, {
178
161
  variant: "overline",
179
162
  color: "text.secondary",
180
- children: site.name
163
+ children: siteName
181
164
  }) : null,
182
165
  /*#__PURE__*/ _jsx(Typography, {
183
166
  variant: "h4",
184
167
  component: "h1",
185
168
  children: heading
186
169
  }),
187
- /*#__PURE__*/ _jsx(Typography, {
170
+ lede ? /*#__PURE__*/ _jsx(Typography, {
188
171
  variant: "body1",
189
172
  color: "text.secondary",
190
173
  children: lede
191
- })
174
+ }) : null
192
175
  ]
193
176
  }),
194
- job === 'missing' ? /*#__PURE__*/ _jsx(Alert, {
177
+ children
178
+ ]
179
+ })
180
+ });
181
+ }
182
+ export function AiSiteBuildPage({ hostId, segments, basePath }) {
183
+ var _split_, _ready_sitePublish, _ready_refundedCredits;
184
+ var _ready_review, _ready_review1;
185
+ const { data: user } = useUser();
186
+ const jobId = (segments == null ? void 0 : segments[0]) ? decodeURIComponent(String(segments[0])) : null;
187
+ const orgSlug = (_split_ = (basePath != null ? basePath : '').split('/')[1]) != null ? _split_ : '';
188
+ // `/{orgSlug}/hosts/{subdomain}/ai-jobs`: the site's subdomain, which a console URL names it by.
189
+ const hostSubdomain = (basePath != null ? basePath : '').split('/')[3] || null;
190
+ const site = useAiJobSite(hostId);
191
+ const orgId = site.status === 'ready' ? site.orgId : null;
192
+ const siteName = site.status === 'ready' ? site.name : undefined;
193
+ const [job, setJob, retry] = useAiJobById(user, orgId, jobId);
194
+ const [busy, setBusy] = useState(false);
195
+ const [notice, setNotice] = useState(null);
196
+ // A failed guided start's Try again reopens its questions, filled in (AGL-3596);
197
+ // `?retry=1` — what the AI jobs drawer links — opens them on arrival.
198
+ const [retrying, setRetrying] = useState(()=>typeof window !== 'undefined' && new URLSearchParams(window.location.search).get('retry') === '1');
199
+ const tryAgain = useCallback(async ()=>{
200
+ if (!orgId || !job || typeof job !== 'object') return;
201
+ setBusy(true);
202
+ setNotice(null);
203
+ const decision = await resumeAiJobRequest(user, orgId, job);
204
+ if (decision.job) setJob(decision.job);
205
+ if (decision.error) setNotice(decision.error);
206
+ setBusy(false);
207
+ }, [
208
+ orgId,
209
+ job,
210
+ user,
211
+ setJob
212
+ ]);
213
+ const ready = job && typeof job === 'object' ? job : null;
214
+ const copy = ready ? aiJobPageCopy(ready, PLATFORM_BRAND_NAME) : null;
215
+ // The shell's header names the job's page as the page does, and its trail
216
+ // walks back to the site's AI jobs.
217
+ const record = /*#__PURE__*/ _jsx(PageHeaderRecord, {
218
+ title: copy == null ? void 0 : copy.heading
219
+ });
220
+ if (site.status === 'error') {
221
+ return /*#__PURE__*/ _jsx(Frame, {
222
+ heading: "This site could not be read",
223
+ children: /*#__PURE__*/ _jsx(Alert, {
224
+ severity: "warning",
225
+ children: 'The site this job belongs to could not be loaded. Check your connection and reload the page.'
226
+ })
227
+ });
228
+ }
229
+ if (job === 'missing') {
230
+ return /*#__PURE__*/ _jsxs(Frame, {
231
+ siteName: siteName,
232
+ heading: "This job could not be found",
233
+ children: [
234
+ /*#__PURE__*/ _jsx(Alert, {
195
235
  severity: "info",
196
- children: 'This job could not be found. It may belong to another workspace.'
197
- }) : !ready ? /*#__PURE__*/ _jsx(Stack, {
198
- sx: {
199
- alignItems: 'center',
200
- py: 4
201
- },
202
- children: /*#__PURE__*/ _jsx(CircularProgress, {
203
- "aria-label": "Loading the job"
236
+ children: 'It may belong to another workspace, or it may have expired.'
237
+ }),
238
+ basePath ? /*#__PURE__*/ _jsx(Box, {
239
+ children: /*#__PURE__*/ _jsx(Button, {
240
+ variant: "outlined",
241
+ component: AppLink,
242
+ href: basePath,
243
+ children: 'See this site’s AI jobs'
204
244
  })
205
- }) : /*#__PURE__*/ _jsxs(_Fragment, {
206
- children: [
207
- notice && /*#__PURE__*/ _jsx(Alert, {
208
- severity: "warning",
209
- children: notice
210
- }),
211
- /*#__PURE__*/ _jsxs(Card, {
212
- variant: "outlined",
213
- sx: {
214
- borderRadius: 2
215
- },
216
- children: [
217
- phase === 'working' && /*#__PURE__*/ _jsx(LinearProgress, {
218
- "aria-label": "Building"
219
- }),
220
- /*#__PURE__*/ _jsx(Box, {
221
- component: "ol",
222
- "aria-label": "Progress",
223
- sx: {
224
- listStyle: 'none',
225
- m: 0,
226
- p: {
227
- xs: 2,
228
- sm: 3
229
- }
230
- },
231
- children: /*#__PURE__*/ _jsx(Stack, {
232
- spacing: 2,
233
- children: rows.map((row)=>/*#__PURE__*/ _jsxs(Stack, {
234
- component: "li",
235
- direction: "row",
236
- spacing: 2,
237
- sx: {
238
- alignItems: 'center'
239
- },
240
- children: [
241
- /*#__PURE__*/ _jsx(Box, {
242
- sx: {
243
- width: (theme)=>theme.spacing(3),
244
- display: 'flex',
245
- justifyContent: 'center'
246
- },
247
- children: /*#__PURE__*/ _jsx(RowIcon, {
248
- state: row.state
249
- })
250
- }),
251
- /*#__PURE__*/ _jsx(Typography, {
252
- variant: "body1",
253
- color: row.state === 'waiting' ? 'text.secondary' : 'text.primary',
254
- children: row.label
255
- })
256
- ]
257
- }, row.id))
258
- })
259
- })
260
- ]
261
- }),
262
- credits && /*#__PURE__*/ _jsx(Typography, {
263
- variant: "body2",
264
- color: "text.secondary",
265
- children: credits
266
- }),
267
- phase === 'done' && /*#__PURE__*/ _jsxs(Stack, {
268
- direction: {
269
- xs: 'column',
270
- sm: 'row'
271
- },
245
+ }) : null
246
+ ]
247
+ });
248
+ }
249
+ if (job === 'error') {
250
+ return /*#__PURE__*/ _jsx(Frame, {
251
+ siteName: siteName,
252
+ heading: "This job could not be loaded",
253
+ children: /*#__PURE__*/ _jsx(Alert, {
254
+ severity: "warning",
255
+ action: /*#__PURE__*/ _jsx(Button, {
256
+ color: "inherit",
257
+ size: "small",
258
+ onClick: retry,
259
+ children: 'Try again'
260
+ }),
261
+ children: 'Something went wrong reading it. It may still be running: try again in a moment.'
262
+ })
263
+ });
264
+ }
265
+ if (!ready || !copy) {
266
+ return /*#__PURE__*/ _jsx(Frame, {
267
+ siteName: siteName,
268
+ heading: "Building your site",
269
+ children: /*#__PURE__*/ _jsx(Stack, {
270
+ sx: {
271
+ alignItems: 'center',
272
+ py: 4
273
+ },
274
+ children: /*#__PURE__*/ _jsx(CircularProgress, {
275
+ "aria-label": "Loading the job"
276
+ })
277
+ })
278
+ });
279
+ }
280
+ const phase = aiSiteBuildPhase(ready);
281
+ const rows = aiSiteBuildRows(ready);
282
+ const credits = aiSiteBuildCreditsLine(ready);
283
+ const links = phase === 'done' ? aiSiteBuildDoneLinks(ready, orgSlug) : {
284
+ view: null,
285
+ pages: null
286
+ };
287
+ const sitePublish = ready.kind === 'site' && phase === 'done' ? (_ready_sitePublish = ready.sitePublish) != null ? _ready_sitePublish : null : null;
288
+ const liveUrl = sitePublish && sitePublish.published.length > 0 ? sitePublish.liveUrl : null;
289
+ const retryRefusal = (_ready_review = ready.review) == null ? void 0 : _ready_review.retryRefusal;
290
+ const canRetry = phase === 'stopped' && ((_ready_review1 = ready.review) == null ? void 0 : _ready_review1.reason) === 'doctrine';
291
+ // A guided start that ended without building its site starts over from its
292
+ // own answers, as a fresh job: the questions reopen filled in.
293
+ const restartAnswers = ready.kind === 'site' && (phase === 'failed' || phase === 'canceled') ? aiSiteStartAnswersFromInputs(ready.siteInputs) : null;
294
+ const refund = phase === 'failed' || phase === 'stopped' || phase === 'canceled' ? aiJobRefundCopy(ready) : null;
295
+ return /*#__PURE__*/ _jsxs(Frame, {
296
+ siteName: siteName,
297
+ heading: copy.heading,
298
+ lede: copy.lede,
299
+ children: [
300
+ record,
301
+ notice && /*#__PURE__*/ _jsx(Alert, {
302
+ severity: "warning",
303
+ children: notice
304
+ }),
305
+ /*#__PURE__*/ _jsxs(Card, {
306
+ variant: "outlined",
307
+ sx: {
308
+ borderRadius: 2
309
+ },
310
+ children: [
311
+ phase === 'working' && /*#__PURE__*/ _jsx(LinearProgress, {
312
+ "aria-label": "Building"
313
+ }),
314
+ /*#__PURE__*/ _jsx(Box, {
315
+ component: "ol",
316
+ "aria-label": "Progress",
317
+ sx: {
318
+ listStyle: 'none',
319
+ m: 0,
320
+ p: {
321
+ xs: 2,
322
+ sm: 3
323
+ }
324
+ },
325
+ children: /*#__PURE__*/ _jsx(Stack, {
272
326
  spacing: 2,
273
- children: [
274
- links.view && /*#__PURE__*/ _jsx(Button, {
275
- variant: "contained",
276
- size: "large",
277
- component: AppLink,
278
- href: links.view,
279
- children: 'View your site'
280
- }),
281
- links.pages && /*#__PURE__*/ _jsx(Button, {
282
- variant: "outlined",
283
- size: "large",
284
- component: AppLink,
285
- href: links.pages,
286
- children: 'Edit your pages'
287
- })
288
- ]
289
- }),
290
- (phase === 'stopped' || phase === 'failed' || phase === 'canceled') && /*#__PURE__*/ _jsxs(Stack, {
291
- spacing: 1,
292
- children: [
293
- retryRefusal && /*#__PURE__*/ _jsx(Typography, {
294
- variant: "body2",
295
- color: "text.secondary",
296
- children: retryRefusal
297
- }),
298
- /*#__PURE__*/ _jsxs(Stack, {
299
- direction: {
300
- xs: 'column',
301
- sm: 'row'
302
- },
327
+ children: rows.map((row)=>/*#__PURE__*/ _jsxs(Stack, {
328
+ component: "li",
329
+ direction: "row",
303
330
  spacing: 2,
304
331
  sx: {
305
- alignItems: {
306
- sm: 'center'
307
- }
332
+ alignItems: 'center'
308
333
  },
309
334
  children: [
310
- canRetry && /*#__PURE__*/ _jsx(Button, {
311
- variant: "contained",
312
- disabled: busy || Boolean(retryRefusal),
313
- onClick: ()=>void tryAgain(),
314
- children: 'Try again'
335
+ /*#__PURE__*/ _jsx(Box, {
336
+ sx: {
337
+ width: (theme)=>theme.spacing(3),
338
+ display: 'flex',
339
+ justifyContent: 'center'
340
+ },
341
+ children: /*#__PURE__*/ _jsx(RowIcon, {
342
+ state: row.state
343
+ })
315
344
  }),
316
- aiSiteStarterFallbackOffered(ready) && user ? /*#__PURE__*/ _jsx(AiSiteStarterFallback, {
317
- job: ready,
318
- user: user
319
- }) : null
345
+ /*#__PURE__*/ _jsx(Typography, {
346
+ variant: "body1",
347
+ color: row.state === 'waiting' ? 'text.secondary' : 'text.primary',
348
+ children: row.label
349
+ })
320
350
  ]
351
+ }, row.id))
352
+ })
353
+ })
354
+ ]
355
+ }),
356
+ refund && ((_ready_refundedCredits = ready.refundedCredits) != null ? _ready_refundedCredits : 0) > 0 ? /*#__PURE__*/ _jsx(Alert, {
357
+ severity: "info",
358
+ children: refund
359
+ }) : credits ? /*#__PURE__*/ _jsx(Typography, {
360
+ variant: "body2",
361
+ color: "text.secondary",
362
+ children: credits
363
+ }) : null,
364
+ retrying && restartAnswers && hostId ? /*#__PURE__*/ _jsx(AiSiteStartCard, {
365
+ hostId: hostId,
366
+ orgId: orgId != null ? orgId : undefined,
367
+ orgSlug: orgSlug,
368
+ host: hostSubdomain,
369
+ initialAnswers: restartAnswers,
370
+ startBlank: ()=>setRetrying(false),
371
+ leave: ()=>setRetrying(false)
372
+ }) : null,
373
+ sitePublish && sitePublish.drafts.length > 0 && // The pages the publish left as drafts, each with its plain reason;
374
+ // Edit your pages is where they are fixed and published.
375
+ /*#__PURE__*/ _jsxs(Alert, {
376
+ severity: "warning",
377
+ children: [
378
+ /*#__PURE__*/ _jsx(Typography, {
379
+ variant: "body2",
380
+ sx: {
381
+ mb: 1
382
+ },
383
+ children: sitePublish.drafts.length === 1 ? 'This page stayed a draft:' : 'These pages stayed drafts:'
384
+ }),
385
+ /*#__PURE__*/ _jsx(Box, {
386
+ component: "ul",
387
+ sx: {
388
+ m: 0,
389
+ pl: 2.5
390
+ },
391
+ children: sitePublish.drafts.map((draft)=>/*#__PURE__*/ _jsx("li", {
392
+ children: /*#__PURE__*/ _jsx(Typography, {
393
+ variant: "body2",
394
+ children: `${draft.label}: ${draft.reason}`
321
395
  })
322
- ]
396
+ }, draft.id))
397
+ }),
398
+ /*#__PURE__*/ _jsx(Typography, {
399
+ variant: "body2",
400
+ sx: {
401
+ mt: 1
402
+ },
403
+ children: 'Open Edit your pages to fix and publish them.'
404
+ })
405
+ ]
406
+ }),
407
+ phase === 'done' && /*#__PURE__*/ _jsxs(Stack, {
408
+ direction: {
409
+ xs: 'column',
410
+ sm: 'row'
411
+ },
412
+ spacing: 2,
413
+ children: [
414
+ liveUrl ? // The live site, in a tab of its own: the console stays where it is.
415
+ /*#__PURE__*/ _jsx(Button, {
416
+ variant: "contained",
417
+ size: "large",
418
+ component: "a",
419
+ href: liveUrl,
420
+ target: "_blank",
421
+ rel: "noopener noreferrer",
422
+ children: 'View your site'
423
+ }) : links.view ? /*#__PURE__*/ _jsx(Button, {
424
+ variant: "contained",
425
+ size: "large",
426
+ component: AppLink,
427
+ href: links.view,
428
+ children: 'View your site'
429
+ }) : null,
430
+ links.pages && /*#__PURE__*/ _jsx(Button, {
431
+ variant: "outlined",
432
+ size: "large",
433
+ component: AppLink,
434
+ href: links.pages,
435
+ children: 'Edit your pages'
436
+ })
437
+ ]
438
+ }),
439
+ (phase === 'stopped' || phase === 'failed' || phase === 'canceled') && /*#__PURE__*/ _jsxs(Stack, {
440
+ spacing: 1,
441
+ children: [
442
+ retryRefusal && /*#__PURE__*/ _jsx(Typography, {
443
+ variant: "body2",
444
+ color: "text.secondary",
445
+ children: retryRefusal
446
+ }),
447
+ /*#__PURE__*/ _jsxs(Stack, {
448
+ direction: {
449
+ xs: 'column',
450
+ sm: 'row'
451
+ },
452
+ spacing: 2,
453
+ sx: {
454
+ alignItems: {
455
+ sm: 'center'
456
+ }
457
+ },
458
+ children: [
459
+ restartAnswers && hostId && /*#__PURE__*/ _jsx(Button, {
460
+ variant: "contained",
461
+ onClick: ()=>setRetrying(true),
462
+ children: 'Try again'
463
+ }),
464
+ canRetry && /*#__PURE__*/ _jsx(Button, {
465
+ variant: "contained",
466
+ disabled: busy || Boolean(retryRefusal),
467
+ onClick: ()=>void tryAgain(),
468
+ children: 'Try again'
469
+ }),
470
+ aiSiteStarterFallbackOffered(ready) && user ? /*#__PURE__*/ _jsx(AiSiteStarterFallback, {
471
+ job: ready,
472
+ user: user
473
+ }) : null
474
+ ]
475
+ })
476
+ ]
477
+ }),
478
+ ready.plan && ready.plan.screens.length > 0 && /*#__PURE__*/ _jsxs(Accordion, {
479
+ variant: "outlined",
480
+ disableGutters: true,
481
+ sx: {
482
+ borderRadius: 2,
483
+ '&::before': {
484
+ display: 'none'
485
+ }
486
+ },
487
+ children: [
488
+ /*#__PURE__*/ _jsx(AccordionSummary, {
489
+ expandIcon: /*#__PURE__*/ _jsx(MdiIcon, {
490
+ path: mdiChevronDown.path
323
491
  }),
324
- ready.plan && ready.plan.screens.length > 0 && /*#__PURE__*/ _jsxs(Accordion, {
325
- variant: "outlined",
326
- disableGutters: true,
492
+ children: /*#__PURE__*/ _jsx(Typography, {
493
+ variant: "subtitle1",
494
+ children: 'What we’re building'
495
+ })
496
+ }),
497
+ /*#__PURE__*/ _jsx(AccordionDetails, {
498
+ children: /*#__PURE__*/ _jsx(Stack, {
499
+ component: "ul",
500
+ spacing: 1.5,
327
501
  sx: {
328
- borderRadius: 2,
329
- '&::before': {
330
- display: 'none'
331
- }
502
+ m: 0,
503
+ pl: 2.5
332
504
  },
333
- children: [
334
- /*#__PURE__*/ _jsx(AccordionSummary, {
335
- expandIcon: /*#__PURE__*/ _jsx(MdiIcon, {
336
- path: mdiChevronDown.path
337
- }),
338
- children: /*#__PURE__*/ _jsx(Typography, {
339
- variant: "subtitle1",
340
- children: 'What we’re building'
341
- })
342
- }),
343
- /*#__PURE__*/ _jsx(AccordionDetails, {
344
- children: /*#__PURE__*/ _jsx(Stack, {
345
- component: "ul",
346
- spacing: 1.5,
347
- sx: {
348
- m: 0,
349
- pl: 2.5
350
- },
351
- children: ready.plan.screens.map((screen, index)=>/*#__PURE__*/ _jsxs(Box, {
352
- component: "li",
353
- children: [
354
- /*#__PURE__*/ _jsx(Typography, {
355
- variant: "body1",
356
- children: `${screen.title} — ${screen.slug}`
357
- }),
358
- screen.sections.length > 0 && /*#__PURE__*/ _jsx(Typography, {
359
- variant: "body2",
360
- color: "text.secondary",
361
- children: screen.sections.map((section)=>section.name).join(', ')
362
- })
363
- ]
364
- }, `${screen.slug}-${index}`))
365
- })
366
- })
367
- ]
505
+ children: ready.plan.screens.map((screen, index)=>/*#__PURE__*/ _jsxs(Box, {
506
+ component: "li",
507
+ children: [
508
+ /*#__PURE__*/ _jsx(Typography, {
509
+ variant: "body1",
510
+ children: `${screen.title} — ${screen.slug}`
511
+ }),
512
+ screen.sections.length > 0 && /*#__PURE__*/ _jsx(Typography, {
513
+ variant: "body2",
514
+ color: "text.secondary",
515
+ children: screen.sections.map((section)=>section.name).join(', ')
516
+ })
517
+ ]
518
+ }, `${screen.slug}-${index}`))
368
519
  })
369
- ]
370
- })
371
- ]
372
- })
520
+ })
521
+ ]
522
+ })
523
+ ]
373
524
  });
374
525
  }
375
526
  export default AiSiteBuildPage;