@aglyn/plugins-logic 1.0.0-beta.247 → 1.0.0-beta.249

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-logic",
3
- "version": "1.0.0-beta.247",
3
+ "version": "1.0.0-beta.249",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,13 +25,13 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.247",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.247",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.247",
31
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.247",
32
- "@aglyn/shared-util-timestamp": "1.0.0-beta.247",
33
- "@aglyn/tenant-data-admin": "1.0.0-beta.247",
34
- "@aglyn/tenant-feature-instance": "1.0.0-beta.247",
28
+ "@aglyn/aglyn": "1.0.0-beta.249",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.249",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.249",
31
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.249",
32
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.249",
33
+ "@aglyn/tenant-data-admin": "1.0.0-beta.249",
34
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.249",
35
35
  "@swc/helpers": "0.5.23"
36
36
  },
37
37
  "peerDependencies": {
@@ -34,7 +34,7 @@ import { collection, doc, getCountFromServer, getDocs, limit, query } from "fire
34
34
  import { useCallback, useEffect, useMemo, useState } from "react";
35
35
  import { useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
36
36
  import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
37
- import { formatParameterOptions, parseParameterOptions } from "../model/parameter-options.js";
37
+ import { ParameterChoicesEditor } from "./parameter-choices-editor.component.js";
38
38
  import WhereUsedDialog from "./where-used-dialog.component.js";
39
39
  import { FormulaBuilderButton } from "./formula-builder.component.js";
40
40
  import { formulaNames } from "../model/formula-names.js";
@@ -108,74 +108,118 @@ function emptyDraft() {
108
108
  /**
109
109
  * What a VISITOR meets for one parameter (AGL-3202): the label above the
110
110
  * input, what it starts with, and — for a question with fixed answers — the
111
- * choices. Empty fields are dropped from the definition rather than stored
112
- * as empty strings, so a function nobody has dressed for visitors saves
113
- * exactly the shape it always did.
111
+ * choices, one row each (AGL-3768). Empty fields are dropped from the
112
+ * definition rather than stored as empty strings, so a function nobody has
113
+ * dressed for visitors saves exactly the shape it always did.
114
114
  *
115
- * The choices keep their own text while being typed. Parsing every keystroke
116
- * back into the box would eat the space after a comma, and the colon after a
117
- * value, the moment they were typed.
115
+ * "Starts as" is picked, not typed, wherever there is a list to pick from:
116
+ * the choices when there are any, on or off for a true/false.
118
117
  */ function ParameterAudienceFields(props) {
119
- var _parameter_label, _parameter_defaultValue;
118
+ var _parameter_options, _parameter_label, _parameter_defaultValue;
120
119
  const { parameter, onChange } = props;
121
- const [choices, setChoices] = useState(()=>formatParameterOptions(parameter.options));
122
120
  const assign = (field, value)=>{
123
121
  const next = _extends({}, parameter);
124
122
  if (value) next[field] = value;
125
123
  else delete next[field];
126
124
  onChange(next);
127
125
  };
126
+ const options = (_parameter_options = parameter.options) != null ? _parameter_options : [];
127
+ const startsAsChoices = parameter.type === 'boolean' ? [
128
+ {
129
+ value: 'true',
130
+ label: 'On'
131
+ },
132
+ {
133
+ value: 'false',
134
+ label: 'Off'
135
+ }
136
+ ] : options.length ? options.map((option)=>{
137
+ var _option_label;
138
+ return {
139
+ value: option.value,
140
+ label: (_option_label = option.label) != null ? _option_label : option.value
141
+ };
142
+ }) : null;
128
143
  return /*#__PURE__*/ _jsxs(Stack, {
129
- direction: "row",
130
144
  spacing: 1,
131
- sx: {
132
- alignItems: 'center'
133
- },
134
145
  children: [
135
- /*#__PURE__*/ _jsx(Typography, {
136
- variant: "body2",
137
- color: "text.secondary",
146
+ /*#__PURE__*/ _jsxs(Stack, {
147
+ direction: "row",
148
+ spacing: 1,
138
149
  sx: {
139
- width: 110,
140
- flexShrink: 0
150
+ alignItems: 'center'
141
151
  },
142
- noWrap: true,
143
- children: parameter.name || '—'
144
- }),
145
- /*#__PURE__*/ _jsx(TextField, {
146
- label: "Label",
147
- placeholder: parameter.name,
148
- value: (_parameter_label = parameter.label) != null ? _parameter_label : '',
149
- onChange: (event)=>assign('label', event.target.value.slice(0, 80)),
150
- size: "small",
151
- sx: {
152
- flex: 2
153
- }
154
- }),
155
- /*#__PURE__*/ _jsx(TextField, {
156
- label: "Starts as",
157
- value: (_parameter_defaultValue = parameter.defaultValue) != null ? _parameter_defaultValue : '',
158
- onChange: (event)=>assign('defaultValue', event.target.value.slice(0, 120)),
159
- size: "small",
160
- sx: {
161
- flex: 1
162
- }
152
+ children: [
153
+ /*#__PURE__*/ _jsx(Typography, {
154
+ variant: "body2",
155
+ color: "text.secondary",
156
+ sx: {
157
+ width: 110,
158
+ flexShrink: 0
159
+ },
160
+ noWrap: true,
161
+ children: parameter.name || '—'
162
+ }),
163
+ /*#__PURE__*/ _jsx(TextField, {
164
+ label: "Label",
165
+ placeholder: parameter.name,
166
+ value: (_parameter_label = parameter.label) != null ? _parameter_label : '',
167
+ onChange: (event)=>assign('label', event.target.value.slice(0, 80)),
168
+ size: "small",
169
+ sx: {
170
+ flex: 2
171
+ }
172
+ }),
173
+ startsAsChoices ? /*#__PURE__*/ _jsxs(TextField, {
174
+ select: true,
175
+ label: "Starts as",
176
+ value: startsAsChoices.some((choice)=>choice.value === parameter.defaultValue) ? parameter.defaultValue : '',
177
+ onChange: (event)=>assign('defaultValue', event.target.value),
178
+ size: "small",
179
+ sx: {
180
+ flex: 1
181
+ },
182
+ children: [
183
+ /*#__PURE__*/ _jsx(MenuItem, {
184
+ value: "",
185
+ children: /*#__PURE__*/ _jsx("em", {
186
+ children: 'Nothing chosen'
187
+ })
188
+ }),
189
+ startsAsChoices.map((choice)=>/*#__PURE__*/ _jsx(MenuItem, {
190
+ value: choice.value,
191
+ children: choice.label
192
+ }, choice.value))
193
+ ]
194
+ }) : /*#__PURE__*/ _jsx(TextField, {
195
+ label: "Starts as",
196
+ value: (_parameter_defaultValue = parameter.defaultValue) != null ? _parameter_defaultValue : '',
197
+ onChange: (event)=>assign('defaultValue', parameter.type === 'number' ? event.target.value.replace(/[^0-9.-]/g, '') : event.target.value.slice(0, 120)),
198
+ slotProps: parameter.type === 'number' ? {
199
+ htmlInput: {
200
+ inputMode: 'decimal'
201
+ }
202
+ } : undefined,
203
+ size: "small",
204
+ sx: {
205
+ flex: 1
206
+ }
207
+ })
208
+ ]
163
209
  }),
164
- /*#__PURE__*/ _jsx(TextField, {
165
- label: "Choices",
166
- placeholder: "value: Label, value: Label",
167
- value: choices,
168
- onChange: (event)=>{
169
- setChoices(event.target.value);
170
- const options = parseParameterOptions(event.target.value);
210
+ parameter.type === 'boolean' ? null : /*#__PURE__*/ _jsx(ParameterChoicesEditor, {
211
+ parameterName: parameter.name,
212
+ type: parameter.type,
213
+ options: parameter.options,
214
+ onChange: (nextOptions)=>{
171
215
  const next = _extends({}, parameter);
172
- if (options.length) next.options = options;
216
+ if (nextOptions.length) next.options = nextOptions;
173
217
  else delete next.options;
218
+ // A start that is no longer a choice would preselect nothing.
219
+ if (nextOptions.length && next.defaultValue !== undefined && !nextOptions.some((option)=>option.value === next.defaultValue)) {
220
+ delete next.defaultValue;
221
+ }
174
222
  onChange(next);
175
- },
176
- size: "small",
177
- sx: {
178
- flex: 3
179
223
  }
180
224
  })
181
225
  ]
@@ -899,7 +943,7 @@ function emptyDraft() {
899
943
  /*#__PURE__*/ _jsx(Typography, {
900
944
  variant: "caption",
901
945
  color: "text.secondary",
902
- children: 'Used by a Function Widget on a page. A parameter with ' + 'choices is asked as a list, a number as a number box and ' + 'a true/false as a switch.'
946
+ children: 'Used by a Function Widget on a page. A parameter with ' + 'choices is asked as a list — Add choice gives it one — a ' + 'number as a number box and a true/false as a switch.'
903
947
  }),
904
948
  ((_ref8 = draft == null ? void 0 : draft.parameters) != null ? _ref8 : []).map((parameter, index)=>/*#__PURE__*/ _jsx(ParameterAudienceFields, {
905
949
  parameter: parameter,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/components/host-functions-card.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 {\n type AglynOrgBilling,\n checkQuota,\n evaluateHostFunction,\n FUNCTION_BUILTIN_NAMES,\n type FunctionComparator,\n functionGlobals,\n functionReferencedNames,\n type FunctionValueType,\n type HostFunction,\n type HostFunctionParameter,\n type HostVariable,\n pluginDocsHelp,\n VARIABLE_NAME_PATTERN,\n} from '@aglyn/aglyn'\n/*\n * The MODULE, not the barrel, for the two PURE helpers — every spec that\n * renders this card mocks `@aglyn/tenant-feature-instance` wholesale to stage\n * its Firestore hooks, and a query builder imported through that barrel\n * disappears under the mock. Neither of these is a hook.\n */\nimport {\n ceilingedWindow,\n collectionCeiling,\n} from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n IconButton,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n getCountFromServer,\n getDocs,\n limit,\n query,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostResourceApi,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\nimport {\n formatParameterOptions,\n parseParameterOptions,\n} from '../model/parameter-options'\nimport WhereUsedDialog from './where-used-dialog.component'\nimport { FormulaBuilderButton } from './formula-builder.component'\nimport { formulaNames } from '../model/formula-names'\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport {\n HOST_LOGIC_ZONE,\n LOGIC_FUNCTION_EDITOR_ZONE,\n type LogicProposal,\n} from './logic-zones'\nimport {\n fetchWhereUsed,\n summarizeDependents,\n type WhereUsedResult,\n} from '@aglyn/aglyn/app-utils/where-used'\n\n/**\n * How many functions the card reads.\n *\n * A CEILING, not a page size — see the query, which explains why this list\n * cannot be paged by the server without making the duplicate-name check lie.\n */\nconst FUNCTION_CEILING = 100\n\nexport interface HostFunctionsCardProps {\n hostId: string\n /** Resolved entitlement source for quota checks (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\nconst VALUE_TYPES: { value: FunctionValueType; label: string }[] = [\n { value: 'number', label: 'Number' },\n { value: 'text', label: 'Text' },\n { value: 'boolean', label: 'True/false' },\n]\n\nconst COMPARATORS: FunctionComparator[] = ['==', '!=', '<', '<=', '>', '>=']\n\ninterface FunctionDraft extends HostFunction {\n id: string | null\n}\n\nfunction emptyDraft(): FunctionDraft {\n return {\n id: null,\n name: '',\n parameters: [{ name: 'P1', type: 'number', required: true }],\n variables: [{ name: 'P3', type: 'number' }],\n operations: [\n {\n if: { left: '', comparator: '<=', right: '' },\n then: [{ set: '', expression: '' }],\n otherwise: [],\n },\n ],\n returnValue: '',\n }\n}\n\n/**\n * What a VISITOR meets for one parameter (AGL-3202): the label above the\n * input, what it starts with, and — for a question with fixed answers — the\n * choices. Empty fields are dropped from the definition rather than stored\n * as empty strings, so a function nobody has dressed for visitors saves\n * exactly the shape it always did.\n *\n * The choices keep their own text while being typed. Parsing every keystroke\n * back into the box would eat the space after a comma, and the colon after a\n * value, the moment they were typed.\n */\nfunction ParameterAudienceFields(props: {\n parameter: HostFunctionParameter\n onChange: (next: HostFunctionParameter) => void\n}) {\n const { parameter, onChange } = props\n const [choices, setChoices] = useState(() =>\n formatParameterOptions(parameter.options),\n )\n const assign = (field: 'label' | 'defaultValue', value: string) => {\n const next = { ...parameter }\n if (value) next[field] = value\n else delete next[field]\n onChange(next)\n }\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ width: 110, flexShrink: 0 }}\n noWrap\n >\n {parameter.name || '—'}\n </Typography>\n <TextField\n label=\"Label\"\n placeholder={parameter.name}\n value={parameter.label ?? ''}\n onChange={(event) => assign('label', event.target.value.slice(0, 80))}\n size=\"small\"\n sx={{ flex: 2 }}\n />\n <TextField\n label=\"Starts as\"\n value={parameter.defaultValue ?? ''}\n onChange={(event) =>\n assign('defaultValue', event.target.value.slice(0, 120))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <TextField\n label=\"Choices\"\n placeholder=\"value: Label, value: Label\"\n value={choices}\n onChange={(event) => {\n setChoices(event.target.value)\n const options = parseParameterOptions(event.target.value)\n const next = { ...parameter }\n if (options.length) next.options = options\n else delete next.options\n onChange(next)\n }}\n size=\"small\"\n sx={{ flex: 3 }}\n />\n </Stack>\n )\n}\n\n/** Small labelled row header matching the mockup's section styling. */\nfunction SectionLabel(props: { children: string }) {\n return (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {props.children}\n </Typography>\n )\n}\n\n/**\n * No-code function builder (Component Builder, AGL-92): the mockup's Edit\n * Function dialog — Parameters with required toggles, local Variables,\n * numbered conditional operation cards (If below is TRUE / Then do this /\n * Otherwise do this), a Return value select, and a test-run panel driving\n * the shared evaluator. Definitions persist to `hosts/{hostId}/functions`;\n * prop/event wiring lands with AGL-93.\n */\nexport function HostFunctionsCard(props: HostFunctionsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const createHostResource = useHostResourceApi()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { org } = props\n const {\n data: functionDocs,\n status: functionsStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing destructures a whole stored function into `draft`\n * and writes `{...definition}` back, so `merge: true` protects nothing —\n * the payload is literally every field of the definition. `parameters`\n * and `operations` are arrays, which a merge replaces wholesale rather\n * than diffing, so a cached seed does not lose one edit: it restores that\n * snapshot's entire logic body and parameter list, and every caller's\n * arguments are positional against the list it just reverted.\n */\n fromCache: functionsFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501) —\n * the same decision as the variables card beside it, for the same two\n * reasons.\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window is a\n * pseudo-random hundred that the `localeCompare` below dresses up as an\n * alphabetical list, and nothing said the list was bounded.\n *\n * `collectionCeiling` does not change WHICH hundred — document-id order is\n * what the bare cap already returned. What it changes is that the order is\n * NAMED, so the obvious next edit is caught: ordering on `name` would HIDE\n * every function written without one rather than mis-sorting the list, and\n * `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.functions` copies one only if the export carried it.\n *\n * The QUERY is not paged because `nameTaken` below tests the draft against\n * these rows: case-insensitive uniqueness is what keeps legacy\n * `{{fn:name(...)}}` resolution unambiguous (AGL-185), and on a ten-row\n * server page that check would compare a new function against a tenth of\n * the site and create the duplicate it exists to prevent.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'functions'),\n FUNCTION_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readFunctions, truncated: functionsTruncated } =\n ceilingedWindow<any>(functionDocs, FUNCTION_CEILING)\n // Sorting is safe here in a way it is not on a paged list: these rows are\n // the whole collection below the ceiling, not a slice of one.\n const functions = useMemo(\n () =>\n readFunctions\n .filter((definition: any) => !definition.deletedAt)\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [readFunctions],\n )\n // The page is a SLICE: the rows are already in hand and `nameTaken` needs\n // all of them.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleFunctions = useMemo(\n () => functions.slice(page * pageSize, page * pageSize + pageSize),\n [functions, page, pageSize],\n )\n /**\n * The function HEAD-COUNT is a server aggregate, not the length of the\n * capped listener (AGL-1716, the AGL-1706 shape) — the same fix as the\n * variables card beside it, for the same reason.\n *\n * The listener is `limit(100)` and `functions.length` fed\n * `checkQuota(org, 'functionsPerHost', …)`, whose bands are 1 / 10 / 50 /\n * 250 / 500 / 1,000. Everything from Business up sits above the window, so\n * on those plans the gate compared 100 against hundreds and could never\n * refuse, while `api/hosts/resources` counted the collection and did.\n *\n * UNFILTERED, matching that route's plain `collection('functions').count()`\n * — soft-deleted functions have always counted server-side, so this is the\n * card catching up with the verdict it exists to predict. Only a create\n * moves the number, so that is where it is re-read.\n */\n const [functionCountEpoch, setFunctionCountEpoch] = useState(0)\n const [serverFunctionCount, setServerFunctionCount] = useState<number | null>(\n null,\n )\n useEffect(() => {\n let active = true\n void getCountFromServer(collection(firestore, 'hosts', hostId, 'functions'))\n .then((snapshot) => {\n if (active) setServerFunctionCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the loaded rows — a LOWER bound and the prior\n // behaviour, never 0, which `checkQuota` would answer as \"no usage\"\n // on a site that is over its band.\n })\n return () => {\n active = false\n }\n }, [firestore, hostId, functionCountEpoch])\n const functionCount = serverFunctionCount ?? functions.length\n\n const [draft, setDraft] = useState<FunctionDraft | null>(null)\n\n // Where-used dialog (AGL-193).\n const [usage, setUsage] = useState<{\n name: string\n result: WhereUsedResult\n } | null>(null)\n const [usageLoading, setUsageLoading] = useState<string | null>(null)\n\n const [testArgs, setTestArgs] = useState<Record<string, string>>({})\n const [testResult, setTestResult] = useState<string | null>(null)\n\n const patch = useCallback(\n (updater: (previous: FunctionDraft) => FunctionDraft) =>\n setDraft((previous) => (previous ? updater(previous) : previous)),\n [],\n )\n\n /**\n * The shell's zone renderer (AGL-3603), for what other plugins add beside\n * Add function and inside a saved function's editor; `null` outside the\n * console shell.\n */\n const ExtensionZone = useConsoleWidgetSlot()\n /*\n * Opens a function another plugin proposed in this editor, unsaved: a new\n * one as Add function opens one — so the plan's cap is asked first — and a\n * change to a saved one in place of what the editor holds. Save is the\n * only write.\n */\n const propose = useCallback(\n (proposal: LogicProposal) => {\n if (proposal.kind !== 'function') return false\n if (!proposal.functionId) {\n const quota = checkQuota(org, 'functionsPerHost', functionCount)\n if (!quota.allowed) {\n enqueueSnackbar(`Function limit reached (${quota.limit}) — upgrade in Billing`, {\n variant: 'warning',\n persist: false,\n })\n return false\n }\n }\n setTestArgs({})\n setTestResult(null)\n setDraft({ ...proposal.definition, id: proposal.functionId })\n return true\n },\n [org, functionCount, enqueueSnackbar],\n )\n /*\n * The saved function the editor has open, named as it is STORED: a rename\n * being typed is not a different function.\n */\n const storedName = draft?.id\n ? functions.find((row: any) => row.$id === draft.id)?.name ?? draft.name\n : null\n\n const names = [\n ...(draft?.parameters ?? []).map((parameter) => parameter.name),\n ...(draft?.variables ?? []).map((variable) => variable.name),\n ].filter((name) => VARIABLE_NAME_PATTERN.test(name))\n\n /**\n * The site's variables, for the formula builder's value picker\n * (AGL-3757). Read the first time a builder opens, like the test run's\n * read below, so an author who never builds a formula costs nothing.\n */\n const [siteVariables, setSiteVariables] = useState<HostVariable[] | null>(\n null,\n )\n const loadSiteVariables = useCallback(() => {\n if (siteVariables) return\n setSiteVariables([])\n getDocs(query(collection(firestore, 'hosts', hostId, 'variables'), limit(100)))\n .then((snapshot) => {\n const rows: HostVariable[] = []\n snapshot.forEach((row) => {\n const data = row.data() as HostVariable & { deletedAt?: unknown }\n if (data?.name && !data.deletedAt) rows.push(data)\n })\n setSiteVariables(rows)\n })\n .catch((error) => {\n // The builder still offers the function's own names.\n console.error(error)\n })\n }, [siteVariables, firestore, hostId])\n const formulaNameOptions = formulaNames({\n parameters: draft?.parameters ?? [],\n locals: draft?.variables ?? [],\n siteVariables: siteVariables ?? [],\n })\n\n // Case-insensitive uniqueness (AGL-185): function names must stay\n // unambiguous for legacy {{fn:name(...)}} token resolution.\n const nameTaken = Boolean(\n draft &&\n functions.some(\n (definition: any) =>\n String(definition.name ?? '').toLowerCase() ===\n draft.name.trim().toLowerCase() && definition.$id !== draft.id,\n ),\n )\n\n /**\n * A test run sees what a published page sees (AGL-3202): the site\n * variables the draft names. Read on the click, and only when the draft\n * names something outside itself, so opening this card still costs the one\n * functions window and nothing else — a listener here would bill a hundred\n * variable reads to every author who never presses Run.\n */\n const handleTestRun = useCallback(async () => {\n if (!draft) return\n let globals: Record<string, number | string | boolean> = {}\n if (functionReferencedNames(draft).length) {\n try {\n const snapshot = await getDocs(\n query(collection(firestore, 'hosts', hostId, 'variables'), limit(100)),\n )\n const lookup: Record<string, HostVariable> = {}\n snapshot.forEach((row) => {\n const data = row.data() as HostVariable & { deletedAt?: unknown }\n if (data?.name && !data.deletedAt) lookup[row.id] = data\n })\n globals = functionGlobals(draft, lookup)\n } catch (error) {\n // The run still happens: an unreadable variable list reads as the\n // evaluator's own \"Unknown name\", which names what was missing.\n console.error(error)\n }\n }\n const result = evaluateHostFunction(draft, testArgs, { globals })\n setTestResult(\n result.ok === false\n ? `Error: ${result.error}`\n : `Result: ${String(result.value)}`,\n )\n }, [draft, testArgs, firestore, hostId])\n\n const handleSave = useCallback(async () => {\n if (!draft || !draft.name.trim() || nameTaken) return\n const { id: draftId, ...definition } = draft\n const fields = { ...definition, name: draft.name.trim().slice(0, 60) }\n try {\n if (draftId) {\n /**\n * Edit stays client-direct (no quota consumed) — and is refused when\n * its seed was never confirmed by the server (AGL-1358). `fields` is\n * the whole definition spread out of the listener row, so `merge:\n * true` has nothing left to protect.\n *\n * The guard WRAPS the write. An early return is a shape you can keep\n * while losing the protection; here the write is only reachable\n * through the verdict.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'function',\n unreadable: functionsStatus === 'error',\n fromCache: functionsFromCache,\n },\n async () => {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'functions', draftId),\n { ...fields, updatedAt: Timestamp.now() },\n { merge: true },\n ),\n })\n },\n )\n // Before `setDraft(null)`, so a refusal keeps the dialog open with\n // the whole edited body and its test run still on screen.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n } else {\n // New function rides the quota-enforcing resources API (AGL-473).\n await createHostResource({ hostId, resource: 'function', data: fields })\n // A create moves the count; the one-shot aggregate below does not\n // refresh itself the way the listener refreshes the rows.\n setFunctionCountEpoch((epoch) => epoch + 1)\n }\n setDraft(null)\n setTestResult(null)\n enqueueSnackbar('Function saved', { variant: 'success', persist: false })\n } catch (error: any) {\n console.error(error)\n enqueueSnackbar(error?.message ?? 'An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }, [\n user,\n draft,\n nameTaken,\n firestore,\n hostId,\n createHostResource,\n enqueueSnackbar,\n functionsStatus,\n functionsFromCache,\n ])\n\n const handleShowUsage = useCallback(\n (definition: any) => async () => {\n setUsageLoading(definition.$id)\n const result = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'function',\n id: definition.$id,\n name: definition.name,\n })\n setUsageLoading(null)\n setUsage({ name: definition.name, result })\n },\n [user, hostId],\n )\n\n const handleDelete = useCallback(\n (definition: any) => async () => {\n // Dependents warning (AGL-187): screens/layouts binding the function\n // and workflow steps calling it.\n const scan = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'function',\n id: definition.$id,\n name: definition.name,\n })\n const confirmed = await confirm({\n title: 'Delete this function?',\n description: scan.total\n ? `\"${definition.name}\" is used in ${summarizeDependents(scan)} ` +\n 'and those bindings and workflow steps will stop running.'\n : `\"${definition.name}\" will no longer be runnable.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.update(\n doc(firestore, 'hosts', hostId, 'functions', definition.$id),\n { deletedAt: Timestamp.now() },\n ),\n })\n enqueueSnackbar('Function deleted', {\n variant: 'success',\n persist: false,\n })\n },\n [user, confirm, firestore, hostId, enqueueSnackbar],\n )\n\n const setRow = (\n section: 'then' | 'otherwise',\n operationIndex: number,\n rowIndex: number,\n key: 'set' | 'expression',\n value: string,\n ) =>\n patch((previous) => {\n const operations = previous.operations.map((operation, index) =>\n index === operationIndex\n ? {\n ...operation,\n [section]: operation[section].map((row, index2) =>\n index2 === rowIndex ? { ...row, [key]: value } : row,\n ),\n }\n : operation,\n )\n return { ...previous, operations }\n })\n\n const renderSetRows = (section: 'then' | 'otherwise', operationIndex: number) => {\n const operation = draft?.operations[operationIndex]\n if (!operation) return null\n return (\n <Stack spacing={1}>\n {operation[section].map((row, rowIndex) => (\n <Stack\n key={rowIndex}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"caption\">{'SET'}</Typography>\n <TextField\n value={row.set}\n onChange={(event) =>\n setRow(section, operationIndex, rowIndex, 'set', event.target.value)\n }\n size=\"small\"\n select\n sx={{ minWidth: 90 }}\n >\n {names.map((name) => (\n <MenuItem key={name} value={name}>\n {name}\n </MenuItem>\n ))}\n </TextField>\n <Typography variant=\"caption\">{'equal to'}</Typography>\n <TextField\n value={row.expression}\n placeholder=\"P1 + P2\"\n onChange={(event) =>\n setRow(\n section,\n operationIndex,\n rowIndex,\n 'expression',\n event.target.value,\n )\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={row.expression}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n setRow(section, operationIndex, rowIndex, 'expression', expression)\n }\n />\n <IconButton\n size=\"small\"\n aria-label=\"remove operation row\"\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index) =>\n index === operationIndex\n ? {\n ...op,\n [section]: op[section].filter(\n (_, index2) => index2 !== rowIndex,\n ),\n }\n : op,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index) =>\n index === operationIndex\n ? {\n ...op,\n [section]: [...op[section], { set: '', expression: '' }],\n }\n : op,\n ),\n }))\n }\n >\n {'Add set'}\n </Button>\n </Stack>\n )\n }\n\n return (\n <CardDisplay\n header={'Functions'}\n help={pluginDocsHelp('bindings', { anchor: '#functions-card' })}\n // Another way to start a function (AGL-3603), in the card's header.\n actions={\n ExtensionZone ? (\n <ExtensionZone\n slot={HOST_LOGIC_ZONE.id}\n hostId={hostId}\n orgId={org?.$id}\n kind=\"function\"\n propose={propose}\n />\n ) : null\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {functions.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Build no-code logic: parameters in, conditional operations, ' +\n 'a value out. Wire functions into components and workflows ' +\n 'as the builder grows.'}\n </Typography>\n ) : (\n visibleFunctions.map((definition: any) => (\n <Stack\n key={definition.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {definition.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`${(definition.parameters ?? []).map((p: any) => p.name).join(', ') || 'no parameters'} → ${definition.returnValue || '—'}`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n disabled={usageLoading === definition.$id}\n onClick={handleShowUsage(definition)}\n >\n {usageLoading === definition.$id ? 'Scanning…' : 'Usage'}\n </Button>\n <Button\n size=\"small\"\n onClick={() => {\n setTestArgs({})\n setTestResult(null)\n setDraft({\n id: definition.$id,\n name: definition.name ?? '',\n parameters: definition.parameters ?? [],\n variables: definition.variables ?? [],\n operations: definition.operations ?? [],\n returnValue: definition.returnValue ?? '',\n })\n }}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDelete(definition)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ))\n )}\n {functions.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleFunctions.length}\n // The functions the card HOLDS. Not `functionCount`, which is the\n // site's total including soft-deleted rows and answers the quota's\n // question rather than the reader's.\n count={functions.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {functionsTruncated ? (\n <Alert severity=\"info\">\n {`Showing ${FUNCTION_CEILING} functions, ordered by id. This site ` +\n 'has more — the duplicate-name check below only covers the ' +\n 'ones listed here, so a name may already be taken by one that ' +\n 'is not.'}\n </Alert>\n ) : null}\n <Button\n size=\"small\"\n color=\"primary\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() => {\n // Plan cap (AGL-99): dark-launch — plan-less workspaces uncapped.\n // The site's functions, not this page of them (AGL-1716).\n const quota = checkQuota(org, 'functionsPerHost', functionCount)\n if (!quota.allowed) {\n return void enqueueSnackbar(\n `Function limit reached (${quota.limit}) — upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setTestArgs({})\n setTestResult(null)\n setDraft(emptyDraft())\n }}\n >\n {'Add function'}\n </Button>\n </Stack>\n\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>\n {draft?.id ? 'Edit Function' : 'Add Function'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n {ExtensionZone && draft?.id && storedName != null ? (\n <ExtensionZone\n slot={LOGIC_FUNCTION_EDITOR_ZONE.id}\n hostId={hostId}\n orgId={org?.$id}\n target={{ id: draft.id, name: storedName }}\n propose={propose}\n />\n ) : null}\n <TextField\n label=\"Name\"\n helperText={\n nameTaken\n ? 'A function with this name already exists'\n : 'Used to identify the function'\n }\n error={nameTaken}\n value={draft?.name ?? ''}\n onChange={(event) =>\n patch((previous) => ({ ...previous, name: event.target.value }))\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n\n <SectionLabel>{'Parameters'}</SectionLabel>\n {(draft?.parameters ?? []).map((parameter, index) => (\n <Stack\n key={index}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <TextField\n label=\"Name\"\n value={parameter.name}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? {\n ...p,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : p,\n ),\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n <TextField\n label=\"Type\"\n value={parameter.type}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? { ...p, type: event.target.value as FunctionValueType }\n : p,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 130 }}\n >\n {VALUE_TYPES.map((type) => (\n <MenuItem key={type.value} value={type.value}>\n {type.label}\n </MenuItem>\n ))}\n </TextField>\n <Stack\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center', flex: 1 }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Required'}\n </Typography>\n <Switch\n size=\"small\"\n checked={Boolean(parameter.required)}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? { ...p, required: event.target.checked }\n : p,\n ),\n }))\n }\n />\n </Stack>\n <IconButton\n size=\"small\"\n aria-label=\"remove parameter\"\n onClick={() =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.filter(\n (_, index2) => index2 !== index,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n parameters: [\n ...previous.parameters,\n {\n name: `P${previous.parameters.length + 1}`,\n type: 'number',\n required: false,\n },\n ],\n }))\n }\n >\n {'Add parameter'}\n </Button>\n\n {(draft?.parameters ?? []).length ? (\n <>\n <SectionLabel>{'What visitors see'}</SectionLabel>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Used by a Function Widget on a page. A parameter with ' +\n 'choices is asked as a list, a number as a number box and ' +\n 'a true/false as a switch.'}\n </Typography>\n {(draft?.parameters ?? []).map((parameter, index) => (\n <ParameterAudienceFields\n // Keyed by position: the name is being edited one row up.\n key={index}\n parameter={parameter}\n onChange={(next) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index ? next : p,\n ),\n }))\n }\n />\n ))}\n </>\n ) : null}\n\n <SectionLabel>{'Variables'}</SectionLabel>\n {(draft?.variables ?? []).map((variable, index) => (\n <Stack\n key={index}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <TextField\n label=\"Name\"\n value={variable.name}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.map((v, index2) =>\n index2 === index\n ? {\n ...v,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : v,\n ),\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n <TextField\n label=\"Type\"\n value={variable.type}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.map((v, index2) =>\n index2 === index\n ? { ...v, type: event.target.value as FunctionValueType }\n : v,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 130 }}\n >\n {VALUE_TYPES.map((type) => (\n <MenuItem key={type.value} value={type.value}>\n {type.label}\n </MenuItem>\n ))}\n </TextField>\n <IconButton\n size=\"small\"\n aria-label=\"remove variable\"\n sx={{ ml: 'auto' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.filter(\n (_, index2) => index2 !== index,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n variables: [\n ...previous.variables,\n { name: `V${previous.variables.length + 1}`, type: 'number' },\n ],\n }))\n }\n >\n {'Add variable'}\n </Button>\n\n <SectionLabel>{'Operations'}</SectionLabel>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Press ƒx beside a box to build its formula by picking values — ' +\n 'add, smallest of, format as money and more. A box also takes ' +\n 'a formula written out: + − × ÷ and parentheses, any site ' +\n 'variable by its name (a dictionary’s members as ' +\n 'name.member), and ' +\n `${FUNCTION_BUILTIN_NAMES.map((name) => `${name}()`).join(', ')}.`}\n </Typography>\n {(draft?.operations ?? []).map((operation, index) => (\n <Stack\n key={index}\n spacing={1}\n sx={{\n border: 1,\n borderColor: 'divider',\n borderRadius: 1,\n p: 1.5,\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${index + 1} · If below is TRUE`}\n </Typography>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n value={operation.if.left}\n placeholder=\"P1\"\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, left: event.target.value } }\n : op,\n ),\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={operation.if.left}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, left: expression } }\n : op,\n ),\n }))\n }\n />\n <TextField\n value={operation.if.comparator}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? {\n ...op,\n if: {\n ...op.if,\n comparator: event.target\n .value as FunctionComparator,\n },\n }\n : op,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 84 }}\n >\n {COMPARATORS.map((comparator) => (\n <MenuItem key={comparator} value={comparator}>\n {comparator}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n value={operation.if.right}\n placeholder=\"P2\"\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, right: event.target.value } }\n : op,\n ),\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={operation.if.right}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, right: expression } }\n : op,\n ),\n }))\n }\n />\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Then do this'}\n </Typography>\n {renderSetRows('then', index)}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Otherwise do this'}\n </Typography>\n {renderSetRows('otherwise', index)}\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: [\n ...previous.operations,\n {\n if: { left: '', comparator: '<=', right: '' },\n then: [{ set: '', expression: '' }],\n otherwise: [],\n },\n ],\n }))\n }\n >\n {'Add operation'}\n </Button>\n\n <TextField\n label=\"Return value\"\n value={draft?.returnValue ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n returnValue: event.target.value,\n }))\n }\n size=\"small\"\n select\n >\n {names.map((name) => (\n <MenuItem key={name} value={name}>\n {name}\n </MenuItem>\n ))}\n </TextField>\n\n <Divider />\n <SectionLabel>{'Test run'}</SectionLabel>\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n {(draft?.parameters ?? []).map((parameter) => (\n <TextField\n key={parameter.name}\n label={parameter.name}\n value={testArgs[parameter.name] ?? ''}\n onChange={(event) =>\n setTestArgs((previous) => ({\n ...previous,\n [parameter.name]: event.target.value,\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n ))}\n <Button size=\"small\" color=\"primary\" onClick={handleTestRun}>\n {'Run'}\n </Button>\n </Stack>\n {testResult ? (\n <Alert\n severity={testResult.startsWith('Error') ? 'warning' : 'success'}\n >\n {testResult}\n </Alert>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim() || nameTaken}\n onClick={handleSave}\n >\n {'Done'}\n </Button>\n </DialogActions>\n </Dialog>\n <WhereUsedDialog\n hostId={hostId}\n usage={usage}\n onClose={() => setUsage(null)}\n />\n </CardDisplay>\n )\n}\nHostFunctionsCard.displayName = 'HostFunctionsCard'\n\nexport default HostFunctionsCard\n"],"names":["checkQuota","evaluateHostFunction","FUNCTION_BUILTIN_NAMES","functionGlobals","functionReferencedNames","pluginDocsHelp","VARIABLE_NAME_PATTERN","ceilingedWindow","collectionCeiling","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","Divider","IconButton","MenuItem","Stack","Switch","TextField","Typography","collection","doc","getCountFromServer","getDocs","limit","query","useCallback","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","writeSiteWideChange","formatParameterOptions","parseParameterOptions","WhereUsedDialog","FormulaBuilderButton","formulaNames","useConsoleWidgetSlot","HOST_LOGIC_ZONE","LOGIC_FUNCTION_EDITOR_ZONE","fetchWhereUsed","summarizeDependents","FUNCTION_CEILING","VALUE_TYPES","value","label","COMPARATORS","emptyDraft","id","name","parameters","type","required","variables","operations","if","left","comparator","right","then","set","expression","otherwise","returnValue","ParameterAudienceFields","props","parameter","onChange","choices","setChoices","options","assign","field","next","direction","spacing","sx","alignItems","variant","color","width","flexShrink","noWrap","placeholder","event","target","slice","size","flex","defaultValue","length","SectionLabel","children","HostFunctionsCard","functions","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","functionDocs","status","functionsStatus","fromCache","functionsFromCache","idField","rows","readFunctions","truncated","functionsTruncated","filter","definition","deletedAt","sort","a","b","String","localeCompare","page","setPage","pageSize","setPageSize","visibleFunctions","functionCountEpoch","setFunctionCountEpoch","serverFunctionCount","setServerFunctionCount","active","snapshot","count","catch","functionCount","draft","setDraft","usage","setUsage","usageLoading","setUsageLoading","testArgs","setTestArgs","testResult","setTestResult","patch","updater","previous","ExtensionZone","propose","proposal","kind","functionId","quota","allowed","persist","storedName","find","row","$id","names","map","variable","test","siteVariables","setSiteVariables","loadSiteVariables","forEach","push","error","console","formulaNameOptions","locals","nameTaken","Boolean","some","toLowerCase","trim","handleTestRun","globals","lookup","result","ok","handleSave","draftId","fields","verdict","subject","unreadable","write","batch","updatedAt","now","merge","message","resource","epoch","allowDuplicate","handleShowUsage","handleDelete","scan","confirmed","title","description","total","confirmationText","confirmationButtonProps","update","setRow","section","operationIndex","rowIndex","key","operation","index","index2","renderSetRows","select","minWidth","current","onOpen","onUse","aria-label","onClick","op","_","alignSelf","header","help","anchor","actions","slot","orgId","contentGutterX","contentGutterY","p","join","disabled","rowCount","onPageChange","onPageSizeChange","severity","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","pt","helperText","autoFocus","mt","replace","checked","v","ml","border","borderColor","borderRadius","flexWrap","startsWith","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/components/host-functions-card.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 {\n type AglynOrgBilling,\n checkQuota,\n evaluateHostFunction,\n FUNCTION_BUILTIN_NAMES,\n type FunctionComparator,\n functionGlobals,\n functionReferencedNames,\n type FunctionValueType,\n type HostFunction,\n type HostFunctionParameter,\n type HostVariable,\n pluginDocsHelp,\n VARIABLE_NAME_PATTERN,\n} from '@aglyn/aglyn'\n/*\n * The MODULE, not the barrel, for the two PURE helpers — every spec that\n * renders this card mocks `@aglyn/tenant-feature-instance` wholesale to stage\n * its Firestore hooks, and a query builder imported through that barrel\n * disappears under the mock. Neither of these is a hook.\n */\nimport {\n ceilingedWindow,\n collectionCeiling,\n} from '@aglyn/tenant-feature-instance/hooks/host-collection-queries'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { TABLE_PAGE_SIZE_DEFAULT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n Divider,\n IconButton,\n MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n getCountFromServer,\n getDocs,\n limit,\n query,\n} from 'firebase/firestore'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostResourceApi,\n useUser,\n writeGuardedBySeed,\n} from '@aglyn/tenant-feature-instance'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\nimport { ParameterChoicesEditor } from './parameter-choices-editor.component'\nimport WhereUsedDialog from './where-used-dialog.component'\nimport { FormulaBuilderButton } from './formula-builder.component'\nimport { formulaNames } from '../model/formula-names'\nimport { useConsoleWidgetSlot } from '@aglyn/aglyn/app-utils/console-widget-slot-context'\nimport {\n HOST_LOGIC_ZONE,\n LOGIC_FUNCTION_EDITOR_ZONE,\n type LogicProposal,\n} from './logic-zones'\nimport {\n fetchWhereUsed,\n summarizeDependents,\n type WhereUsedResult,\n} from '@aglyn/aglyn/app-utils/where-used'\n\n/**\n * How many functions the card reads.\n *\n * A CEILING, not a page size — see the query, which explains why this list\n * cannot be paged by the server without making the duplicate-name check lie.\n */\nconst FUNCTION_CEILING = 100\n\nexport interface HostFunctionsCardProps {\n hostId: string\n /** Resolved entitlement source for quota checks (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\nconst VALUE_TYPES: { value: FunctionValueType; label: string }[] = [\n { value: 'number', label: 'Number' },\n { value: 'text', label: 'Text' },\n { value: 'boolean', label: 'True/false' },\n]\n\nconst COMPARATORS: FunctionComparator[] = ['==', '!=', '<', '<=', '>', '>=']\n\ninterface FunctionDraft extends HostFunction {\n id: string | null\n}\n\nfunction emptyDraft(): FunctionDraft {\n return {\n id: null,\n name: '',\n parameters: [{ name: 'P1', type: 'number', required: true }],\n variables: [{ name: 'P3', type: 'number' }],\n operations: [\n {\n if: { left: '', comparator: '<=', right: '' },\n then: [{ set: '', expression: '' }],\n otherwise: [],\n },\n ],\n returnValue: '',\n }\n}\n\n/**\n * What a VISITOR meets for one parameter (AGL-3202): the label above the\n * input, what it starts with, and — for a question with fixed answers — the\n * choices, one row each (AGL-3768). Empty fields are dropped from the\n * definition rather than stored as empty strings, so a function nobody has\n * dressed for visitors saves exactly the shape it always did.\n *\n * \"Starts as\" is picked, not typed, wherever there is a list to pick from:\n * the choices when there are any, on or off for a true/false.\n */\nfunction ParameterAudienceFields(props: {\n parameter: HostFunctionParameter\n onChange: (next: HostFunctionParameter) => void\n}) {\n const { parameter, onChange } = props\n const assign = (field: 'label' | 'defaultValue', value: string) => {\n const next = { ...parameter }\n if (value) next[field] = value\n else delete next[field]\n onChange(next)\n }\n const options = parameter.options ?? []\n const startsAsChoices: { value: string; label: string }[] | null =\n parameter.type === 'boolean'\n ? [\n { value: 'true', label: 'On' },\n { value: 'false', label: 'Off' },\n ]\n : options.length\n ? options.map((option) => ({\n value: option.value,\n label: option.label ?? option.value,\n }))\n : null\n return (\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ width: 110, flexShrink: 0 }}\n noWrap\n >\n {parameter.name || '—'}\n </Typography>\n <TextField\n label=\"Label\"\n placeholder={parameter.name}\n value={parameter.label ?? ''}\n onChange={(event) => assign('label', event.target.value.slice(0, 80))}\n size=\"small\"\n sx={{ flex: 2 }}\n />\n {startsAsChoices ? (\n <TextField\n select\n label=\"Starts as\"\n value={\n startsAsChoices.some(\n (choice) => choice.value === parameter.defaultValue,\n )\n ? parameter.defaultValue\n : ''\n }\n onChange={(event) => assign('defaultValue', event.target.value)}\n size=\"small\"\n sx={{ flex: 1 }}\n >\n <MenuItem value=\"\">\n <em>{'Nothing chosen'}</em>\n </MenuItem>\n {startsAsChoices.map((choice) => (\n <MenuItem key={choice.value} value={choice.value}>\n {choice.label}\n </MenuItem>\n ))}\n </TextField>\n ) : (\n <TextField\n label=\"Starts as\"\n value={parameter.defaultValue ?? ''}\n onChange={(event) =>\n assign(\n 'defaultValue',\n parameter.type === 'number'\n ? event.target.value.replace(/[^0-9.-]/g, '')\n : event.target.value.slice(0, 120),\n )\n }\n slotProps={\n parameter.type === 'number'\n ? { htmlInput: { inputMode: 'decimal' } }\n : undefined\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n )}\n </Stack>\n {parameter.type === 'boolean' ? null : (\n <ParameterChoicesEditor\n parameterName={parameter.name}\n type={parameter.type}\n options={parameter.options}\n onChange={(nextOptions) => {\n const next = { ...parameter }\n if (nextOptions.length) next.options = nextOptions\n else delete next.options\n // A start that is no longer a choice would preselect nothing.\n if (\n nextOptions.length &&\n next.defaultValue !== undefined &&\n !nextOptions.some((option) => option.value === next.defaultValue)\n ) {\n delete next.defaultValue\n }\n onChange(next)\n }}\n />\n )}\n </Stack>\n )\n}\n\n/** Small labelled row header matching the mockup's section styling. */\nfunction SectionLabel(props: { children: string }) {\n return (\n <Typography variant=\"overline\" color=\"text.secondary\">\n {props.children}\n </Typography>\n )\n}\n\n/**\n * No-code function builder (Component Builder, AGL-92): the mockup's Edit\n * Function dialog — Parameters with required toggles, local Variables,\n * numbered conditional operation cards (If below is TRUE / Then do this /\n * Otherwise do this), a Return value select, and a test-run panel driving\n * the shared evaluator. Definitions persist to `hosts/{hostId}/functions`;\n * prop/event wiring lands with AGL-93.\n */\nexport function HostFunctionsCard(props: HostFunctionsCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const createHostResource = useHostResourceApi()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const { org } = props\n const {\n data: functionDocs,\n status: functionsStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing destructures a whole stored function into `draft`\n * and writes `{...definition}` back, so `merge: true` protects nothing —\n * the payload is literally every field of the definition. `parameters`\n * and `operations` are arrays, which a merge replaces wholesale rather\n * than diffing, so a cached seed does not lose one edit: it restores that\n * snapshot's entire logic body and parameter list, and every caller's\n * arguments are positional against the list it just reverted.\n */\n fromCache: functionsFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501) —\n * the same decision as the variables card beside it, for the same two\n * reasons.\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window is a\n * pseudo-random hundred that the `localeCompare` below dresses up as an\n * alphabetical list, and nothing said the list was bounded.\n *\n * `collectionCeiling` does not change WHICH hundred — document-id order is\n * what the bare cap already returned. What it changes is that the order is\n * NAMED, so the obvious next edit is caught: ordering on `name` would HIDE\n * every function written without one rather than mis-sorting the list, and\n * `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.functions` copies one only if the export carried it.\n *\n * The QUERY is not paged because `nameTaken` below tests the draft against\n * these rows: case-insensitive uniqueness is what keeps legacy\n * `{{fn:name(...)}}` resolution unambiguous (AGL-185), and on a ten-row\n * server page that check would compare a new function against a tenth of\n * the site and create the duplicate it exists to prevent.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'functions'),\n FUNCTION_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readFunctions, truncated: functionsTruncated } =\n ceilingedWindow<any>(functionDocs, FUNCTION_CEILING)\n // Sorting is safe here in a way it is not on a paged list: these rows are\n // the whole collection below the ceiling, not a slice of one.\n const functions = useMemo(\n () =>\n readFunctions\n .filter((definition: any) => !definition.deletedAt)\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [readFunctions],\n )\n // The page is a SLICE: the rows are already in hand and `nameTaken` needs\n // all of them.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleFunctions = useMemo(\n () => functions.slice(page * pageSize, page * pageSize + pageSize),\n [functions, page, pageSize],\n )\n /**\n * The function HEAD-COUNT is a server aggregate, not the length of the\n * capped listener (AGL-1716, the AGL-1706 shape) — the same fix as the\n * variables card beside it, for the same reason.\n *\n * The listener is `limit(100)` and `functions.length` fed\n * `checkQuota(org, 'functionsPerHost', …)`, whose bands are 1 / 10 / 50 /\n * 250 / 500 / 1,000. Everything from Business up sits above the window, so\n * on those plans the gate compared 100 against hundreds and could never\n * refuse, while `api/hosts/resources` counted the collection and did.\n *\n * UNFILTERED, matching that route's plain `collection('functions').count()`\n * — soft-deleted functions have always counted server-side, so this is the\n * card catching up with the verdict it exists to predict. Only a create\n * moves the number, so that is where it is re-read.\n */\n const [functionCountEpoch, setFunctionCountEpoch] = useState(0)\n const [serverFunctionCount, setServerFunctionCount] = useState<number | null>(\n null,\n )\n useEffect(() => {\n let active = true\n void getCountFromServer(collection(firestore, 'hosts', hostId, 'functions'))\n .then((snapshot) => {\n if (active) setServerFunctionCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the loaded rows — a LOWER bound and the prior\n // behaviour, never 0, which `checkQuota` would answer as \"no usage\"\n // on a site that is over its band.\n })\n return () => {\n active = false\n }\n }, [firestore, hostId, functionCountEpoch])\n const functionCount = serverFunctionCount ?? functions.length\n\n const [draft, setDraft] = useState<FunctionDraft | null>(null)\n\n // Where-used dialog (AGL-193).\n const [usage, setUsage] = useState<{\n name: string\n result: WhereUsedResult\n } | null>(null)\n const [usageLoading, setUsageLoading] = useState<string | null>(null)\n\n const [testArgs, setTestArgs] = useState<Record<string, string>>({})\n const [testResult, setTestResult] = useState<string | null>(null)\n\n const patch = useCallback(\n (updater: (previous: FunctionDraft) => FunctionDraft) =>\n setDraft((previous) => (previous ? updater(previous) : previous)),\n [],\n )\n\n /**\n * The shell's zone renderer (AGL-3603), for what other plugins add beside\n * Add function and inside a saved function's editor; `null` outside the\n * console shell.\n */\n const ExtensionZone = useConsoleWidgetSlot()\n /*\n * Opens a function another plugin proposed in this editor, unsaved: a new\n * one as Add function opens one — so the plan's cap is asked first — and a\n * change to a saved one in place of what the editor holds. Save is the\n * only write.\n */\n const propose = useCallback(\n (proposal: LogicProposal) => {\n if (proposal.kind !== 'function') return false\n if (!proposal.functionId) {\n const quota = checkQuota(org, 'functionsPerHost', functionCount)\n if (!quota.allowed) {\n enqueueSnackbar(`Function limit reached (${quota.limit}) — upgrade in Billing`, {\n variant: 'warning',\n persist: false,\n })\n return false\n }\n }\n setTestArgs({})\n setTestResult(null)\n setDraft({ ...proposal.definition, id: proposal.functionId })\n return true\n },\n [org, functionCount, enqueueSnackbar],\n )\n /*\n * The saved function the editor has open, named as it is STORED: a rename\n * being typed is not a different function.\n */\n const storedName = draft?.id\n ? functions.find((row: any) => row.$id === draft.id)?.name ?? draft.name\n : null\n\n const names = [\n ...(draft?.parameters ?? []).map((parameter) => parameter.name),\n ...(draft?.variables ?? []).map((variable) => variable.name),\n ].filter((name) => VARIABLE_NAME_PATTERN.test(name))\n\n /**\n * The site's variables, for the formula builder's value picker\n * (AGL-3757). Read the first time a builder opens, like the test run's\n * read below, so an author who never builds a formula costs nothing.\n */\n const [siteVariables, setSiteVariables] = useState<HostVariable[] | null>(\n null,\n )\n const loadSiteVariables = useCallback(() => {\n if (siteVariables) return\n setSiteVariables([])\n getDocs(query(collection(firestore, 'hosts', hostId, 'variables'), limit(100)))\n .then((snapshot) => {\n const rows: HostVariable[] = []\n snapshot.forEach((row) => {\n const data = row.data() as HostVariable & { deletedAt?: unknown }\n if (data?.name && !data.deletedAt) rows.push(data)\n })\n setSiteVariables(rows)\n })\n .catch((error) => {\n // The builder still offers the function's own names.\n console.error(error)\n })\n }, [siteVariables, firestore, hostId])\n const formulaNameOptions = formulaNames({\n parameters: draft?.parameters ?? [],\n locals: draft?.variables ?? [],\n siteVariables: siteVariables ?? [],\n })\n\n // Case-insensitive uniqueness (AGL-185): function names must stay\n // unambiguous for legacy {{fn:name(...)}} token resolution.\n const nameTaken = Boolean(\n draft &&\n functions.some(\n (definition: any) =>\n String(definition.name ?? '').toLowerCase() ===\n draft.name.trim().toLowerCase() && definition.$id !== draft.id,\n ),\n )\n\n /**\n * A test run sees what a published page sees (AGL-3202): the site\n * variables the draft names. Read on the click, and only when the draft\n * names something outside itself, so opening this card still costs the one\n * functions window and nothing else — a listener here would bill a hundred\n * variable reads to every author who never presses Run.\n */\n const handleTestRun = useCallback(async () => {\n if (!draft) return\n let globals: Record<string, number | string | boolean> = {}\n if (functionReferencedNames(draft).length) {\n try {\n const snapshot = await getDocs(\n query(collection(firestore, 'hosts', hostId, 'variables'), limit(100)),\n )\n const lookup: Record<string, HostVariable> = {}\n snapshot.forEach((row) => {\n const data = row.data() as HostVariable & { deletedAt?: unknown }\n if (data?.name && !data.deletedAt) lookup[row.id] = data\n })\n globals = functionGlobals(draft, lookup)\n } catch (error) {\n // The run still happens: an unreadable variable list reads as the\n // evaluator's own \"Unknown name\", which names what was missing.\n console.error(error)\n }\n }\n const result = evaluateHostFunction(draft, testArgs, { globals })\n setTestResult(\n result.ok === false\n ? `Error: ${result.error}`\n : `Result: ${String(result.value)}`,\n )\n }, [draft, testArgs, firestore, hostId])\n\n const handleSave = useCallback(async () => {\n if (!draft || !draft.name.trim() || nameTaken) return\n const { id: draftId, ...definition } = draft\n const fields = { ...definition, name: draft.name.trim().slice(0, 60) }\n try {\n if (draftId) {\n /**\n * Edit stays client-direct (no quota consumed) — and is refused when\n * its seed was never confirmed by the server (AGL-1358). `fields` is\n * the whole definition spread out of the listener row, so `merge:\n * true` has nothing left to protect.\n *\n * The guard WRAPS the write. An early return is a shape you can keep\n * while losing the protection; here the write is only reachable\n * through the verdict.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'function',\n unreadable: functionsStatus === 'error',\n fromCache: functionsFromCache,\n },\n async () => {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'functions', draftId),\n { ...fields, updatedAt: Timestamp.now() },\n { merge: true },\n ),\n })\n },\n )\n // Before `setDraft(null)`, so a refusal keeps the dialog open with\n // the whole edited body and its test run still on screen.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n } else {\n // New function rides the quota-enforcing resources API (AGL-473).\n await createHostResource({ hostId, resource: 'function', data: fields })\n // A create moves the count; the one-shot aggregate below does not\n // refresh itself the way the listener refreshes the rows.\n setFunctionCountEpoch((epoch) => epoch + 1)\n }\n setDraft(null)\n setTestResult(null)\n enqueueSnackbar('Function saved', { variant: 'success', persist: false })\n } catch (error: any) {\n console.error(error)\n enqueueSnackbar(error?.message ?? 'An error has occurred', {\n variant: 'error',\n allowDuplicate: true,\n })\n }\n }, [\n user,\n draft,\n nameTaken,\n firestore,\n hostId,\n createHostResource,\n enqueueSnackbar,\n functionsStatus,\n functionsFromCache,\n ])\n\n const handleShowUsage = useCallback(\n (definition: any) => async () => {\n setUsageLoading(definition.$id)\n const result = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'function',\n id: definition.$id,\n name: definition.name,\n })\n setUsageLoading(null)\n setUsage({ name: definition.name, result })\n },\n [user, hostId],\n )\n\n const handleDelete = useCallback(\n (definition: any) => async () => {\n // Dependents warning (AGL-187): screens/layouts binding the function\n // and workflow steps calling it.\n const scan = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'function',\n id: definition.$id,\n name: definition.name,\n })\n const confirmed = await confirm({\n title: 'Delete this function?',\n description: scan.total\n ? `\"${definition.name}\" is used in ${summarizeDependents(scan)} ` +\n 'and those bindings and workflow steps will stop running.'\n : `\"${definition.name}\" will no longer be runnable.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.update(\n doc(firestore, 'hosts', hostId, 'functions', definition.$id),\n { deletedAt: Timestamp.now() },\n ),\n })\n enqueueSnackbar('Function deleted', {\n variant: 'success',\n persist: false,\n })\n },\n [user, confirm, firestore, hostId, enqueueSnackbar],\n )\n\n const setRow = (\n section: 'then' | 'otherwise',\n operationIndex: number,\n rowIndex: number,\n key: 'set' | 'expression',\n value: string,\n ) =>\n patch((previous) => {\n const operations = previous.operations.map((operation, index) =>\n index === operationIndex\n ? {\n ...operation,\n [section]: operation[section].map((row, index2) =>\n index2 === rowIndex ? { ...row, [key]: value } : row,\n ),\n }\n : operation,\n )\n return { ...previous, operations }\n })\n\n const renderSetRows = (section: 'then' | 'otherwise', operationIndex: number) => {\n const operation = draft?.operations[operationIndex]\n if (!operation) return null\n return (\n <Stack spacing={1}>\n {operation[section].map((row, rowIndex) => (\n <Stack\n key={rowIndex}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Typography variant=\"caption\">{'SET'}</Typography>\n <TextField\n value={row.set}\n onChange={(event) =>\n setRow(section, operationIndex, rowIndex, 'set', event.target.value)\n }\n size=\"small\"\n select\n sx={{ minWidth: 90 }}\n >\n {names.map((name) => (\n <MenuItem key={name} value={name}>\n {name}\n </MenuItem>\n ))}\n </TextField>\n <Typography variant=\"caption\">{'equal to'}</Typography>\n <TextField\n value={row.expression}\n placeholder=\"P1 + P2\"\n onChange={(event) =>\n setRow(\n section,\n operationIndex,\n rowIndex,\n 'expression',\n event.target.value,\n )\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={row.expression}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n setRow(section, operationIndex, rowIndex, 'expression', expression)\n }\n />\n <IconButton\n size=\"small\"\n aria-label=\"remove operation row\"\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index) =>\n index === operationIndex\n ? {\n ...op,\n [section]: op[section].filter(\n (_, index2) => index2 !== rowIndex,\n ),\n }\n : op,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index) =>\n index === operationIndex\n ? {\n ...op,\n [section]: [...op[section], { set: '', expression: '' }],\n }\n : op,\n ),\n }))\n }\n >\n {'Add set'}\n </Button>\n </Stack>\n )\n }\n\n return (\n <CardDisplay\n header={'Functions'}\n help={pluginDocsHelp('bindings', { anchor: '#functions-card' })}\n // Another way to start a function (AGL-3603), in the card's header.\n actions={\n ExtensionZone ? (\n <ExtensionZone\n slot={HOST_LOGIC_ZONE.id}\n hostId={hostId}\n orgId={org?.$id}\n kind=\"function\"\n propose={propose}\n />\n ) : null\n }\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {functions.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Build no-code logic: parameters in, conditional operations, ' +\n 'a value out. Wire functions into components and workflows ' +\n 'as the builder grows.'}\n </Typography>\n ) : (\n visibleFunctions.map((definition: any) => (\n <Stack\n key={definition.$id}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap>\n {definition.name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`${(definition.parameters ?? []).map((p: any) => p.name).join(', ') || 'no parameters'} → ${definition.returnValue || '—'}`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n disabled={usageLoading === definition.$id}\n onClick={handleShowUsage(definition)}\n >\n {usageLoading === definition.$id ? 'Scanning…' : 'Usage'}\n </Button>\n <Button\n size=\"small\"\n onClick={() => {\n setTestArgs({})\n setTestResult(null)\n setDraft({\n id: definition.$id,\n name: definition.name ?? '',\n parameters: definition.parameters ?? [],\n variables: definition.variables ?? [],\n operations: definition.operations ?? [],\n returnValue: definition.returnValue ?? '',\n })\n }}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDelete(definition)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ))\n )}\n {functions.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleFunctions.length}\n // The functions the card HOLDS. Not `functionCount`, which is the\n // site's total including soft-deleted rows and answers the quota's\n // question rather than the reader's.\n count={functions.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {functionsTruncated ? (\n <Alert severity=\"info\">\n {`Showing ${FUNCTION_CEILING} functions, ordered by id. This site ` +\n 'has more — the duplicate-name check below only covers the ' +\n 'ones listed here, so a name may already be taken by one that ' +\n 'is not.'}\n </Alert>\n ) : null}\n <Button\n size=\"small\"\n color=\"primary\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() => {\n // Plan cap (AGL-99): dark-launch — plan-less workspaces uncapped.\n // The site's functions, not this page of them (AGL-1716).\n const quota = checkQuota(org, 'functionsPerHost', functionCount)\n if (!quota.allowed) {\n return void enqueueSnackbar(\n `Function limit reached (${quota.limit}) — upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setTestArgs({})\n setTestResult(null)\n setDraft(emptyDraft())\n }}\n >\n {'Add function'}\n </Button>\n </Stack>\n\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>\n {draft?.id ? 'Edit Function' : 'Add Function'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, pt: 1 }}\n >\n {ExtensionZone && draft?.id && storedName != null ? (\n <ExtensionZone\n slot={LOGIC_FUNCTION_EDITOR_ZONE.id}\n hostId={hostId}\n orgId={org?.$id}\n target={{ id: draft.id, name: storedName }}\n propose={propose}\n />\n ) : null}\n <TextField\n label=\"Name\"\n helperText={\n nameTaken\n ? 'A function with this name already exists'\n : 'Used to identify the function'\n }\n error={nameTaken}\n value={draft?.name ?? ''}\n onChange={(event) =>\n patch((previous) => ({ ...previous, name: event.target.value }))\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n\n <SectionLabel>{'Parameters'}</SectionLabel>\n {(draft?.parameters ?? []).map((parameter, index) => (\n <Stack\n key={index}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <TextField\n label=\"Name\"\n value={parameter.name}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? {\n ...p,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : p,\n ),\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n <TextField\n label=\"Type\"\n value={parameter.type}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? { ...p, type: event.target.value as FunctionValueType }\n : p,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 130 }}\n >\n {VALUE_TYPES.map((type) => (\n <MenuItem key={type.value} value={type.value}>\n {type.label}\n </MenuItem>\n ))}\n </TextField>\n <Stack\n direction=\"row\"\n spacing={0.5}\n sx={{ alignItems: 'center', flex: 1 }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Required'}\n </Typography>\n <Switch\n size=\"small\"\n checked={Boolean(parameter.required)}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index\n ? { ...p, required: event.target.checked }\n : p,\n ),\n }))\n }\n />\n </Stack>\n <IconButton\n size=\"small\"\n aria-label=\"remove parameter\"\n onClick={() =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.filter(\n (_, index2) => index2 !== index,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n parameters: [\n ...previous.parameters,\n {\n name: `P${previous.parameters.length + 1}`,\n type: 'number',\n required: false,\n },\n ],\n }))\n }\n >\n {'Add parameter'}\n </Button>\n\n {(draft?.parameters ?? []).length ? (\n <>\n <SectionLabel>{'What visitors see'}</SectionLabel>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Used by a Function Widget on a page. A parameter with ' +\n 'choices is asked as a list — Add choice gives it one — a ' +\n 'number as a number box and a true/false as a switch.'}\n </Typography>\n {(draft?.parameters ?? []).map((parameter, index) => (\n <ParameterAudienceFields\n // Keyed by position: the name is being edited one row up.\n key={index}\n parameter={parameter}\n onChange={(next) =>\n patch((previous) => ({\n ...previous,\n parameters: previous.parameters.map((p, index2) =>\n index2 === index ? next : p,\n ),\n }))\n }\n />\n ))}\n </>\n ) : null}\n\n <SectionLabel>{'Variables'}</SectionLabel>\n {(draft?.variables ?? []).map((variable, index) => (\n <Stack\n key={index}\n direction=\"row\"\n spacing={1}\n sx={{ alignItems: 'center' }}\n >\n <TextField\n label=\"Name\"\n value={variable.name}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.map((v, index2) =>\n index2 === index\n ? {\n ...v,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : v,\n ),\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n <TextField\n label=\"Type\"\n value={variable.type}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.map((v, index2) =>\n index2 === index\n ? { ...v, type: event.target.value as FunctionValueType }\n : v,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 130 }}\n >\n {VALUE_TYPES.map((type) => (\n <MenuItem key={type.value} value={type.value}>\n {type.label}\n </MenuItem>\n ))}\n </TextField>\n <IconButton\n size=\"small\"\n aria-label=\"remove variable\"\n sx={{ ml: 'auto' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n variables: previous.variables.filter(\n (_, index2) => index2 !== index,\n ),\n }))\n }\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n variables: [\n ...previous.variables,\n { name: `V${previous.variables.length + 1}`, type: 'number' },\n ],\n }))\n }\n >\n {'Add variable'}\n </Button>\n\n <SectionLabel>{'Operations'}</SectionLabel>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Press ƒx beside a box to build its formula by picking values — ' +\n 'add, smallest of, format as money and more. A box also takes ' +\n 'a formula written out: + − × ÷ and parentheses, any site ' +\n 'variable by its name (a dictionary’s members as ' +\n 'name.member), and ' +\n `${FUNCTION_BUILTIN_NAMES.map((name) => `${name}()`).join(', ')}.`}\n </Typography>\n {(draft?.operations ?? []).map((operation, index) => (\n <Stack\n key={index}\n spacing={1}\n sx={{\n border: 1,\n borderColor: 'divider',\n borderRadius: 1,\n p: 1.5,\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${index + 1} · If below is TRUE`}\n </Typography>\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n value={operation.if.left}\n placeholder=\"P1\"\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, left: event.target.value } }\n : op,\n ),\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={operation.if.left}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, left: expression } }\n : op,\n ),\n }))\n }\n />\n <TextField\n value={operation.if.comparator}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? {\n ...op,\n if: {\n ...op.if,\n comparator: event.target\n .value as FunctionComparator,\n },\n }\n : op,\n ),\n }))\n }\n size=\"small\"\n select\n sx={{ width: 84 }}\n >\n {COMPARATORS.map((comparator) => (\n <MenuItem key={comparator} value={comparator}>\n {comparator}\n </MenuItem>\n ))}\n </TextField>\n <TextField\n value={operation.if.right}\n placeholder=\"P2\"\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, right: event.target.value } }\n : op,\n ),\n }))\n }\n size=\"small\"\n sx={{ flex: 1 }}\n />\n <FormulaBuilderButton\n current={operation.if.right}\n names={formulaNameOptions}\n onOpen={loadSiteVariables}\n onUse={(expression) =>\n patch((previous) => ({\n ...previous,\n operations: previous.operations.map((op, index2) =>\n index2 === index\n ? { ...op, if: { ...op.if, right: expression } }\n : op,\n ),\n }))\n }\n />\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Then do this'}\n </Typography>\n {renderSetRows('then', index)}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Otherwise do this'}\n </Typography>\n {renderSetRows('otherwise', index)}\n </Stack>\n ))}\n <Button\n size=\"small\"\n sx={{ alignSelf: 'flex-start' }}\n onClick={() =>\n patch((previous) => ({\n ...previous,\n operations: [\n ...previous.operations,\n {\n if: { left: '', comparator: '<=', right: '' },\n then: [{ set: '', expression: '' }],\n otherwise: [],\n },\n ],\n }))\n }\n >\n {'Add operation'}\n </Button>\n\n <TextField\n label=\"Return value\"\n value={draft?.returnValue ?? ''}\n onChange={(event) =>\n patch((previous) => ({\n ...previous,\n returnValue: event.target.value,\n }))\n }\n size=\"small\"\n select\n >\n {names.map((name) => (\n <MenuItem key={name} value={name}>\n {name}\n </MenuItem>\n ))}\n </TextField>\n\n <Divider />\n <SectionLabel>{'Test run'}</SectionLabel>\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n {(draft?.parameters ?? []).map((parameter) => (\n <TextField\n key={parameter.name}\n label={parameter.name}\n value={testArgs[parameter.name] ?? ''}\n onChange={(event) =>\n setTestArgs((previous) => ({\n ...previous,\n [parameter.name]: event.target.value,\n }))\n }\n size=\"small\"\n sx={{ width: 110 }}\n />\n ))}\n <Button size=\"small\" color=\"primary\" onClick={handleTestRun}>\n {'Run'}\n </Button>\n </Stack>\n {testResult ? (\n <Alert\n severity={testResult.startsWith('Error') ? 'warning' : 'success'}\n >\n {testResult}\n </Alert>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!draft?.name.trim() || nameTaken}\n onClick={handleSave}\n >\n {'Done'}\n </Button>\n </DialogActions>\n </Dialog>\n <WhereUsedDialog\n hostId={hostId}\n usage={usage}\n onClose={() => setUsage(null)}\n />\n </CardDisplay>\n )\n}\nHostFunctionsCard.displayName = 'HostFunctionsCard'\n\nexport default HostFunctionsCard\n"],"names":["checkQuota","evaluateHostFunction","FUNCTION_BUILTIN_NAMES","functionGlobals","functionReferencedNames","pluginDocsHelp","VARIABLE_NAME_PATTERN","ceilingedWindow","collectionCeiling","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","Divider","IconButton","MenuItem","Stack","Switch","TextField","Typography","collection","doc","getCountFromServer","getDocs","limit","query","useCallback","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","writeSiteWideChange","ParameterChoicesEditor","WhereUsedDialog","FormulaBuilderButton","formulaNames","useConsoleWidgetSlot","HOST_LOGIC_ZONE","LOGIC_FUNCTION_EDITOR_ZONE","fetchWhereUsed","summarizeDependents","FUNCTION_CEILING","VALUE_TYPES","value","label","COMPARATORS","emptyDraft","id","name","parameters","type","required","variables","operations","if","left","comparator","right","then","set","expression","otherwise","returnValue","ParameterAudienceFields","props","parameter","onChange","assign","field","next","options","startsAsChoices","length","map","option","spacing","direction","sx","alignItems","variant","color","width","flexShrink","noWrap","placeholder","event","target","slice","size","flex","select","some","choice","defaultValue","em","replace","slotProps","htmlInput","inputMode","undefined","parameterName","nextOptions","SectionLabel","children","HostFunctionsCard","functions","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","functionDocs","status","functionsStatus","fromCache","functionsFromCache","idField","rows","readFunctions","truncated","functionsTruncated","filter","definition","deletedAt","sort","a","b","String","localeCompare","page","setPage","pageSize","setPageSize","visibleFunctions","functionCountEpoch","setFunctionCountEpoch","serverFunctionCount","setServerFunctionCount","active","snapshot","count","catch","functionCount","draft","setDraft","usage","setUsage","usageLoading","setUsageLoading","testArgs","setTestArgs","testResult","setTestResult","patch","updater","previous","ExtensionZone","propose","proposal","kind","functionId","quota","allowed","persist","storedName","find","row","$id","names","variable","test","siteVariables","setSiteVariables","loadSiteVariables","forEach","push","error","console","formulaNameOptions","locals","nameTaken","Boolean","toLowerCase","trim","handleTestRun","globals","lookup","result","ok","handleSave","draftId","fields","verdict","subject","unreadable","write","batch","updatedAt","now","merge","message","resource","epoch","allowDuplicate","handleShowUsage","handleDelete","scan","confirmed","title","description","total","confirmationText","confirmationButtonProps","update","setRow","section","operationIndex","rowIndex","key","operation","index","index2","renderSetRows","minWidth","current","onOpen","onUse","aria-label","onClick","op","_","alignSelf","header","help","anchor","actions","slot","orgId","contentGutterX","contentGutterY","p","join","disabled","rowCount","onPageChange","onPageSizeChange","severity","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","pt","helperText","autoFocus","mt","checked","v","ml","border","borderColor","borderRadius","flexWrap","startsWith","displayName"],"mappings":"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"}
@@ -0,0 +1,31 @@
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
+ */
17
+ import type { FunctionValueType, HostFunctionParameterOption } from '@aglyn/aglyn';
18
+ export interface ParameterChoicesEditorProps {
19
+ /** The parameter's name, for the remove buttons' labels. */
20
+ parameterName: string;
21
+ type: FunctionValueType;
22
+ options: HostFunctionParameterOption[] | undefined;
23
+ onChange: (options: HostFunctionParameterOption[]) => void;
24
+ }
25
+ /**
26
+ * A parameter's choices as rows (AGL-3768): what the function receives and
27
+ * what a visitor reads, one choice per row. The rows are this editor's own
28
+ * state, so a choice whose value is still blank is not dropped mid-edit.
29
+ */
30
+ export declare function ParameterChoicesEditor(props: ParameterChoicesEditorProps): import("react").JSX.Element;
31
+ export default ParameterChoicesEditor;
@@ -0,0 +1,124 @@
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 { _ as _extends } from "@swc/helpers/_/_extends";
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ import { Button, IconButton, Stack, TextField, Typography } from "@mui/material";
20
+ import { useState } from "react";
21
+ import { choiceRowsFromOptions, optionsFromChoiceRows } from "../model/parameter-options.js";
22
+ /**
23
+ * A parameter's choices as rows (AGL-3768): what the function receives and
24
+ * what a visitor reads, one choice per row. The rows are this editor's own
25
+ * state, so a choice whose value is still blank is not dropped mid-edit.
26
+ */ export function ParameterChoicesEditor(props) {
27
+ const { parameterName, type, options, onChange } = props;
28
+ const [rows, setRows] = useState(()=>choiceRowsFromOptions(options));
29
+ const commit = (next)=>{
30
+ setRows(next);
31
+ onChange(optionsFromChoiceRows(next));
32
+ };
33
+ const update = (index, patch)=>commit(rows.map((row, at)=>at === index ? _extends({}, row, patch) : row));
34
+ const duplicate = (index)=>{
35
+ const value = rows[index].value.trim();
36
+ return Boolean(value) && rows.findIndex((row)=>row.value.trim() === value) < index;
37
+ };
38
+ return /*#__PURE__*/ _jsxs(Stack, {
39
+ spacing: 1,
40
+ sx: {
41
+ pl: {
42
+ xs: 0,
43
+ sm: '118px'
44
+ }
45
+ },
46
+ children: [
47
+ rows.map((row, index)=>/*#__PURE__*/ _jsxs(Stack, {
48
+ direction: "row",
49
+ spacing: 1,
50
+ sx: {
51
+ alignItems: 'center'
52
+ },
53
+ children: [
54
+ /*#__PURE__*/ _jsx(TextField, {
55
+ label: "Function gets",
56
+ value: row.value,
57
+ onChange: (event)=>update(index, {
58
+ value: type === 'number' ? event.target.value.replace(/[^0-9.-]/g, '') : event.target.value.slice(0, 120)
59
+ }),
60
+ error: duplicate(index),
61
+ helperText: duplicate(index) ? 'Already a choice' : undefined,
62
+ slotProps: type === 'number' ? {
63
+ htmlInput: {
64
+ inputMode: 'decimal'
65
+ }
66
+ } : undefined,
67
+ size: "small",
68
+ sx: {
69
+ flex: 1,
70
+ minWidth: 0
71
+ }
72
+ }),
73
+ /*#__PURE__*/ _jsx(TextField, {
74
+ label: "Visitors see",
75
+ placeholder: row.value,
76
+ value: row.label,
77
+ onChange: (event)=>update(index, {
78
+ label: event.target.value.slice(0, 80)
79
+ }),
80
+ size: "small",
81
+ sx: {
82
+ flex: 2,
83
+ minWidth: 0
84
+ }
85
+ }),
86
+ /*#__PURE__*/ _jsx(IconButton, {
87
+ size: "small",
88
+ "aria-label": `Remove choice ${index + 1} of ${parameterName || 'parameter'}`,
89
+ onClick: ()=>commit(rows.filter((_, at)=>at !== index)),
90
+ children: '×'
91
+ })
92
+ ]
93
+ }, index)),
94
+ /*#__PURE__*/ _jsxs(Stack, {
95
+ direction: "row",
96
+ spacing: 1,
97
+ sx: {
98
+ alignItems: 'center'
99
+ },
100
+ children: [
101
+ /*#__PURE__*/ _jsx(Button, {
102
+ size: "small",
103
+ onClick: ()=>commit([
104
+ ...rows,
105
+ {
106
+ value: '',
107
+ label: ''
108
+ }
109
+ ]),
110
+ children: 'Add choice'
111
+ }),
112
+ rows.length ? null : /*#__PURE__*/ _jsx(Typography, {
113
+ variant: "caption",
114
+ color: "text.secondary",
115
+ children: 'Give it choices to ask it as a list.'
116
+ })
117
+ ]
118
+ })
119
+ ]
120
+ });
121
+ }
122
+ export default ParameterChoicesEditor;
123
+
124
+ //# sourceMappingURL=parameter-choices-editor.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/components/parameter-choices-editor.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 type { FunctionValueType, HostFunctionParameterOption } from '@aglyn/aglyn'\nimport { Button, IconButton, Stack, TextField, Typography } from '@mui/material'\nimport { useState } from 'react'\nimport {\n choiceRowsFromOptions,\n optionsFromChoiceRows,\n type ParameterChoiceRow,\n} from '../model/parameter-options'\n\nexport interface ParameterChoicesEditorProps {\n /** The parameter's name, for the remove buttons' labels. */\n parameterName: string\n type: FunctionValueType\n options: HostFunctionParameterOption[] | undefined\n onChange: (options: HostFunctionParameterOption[]) => void\n}\n\n/**\n * A parameter's choices as rows (AGL-3768): what the function receives and\n * what a visitor reads, one choice per row. The rows are this editor's own\n * state, so a choice whose value is still blank is not dropped mid-edit.\n */\nexport function ParameterChoicesEditor(props: ParameterChoicesEditorProps) {\n const { parameterName, type, options, onChange } = props\n const [rows, setRows] = useState<ParameterChoiceRow[]>(() =>\n choiceRowsFromOptions(options),\n )\n const commit = (next: ParameterChoiceRow[]) => {\n setRows(next)\n onChange(optionsFromChoiceRows(next))\n }\n const update = (index: number, patch: Partial<ParameterChoiceRow>) =>\n commit(rows.map((row, at) => (at === index ? { ...row, ...patch } : row)))\n const duplicate = (index: number) => {\n const value = rows[index].value.trim()\n return Boolean(value) && rows.findIndex((row) => row.value.trim() === value) < index\n }\n\n return (\n <Stack spacing={1} sx={{ pl: { xs: 0, sm: '118px' } }}>\n {rows.map((row, index) => (\n <Stack key={index} direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <TextField\n label=\"Function gets\"\n value={row.value}\n onChange={(event) =>\n update(index, {\n value:\n type === 'number'\n ? event.target.value.replace(/[^0-9.-]/g, '')\n : event.target.value.slice(0, 120),\n })\n }\n error={duplicate(index)}\n helperText={duplicate(index) ? 'Already a choice' : undefined}\n slotProps={\n type === 'number' ? { htmlInput: { inputMode: 'decimal' } } : undefined\n }\n size=\"small\"\n sx={{ flex: 1, minWidth: 0 }}\n />\n <TextField\n label=\"Visitors see\"\n placeholder={row.value}\n value={row.label}\n onChange={(event) => update(index, { label: event.target.value.slice(0, 80) })}\n size=\"small\"\n sx={{ flex: 2, minWidth: 0 }}\n />\n <IconButton\n size=\"small\"\n aria-label={`Remove choice ${index + 1} of ${parameterName || 'parameter'}`}\n onClick={() => commit(rows.filter((_, at) => at !== index))}\n >\n {'×'}\n </IconButton>\n </Stack>\n ))}\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Button\n size=\"small\"\n onClick={() => commit([...rows, { value: '', label: '' }])}\n >\n {'Add choice'}\n </Button>\n {rows.length ? null : (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Give it choices to ask it as a list.'}\n </Typography>\n )}\n </Stack>\n </Stack>\n )\n}\n\nexport default ParameterChoicesEditor\n"],"names":["Button","IconButton","Stack","TextField","Typography","useState","choiceRowsFromOptions","optionsFromChoiceRows","ParameterChoicesEditor","props","parameterName","type","options","onChange","rows","setRows","commit","next","update","index","patch","map","row","at","duplicate","value","trim","Boolean","findIndex","spacing","sx","pl","xs","sm","direction","alignItems","label","event","target","replace","slice","error","helperText","undefined","slotProps","htmlInput","inputMode","size","flex","minWidth","placeholder","aria-label","onClick","filter","_","length","variant","color"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;AAGA,SAASA,MAAM,EAAEC,UAAU,EAAEC,KAAK,EAAEC,SAAS,EAAEC,UAAU,QAAQ,gBAAe;AAChF,SAASC,QAAQ,QAAQ,QAAO;AAChC,SACEC,qBAAqB,EACrBC,qBAAqB,QAEhB,gCAA4B;AAUnC;;;;CAIC,GACD,OAAO,SAASC,uBAAuBC,KAAkC;IACvE,MAAM,EAAEC,aAAa,EAAEC,IAAI,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGJ;IACnD,MAAM,CAACK,MAAMC,QAAQ,GAAGV,SAA+B,IACrDC,sBAAsBM;IAExB,MAAMI,SAAS,CAACC;QACdF,QAAQE;QACRJ,SAASN,sBAAsBU;IACjC;IACA,MAAMC,SAAS,CAACC,OAAeC,QAC7BJ,OAAOF,KAAKO,GAAG,CAAC,CAACC,KAAKC,KAAQA,OAAOJ,QAAQ,aAAKG,KAAQF,SAAUE;IACtE,MAAME,YAAY,CAACL;QACjB,MAAMM,QAAQX,IAAI,CAACK,MAAM,CAACM,KAAK,CAACC,IAAI;QACpC,OAAOC,QAAQF,UAAUX,KAAKc,SAAS,CAAC,CAACN,MAAQA,IAAIG,KAAK,CAACC,IAAI,OAAOD,SAASN;IACjF;IAEA,qBACE,MAACjB;QAAM2B,SAAS;QAAGC,IAAI;YAAEC,IAAI;gBAAEC,IAAI;gBAAGC,IAAI;YAAQ;QAAE;;YACjDnB,KAAKO,GAAG,CAAC,CAACC,KAAKH,sBACd,MAACjB;oBAAkBgC,WAAU;oBAAML,SAAS;oBAAGC,IAAI;wBAAEK,YAAY;oBAAS;;sCACxE,KAAChC;4BACCiC,OAAM;4BACNX,OAAOH,IAAIG,KAAK;4BAChBZ,UAAU,CAACwB,QACTnB,OAAOC,OAAO;oCACZM,OACEd,SAAS,WACL0B,MAAMC,MAAM,CAACb,KAAK,CAACc,OAAO,CAAC,aAAa,MACxCF,MAAMC,MAAM,CAACb,KAAK,CAACe,KAAK,CAAC,GAAG;gCACpC;4BAEFC,OAAOjB,UAAUL;4BACjBuB,YAAYlB,UAAUL,SAAS,qBAAqBwB;4BACpDC,WACEjC,SAAS,WAAW;gCAAEkC,WAAW;oCAAEC,WAAW;gCAAU;4BAAE,IAAIH;4BAEhEI,MAAK;4BACLjB,IAAI;gCAAEkB,MAAM;gCAAGC,UAAU;4BAAE;;sCAE7B,KAAC9C;4BACCiC,OAAM;4BACNc,aAAa5B,IAAIG,KAAK;4BACtBA,OAAOH,IAAIc,KAAK;4BAChBvB,UAAU,CAACwB,QAAUnB,OAAOC,OAAO;oCAAEiB,OAAOC,MAAMC,MAAM,CAACb,KAAK,CAACe,KAAK,CAAC,GAAG;gCAAI;4BAC5EO,MAAK;4BACLjB,IAAI;gCAAEkB,MAAM;gCAAGC,UAAU;4BAAE;;sCAE7B,KAAChD;4BACC8C,MAAK;4BACLI,cAAY,CAAC,cAAc,EAAEhC,QAAQ,EAAE,IAAI,EAAET,iBAAiB,aAAa;4BAC3E0C,SAAS,IAAMpC,OAAOF,KAAKuC,MAAM,CAAC,CAACC,GAAG/B,KAAOA,OAAOJ;sCAEnD;;;mBAjCOA;0BAqCd,MAACjB;gBAAMgC,WAAU;gBAAML,SAAS;gBAAGC,IAAI;oBAAEK,YAAY;gBAAS;;kCAC5D,KAACnC;wBACC+C,MAAK;wBACLK,SAAS,IAAMpC,OAAO;mCAAIF;gCAAM;oCAAEW,OAAO;oCAAIW,OAAO;gCAAG;6BAAE;kCAExD;;oBAEFtB,KAAKyC,MAAM,GAAG,qBACb,KAACnD;wBAAWoD,SAAQ;wBAAUC,OAAM;kCACjC;;;;;;AAMb;AAEA,eAAejD,uBAAsB"}
@@ -24,3 +24,19 @@ import { type HostFunctionParameterOption } from '@aglyn/aglyn';
24
24
  export declare function parseParameterOptions(text: string): HostFunctionParameterOption[];
25
25
  /** The inverse, for showing a stored list in that one line. */
26
26
  export declare function formatParameterOptions(options: HostFunctionParameterOption[] | undefined): string;
27
+ /** One row of the choices editor, blanks and all, as the author sees it. */
28
+ export interface ParameterChoiceRow {
29
+ /** What the function receives. */
30
+ value: string;
31
+ /** What the visitor reads; the value when blank. */
32
+ label: string;
33
+ }
34
+ /** The rows a stored choice list opens as. */
35
+ export declare function choiceRowsFromOptions(options: HostFunctionParameterOption[] | undefined): ParameterChoiceRow[];
36
+ /**
37
+ * The choice list rows store as (AGL-3768) — the same shape the one-line
38
+ * grammar produced. A row with no value is not a choice yet; the second row
39
+ * of a value is dropped, since a list cannot tell the function which of two
40
+ * identical values was picked; a label equal to its value is not stored.
41
+ */
42
+ export declare function optionsFromChoiceRows(rows: readonly ParameterChoiceRow[]): HostFunctionParameterOption[];
@@ -25,5 +25,36 @@
25
25
  /** The inverse, for showing a stored list in that one line. */ export function formatParameterOptions(options) {
26
26
  return formatFunctionParameterOptions(options);
27
27
  }
28
+ /** The rows a stored choice list opens as. */ export function choiceRowsFromOptions(options) {
29
+ return (options != null ? options : []).map((option)=>{
30
+ var _option_label;
31
+ return {
32
+ value: option.value,
33
+ label: (_option_label = option.label) != null ? _option_label : ''
34
+ };
35
+ });
36
+ }
37
+ /**
38
+ * The choice list rows store as (AGL-3768) — the same shape the one-line
39
+ * grammar produced. A row with no value is not a choice yet; the second row
40
+ * of a value is dropped, since a list cannot tell the function which of two
41
+ * identical values was picked; a label equal to its value is not stored.
42
+ */ export function optionsFromChoiceRows(rows) {
43
+ const options = [];
44
+ const seen = new Set();
45
+ for (const row of rows){
46
+ const value = row.value.trim();
47
+ if (!value || seen.has(value)) continue;
48
+ seen.add(value);
49
+ const label = row.label.trim();
50
+ options.push(label && label !== value ? {
51
+ value,
52
+ label
53
+ } : {
54
+ value
55
+ });
56
+ }
57
+ return options;
58
+ }
28
59
 
29
60
  //# sourceMappingURL=parameter-options.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/model/parameter-options.ts"],"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 formatFunctionParameterOptions,\n type HostFunctionParameterOption,\n parseFunctionParameterOptions,\n} from '@aglyn/aglyn'\n\n/**\n * A parameter's choice list as one line of text (AGL-3202). The grammar lives\n * in core — `parseFunctionParameterOptions` — because the canvas's Function\n * Input element reads the same line and a plugin may not import another. These\n * are the names the function builder has always called it by.\n */\nexport function parseParameterOptions(\n text: string,\n): HostFunctionParameterOption[] {\n return parseFunctionParameterOptions(text)\n}\n\n/** The inverse, for showing a stored list in that one line. */\nexport function formatParameterOptions(\n options: HostFunctionParameterOption[] | undefined,\n): string {\n return formatFunctionParameterOptions(options)\n}\n"],"names":["formatFunctionParameterOptions","parseFunctionParameterOptions","parseParameterOptions","text","formatParameterOptions","options"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,8BAA8B,EAE9BC,6BAA6B,QACxB,eAAc;AAErB;;;;;CAKC,GACD,OAAO,SAASC,sBACdC,IAAY;IAEZ,OAAOF,8BAA8BE;AACvC;AAEA,6DAA6D,GAC7D,OAAO,SAASC,uBACdC,OAAkD;IAElD,OAAOL,+BAA+BK;AACxC"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/model/parameter-options.ts"],"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 formatFunctionParameterOptions,\n type HostFunctionParameterOption,\n parseFunctionParameterOptions,\n} from '@aglyn/aglyn'\n\n/**\n * A parameter's choice list as one line of text (AGL-3202). The grammar lives\n * in core — `parseFunctionParameterOptions` — because the canvas's Function\n * Input element reads the same line and a plugin may not import another. These\n * are the names the function builder has always called it by.\n */\nexport function parseParameterOptions(\n text: string,\n): HostFunctionParameterOption[] {\n return parseFunctionParameterOptions(text)\n}\n\n/** The inverse, for showing a stored list in that one line. */\nexport function formatParameterOptions(\n options: HostFunctionParameterOption[] | undefined,\n): string {\n return formatFunctionParameterOptions(options)\n}\n\n/** One row of the choices editor, blanks and all, as the author sees it. */\nexport interface ParameterChoiceRow {\n /** What the function receives. */\n value: string\n /** What the visitor reads; the value when blank. */\n label: string\n}\n\n/** The rows a stored choice list opens as. */\nexport function choiceRowsFromOptions(\n options: HostFunctionParameterOption[] | undefined,\n): ParameterChoiceRow[] {\n return (options ?? []).map((option) => ({\n value: option.value,\n label: option.label ?? '',\n }))\n}\n\n/**\n * The choice list rows store as (AGL-3768) — the same shape the one-line\n * grammar produced. A row with no value is not a choice yet; the second row\n * of a value is dropped, since a list cannot tell the function which of two\n * identical values was picked; a label equal to its value is not stored.\n */\nexport function optionsFromChoiceRows(\n rows: readonly ParameterChoiceRow[],\n): HostFunctionParameterOption[] {\n const options: HostFunctionParameterOption[] = []\n const seen = new Set<string>()\n for (const row of rows) {\n const value = row.value.trim()\n if (!value || seen.has(value)) continue\n seen.add(value)\n const label = row.label.trim()\n options.push(label && label !== value ? { value, label } : { value })\n }\n return options\n}\n"],"names":["formatFunctionParameterOptions","parseFunctionParameterOptions","parseParameterOptions","text","formatParameterOptions","options","choiceRowsFromOptions","map","option","value","label","optionsFromChoiceRows","rows","seen","Set","row","trim","has","add","push"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,8BAA8B,EAE9BC,6BAA6B,QACxB,eAAc;AAErB;;;;;CAKC,GACD,OAAO,SAASC,sBACdC,IAAY;IAEZ,OAAOF,8BAA8BE;AACvC;AAEA,6DAA6D,GAC7D,OAAO,SAASC,uBACdC,OAAkD;IAElD,OAAOL,+BAA+BK;AACxC;AAUA,4CAA4C,GAC5C,OAAO,SAASC,sBACdD,OAAkD;IAElD,OAAO,CAACA,kBAAAA,UAAW,EAAE,EAAEE,GAAG,CAAC,CAACC;YAEnBA;eAF+B;YACtCC,OAAOD,OAAOC,KAAK;YACnBC,KAAK,GAAEF,gBAAAA,OAAOE,KAAK,YAAZF,gBAAgB;QACzB;;AACF;AAEA;;;;;CAKC,GACD,OAAO,SAASG,sBACdC,IAAmC;IAEnC,MAAMP,UAAyC,EAAE;IACjD,MAAMQ,OAAO,IAAIC;IACjB,KAAK,MAAMC,OAAOH,KAAM;QACtB,MAAMH,QAAQM,IAAIN,KAAK,CAACO,IAAI;QAC5B,IAAI,CAACP,SAASI,KAAKI,GAAG,CAACR,QAAQ;QAC/BI,KAAKK,GAAG,CAACT;QACT,MAAMC,QAAQK,IAAIL,KAAK,CAACM,IAAI;QAC5BX,QAAQc,IAAI,CAACT,SAASA,UAAUD,QAAQ;YAAEA;YAAOC;QAAM,IAAI;YAAED;QAAM;IACrE;IACA,OAAOJ;AACT"}