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

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.
@@ -36,6 +36,8 @@ import { useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writ
36
36
  import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
37
37
  import { formatParameterOptions, parseParameterOptions } from "../model/parameter-options.js";
38
38
  import WhereUsedDialog from "./where-used-dialog.component.js";
39
+ import { FormulaBuilderButton } from "./formula-builder.component.js";
40
+ import { formulaNames } from "../model/formula-names.js";
39
41
  import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
40
42
  import { HOST_LOGIC_ZONE, LOGIC_FUNCTION_EDITOR_ZONE } from "./logic-zones.js";
41
43
  import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/where-used";
@@ -194,7 +196,7 @@ function emptyDraft() {
194
196
  * the shared evaluator. Definitions persist to `hosts/{hostId}/functions`;
195
197
  * prop/event wiring lands with AGL-93.
196
198
  */ export function HostFunctionsCard(props) {
197
- var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10;
199
+ var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9, _ref10, _ref11, _ref12;
198
200
  var _functions_find;
199
201
  const { hostId } = props;
200
202
  const firestore = useFirestore();
@@ -340,6 +342,35 @@ function emptyDraft() {
340
342
  ...((_ref1 = draft == null ? void 0 : draft.parameters) != null ? _ref1 : []).map((parameter)=>parameter.name),
341
343
  ...((_ref2 = draft == null ? void 0 : draft.variables) != null ? _ref2 : []).map((variable)=>variable.name)
342
344
  ].filter((name)=>VARIABLE_NAME_PATTERN.test(name));
345
+ /**
346
+ * The site's variables, for the formula builder's value picker
347
+ * (AGL-3757). Read the first time a builder opens, like the test run's
348
+ * read below, so an author who never builds a formula costs nothing.
349
+ */ const [siteVariables, setSiteVariables] = useState(null);
350
+ const loadSiteVariables = useCallback(()=>{
351
+ if (siteVariables) return;
352
+ setSiteVariables([]);
353
+ getDocs(query(collection(firestore, 'hosts', hostId, 'variables'), limit(100))).then((snapshot)=>{
354
+ const rows = [];
355
+ snapshot.forEach((row)=>{
356
+ const data = row.data();
357
+ if ((data == null ? void 0 : data.name) && !data.deletedAt) rows.push(data);
358
+ });
359
+ setSiteVariables(rows);
360
+ }).catch((error)=>{
361
+ // The builder still offers the function's own names.
362
+ console.error(error);
363
+ });
364
+ }, [
365
+ siteVariables,
366
+ firestore,
367
+ hostId
368
+ ]);
369
+ const formulaNameOptions = formulaNames({
370
+ parameters: (_ref3 = draft == null ? void 0 : draft.parameters) != null ? _ref3 : [],
371
+ locals: (_ref4 = draft == null ? void 0 : draft.variables) != null ? _ref4 : [],
372
+ siteVariables: siteVariables != null ? siteVariables : []
373
+ });
343
374
  // Case-insensitive uniqueness (AGL-185): function names must stay
344
375
  // unambiguous for legacy {{fn:name(...)}} token resolution.
345
376
  const nameTaken = Boolean(draft && functions.some((definition)=>{
@@ -566,6 +597,12 @@ function emptyDraft() {
566
597
  flex: 1
567
598
  }
568
599
  }),
600
+ /*#__PURE__*/ _jsx(FormulaBuilderButton, {
601
+ current: row.expression,
602
+ names: formulaNameOptions,
603
+ onOpen: loadSiteVariables,
604
+ onUse: (expression)=>setRow(section, operationIndex, rowIndex, 'expression', expression)
605
+ }),
569
606
  /*#__PURE__*/ _jsx(IconButton, {
570
607
  size: "small",
571
608
  "aria-label": "remove operation row",
@@ -752,7 +789,7 @@ function emptyDraft() {
752
789
  label: "Name",
753
790
  helperText: nameTaken ? 'A function with this name already exists' : 'Used to identify the function',
754
791
  error: nameTaken,
755
- value: (_ref3 = draft == null ? void 0 : draft.name) != null ? _ref3 : '',
792
+ value: (_ref5 = draft == null ? void 0 : draft.name) != null ? _ref5 : '',
756
793
  onChange: (event)=>patch((previous)=>_extends({}, previous, {
757
794
  name: event.target.value
758
795
  })),
@@ -765,7 +802,7 @@ function emptyDraft() {
765
802
  /*#__PURE__*/ _jsx(SectionLabel, {
766
803
  children: 'Parameters'
767
804
  }),
768
- ((_ref4 = draft == null ? void 0 : draft.parameters) != null ? _ref4 : []).map((parameter, index)=>/*#__PURE__*/ _jsxs(Stack, {
805
+ ((_ref6 = draft == null ? void 0 : draft.parameters) != null ? _ref6 : []).map((parameter, index)=>/*#__PURE__*/ _jsxs(Stack, {
769
806
  direction: "row",
770
807
  spacing: 1,
771
808
  sx: {
@@ -854,7 +891,7 @@ function emptyDraft() {
854
891
  })),
855
892
  children: 'Add parameter'
856
893
  }),
857
- ((_ref5 = draft == null ? void 0 : draft.parameters) != null ? _ref5 : []).length ? /*#__PURE__*/ _jsxs(_Fragment, {
894
+ ((_ref7 = draft == null ? void 0 : draft.parameters) != null ? _ref7 : []).length ? /*#__PURE__*/ _jsxs(_Fragment, {
858
895
  children: [
859
896
  /*#__PURE__*/ _jsx(SectionLabel, {
860
897
  children: 'What visitors see'
@@ -864,7 +901,7 @@ function emptyDraft() {
864
901
  color: "text.secondary",
865
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.'
866
903
  }),
867
- ((_ref6 = draft == null ? void 0 : draft.parameters) != null ? _ref6 : []).map((parameter, index)=>/*#__PURE__*/ _jsx(ParameterAudienceFields, {
904
+ ((_ref8 = draft == null ? void 0 : draft.parameters) != null ? _ref8 : []).map((parameter, index)=>/*#__PURE__*/ _jsx(ParameterAudienceFields, {
868
905
  parameter: parameter,
869
906
  onChange: (next)=>patch((previous)=>_extends({}, previous, {
870
907
  parameters: previous.parameters.map((p, index2)=>index2 === index ? next : p)
@@ -875,7 +912,7 @@ function emptyDraft() {
875
912
  /*#__PURE__*/ _jsx(SectionLabel, {
876
913
  children: 'Variables'
877
914
  }),
878
- ((_ref7 = draft == null ? void 0 : draft.variables) != null ? _ref7 : []).map((variable, index)=>/*#__PURE__*/ _jsxs(Stack, {
915
+ ((_ref9 = draft == null ? void 0 : draft.variables) != null ? _ref9 : []).map((variable, index)=>/*#__PURE__*/ _jsxs(Stack, {
879
916
  direction: "row",
880
917
  spacing: 1,
881
918
  sx: {
@@ -948,9 +985,9 @@ function emptyDraft() {
948
985
  /*#__PURE__*/ _jsx(Typography, {
949
986
  variant: "caption",
950
987
  color: "text.secondary",
951
- children: 'An expression can use + − × ÷ and parentheses, any site ' + 'variable by its name (a dictionary’s members as ' + 'name.member), and ' + `${FUNCTION_BUILTIN_NAMES.map((name)=>`${name}()`).join(', ')}.`
988
+ children: 'Press ƒx beside a box to build its formula by picking values — ' + 'add, smallest of, format as money and more. A box also takes ' + 'a formula written out: + − × ÷ and parentheses, any site ' + 'variable by its name (a dictionary’s members as ' + 'name.member), and ' + `${FUNCTION_BUILTIN_NAMES.map((name)=>`${name}()`).join(', ')}.`
952
989
  }),
953
- ((_ref8 = draft == null ? void 0 : draft.operations) != null ? _ref8 : []).map((operation, index)=>/*#__PURE__*/ _jsxs(Stack, {
990
+ ((_ref10 = draft == null ? void 0 : draft.operations) != null ? _ref10 : []).map((operation, index)=>/*#__PURE__*/ _jsxs(Stack, {
954
991
  spacing: 1,
955
992
  sx: {
956
993
  border: 1,
@@ -986,6 +1023,18 @@ function emptyDraft() {
986
1023
  flex: 1
987
1024
  }
988
1025
  }),
1026
+ /*#__PURE__*/ _jsx(FormulaBuilderButton, {
1027
+ current: operation.if.left,
1028
+ names: formulaNameOptions,
1029
+ onOpen: loadSiteVariables,
1030
+ onUse: (expression)=>patch((previous)=>_extends({}, previous, {
1031
+ operations: previous.operations.map((op, index2)=>index2 === index ? _extends({}, op, {
1032
+ if: _extends({}, op.if, {
1033
+ left: expression
1034
+ })
1035
+ }) : op)
1036
+ }))
1037
+ }),
989
1038
  /*#__PURE__*/ _jsx(TextField, {
990
1039
  value: operation.if.comparator,
991
1040
  onChange: (event)=>patch((previous)=>_extends({}, previous, {
@@ -1019,6 +1068,18 @@ function emptyDraft() {
1019
1068
  sx: {
1020
1069
  flex: 1
1021
1070
  }
1071
+ }),
1072
+ /*#__PURE__*/ _jsx(FormulaBuilderButton, {
1073
+ current: operation.if.right,
1074
+ names: formulaNameOptions,
1075
+ onOpen: loadSiteVariables,
1076
+ onUse: (expression)=>patch((previous)=>_extends({}, previous, {
1077
+ operations: previous.operations.map((op, index2)=>index2 === index ? _extends({}, op, {
1078
+ if: _extends({}, op.if, {
1079
+ right: expression
1080
+ })
1081
+ }) : op)
1082
+ }))
1022
1083
  })
1023
1084
  ]
1024
1085
  }),
@@ -1064,7 +1125,7 @@ function emptyDraft() {
1064
1125
  }),
1065
1126
  /*#__PURE__*/ _jsx(TextField, {
1066
1127
  label: "Return value",
1067
- value: (_ref9 = draft == null ? void 0 : draft.returnValue) != null ? _ref9 : '',
1128
+ value: (_ref11 = draft == null ? void 0 : draft.returnValue) != null ? _ref11 : '',
1068
1129
  onChange: (event)=>patch((previous)=>_extends({}, previous, {
1069
1130
  returnValue: event.target.value
1070
1131
  })),
@@ -1086,7 +1147,7 @@ function emptyDraft() {
1086
1147
  flexWrap: 'wrap'
1087
1148
  },
1088
1149
  children: [
1089
- ((_ref10 = draft == null ? void 0 : draft.parameters) != null ? _ref10 : []).map((parameter)=>{
1150
+ ((_ref12 = draft == null ? void 0 : draft.parameters) != null ? _ref12 : []).map((parameter)=>{
1090
1151
  var _testArgs_parameter_name;
1091
1152
  return /*#__PURE__*/ _jsx(TextField, {
1092
1153
  label: parameter.name,
@@ -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 { 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 // 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 <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 {'An expression can use + − × ÷ 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 <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 </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","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","nameTaken","Boolean","some","toLowerCase","trim","handleTestRun","globals","lookup","forEach","error","console","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","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 {\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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"}
@@ -32,13 +32,16 @@ import { useSnackbar } from "@aglyn/shared-ui-snackstack";
32
32
  import { Timestamp } from "@aglyn/shared-util-timestamp";
33
33
  import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
34
34
  import { collection, doc, getCountFromServer } from "firebase/firestore";
35
- import { useCallback, useEffect, useMemo, useState } from "react";
35
+ import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from "react";
36
36
  import { useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
37
37
  import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
38
38
  import WhereUsedDialog from "./where-used-dialog.component.js";
39
39
  import { useConsoleWidgetSlot } from "@aglyn/aglyn/app-utils/console-widget-slot-context";
40
40
  import { HOST_LOGIC_ZONE } from "./logic-zones.js";
41
41
  import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/where-used";
42
+ // The entry/item editor is its own chunk, loaded when a dictionary or list
43
+ // variable is opened (AGL-3757).
44
+ const StructuredValueEditor = /*#__PURE__*/ lazy(()=>import("./structured-value-editor.component.js"));
42
45
  /**
43
46
  * How many variables the card reads.
44
47
  *
@@ -96,14 +99,16 @@ import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/wher
96
99
  });
97
100
  case 'dictionary':
98
101
  case 'collection':
99
- return /*#__PURE__*/ _jsx(TextField, {
100
- label: "Value (JSON)",
101
- placeholder: draft.type === 'dictionary' ? '{"key": "value"}' : '["a", "b"]',
102
- value: draft.value,
103
- onChange: (event)=>onChange(event.target.value),
104
- size: "small",
105
- multiline: true,
106
- minRows: 3
102
+ var _draft_id;
103
+ // Rows, never typed JSON (AGL-3757). Keyed by the draft and type so
104
+ // opening another variable, or switching type, reads its value afresh.
105
+ return /*#__PURE__*/ _jsx(Suspense, {
106
+ fallback: null,
107
+ children: /*#__PURE__*/ _jsx(StructuredValueEditor, {
108
+ shape: draft.type,
109
+ value: draft.value,
110
+ onChange: onChange
111
+ }, `${(_draft_id = draft.id) != null ? _draft_id : 'new'}:${draft.type}`)
107
112
  });
108
113
  default:
109
114
  return /*#__PURE__*/ _jsx(TextField, {