@aglyn/plugins-ai 1.0.0-beta.237 → 1.0.0-beta.238
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/package.json +17 -17
- package/src/lib/components/ai-credits-prompt.component.d.ts +11 -4
- package/src/lib/components/ai-credits-prompt.component.js +84 -34
- package/src/lib/components/ai-credits-prompt.component.js.map +1 -1
- package/src/lib/components/ai-job-cancel.component.d.ts +38 -0
- package/src/lib/components/ai-job-cancel.component.js +156 -0
- package/src/lib/components/ai-job-cancel.component.js.map +1 -0
- package/src/lib/components/ai-job-plan.component.js +12 -1
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.js +141 -72
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +22 -2
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.d.ts +19 -2
- package/src/lib/components/ai-usage-strip.component.js +40 -9
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +12 -16
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +87 -51
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.js +4 -1
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-cancel.d.ts +71 -0
- package/src/lib/jobs/ai-job-cancel.js +102 -0
- package/src/lib/jobs/ai-job-cancel.js.map +1 -0
- package/src/lib/jobs/ai-job-component-step.js +4 -1
- package/src/lib/jobs/ai-job-component-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.js +2 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.js +4 -1
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +2 -0
- package/src/lib/jobs/ai-job-layout-language.js +13 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +6 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +8 -0
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +12 -1
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +20 -1
- package/src/lib/jobs/ai-job-plan-step.js +49 -9
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +15 -0
- package/src/lib/jobs/ai-job-site-content.js +66 -7
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +4 -1
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-template-step.js +4 -1
- package/src/lib/jobs/ai-job-template-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +37 -12
- package/src/lib/jobs/ai-jobs.js +184 -28
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +143 -70
- package/src/lib/jobs/ai-layout-stock-photos.js +649 -176
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.d.ts +30 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js +220 -0
- package/src/lib/jobs/fixtures/ai-ceramics-portfolio-site-plan.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js +151 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-pixabay-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +6 -0
- package/src/lib/layout-language/ai-layout-compiler.js +304 -8
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +6 -3
- package/src/lib/layout-language/ai-layout-design.js +5 -3
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-frame.js +58 -3
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +13 -1
- package/src/lib/layout-language/ai-layout-listings.js +61 -46
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +8 -0
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +82 -0
- package/src/lib/layout-language/ai-layout-storefront.js +223 -0
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -0
- package/src/lib/model/ai-build-job.d.ts +9 -1
- package/src/lib/model/ai-build-job.js +19 -5
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-progress.d.ts +2 -2
- package/src/lib/model/ai-build-progress.js +6 -4
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +69 -2
- package/src/lib/model/ai-credit-estimate.js +91 -3
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-job-cancel-copy.d.ts +44 -0
- package/src/lib/model/ai-job-cancel-copy.js +53 -0
- package/src/lib/model/ai-job-cancel-copy.js.map +1 -0
- package/src/lib/model/ai-job-failure-copy.d.ts +4 -1
- package/src/lib/model/ai-job-failure-copy.js +8 -3
- package/src/lib/model/ai-job-failure-copy.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +20 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-build-progress.js +7 -4
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +19 -2
- package/src/lib/model/ai-site-job.js +29 -8
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +4 -1
- package/src/lib/model/ai-site-kinds.js +34 -6
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +37 -1
- package/src/lib/runtime/ai-doctrine-validators.js +151 -6
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +4 -3
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +53 -7
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/server/ai-jobs-cancel.d.ts +13 -5
- package/src/lib/server/ai-jobs-cancel.js +27 -9
- package/src/lib/server/ai-jobs-cancel.js.map +1 -1
- package/src/lib/server/ai-jobs-gate.d.ts +12 -2
- package/src/lib/server/ai-jobs-gate.js +20 -9
- package/src/lib/server/ai-jobs-gate.js.map +1 -1
- package/src/lib/usage/ai-usage-meter.d.ts +2 -1
- package/src/lib/usage/ai-usage-meter.js +17 -1
- package/src/lib/usage/ai-usage-meter.js.map +1 -1
- package/src/lib/usage/ai-usage-wire.d.ts +6 -0
- package/src/lib/usage/ai-usage-wire.js.map +1 -1
- package/src/lib/usage/assist-usage.d.ts +7 -0
- package/src/lib/usage/assist-usage.js +14 -4
- package/src/lib/usage/assist-usage.js.map +1 -1
- package/src/lib/usage/free-ai-credits-left.d.ts +7 -0
- package/src/lib/usage/free-ai-credits-left.js +4 -2
- package/src/lib/usage/free-ai-credits-left.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aglyn/plugins-ai",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.238",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,22 +25,22 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-data-enums": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-data-mdi": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-data-types": "1.0.0-beta.
|
|
32
|
-
"@aglyn/shared-ui-email-campaigns": "1.0.0-beta.
|
|
33
|
-
"@aglyn/shared-ui-jsx": "1.0.0-beta.
|
|
34
|
-
"@aglyn/shared-ui-snackstack": "1.0.0-beta.
|
|
35
|
-
"@aglyn/shared-ui-theme": "1.0.0-beta.
|
|
36
|
-
"@aglyn/shared-util-email": "1.0.0-beta.
|
|
37
|
-
"@aglyn/shared-util-errors": "1.0.0-beta.
|
|
38
|
-
"@aglyn/shared-util-http": "1.0.0-beta.
|
|
39
|
-
"@aglyn/shared-util-timestamp": "1.0.0-beta.
|
|
40
|
-
"@aglyn/shared-util-tools": "1.0.0-beta.
|
|
41
|
-
"@aglyn/tenant-data-admin": "1.0.0-beta.
|
|
42
|
-
"@aglyn/tenant-feature-instance": "1.0.0-beta.
|
|
43
|
-
"@aglyn/tenant-runtime": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.238",
|
|
29
|
+
"@aglyn/shared-data-enums": "1.0.0-beta.238",
|
|
30
|
+
"@aglyn/shared-data-mdi": "1.0.0-beta.238",
|
|
31
|
+
"@aglyn/shared-data-types": "1.0.0-beta.238",
|
|
32
|
+
"@aglyn/shared-ui-email-campaigns": "1.0.0-beta.238",
|
|
33
|
+
"@aglyn/shared-ui-jsx": "1.0.0-beta.238",
|
|
34
|
+
"@aglyn/shared-ui-snackstack": "1.0.0-beta.238",
|
|
35
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.238",
|
|
36
|
+
"@aglyn/shared-util-email": "1.0.0-beta.238",
|
|
37
|
+
"@aglyn/shared-util-errors": "1.0.0-beta.238",
|
|
38
|
+
"@aglyn/shared-util-http": "1.0.0-beta.238",
|
|
39
|
+
"@aglyn/shared-util-timestamp": "1.0.0-beta.238",
|
|
40
|
+
"@aglyn/shared-util-tools": "1.0.0-beta.238",
|
|
41
|
+
"@aglyn/tenant-data-admin": "1.0.0-beta.238",
|
|
42
|
+
"@aglyn/tenant-feature-instance": "1.0.0-beta.238",
|
|
43
|
+
"@aglyn/tenant-runtime": "1.0.0-beta.238",
|
|
44
44
|
"@swc/helpers": "0.5.23"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
@@ -17,10 +17,17 @@
|
|
|
17
17
|
import { type AiCreditsPrompt } from '../model/ai-credit-estimate';
|
|
18
18
|
/**
|
|
19
19
|
* What a Free job past what is left asks before it starts (AGL-3722), on the
|
|
20
|
-
* Assist build plan card
|
|
21
|
-
* about what it costs, what is left,
|
|
22
|
-
* and its
|
|
23
|
-
* starts anything; nothing is started by
|
|
20
|
+
* Assist build plan card, in the guided start, on a build's page and in the
|
|
21
|
+
* jobs drawer alike: the plain sentence — about what it costs, what is left,
|
|
22
|
+
* that it builds what it can and pauses — and its ways on. Only "Build what
|
|
23
|
+
* fits" (or the smaller first build) starts anything; nothing is started by
|
|
24
|
+
* showing this.
|
|
25
|
+
*
|
|
26
|
+
* The ways on are one set of option buttons (Zach, 2026-10-10): the same
|
|
27
|
+
* shape and height, full width so a long label never wraps beside another,
|
|
28
|
+
* sentence case, a short label with its figure under it, and the recommended
|
|
29
|
+
* one drawn as the primary button. Theme tokens only, so it reads the same in
|
|
30
|
+
* the Assist panel's narrow column and in light or dark.
|
|
24
31
|
*/
|
|
25
32
|
export interface AiCreditsPromptProps {
|
|
26
33
|
prompt: AiCreditsPrompt;
|
|
@@ -14,50 +14,100 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
18
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
19
|
+
import { Box, Button, Stack, Typography } from "@mui/material";
|
|
20
|
+
import { useId } from "react";
|
|
21
|
+
import { aiCreditsChoices, aiCreditsPromptText } from "../model/ai-credit-estimate.js";
|
|
20
22
|
import { aiCreditsBillingHref } from "./ai-job-links.js";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
function AiCreditsChoiceButton({ choice, busy, href, onClick }) {
|
|
24
|
+
const detailId = `${useId()}-detail`;
|
|
25
|
+
return /*#__PURE__*/ _jsxs(Button, _extends({
|
|
26
|
+
fullWidth: true,
|
|
27
|
+
size: "medium",
|
|
28
|
+
variant: choice.recommended ? 'contained' : 'outlined',
|
|
29
|
+
color: "primary",
|
|
30
|
+
disabled: busy && choice.key !== 'upgrade',
|
|
31
|
+
"aria-label": choice.label,
|
|
32
|
+
"aria-describedby": detailId,
|
|
33
|
+
"data-choice": choice.key
|
|
34
|
+
}, href ? {
|
|
35
|
+
href
|
|
36
|
+
} : {
|
|
37
|
+
onClick
|
|
38
|
+
}, {
|
|
24
39
|
sx: {
|
|
25
|
-
|
|
40
|
+
minHeight: 56,
|
|
41
|
+
px: 1.5,
|
|
42
|
+
py: 1,
|
|
43
|
+
display: 'flex',
|
|
44
|
+
flexDirection: 'column',
|
|
45
|
+
alignItems: 'flex-start',
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
textAlign: 'left',
|
|
48
|
+
textTransform: 'none',
|
|
49
|
+
lineHeight: 1.3
|
|
26
50
|
},
|
|
51
|
+
children: [
|
|
52
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
53
|
+
component: "span",
|
|
54
|
+
variant: "body2",
|
|
55
|
+
sx: {
|
|
56
|
+
fontWeight: 600,
|
|
57
|
+
color: 'inherit'
|
|
58
|
+
},
|
|
59
|
+
children: choice.label
|
|
60
|
+
}),
|
|
61
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
62
|
+
id: detailId,
|
|
63
|
+
component: "span",
|
|
64
|
+
variant: "caption",
|
|
65
|
+
sx: {
|
|
66
|
+
color: 'inherit',
|
|
67
|
+
opacity: 0.8
|
|
68
|
+
},
|
|
69
|
+
children: choice.detail
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
export function AiCreditsPromptNotice({ prompt, noun, orgSlug, busy = false, onBuildWhatFits, onSmaller }) {
|
|
75
|
+
const choices = aiCreditsChoices(prompt, {
|
|
76
|
+
smaller: Boolean(onSmaller),
|
|
77
|
+
upgrade: Boolean(orgSlug)
|
|
78
|
+
});
|
|
79
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
27
80
|
role: "alert",
|
|
28
81
|
"aria-label": "More than your credits left",
|
|
82
|
+
sx: {
|
|
83
|
+
mt: 1,
|
|
84
|
+
p: 1.5,
|
|
85
|
+
border: 1,
|
|
86
|
+
borderColor: 'warning.main',
|
|
87
|
+
borderRadius: 1,
|
|
88
|
+
bgcolor: 'background.paper'
|
|
89
|
+
},
|
|
29
90
|
children: [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
91
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
92
|
+
variant: "body2",
|
|
93
|
+
sx: {
|
|
94
|
+
color: 'text.primary'
|
|
95
|
+
},
|
|
96
|
+
children: aiCreditsPromptText(prompt, noun)
|
|
97
|
+
}),
|
|
98
|
+
/*#__PURE__*/ _jsx(Stack, {
|
|
33
99
|
spacing: 1,
|
|
34
|
-
useFlexGap: true,
|
|
35
100
|
sx: {
|
|
36
|
-
mt: 1
|
|
37
|
-
flexWrap: 'wrap'
|
|
101
|
+
mt: 1.5
|
|
38
102
|
},
|
|
39
|
-
children:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}),
|
|
47
|
-
prompt.smaller && onSmaller ? /*#__PURE__*/ _jsx(Button, {
|
|
48
|
-
size: "small",
|
|
49
|
-
variant: "outlined",
|
|
50
|
-
disabled: busy,
|
|
51
|
-
onClick: onSmaller,
|
|
52
|
-
children: aiCreditsSmallerText(prompt.smaller)
|
|
53
|
-
}) : null,
|
|
54
|
-
orgSlug ? /*#__PURE__*/ _jsx(Button, {
|
|
55
|
-
size: "small",
|
|
56
|
-
color: "inherit",
|
|
57
|
-
href: aiCreditsBillingHref(orgSlug),
|
|
58
|
-
children: 'Upgrade'
|
|
59
|
-
}) : null
|
|
60
|
-
]
|
|
103
|
+
children: choices.map((choice)=>/*#__PURE__*/ _jsx(AiCreditsChoiceButton, _extends({
|
|
104
|
+
choice: choice,
|
|
105
|
+
busy: busy
|
|
106
|
+
}, choice.key === 'upgrade' && orgSlug ? {
|
|
107
|
+
href: aiCreditsBillingHref(orgSlug)
|
|
108
|
+
} : {
|
|
109
|
+
onClick: choice.key === 'smaller' ? onSmaller : onBuildWhatFits
|
|
110
|
+
}), choice.key))
|
|
61
111
|
})
|
|
62
112
|
]
|
|
63
113
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-credits-prompt.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-credits-prompt.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { Box, Button, Stack, Typography } from '@mui/material'\nimport { useId } from 'react'\nimport {\n aiCreditsChoices,\n aiCreditsPromptText,\n type AiCreditsChoice,\n type AiCreditsPrompt,\n} from '../model/ai-credit-estimate'\nimport { aiCreditsBillingHref } from './ai-job-links'\n\n/**\n * What a Free job past what is left asks before it starts (AGL-3722), on the\n * Assist build plan card, in the guided start, on a build's page and in the\n * jobs drawer alike: the plain sentence — about what it costs, what is left,\n * that it builds what it can and pauses — and its ways on. Only \"Build what\n * fits\" (or the smaller first build) starts anything; nothing is started by\n * showing this.\n *\n * The ways on are one set of option buttons (Zach, 2026-10-10): the same\n * shape and height, full width so a long label never wraps beside another,\n * sentence case, a short label with its figure under it, and the recommended\n * one drawn as the primary button. Theme tokens only, so it reads the same in\n * the Assist panel's narrow column and in light or dark.\n */\nexport interface AiCreditsPromptProps {\n prompt: AiCreditsPrompt\n noun: 'build' | 'site'\n /** The workspace's path slug, for Upgrade; Upgrade is left out without it. */\n orgSlug?: string | null\n busy?: boolean\n /** \"Build what fits\": start it, to pause where the credits run out. */\n onBuildWhatFits: () => void\n /** The smaller first build; offered only when the prompt has one and this is given. */\n onSmaller?: () => void\n}\n\nfunction AiCreditsChoiceButton({\n choice,\n busy,\n href,\n onClick,\n}: {\n choice: AiCreditsChoice\n busy: boolean\n href?: string\n onClick?: () => void\n}): JSX.Element {\n const detailId = `${useId()}-detail`\n return (\n <Button\n fullWidth\n size=\"medium\"\n variant={choice.recommended ? 'contained' : 'outlined'}\n color=\"primary\"\n disabled={busy && choice.key !== 'upgrade'}\n aria-label={choice.label}\n aria-describedby={detailId}\n data-choice={choice.key}\n {...(href ? { href } : { onClick })}\n sx={{\n minHeight: 56,\n px: 1.5,\n py: 1,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n justifyContent: 'center',\n textAlign: 'left',\n textTransform: 'none',\n lineHeight: 1.3,\n }}\n >\n <Typography component=\"span\" variant=\"body2\" sx={{ fontWeight: 600, color: 'inherit' }}>\n {choice.label}\n </Typography>\n <Typography id={detailId} component=\"span\" variant=\"caption\" sx={{ color: 'inherit', opacity: 0.8 }}>\n {choice.detail}\n </Typography>\n </Button>\n )\n}\n\nexport function AiCreditsPromptNotice({\n prompt,\n noun,\n orgSlug,\n busy = false,\n onBuildWhatFits,\n onSmaller,\n}: AiCreditsPromptProps): JSX.Element {\n const choices = aiCreditsChoices(prompt, { smaller: Boolean(onSmaller), upgrade: Boolean(orgSlug) })\n return (\n <Box\n role=\"alert\"\n aria-label=\"More than your credits left\"\n sx={{\n mt: 1,\n p: 1.5,\n border: 1,\n borderColor: 'warning.main',\n borderRadius: 1,\n bgcolor: 'background.paper',\n }}\n >\n <Typography variant=\"body2\" sx={{ color: 'text.primary' }}>\n {aiCreditsPromptText(prompt, noun)}\n </Typography>\n <Stack spacing={1} sx={{ mt: 1.5 }}>\n {choices.map((choice) => (\n <AiCreditsChoiceButton\n key={choice.key}\n choice={choice}\n busy={busy}\n {...(choice.key === 'upgrade' && orgSlug\n ? { href: aiCreditsBillingHref(orgSlug) }\n : { onClick: choice.key === 'smaller' ? onSmaller : onBuildWhatFits })}\n />\n ))}\n </Stack>\n </Box>\n )\n}\n\nexport default AiCreditsPromptNotice\n"],"names":["Box","Button","Stack","Typography","useId","aiCreditsChoices","aiCreditsPromptText","aiCreditsBillingHref","AiCreditsChoiceButton","choice","busy","href","onClick","detailId","fullWidth","size","variant","recommended","color","disabled","key","aria-label","label","aria-describedby","data-choice","sx","minHeight","px","py","display","flexDirection","alignItems","justifyContent","textAlign","textTransform","lineHeight","component","fontWeight","id","opacity","detail","AiCreditsPromptNotice","prompt","noun","orgSlug","onBuildWhatFits","onSmaller","choices","smaller","Boolean","upgrade","role","mt","p","border","borderColor","borderRadius","bgcolor","spacing","map"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;AAEA,SAASA,GAAG,EAAEC,MAAM,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAe;AAC9D,SAASC,KAAK,QAAQ,QAAO;AAC7B,SACEC,gBAAgB,EAChBC,mBAAmB,QAGd,iCAA6B;AACpC,SAASC,oBAAoB,QAAQ,oBAAgB;AA4BrD,SAASC,sBAAsB,EAC7BC,MAAM,EACNC,IAAI,EACJC,IAAI,EACJC,OAAO,EAMR;IACC,MAAMC,WAAW,GAAGT,QAAQ,OAAO,CAAC;IACpC,qBACE,MAACH;QACCa,SAAS;QACTC,MAAK;QACLC,SAASP,OAAOQ,WAAW,GAAG,cAAc;QAC5CC,OAAM;QACNC,UAAUT,QAAQD,OAAOW,GAAG,KAAK;QACjCC,cAAYZ,OAAOa,KAAK;QACxBC,oBAAkBV;QAClBW,eAAaf,OAAOW,GAAG;OAClBT,OAAO;QAAEA;IAAK,IAAI;QAAEC;IAAQ;QACjCa,IAAI;YACFC,WAAW;YACXC,IAAI;YACJC,IAAI;YACJC,SAAS;YACTC,eAAe;YACfC,YAAY;YACZC,gBAAgB;YAChBC,WAAW;YACXC,eAAe;YACfC,YAAY;QACd;;0BAEA,KAAChC;gBAAWiC,WAAU;gBAAOpB,SAAQ;gBAAQS,IAAI;oBAAEY,YAAY;oBAAKnB,OAAO;gBAAU;0BAClFT,OAAOa,KAAK;;0BAEf,KAACnB;gBAAWmC,IAAIzB;gBAAUuB,WAAU;gBAAOpB,SAAQ;gBAAUS,IAAI;oBAAEP,OAAO;oBAAWqB,SAAS;gBAAI;0BAC/F9B,OAAO+B,MAAM;;;;AAItB;AAEA,OAAO,SAASC,sBAAsB,EACpCC,MAAM,EACNC,IAAI,EACJC,OAAO,EACPlC,OAAO,KAAK,EACZmC,eAAe,EACfC,SAAS,EACY;IACrB,MAAMC,UAAU1C,iBAAiBqC,QAAQ;QAAEM,SAASC,QAAQH;QAAYI,SAASD,QAAQL;IAAS;IAClG,qBACE,MAAC5C;QACCmD,MAAK;QACL9B,cAAW;QACXI,IAAI;YACF2B,IAAI;YACJC,GAAG;YACHC,QAAQ;YACRC,aAAa;YACbC,cAAc;YACdC,SAAS;QACX;;0BAEA,KAACtD;gBAAWa,SAAQ;gBAAQS,IAAI;oBAAEP,OAAO;gBAAe;0BACrDZ,oBAAoBoC,QAAQC;;0BAE/B,KAACzC;gBAAMwD,SAAS;gBAAGjC,IAAI;oBAAE2B,IAAI;gBAAI;0BAC9BL,QAAQY,GAAG,CAAC,CAAClD,uBACZ,KAACD;wBAECC,QAAQA;wBACRC,MAAMA;uBACDD,OAAOW,GAAG,KAAK,aAAawB,UAC7B;wBAAEjC,MAAMJ,qBAAqBqC;oBAAS,IACtC;wBAAEhC,SAASH,OAAOW,GAAG,KAAK,YAAY0B,YAAYD;oBAAgB,IALjEpC,OAAOW,GAAG;;;;AAW3B;AAEA,eAAeqB,sBAAqB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token';
|
|
2
|
+
import { type ButtonProps } from '@mui/material';
|
|
3
|
+
import { type ReactNode } from 'react';
|
|
4
|
+
import { type AiJobSummary } from '../model/ai-jobs.types';
|
|
5
|
+
/**
|
|
6
|
+
* Cancel an AI job, after saying what it does (AGL-3616). One confirm dialog
|
|
7
|
+
* and one request for every surface that offers Cancel — the job's page, a
|
|
8
|
+
* row of the site's AI jobs list, and the AI jobs list the top-bar chip
|
|
9
|
+
* opens — through the cancel door the Assist panel's list always used.
|
|
10
|
+
*
|
|
11
|
+
* `useAiJobCancel` owns the dialog: `ask(job)` opens it, Keep building
|
|
12
|
+
* closes it, and Cancel job posts the cancel and hands the job the door
|
|
13
|
+
* answered with to `onJob`, so the surface shows "Stopping…" or "Canceled"
|
|
14
|
+
* without waiting for its stream. A refusal stays in the dialog, in the
|
|
15
|
+
* door's own words.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useAiJobCancel({ user, orgId, onJob, }: {
|
|
18
|
+
user: MaybeTokenSource;
|
|
19
|
+
orgId: string | null;
|
|
20
|
+
onJob?: (job: AiJobSummary) => void;
|
|
21
|
+
}): {
|
|
22
|
+
ask: (job: AiJobSummary) => void;
|
|
23
|
+
busyJobId: string | null;
|
|
24
|
+
dialog: ReactNode;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The Cancel button: enabled while the job can still be stopped, and
|
|
28
|
+
* disabled with the reason as its tooltip once it is done, failed, canceled
|
|
29
|
+
* or already stopping.
|
|
30
|
+
*/
|
|
31
|
+
export declare function AiJobCancelButton({ job, user, orgId, onJob, size, variant, }: {
|
|
32
|
+
job: AiJobSummary;
|
|
33
|
+
user: MaybeTokenSource;
|
|
34
|
+
orgId: string | null;
|
|
35
|
+
onJob?: (job: AiJobSummary) => void;
|
|
36
|
+
size?: ButtonProps['size'];
|
|
37
|
+
variant?: ButtonProps['variant'];
|
|
38
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
|
+
import { Alert, Box, Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Tooltip } from "@mui/material";
|
|
19
|
+
import { useCallback, useRef, useState } from "react";
|
|
20
|
+
import { AI_JOB_CANCEL_CONFIRM_COPY, AI_JOB_CANCEL_TITLE, aiJobCancelBlockedReason } from "../model/ai-job-cancel-copy.js";
|
|
21
|
+
import { AI_JOB_TERMINAL_STATUSES } from "../model/ai-jobs.types.js";
|
|
22
|
+
import { cancelAiJobRequest } from "./ai-job-requests.js";
|
|
23
|
+
/**
|
|
24
|
+
* Cancel an AI job, after saying what it does (AGL-3616). One confirm dialog
|
|
25
|
+
* and one request for every surface that offers Cancel — the job's page, a
|
|
26
|
+
* row of the site's AI jobs list, and the AI jobs list the top-bar chip
|
|
27
|
+
* opens — through the cancel door the Assist panel's list always used.
|
|
28
|
+
*
|
|
29
|
+
* `useAiJobCancel` owns the dialog: `ask(job)` opens it, Keep building
|
|
30
|
+
* closes it, and Cancel job posts the cancel and hands the job the door
|
|
31
|
+
* answered with to `onJob`, so the surface shows "Stopping…" or "Canceled"
|
|
32
|
+
* without waiting for its stream. A refusal stays in the dialog, in the
|
|
33
|
+
* door's own words.
|
|
34
|
+
*/ export function useAiJobCancel({ user, orgId, onJob }) {
|
|
35
|
+
var _ref;
|
|
36
|
+
const [target, setTarget] = useState(null);
|
|
37
|
+
const [busy, setBusy] = useState(false);
|
|
38
|
+
const [error, setError] = useState(null);
|
|
39
|
+
const onJobRef = useRef(onJob);
|
|
40
|
+
onJobRef.current = onJob;
|
|
41
|
+
const ask = useCallback((job)=>{
|
|
42
|
+
if (aiJobCancelBlockedReason(job)) return;
|
|
43
|
+
setError(null);
|
|
44
|
+
setTarget(job);
|
|
45
|
+
}, []);
|
|
46
|
+
const close = useCallback(()=>{
|
|
47
|
+
if (busy) return;
|
|
48
|
+
setTarget(null);
|
|
49
|
+
setError(null);
|
|
50
|
+
}, [
|
|
51
|
+
busy
|
|
52
|
+
]);
|
|
53
|
+
const confirm = useCallback(async ()=>{
|
|
54
|
+
if (!target || !orgId) return;
|
|
55
|
+
setBusy(true);
|
|
56
|
+
setError(null);
|
|
57
|
+
const { job, error: refused } = await cancelAiJobRequest(user, orgId, target.id);
|
|
58
|
+
setBusy(false);
|
|
59
|
+
if (job) onJobRef.current == null ? void 0 : onJobRef.current.call(onJobRef, job);
|
|
60
|
+
if (refused) {
|
|
61
|
+
setError(refused);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
setTarget(null);
|
|
65
|
+
}, [
|
|
66
|
+
target,
|
|
67
|
+
orgId,
|
|
68
|
+
user
|
|
69
|
+
]);
|
|
70
|
+
const dialog = /*#__PURE__*/ _jsxs(Dialog, {
|
|
71
|
+
open: target !== null,
|
|
72
|
+
onClose: close,
|
|
73
|
+
"aria-labelledby": "ai-job-cancel-title",
|
|
74
|
+
maxWidth: "xs",
|
|
75
|
+
fullWidth: true,
|
|
76
|
+
children: [
|
|
77
|
+
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
78
|
+
id: "ai-job-cancel-title",
|
|
79
|
+
children: AI_JOB_CANCEL_TITLE
|
|
80
|
+
}),
|
|
81
|
+
/*#__PURE__*/ _jsxs(DialogContent, {
|
|
82
|
+
children: [
|
|
83
|
+
/*#__PURE__*/ _jsx(DialogContentText, {
|
|
84
|
+
children: AI_JOB_CANCEL_CONFIRM_COPY
|
|
85
|
+
}),
|
|
86
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
87
|
+
severity: "warning",
|
|
88
|
+
sx: {
|
|
89
|
+
mt: 2
|
|
90
|
+
},
|
|
91
|
+
children: error
|
|
92
|
+
}) : null
|
|
93
|
+
]
|
|
94
|
+
}),
|
|
95
|
+
/*#__PURE__*/ _jsxs(DialogActions, {
|
|
96
|
+
children: [
|
|
97
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
98
|
+
onClick: close,
|
|
99
|
+
disabled: busy,
|
|
100
|
+
children: 'Keep building'
|
|
101
|
+
}),
|
|
102
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
103
|
+
color: "error",
|
|
104
|
+
variant: "contained",
|
|
105
|
+
onClick: ()=>void confirm(),
|
|
106
|
+
disabled: busy || !orgId,
|
|
107
|
+
children: busy ? 'Canceling…' : 'Cancel job'
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
ask,
|
|
115
|
+
busyJobId: busy ? (_ref = target == null ? void 0 : target.id) != null ? _ref : null : null,
|
|
116
|
+
dialog
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The Cancel button: enabled while the job can still be stopped, and
|
|
121
|
+
* disabled with the reason as its tooltip once it is done, failed, canceled
|
|
122
|
+
* or already stopping.
|
|
123
|
+
*/ export function AiJobCancelButton({ job, user, orgId, onJob, size = 'medium', variant = 'outlined' }) {
|
|
124
|
+
const { ask, busyJobId, dialog } = useAiJobCancel({
|
|
125
|
+
user,
|
|
126
|
+
orgId,
|
|
127
|
+
onJob
|
|
128
|
+
});
|
|
129
|
+
const blocked = aiJobCancelBlockedReason(job);
|
|
130
|
+
const stopping = Boolean(job.cancelRequested) && !AI_JOB_TERMINAL_STATUSES.includes(job.status);
|
|
131
|
+
const button = /*#__PURE__*/ _jsx(Button, {
|
|
132
|
+
size: size,
|
|
133
|
+
variant: variant,
|
|
134
|
+
color: "error",
|
|
135
|
+
disabled: Boolean(blocked) || busyJobId === job.id || !orgId,
|
|
136
|
+
onClick: ()=>ask(job),
|
|
137
|
+
children: stopping ? 'Stopping…' : 'Cancel'
|
|
138
|
+
});
|
|
139
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
140
|
+
children: [
|
|
141
|
+
blocked ? /*#__PURE__*/ _jsx(Tooltip, {
|
|
142
|
+
title: blocked,
|
|
143
|
+
children: /*#__PURE__*/ _jsx(Box, {
|
|
144
|
+
component: "span",
|
|
145
|
+
sx: {
|
|
146
|
+
display: 'inline-flex'
|
|
147
|
+
},
|
|
148
|
+
children: button
|
|
149
|
+
})
|
|
150
|
+
}) : button,
|
|
151
|
+
dialog
|
|
152
|
+
]
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=ai-job-cancel.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-cancel.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type { MaybeTokenSource } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Alert,\n Box,\n Button,\n type ButtonProps,\n Dialog,\n DialogActions,\n DialogContent,\n DialogContentText,\n DialogTitle,\n Tooltip,\n} from '@mui/material'\nimport { type ReactNode, useCallback, useRef, useState } from 'react'\nimport {\n AI_JOB_CANCEL_CONFIRM_COPY,\n AI_JOB_CANCEL_TITLE,\n aiJobCancelBlockedReason,\n} from '../model/ai-job-cancel-copy'\nimport { AI_JOB_TERMINAL_STATUSES, type AiJobSummary } from '../model/ai-jobs.types'\nimport { cancelAiJobRequest } from './ai-job-requests'\n\n/**\n * Cancel an AI job, after saying what it does (AGL-3616). One confirm dialog\n * and one request for every surface that offers Cancel — the job's page, a\n * row of the site's AI jobs list, and the AI jobs list the top-bar chip\n * opens — through the cancel door the Assist panel's list always used.\n *\n * `useAiJobCancel` owns the dialog: `ask(job)` opens it, Keep building\n * closes it, and Cancel job posts the cancel and hands the job the door\n * answered with to `onJob`, so the surface shows \"Stopping…\" or \"Canceled\"\n * without waiting for its stream. A refusal stays in the dialog, in the\n * door's own words.\n */\nexport function useAiJobCancel({\n user,\n orgId,\n onJob,\n}: {\n user: MaybeTokenSource\n orgId: string | null\n onJob?: (job: AiJobSummary) => void\n}): { ask: (job: AiJobSummary) => void; busyJobId: string | null; dialog: ReactNode } {\n const [target, setTarget] = useState<AiJobSummary | null>(null)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const onJobRef = useRef(onJob)\n onJobRef.current = onJob\n\n const ask = useCallback((job: AiJobSummary) => {\n if (aiJobCancelBlockedReason(job)) return\n setError(null)\n setTarget(job)\n }, [])\n const close = useCallback(() => {\n if (busy) return\n setTarget(null)\n setError(null)\n }, [busy])\n const confirm = useCallback(async () => {\n if (!target || !orgId) return\n setBusy(true)\n setError(null)\n const { job, error: refused } = await cancelAiJobRequest(user, orgId, target.id)\n setBusy(false)\n if (job) onJobRef.current?.(job)\n if (refused) {\n setError(refused)\n return\n }\n setTarget(null)\n }, [target, orgId, user])\n\n const dialog = (\n <Dialog open={target !== null} onClose={close} aria-labelledby=\"ai-job-cancel-title\" maxWidth=\"xs\" fullWidth>\n <DialogTitle id=\"ai-job-cancel-title\">{AI_JOB_CANCEL_TITLE}</DialogTitle>\n <DialogContent>\n <DialogContentText>{AI_JOB_CANCEL_CONFIRM_COPY}</DialogContentText>\n {error ? (\n <Alert severity=\"warning\" sx={{ mt: 2 }}>\n {error}\n </Alert>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={close} disabled={busy}>\n {'Keep building'}\n </Button>\n <Button color=\"error\" variant=\"contained\" onClick={() => void confirm()} disabled={busy || !orgId}>\n {busy ? 'Canceling…' : 'Cancel job'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n return { ask, busyJobId: busy ? (target?.id ?? null) : null, dialog }\n}\n\n/**\n * The Cancel button: enabled while the job can still be stopped, and\n * disabled with the reason as its tooltip once it is done, failed, canceled\n * or already stopping.\n */\nexport function AiJobCancelButton({\n job,\n user,\n orgId,\n onJob,\n size = 'medium',\n variant = 'outlined',\n}: {\n job: AiJobSummary\n user: MaybeTokenSource\n orgId: string | null\n onJob?: (job: AiJobSummary) => void\n size?: ButtonProps['size']\n variant?: ButtonProps['variant']\n}) {\n const { ask, busyJobId, dialog } = useAiJobCancel({ user, orgId, onJob })\n const blocked = aiJobCancelBlockedReason(job)\n const stopping = Boolean(job.cancelRequested) && !AI_JOB_TERMINAL_STATUSES.includes(job.status)\n const button = (\n <Button\n size={size}\n variant={variant}\n color=\"error\"\n disabled={Boolean(blocked) || busyJobId === job.id || !orgId}\n onClick={() => ask(job)}\n >\n {stopping ? 'Stopping…' : 'Cancel'}\n </Button>\n )\n return (\n <>\n {blocked ? (\n <Tooltip title={blocked}>\n {/* A disabled button fires no pointer events; the span carries the tooltip. */}\n <Box component=\"span\" sx={{ display: 'inline-flex' }}>\n {button}\n </Box>\n </Tooltip>\n ) : (\n button\n )}\n {dialog}\n </>\n )\n}\n"],"names":["Alert","Box","Button","Dialog","DialogActions","DialogContent","DialogContentText","DialogTitle","Tooltip","useCallback","useRef","useState","AI_JOB_CANCEL_CONFIRM_COPY","AI_JOB_CANCEL_TITLE","aiJobCancelBlockedReason","AI_JOB_TERMINAL_STATUSES","cancelAiJobRequest","useAiJobCancel","user","orgId","onJob","target","setTarget","busy","setBusy","error","setError","onJobRef","current","ask","job","close","confirm","refused","id","dialog","open","onClose","aria-labelledby","maxWidth","fullWidth","severity","sx","mt","onClick","disabled","color","variant","busyJobId","AiJobCancelButton","size","blocked","stopping","Boolean","cancelRequested","includes","status","button","title","component","display"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
16
16
|
* See the License for the specific language governing permissions and
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/ import { AI_BUILD_PLAN_CREATION_NOUNS, AI_BUILD_PLAN_EMBED_HOST_NAMES, isAiPlanNewRef } from "../model/ai-build-plan.js";
|
|
19
|
-
import { aiBuildSmaller, aiJobCreditRange } from "../model/ai-build-job.js";
|
|
19
|
+
import { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from "../model/ai-build-job.js";
|
|
20
20
|
import { aiCreditRangeText, aiCreditsPromptFor } from "../model/ai-credit-estimate.js";
|
|
21
21
|
import { aiFreeCreditsResetLabel } from "../model/ai-site-job.js";
|
|
22
22
|
import { AiCreditsPromptNotice } from "./ai-credits-prompt.component.js";
|
|
@@ -96,6 +96,8 @@ export function AiJobPlan({ job, onResume, busy = false, staff = false, user, or
|
|
|
96
96
|
// the home page first, or upgrade — never a refusal with no way on.
|
|
97
97
|
const freeCredits = (_ref = review == null ? void 0 : review.freeCredits) != null ? _ref : null;
|
|
98
98
|
const prompt = plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null;
|
|
99
|
+
// A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.
|
|
100
|
+
const pageCapNote = plan && waiting && review.reason === 'plan' && job.kind === 'build' ? aiBuildFreePageCapNote(plan, Boolean(freeCredits)) : null;
|
|
99
101
|
const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan';
|
|
100
102
|
const publishing = offersPublish && publish ? {
|
|
101
103
|
publish: true
|
|
@@ -229,6 +231,15 @@ export function AiJobPlan({ job, onResume, busy = false, staff = false, user, or
|
|
|
229
231
|
freeCredits && !prompt ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.` : ''
|
|
230
232
|
]
|
|
231
233
|
}),
|
|
234
|
+
pageCapNote && /*#__PURE__*/ _jsx(Typography, {
|
|
235
|
+
variant: "caption",
|
|
236
|
+
color: "text.secondary",
|
|
237
|
+
sx: {
|
|
238
|
+
display: 'block',
|
|
239
|
+
mt: 0.5
|
|
240
|
+
},
|
|
241
|
+
children: pageCapNote
|
|
242
|
+
}),
|
|
232
243
|
waiting && review.retryRefusal && review.reason !== 'plan' && /*#__PURE__*/ _jsx(Typography, {
|
|
233
244
|
variant: "caption",
|
|
234
245
|
color: "text.secondary",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AI_BUILD_PLAN_CREATION_NOUNS,\n AI_BUILD_PLAN_EMBED_HOST_NAMES,\n isAiPlanNewRef,\n type AiBuildPlanEmbed,\n} from '../model/ai-build-plan'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport { aiBuildOpNoun } from '../model/ai-build-progress'\nimport { aiJobConfirmingOwnPlan } from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n/**\n * A third-party player the plan lists, with what it costs the page, read\n * before the member confirms it (rule 16, AGL-3433). The cost is the\n * platform's sentence, never the model's: the player is framed lazily, so its\n * host's code loads when a visitor reaches it, whether or not they press play.\n */\nexport function aiPlanEmbedLine(\n embed: AiBuildPlanEmbed,\n named: (ref: string) => string,\n): string {\n const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host]\n const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where\n const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste'\n return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`\n}\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n /** A reference as a person reads it: the record's name, or what the plan creates. */\n const named = (ref: string | null): string =>\n !ref\n ? ''\n : isAiPlanNewRef(ref)\n ? ref.slice('new:'.length)\n : (plan?.labels[ref] ?? ref)\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'}\n </Typography>\n {plan.reuse.map((entry, index) => (\n <Typography key={`reuse-${index}`} variant=\"body2\" role=\"listitem\">\n Reuses the {entry.kind === 'screen' ? 'page' : entry.kind} {named(entry.id)} — {entry.purpose}\n </Typography>\n ))}\n {plan.create.map((entry, index) => (\n <Typography key={`create-${index}`} variant=\"body2\" role=\"listitem\">\n Creates the {AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun} {entry.name}\n {entry.duplicateOf\n ? `, from a copy of ${named(entry.duplicateOf)}`\n : ''}{' '}\n — {entry.why}\n </Typography>\n ))}\n {plan.screens.map((screen, index) => (\n <Typography key={`screen-${index}`} variant=\"body2\" role=\"listitem\">\n {screen.record\n ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…`\n : `Builds the page ${screen.title} at ${screen.slug}`}\n {screen.duplicateOf\n ? `, from a copy of ${named(screen.duplicateOf)}`\n : ''}\n {screen.layout ? ` in ${named(screen.layout)}` : ''}\n {screen.sections.length\n ? `: ${screen.sections.map((section) => section.name).join(', ')}`\n : ''}\n </Typography>\n ))}\n {(plan.items ?? []).map((item) => (\n <Typography key={`item-${item.slot}`} variant=\"body2\" role=\"listitem\">\n {`Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`}\n {item.why ? ` — ${item.why}` : ''}\n </Typography>\n ))}\n {(plan.embeds ?? []).map((embed, index) => (\n <Typography key={`embed-${index}`} variant=\"body2\" role=\"listitem\">\n {aiPlanEmbedLine(embed, named)}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["AI_BUILD_PLAN_CREATION_NOUNS","AI_BUILD_PLAN_EMBED_HOST_NAMES","isAiPlanNewRef","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","aiBuildOpNoun","aiJobConfirmingOwnPlan","aiSiteStarterFallbackOffered","AiSiteStarterFallback","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","aiPlanEmbedLine","embed","named","host","link","url","asked","AiJobPlan","job","onResume","busy","staff","user","orgSlug","plan","detailsOpen","setDetailsOpen","publish","setPublish","details","ref","slice","labels","waiting","status","range","kind","freeCredits","prompt","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","reuse","entry","index","purpose","create","noun","duplicateOf","why","screens","screen","record","title","dataset","base","slug","layout","sections","section","items","item","op","toLowerCase","slot","embeds","detail","component","my","pl","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","disabled","Boolean","undefined"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/ai-job-plan.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AI_BUILD_PLAN_CREATION_NOUNS,\n AI_BUILD_PLAN_EMBED_HOST_NAMES,\n isAiPlanNewRef,\n type AiBuildPlanEmbed,\n} from '../model/ai-build-plan'\nimport type { AiJobReview, AiJobSummary } from '../model/ai-jobs.types'\nimport { aiBuildFreePageCapNote, aiBuildSmaller, aiJobCreditRange } from '../model/ai-build-job'\nimport { aiCreditRangeText, aiCreditsPromptFor } from '../model/ai-credit-estimate'\nimport { aiFreeCreditsResetLabel } from '../model/ai-site-job'\nimport { AiCreditsPromptNotice } from './ai-credits-prompt.component'\nimport type { AiJobResumeOptions } from './ai-job-requests'\nimport { aiBuildOpNoun } from '../model/ai-build-progress'\nimport { aiJobConfirmingOwnPlan } from '../model/ai-job-activity'\nimport { aiSiteStarterFallbackOffered } from '../model/ai-job-failure-copy'\nimport { AiSiteStarterFallback } from './ai-site-starter-fallback.component'\nimport { Box, Button, Checkbox, Collapse, FormControlLabel, Stack, Typography } from '@mui/material'\nimport { useState } from 'react'\n\n/**\n * A job's plan and what it waits for (AGL-2935), inside the AI jobs drawer\n * and the dialog that started the job (AGL-3593): what the job reuses from\n * the site, what it creates and why, the screens it builds — and, while the\n * job waits for a person, the one button that confirms the plan or tries a\n * refused step again. Both send the same request (`resumeAiJobRequest`);\n * this renders.\n */\nexport interface AiJobPlanProps {\n job: AiJobSummary\n /**\n * Confirms the plan, or tries the refused step again. A build whose request\n * asked to publish confirms with `publish` when its box is ticked (AGL-3616).\n */\n onResume: (job: AiJobSummary, options?: AiJobResumeOptions) => void\n /** A resume for this job is in flight. */\n busy?: boolean\n /**\n * The viewer is staff (AGL-3078), who can open where a refused answer broke\n * its rules and the outline of those parts, to tell a shape the rules should\n * allow from an answer that ignored its re-ask. A member reads the findings.\n */\n staff?: boolean\n /**\n * The signed-in user, for \"Use the starter site instead\" on a guided start\n * that did not work out (AGL-3594); the action is drawn only when given.\n */\n user?: Parameters<typeof AiSiteStarterFallback>[0]['user']\n /** The workspace's path slug, for the Upgrade a Free build past what is left offers (AGL-3722). */\n orgSlug?: string | null\n}\n\n/**\n * Where a refused answer broke its rules, and the outline of those parts, as\n * lines staff read (AGL-3078): each finding with the nodes or plan entries it\n * names, then each outlined node indented by its depth, with its element, a\n * Grid's layout as written, and the names of what it sets and holds.\n */\nexport function aiJobReviewDetails(review: AiJobReview | null): string[] {\n if (review?.reason !== 'doctrine') return []\n const lines = review.findings.flatMap((finding) => {\n const where = finding.nodeIds?.length\n ? `nodes ${finding.nodeIds.join(', ')}`\n : finding.paths?.length\n ? `at ${finding.paths.join(', ')}`\n : null\n return where ? [`${finding.rule === null ? '' : `Rule ${finding.rule} `}${finding.code}: ${where}`] : []\n })\n for (const node of review.outline ?? []) {\n lines.push(\n [\n `${' '.repeat(node.depth)}${node.id} ${node.componentId}`,\n ...Object.entries(node.grid ?? {}).map(([name, value]) => `${name}=${JSON.stringify(value)}`),\n ...(node.props.length ? [`props ${node.props.join(', ')}`] : []),\n ...(node.sx?.length ? [`sx ${node.sx.join(', ')}`] : []),\n ...(node.children.length ? [`holds ${node.children.join(', ')}`] : []),\n ].join(' · '),\n )\n }\n return lines\n}\n\n/**\n * A third-party player the plan lists, with what it costs the page, read\n * before the member confirms it (rule 16, AGL-3433). The cost is the\n * platform's sentence, never the model's: the player is framed lazily, so its\n * host's code loads when a visitor reaches it, whether or not they press play.\n */\nexport function aiPlanEmbedLine(\n embed: AiBuildPlanEmbed,\n named: (ref: string) => string,\n): string {\n const host = AI_BUILD_PLAN_EMBED_HOST_NAMES[embed.host]\n const where = isAiPlanNewRef(embed.where) ? `the component ${named(embed.where)}` : embed.where\n const link = embed.url ? ` playing ${embed.url}` : ', its link left for you to paste'\n return `Embeds a ${host} player on ${where}${link}, as you asked (“${embed.asked}”). It loads ${host}’s own code when a visitor reaches it, whether or not they press play.`\n}\n\nexport function AiJobPlan({\n job,\n onResume,\n busy = false,\n staff = false,\n user,\n orgSlug,\n}: AiJobPlanProps): JSX.Element | null {\n const [detailsOpen, setDetailsOpen] = useState(false)\n // Unticked until the person ticks it: a build publishes only when its\n // request asked AND they confirm it here (AGL-3616).\n const [publish, setPublish] = useState(false)\n const { plan, review } = job\n if (!plan && !review) return null\n const details = staff ? aiJobReviewDetails(review) : []\n /** A reference as a person reads it: the record's name, or what the plan creates. */\n const named = (ref: string | null): string =>\n !ref\n ? ''\n : isAiPlanNewRef(ref)\n ? ref.slice('new:'.length)\n : (plan?.labels[ref] ?? ref)\n // A plan the machine is confirming itself is not one to confirm (AGL-3596).\n const waiting = job.status === 'needs_review' && review !== null && !aiJobConfirmingOwnPlan(job)\n // The guard rail (AGL-2911): what the plan is estimated to cost is read\n // before it is confirmed, not after it has been spent. An estimate, and\n // said to be one: what it is likely to cost — what builds like it measured\n // — and its ceiling, every pass at its reserve (AGL-3722). A page job\n // counts the creations it builds before its page (AGL-3031).\n const range = plan && waiting && review.reason === 'plan' ? aiJobCreditRange(job.kind, plan) : null\n // A Free build past what is left asks first (AGL-3722): build what fits,\n // the home page first, or upgrade — never a refusal with no way on.\n const freeCredits = review?.freeCredits ?? null\n const prompt =\n plan && range && job.kind === 'build' ? aiCreditsPromptFor(range, freeCredits, aiBuildSmaller(plan)) : null\n // A Free build at its page cap says so (AGL-3722): pages past it were left for a later request.\n const pageCapNote =\n plan && waiting && review.reason === 'plan' && job.kind === 'build'\n ? aiBuildFreePageCapNote(plan, Boolean(freeCredits))\n : null\n const offersPublish = job.kind === 'build' && job.publishAsked === true && waiting && review.reason === 'plan'\n const publishing = offersPublish && publish ? { publish: true } : {}\n return (\n <Box sx={{ mt: 1 }}>\n {plan && (\n <Stack spacing={0.5} role=\"list\" aria-label=\"Plan\">\n <Typography variant=\"caption\" color=\"text.secondary\">\n {plan.status === 'confirmed' ? 'Confirmed plan' : 'Proposed plan'}\n </Typography>\n {plan.reuse.map((entry, index) => (\n <Typography key={`reuse-${index}`} variant=\"body2\" role=\"listitem\">\n Reuses the {entry.kind === 'screen' ? 'page' : entry.kind} {named(entry.id)} — {entry.purpose}\n </Typography>\n ))}\n {plan.create.map((entry, index) => (\n <Typography key={`create-${index}`} variant=\"body2\" role=\"listitem\">\n Creates the {AI_BUILD_PLAN_CREATION_NOUNS[entry.kind].noun} {entry.name}\n {entry.duplicateOf\n ? `, from a copy of ${named(entry.duplicateOf)}`\n : ''}{' '}\n — {entry.why}\n </Typography>\n ))}\n {plan.screens.map((screen, index) => (\n <Typography key={`screen-${index}`} variant=\"body2\" role=\"listitem\">\n {screen.record\n ? `Builds the record template ${screen.title}, a page per record of ${named(screen.record.dataset)} at /${screen.record.base}/…`\n : `Builds the page ${screen.title} at ${screen.slug}`}\n {screen.duplicateOf\n ? `, from a copy of ${named(screen.duplicateOf)}`\n : ''}\n {screen.layout ? ` in ${named(screen.layout)}` : ''}\n {screen.sections.length\n ? `: ${screen.sections.map((section) => section.name).join(', ')}`\n : ''}\n </Typography>\n ))}\n {(plan.items ?? []).map((item) => (\n <Typography key={`item-${item.slot}`} variant=\"body2\" role=\"listitem\">\n {`Makes the ${aiBuildOpNoun(item.op).toLowerCase()} ${item.name}`}\n {item.why ? ` — ${item.why}` : ''}\n </Typography>\n ))}\n {(plan.embeds ?? []).map((embed, index) => (\n <Typography key={`embed-${index}`} variant=\"body2\" role=\"listitem\">\n {aiPlanEmbedLine(embed, named)}\n </Typography>\n ))}\n </Stack>\n )}\n {/*\n A review written for the member (AGL-3594) carries the checks' own\n sentence as `detail`: its findings are then staff reading too, and the\n member reads the job's one sentence alone.\n */}\n {staff && review?.detail && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 0.5 }}>\n {review.detail}\n </Typography>\n )}\n {review?.reason === 'doctrine' && review.findings.length > 0 && (staff || !review.detail) && (\n <Box\n component=\"ul\"\n sx={{ my: 0.5, pl: 2.5 }}\n aria-label=\"Building rules broken\"\n >\n {review.findings.map((finding, index) => (\n <Typography\n key={`finding-${index}`}\n component=\"li\"\n variant=\"caption\"\n >\n {finding.message}\n </Typography>\n ))}\n </Box>\n )}\n {details.length > 0 && (\n <Box sx={{ mt: 0.5 }}>\n <Button\n size=\"small\"\n aria-expanded={detailsOpen}\n onClick={() => setDetailsOpen((prior) => !prior)}\n >\n {detailsOpen ? 'Hide what was refused' : 'Show what was refused'}\n </Button>\n <Collapse in={detailsOpen} unmountOnExit>\n <Typography\n variant=\"caption\"\n component=\"pre\"\n aria-label=\"What was refused\"\n sx={{ m: 0, fontFamily: 'monospace', whiteSpace: 'pre', overflowX: 'auto' }}\n >\n {details.join('\\n')}\n </Typography>\n </Collapse>\n </Box>\n )}\n {range && range.ceiling > 0 && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1 }}\n >\n {`Estimated cost: ${aiCreditRangeText(range)}. What it costs is what its steps spend.`}\n {freeCredits && !prompt\n ? ` You have ${freeCredits.left.toLocaleString('en-US')} of your free AI credits left this month, until ${aiFreeCreditsResetLabel(freeCredits.resetsOn)}.`\n : ''}\n </Typography>\n )}\n {pageCapNote && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {pageCapNote}\n </Typography>\n )}\n {waiting && review.retryRefusal && review.reason !== 'plan' && (\n <Typography variant=\"caption\" color=\"text.secondary\" component=\"div\" sx={{ mt: 1 }}>\n {review.retryRefusal}\n </Typography>\n )}\n {offersPublish && (\n <FormControlLabel\n sx={{ display: 'flex', mt: 1 }}\n control={<Checkbox size=\"small\" checked={publish} onChange={(event) => setPublish(event.target.checked)} />}\n label={<Typography variant=\"body2\">{'Publish the new pages when they are built'}</Typography>}\n />\n )}\n {waiting && prompt && (\n <AiCreditsPromptNotice\n prompt={prompt}\n noun=\"build\"\n orgSlug={orgSlug}\n busy={busy}\n onBuildWhatFits={() => onResume(job, { ...publishing, creditsConfirmed: true })}\n onSmaller={() => onResume(job, { ...publishing, creditsConfirmed: true, reduce: 'first-page' })}\n />\n )}\n {waiting && !prompt && (\n <Button\n size=\"small\"\n variant=\"contained\"\n // Disabled with its reason above when the Free allowance left\n // cannot pay for another try (AGL-3594).\n disabled={busy || (review.reason !== 'plan' && Boolean(review.retryRefusal))}\n onClick={() => onResume(job, offersPublish && publish ? publishing : undefined)}\n sx={{ mt: 1 }}\n >\n {review.reason === 'plan' ? 'Confirm plan' : 'Try again'}\n </Button>\n )}\n {/* A guided start that did not work out can take the starter instead (AGL-3594). */}\n {waiting && user && aiSiteStarterFallbackOffered(job) && <AiSiteStarterFallback job={job} user={user} />}\n </Box>\n )\n}\n\nexport default AiJobPlan\n"],"names":["AI_BUILD_PLAN_CREATION_NOUNS","AI_BUILD_PLAN_EMBED_HOST_NAMES","isAiPlanNewRef","aiBuildFreePageCapNote","aiBuildSmaller","aiJobCreditRange","aiCreditRangeText","aiCreditsPromptFor","aiFreeCreditsResetLabel","AiCreditsPromptNotice","aiBuildOpNoun","aiJobConfirmingOwnPlan","aiSiteStarterFallbackOffered","AiSiteStarterFallback","Box","Button","Checkbox","Collapse","FormControlLabel","Stack","Typography","useState","aiJobReviewDetails","review","reason","lines","findings","flatMap","finding","where","nodeIds","length","join","paths","rule","code","node","outline","push","repeat","depth","id","componentId","Object","entries","grid","map","name","value","JSON","stringify","props","sx","children","aiPlanEmbedLine","embed","named","host","link","url","asked","AiJobPlan","job","onResume","busy","staff","user","orgSlug","plan","detailsOpen","setDetailsOpen","publish","setPublish","details","ref","slice","labels","waiting","status","range","kind","freeCredits","prompt","pageCapNote","Boolean","offersPublish","publishAsked","publishing","mt","spacing","role","aria-label","variant","color","reuse","entry","index","purpose","create","noun","duplicateOf","why","screens","screen","record","title","dataset","base","slug","layout","sections","section","items","item","op","toLowerCase","slot","embeds","detail","component","my","pl","message","size","aria-expanded","onClick","prior","in","unmountOnExit","m","fontFamily","whiteSpace","overflowX","ceiling","display","left","toLocaleString","resetsOn","retryRefusal","control","checked","onChange","event","target","label","onBuildWhatFits","creditsConfirmed","onSmaller","reduce","disabled","undefined"],"mappings":"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"}
|