@aglyn/plugins-logic 1.0.0-beta.209 → 1.0.0-beta.212

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.209",
3
+ "version": "1.0.0-beta.212",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,12 +25,12 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.209",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.209",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.209",
31
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.209",
32
- "@aglyn/shared-util-timestamp": "1.0.0-beta.209",
33
- "@aglyn/tenant-feature-instance": "1.0.0-beta.209",
28
+ "@aglyn/aglyn": "1.0.0-beta.212",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.212",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.212",
31
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.212",
32
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.212",
33
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.212",
34
34
  "@swc/helpers": "0.5.23"
35
35
  },
36
36
  "peerDependencies": {
@@ -30,9 +30,10 @@ import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagina
30
30
  import { useSnackbar } from "@aglyn/shared-ui-snackstack";
31
31
  import { Timestamp } from "@aglyn/shared-util-timestamp";
32
32
  import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, IconButton, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
33
- import { collection, doc, getCountFromServer, getDocs, limit, query, setDoc, updateDoc } from "firebase/firestore";
33
+ import { collection, doc, getCountFromServer, getDocs, limit, query } from "firebase/firestore";
34
34
  import { useCallback, useEffect, useMemo, useState } from "react";
35
35
  import { useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
36
+ import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
36
37
  import { formatParameterOptions, parseParameterOptions } from "../model/parameter-options.js";
37
38
  import WhereUsedDialog from "./where-used-dialog.component.js";
38
39
  import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/where-used";
@@ -363,10 +364,15 @@ function emptyDraft() {
363
364
  unreadable: functionsStatus === 'error',
364
365
  fromCache: functionsFromCache
365
366
  }, async ()=>{
366
- await setDoc(doc(firestore, 'hosts', hostId, 'functions', draftId), _extends({}, fields, {
367
- updatedAt: Timestamp.now()
368
- }), {
369
- merge: true
367
+ await writeSiteWideChange({
368
+ firestore,
369
+ user,
370
+ hostId,
371
+ write: (batch)=>batch.set(doc(firestore, 'hosts', hostId, 'functions', draftId), _extends({}, fields, {
372
+ updatedAt: Timestamp.now()
373
+ }), {
374
+ merge: true
375
+ })
370
376
  });
371
377
  });
372
378
  // Before `setDraft(null)`, so a refusal keeps the dialog open with
@@ -403,6 +409,7 @@ function emptyDraft() {
403
409
  });
404
410
  }
405
411
  }, [
412
+ user,
406
413
  draft,
407
414
  nameTaken,
408
415
  firestore,
@@ -447,8 +454,13 @@ function emptyDraft() {
447
454
  }
448
455
  }).then(()=>true).catch(()=>false);
449
456
  if (!confirmed) return;
450
- await updateDoc(doc(firestore, 'hosts', hostId, 'functions', definition.$id), {
451
- deletedAt: Timestamp.now()
457
+ await writeSiteWideChange({
458
+ firestore,
459
+ user,
460
+ hostId,
461
+ write: (batch)=>batch.update(doc(firestore, 'hosts', hostId, 'functions', definition.$id), {
462
+ deletedAt: Timestamp.now()
463
+ })
452
464
  });
453
465
  enqueueSnackbar('Function deleted', {
454
466
  variant: 'success',
@@ -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 { collection, doc, getCountFromServer, getDocs, limit, query, setDoc, updateDoc } 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 {\n formatParameterOptions,\n parseParameterOptions,\n} from '../model/parameter-options'\nimport WhereUsedDialog from './where-used-dialog.component'\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 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 setDoc(\n doc(firestore, 'hosts', hostId, 'functions', draftId),\n { ...fields, updatedAt: Timestamp.now() },\n { merge: true },\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 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 updateDoc(\n doc(firestore, 'hosts', hostId, 'functions', definition.$id),\n { deletedAt: Timestamp.now() },\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: '#no-code-functions' })}\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 <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","setDoc","updateDoc","useCallback","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","formatParameterOptions","parseParameterOptions","WhereUsedDialog","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","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","functionDocs","status","functionsStatus","fromCache","functionsFromCache","idField","rows","readFunctions","truncated","functionsTruncated","functions","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","names","map","variable","test","nameTaken","Boolean","some","toLowerCase","trim","$id","handleTestRun","globals","lookup","forEach","row","error","console","result","ok","handleSave","draftId","fields","verdict","subject","unreadable","updatedAt","now","merge","message","persist","resource","epoch","allowDuplicate","handleShowUsage","kind","handleDelete","scan","confirmed","title","description","total","confirmationText","confirmationButtonProps","setRow","section","operationIndex","rowIndex","key","operation","index","index2","renderSetRows","select","minWidth","aria-label","onClick","op","_","alignSelf","header","help","anchor","contentGutterX","contentGutterY","p","join","disabled","rowCount","onPageChange","onPageSizeChange","severity","quota","allowed","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 {\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 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: '#no-code-functions' })}\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 <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","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","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","functionDocs","status","functionsStatus","fromCache","functionsFromCache","idField","rows","readFunctions","truncated","functionsTruncated","functions","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","names","map","variable","test","nameTaken","Boolean","some","toLowerCase","trim","$id","handleTestRun","globals","lookup","forEach","row","error","console","result","ok","handleSave","draftId","fields","verdict","subject","unreadable","write","batch","updatedAt","now","merge","message","persist","resource","epoch","allowDuplicate","handleShowUsage","kind","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","contentGutterX","contentGutterY","p","join","disabled","rowCount","onPageChange","onPageSizeChange","severity","quota","allowed","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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"}
@@ -30,9 +30,10 @@ import { TABLE_PAGE_SIZE_DEFAULT } from "@aglyn/shared-ui-jsx/const/table-pagina
30
30
  import { useSnackbar } from "@aglyn/shared-ui-snackstack";
31
31
  import { Timestamp } from "@aglyn/shared-util-timestamp";
32
32
  import { Alert, Button, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, Stack, Switch, TextField, Typography } from "@mui/material";
33
- import { collection, doc, getCountFromServer, setDoc, updateDoc } from "firebase/firestore";
33
+ import { collection, doc, getCountFromServer } from "firebase/firestore";
34
34
  import { useCallback, useEffect, useMemo, useState } from "react";
35
35
  import { useFirestore, useFirestoreCollection, useHostResourceApi, useUser, writeGuardedBySeed } from "@aglyn/tenant-feature-instance";
36
+ import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
36
37
  import WhereUsedDialog from "./where-used-dialog.component.js";
37
38
  import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/where-used";
38
39
  /**
@@ -305,10 +306,15 @@ import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/wher
305
306
  unreadable: variablesStatus === 'error',
306
307
  fromCache: variablesFromCache
307
308
  }, async ()=>{
308
- await setDoc(doc(firestore, 'hosts', hostId, 'variables', draft.id), _extends({}, fields, {
309
- updatedAt: Timestamp.now()
310
- }), {
311
- merge: true
309
+ await writeSiteWideChange({
310
+ firestore,
311
+ user,
312
+ hostId,
313
+ write: (batch)=>batch.set(doc(firestore, 'hosts', hostId, 'variables', draft.id), _extends({}, fields, {
314
+ updatedAt: Timestamp.now()
315
+ }), {
316
+ merge: true
317
+ })
312
318
  });
313
319
  });
314
320
  // Before `setDraft(null)`, so a refusal keeps the dialog open with
@@ -346,6 +352,7 @@ import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/wher
346
352
  });
347
353
  }
348
354
  }, [
355
+ user,
349
356
  draft,
350
357
  validName,
351
358
  nameTaken,
@@ -390,8 +397,13 @@ import { fetchWhereUsed, summarizeDependents } from "@aglyn/aglyn/app-utils/wher
390
397
  }
391
398
  }).then(()=>true).catch(()=>false);
392
399
  if (!confirmed) return;
393
- await updateDoc(doc(firestore, 'hosts', hostId, 'variables', variable.$id), {
394
- deletedAt: Timestamp.now()
400
+ await writeSiteWideChange({
401
+ firestore,
402
+ user,
403
+ hostId,
404
+ write: (batch)=>batch.update(doc(firestore, 'hosts', hostId, 'variables', variable.$id), {
405
+ deletedAt: Timestamp.now()
406
+ })
395
407
  });
396
408
  enqueueSnackbar('Variable deleted', {
397
409
  variant: 'success',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/components/host-variables-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 formatVariableValue,\n HOST_VARIABLE_TYPE_LABELS,\n type HostVariable,\n type HostVariableType,\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 renders\n * this card mocks `@aglyn/tenant-feature-instance` wholesale to stage its\n * Firestore hooks, and a query builder imported through that barrel disappears\n * under the mock — which fails as \"not a function\" in the component rather than\n * as anything about the test's subject. 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 MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport {\n collection,\n doc,\n getCountFromServer,\n setDoc,\n updateDoc,\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 WhereUsedDialog from './where-used-dialog.component'\nimport {\n fetchWhereUsed,\n summarizeDependents,\n type WhereUsedResult,\n} from '@aglyn/aglyn/app-utils/where-used'\n\n/**\n * How many variables 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 VARIABLE_CEILING = 100\n\n/**\n * How many workflows the computed-variable picker offers.\n *\n * Paid for only while the editor is open, which is what makes a ceiling this\n * size affordable: it is one reader mid-edit rather than every visitor to the\n * page.\n */\nconst WORKFLOW_OPTION_CEILING = 100\n\nexport interface HostVariablesCardProps {\n hostId: string\n /** Resolved entitlement source for quota checks (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\ninterface VariableDraft {\n /** Computed-source workflow doc id (AGL-261); name is the display hint. */\n workflowId: string\n id: string | null\n name: string\n type: HostVariableType\n value: string\n /** Workflow (by name) computing this variable at render (AGL-129). */\n workflowName: string\n}\n\n/** Per-type value editor: mirrors the mockup's type list. */\nfunction VariableValueField(props: {\n draft: VariableDraft\n onChange: (value: string) => void\n}) {\n const { draft, onChange } = props\n switch (draft.type) {\n case 'boolean':\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Switch\n checked={draft.value === 'true'}\n onChange={(event) =>\n onChange(event.target.checked ? 'true' : 'false')\n }\n />\n <Typography variant=\"body2\">\n {draft.value === 'true' ? 'True' : 'False'}\n </Typography>\n </Stack>\n )\n case 'date':\n case 'time':\n return (\n <TextField\n label=\"Value\"\n type={draft.type}\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n slotProps={{ inputLabel: { shrink: true } }}\n />\n )\n case 'number':\n return (\n <TextField\n label=\"Value\"\n value={draft.value}\n onChange={(event) =>\n onChange(event.target.value.replace(/[^0-9.eE+-]/g, ''))\n }\n size=\"small\"\n />\n )\n case 'dictionary':\n case 'collection':\n return (\n <TextField\n label=\"Value (JSON)\"\n placeholder={\n draft.type === 'dictionary' ? '{\"key\": \"value\"}' : '[\"a\", \"b\"]'\n }\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n multiline\n minRows={3}\n />\n )\n default:\n return (\n <TextField\n label=\"Value\"\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n multiline\n />\n )\n }\n}\n\n/**\n * Host variables (Component Builder, AGL-91): the mockup's Edit Variable\n * dialog — name + typed value — persisted to `hosts/{hostId}/variables`.\n * Any string prop can reference a variable with `{{name}}`; the org\n * compose pipeline resolves it at render. Soft delete keeps old tokens\n * rendering literally rather than breaking published pages.\n */\nexport function HostVariablesCard(props: HostVariablesCardProps) {\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 // Where-used dependents dialog (AGL-187).\n const [usage, setUsage] = useState<{\n name: string\n result: WhereUsedResult\n } | null>(null)\n const [usageLoading, setUsageLoading] = useState<string | null>(null)\n const {\n data: variableDocs,\n status: variablesStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing copies a whole stored variable into `draft` and\n * writes all of it back, so `merge: true` protects nothing — every field\n * is in the payload. `value` is the literal every `{{name}}` binding on\n * every published page resolves to, and `workflowId` is what rebinds a\n * computed variable to its source (AGL-261), so a cached seed can point\n * a live binding back at a value or a workflow the author replaced.\n */\n fromCache: variablesFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501).\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window is a\n * pseudo-random hundred that the `localeCompare` below arranges into a\n * convincing A-to-Z list. `variablesPerHost` runs to 5,000, so a Scale\n * site with three hundred variables sees a hundred of them and nothing\n * said so.\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 not\n * mis-sort this list, it would HIDE from it every variable written without\n * one, and `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.variables` copies a name only if the exported\n * document carried it. The document name cannot be absent.\n *\n * The QUERY is not paged because `nameTaken` below tests the draft against\n * these rows. Case-insensitive uniqueness is what keeps legacy `{{name}}`\n * token resolution unambiguous (AGL-185), and on a ten-row server page\n * that check would compare a new variable against a tenth of the site and\n * cheerfully create the duplicate it exists to prevent.\n *\n * The check is still only as complete as the ceiling, and that is now\n * SAID rather than assumed: the notice under the list appears exactly when\n * the probe finds a variable this card did not read.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'variables'),\n VARIABLE_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readVariables, truncated: variablesTruncated } =\n ceilingedWindow<any>(variableDocs, VARIABLE_CEILING)\n const [draft, setDraft] = useState<VariableDraft | null>(null)\n /**\n * The editor has been opened at least once in this session.\n *\n * A LATCH rather than `draft` itself, because the workflow picker below keys its\n * listeners on it. Tracking the dialog would tear that subscription down\n * on Cancel and pay for them again on the next Edit, so a merchant working\n * through ten variables would buy the same window ten times — worse than\n * the mount-time read this replaces. Latched, a reader who never edits pays\n * nothing and a reader who edits pays once.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n /*\n * Workflow picker options (AGL-261): computed variables reference the\n * workflow by doc id instead of a typed name.\n *\n * READ WHEN THE EDITOR OPENS, not when the card mounts (AGL-2501). Nothing\n * outside the dialog below touches these rows — the table shows a computed\n * variable's stored `workflowName`, never a name looked up here — so an\n * unconditional listener would charge every visitor to this page for a\n * hundred workflows to fill a select most of them never see.\n *\n * Ceilinged and ordered for the same reason as the variables above: a bare\n * `limit` is answered in document-id order, so the `localeCompare` below\n * would arrange a pseudo-random hundred into a convincing alphabet and a\n * workflow past it could not be picked, with nothing saying why.\n */\n const { data: workflowDocs } = useFirestoreCollection<any>(\n () =>\n editorOpened\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'workflows'),\n WORKFLOW_OPTION_CEILING,\n )\n : null,\n [firestore, hostId, editorOpened],\n { idField: '$id' },\n )\n const { rows: readWorkflows, truncated: workflowOptionsTruncated } =\n ceilingedWindow<any>(workflowDocs, WORKFLOW_OPTION_CEILING)\n // Sorting the whole ceiling, not a page of it.\n const workflowOptions = readWorkflows\n .filter((workflow: any) => !workflow.deletedAt && workflow.name)\n .map((workflow: any) => ({\n id: workflow.$id as string,\n name: workflow.name as string,\n }))\n .sort((a, b) => a.name.localeCompare(b.name))\n /*\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, so the order\n * on screen is the order of everything the card holds.\n */\n const variables = useMemo(\n () =>\n readVariables\n .filter((variable: any) => !variable.deletedAt)\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [readVariables],\n )\n // The page is a SLICE, because the rows are already in hand and `nameTaken`\n // needs all of them. What the card lacked was not a cheaper read but a\n // control: a hundred variables rendered as one wall.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleVariables = useMemo(\n () => variables.slice(page * pageSize, page * pageSize + pageSize),\n [variables, page, pageSize],\n )\n /**\n * The variable HEAD-COUNT is a server aggregate, not the length of the\n * capped listener (AGL-1716, the AGL-1706 shape).\n *\n * The listener is `limit(100)` and `variables.length` was handed to\n * `checkQuota(org, 'variablesPerHost', …)`. The bands are 3 / 25 / 100 /\n * 1,000 / 5,000, so the window ties Pro's 100 and hides Business's 1,000\n * and Scale's 5,000 entirely: on those plans the gate compared 100 against\n * thousands and could never refuse, while `api/hosts/resources` counted\n * the collection and did. The card offered headroom that did not exist and\n * then failed the create.\n *\n * UNFILTERED, matching the enforcing route: it runs a plain\n * `collection('variables').count()` for this quota — its `softDeletes`\n * branch governs only the flat per-host webhook cap — so a soft-deleted\n * variable has always counted toward `variablesPerHost` server-side while\n * this card excluded it. The card now asks the route's question in the\n * route's terms, which is the only thing that makes a console gate a\n * useful prediction of the route's verdict.\n *\n * THE LIST KEEPS ITS CAP. Only a create moves the number (deletes here are\n * soft, and the route counts them), so that is where it is re-read.\n */\n const [variableCountEpoch, setVariableCountEpoch] = useState(0)\n const [serverVariableCount, setServerVariableCount] = useState<number | null>(\n null,\n )\n useEffect(() => {\n let active = true\n void getCountFromServer(collection(firestore, 'hosts', hostId, 'variables'))\n .then((snapshot) => {\n if (active) setServerVariableCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the loaded rows below — a LOWER bound, and this\n // card's prior behaviour. Deliberately not 0: `checkQuota` answers\n // from whatever it is handed, and 0 used is a confident wrong\n // number in the flattering direction.\n })\n return () => {\n active = false\n }\n }, [firestore, hostId, variableCountEpoch])\n const variableCount = serverVariableCount ?? variables.length\n\n const validName = VARIABLE_NAME_PATTERN.test(draft?.name ?? '')\n // Case-insensitive (AGL-185): names must stay unambiguous for legacy\n // {{name}} token resolution and picker display.\n const nameTaken = Boolean(\n draft &&\n variables.some(\n (variable: any) =>\n String(variable.name ?? '').toLowerCase() ===\n draft.name.trim().toLowerCase() && variable.$id !== draft.id,\n ),\n )\n\n const handleSave = useCallback(async () => {\n if (!draft || !validName || nameTaken) return\n const fields = {\n name: draft.name,\n type: draft.type,\n value: draft.value,\n workflowId: draft.workflowId.trim(),\n workflowName: draft.workflowName.trim(),\n }\n try {\n if (draft.id) {\n /**\n * Edit stays client-direct (no quota consumed) — and is refused when\n * its seed was never confirmed by the server (AGL-1358). `merge:\n * true` protects nothing here: `fields` is every editable key of the\n * stored row, copied off the listener whether or not it was touched.\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: 'variable',\n unreadable: variablesStatus === 'error',\n fromCache: variablesFromCache,\n },\n async () => {\n await setDoc(\n doc(firestore, 'hosts', hostId, 'variables', draft.id),\n { ...fields, updatedAt: Timestamp.now() },\n { merge: true },\n )\n },\n )\n // Before `setDraft(null)`, so a refusal keeps the dialog open with\n // what was typed. A save that silently does nothing sends the user\n // back to retype a form that will be refused again just as quietly.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n } else {\n // New variable rides the quota-enforcing resources API (AGL-473).\n await createHostResource({ hostId, resource: 'variable', data: fields })\n // A create moves the count and the aggregate is a one-shot — the\n // listener refreshes the ROWS for free, the count has to be asked\n // again or the cap drifts stale for the rest of the session.\n setVariableCountEpoch((epoch) => epoch + 1)\n }\n setDraft(null)\n enqueueSnackbar(\n `Saved — use {{${draft.name}}} in any text to bind it`,\n { variant: 'success', persist: false },\n )\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 draft,\n validName,\n nameTaken,\n firestore,\n hostId,\n createHostResource,\n enqueueSnackbar,\n variablesStatus,\n variablesFromCache,\n ])\n\n const handleShowUsage = useCallback(\n (variable: any) => async () => {\n setUsageLoading(variable.$id)\n const result = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'variable',\n id: variable.$id,\n name: variable.name,\n })\n setUsageLoading(null)\n setUsage({ name: variable.name, result })\n },\n [user, hostId],\n )\n\n const handleDelete = useCallback(\n (variable: any) => async () => {\n // Real dependents warning (AGL-187) instead of the generic copy.\n const scan = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'variable',\n id: variable.$id,\n name: variable.name,\n })\n const confirmed = await confirm({\n title: 'Delete this variable?',\n description: scan.total\n ? `\"${variable.name}\" is used in ${summarizeDependents(scan)}. ` +\n 'Those bindings will render as empty or literal tokens after ' +\n 'the next publish.'\n : `\"${variable.name}\" is not referenced by any published ` +\n 'screen, layout, or workflow.',\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await updateDoc(\n doc(firestore, 'hosts', hostId, 'variables', variable.$id),\n { deletedAt: Timestamp.now() },\n )\n enqueueSnackbar('Variable deleted', {\n variant: 'success',\n persist: false,\n })\n },\n [user, confirm, firestore, hostId, enqueueSnackbar],\n )\n\n return (\n <CardDisplay\n header={'Variables'}\n help={pluginDocsHelp('bindings', { anchor: '#typed-variables' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {variables.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Define typed values once and bind them anywhere with ' +\n '{{name}} — change the variable, every page updates on the ' +\n 'next publish.'}\n </Typography>\n ) : (\n visibleVariables.map((variable: any) => (\n <Stack\n key={variable.$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 {`{{${variable.name}}}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`${HOST_VARIABLE_TYPE_LABELS[variable.type as HostVariableType] ?? variable.type} · ${\n formatVariableValue(variable as HostVariable) || '—'\n }`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n disabled={usageLoading === variable.$id}\n onClick={handleShowUsage(variable)}\n >\n {usageLoading === variable.$id ? 'Scanning…' : 'Usage'}\n </Button>\n <Button\n size=\"small\"\n onClick={() =>\n setDraft({\n id: variable.$id,\n name: variable.name ?? '',\n type: variable.type ?? 'text',\n value: variable.value ?? '',\n workflowId: variable.workflowId ?? '',\n workflowName: variable.workflowName ?? '',\n })\n }\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDelete(variable)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ))\n )}\n {variables.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleVariables.length}\n // The variables the card HOLDS. Not `variableCount`, 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={variables.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {variablesTruncated ? (\n <Alert severity=\"info\">\n {`Showing ${VARIABLE_CEILING} variables, 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 variables, not this page of them (AGL-1716).\n const quota = checkQuota(org, 'variablesPerHost', variableCount)\n if (!quota.allowed) {\n return void enqueueSnackbar(\n `Variable limit reached (${quota.limit}) — upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setDraft({\n id: null,\n name: '',\n type: 'text',\n value: '',\n workflowId: '',\n workflowName: '',\n })\n }}\n >\n {'Add variable'}\n </Button>\n </Stack>\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n {draft?.id ? 'Edit Variable' : 'Add Variable'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <TextField\n label=\"Name\"\n helperText={\n nameTaken\n ? 'A variable with this name already exists'\n : 'Used to identify the variable'\n }\n error={(Boolean(draft?.name) && !validName) || nameTaken}\n value={draft?.name ?? ''}\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n <TextField\n label=\"Type\"\n value={draft?.type ?? 'text'}\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n type: event.target.value as HostVariableType,\n value: '',\n }\n : prev,\n )\n }\n size=\"small\"\n select\n >\n {Object.entries(HOST_VARIABLE_TYPE_LABELS).map(\n ([value, label]) => (\n <MenuItem key={value} value={value}>\n {label}\n </MenuItem>\n ),\n )}\n </TextField>\n {draft ? (\n <VariableValueField\n draft={draft}\n onChange={(value) =>\n setDraft((prev) => (prev ? { ...prev, value } : prev))\n }\n />\n ) : null}\n <TextField\n select\n label=\"Computed from workflow (optional)\"\n helperText={\n workflowOptionsTruncated\n ? `Showing ${WORKFLOW_OPTION_CEILING} workflows, ordered by ` +\n 'id. This site has more, so one of them is not offered here.'\n : 'Pick a workflow — its result becomes this ' +\n 'variable\\u2019s value at render; the value above is the ' +\n 'fallback (AGL-129)'\n }\n value={\n draft?.workflowId ||\n workflowOptions.find(\n (option) => option.name === draft?.workflowName,\n )?.id ||\n ''\n }\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n workflowId: event.target.value,\n workflowName:\n workflowOptions.find(\n (option) => option.id === event.target.value,\n )?.name ?? '',\n }\n : prev,\n )\n }\n size=\"small\"\n >\n <MenuItem value=\"\">{'None'}</MenuItem>\n {workflowOptions.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.name}\n </MenuItem>\n ))}\n </TextField>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!validName || nameTaken}\n onClick={handleSave}\n >\n {'Save variable'}\n </Button>\n </DialogActions>\n </Dialog>\n <WhereUsedDialog\n hostId={hostId}\n usage={usage}\n onClose={() => setUsage(null)}\n />\n </CardDisplay>\n )\n}\nHostVariablesCard.displayName = 'HostVariablesCard'\n\nexport default HostVariablesCard\n"],"names":["checkQuota","formatVariableValue","HOST_VARIABLE_TYPE_LABELS","pluginDocsHelp","VARIABLE_NAME_PATTERN","ceilingedWindow","collectionCeiling","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","Switch","TextField","Typography","collection","doc","getCountFromServer","setDoc","updateDoc","useCallback","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","WhereUsedDialog","fetchWhereUsed","summarizeDependents","VARIABLE_CEILING","WORKFLOW_OPTION_CEILING","VariableValueField","props","draft","onChange","type","direction","spacing","sx","alignItems","checked","value","event","target","variant","label","size","slotProps","inputLabel","shrink","replace","placeholder","multiline","minRows","HostVariablesCard","workflowOptions","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","usage","setUsage","usageLoading","setUsageLoading","variableDocs","status","variablesStatus","fromCache","variablesFromCache","idField","rows","readVariables","truncated","variablesTruncated","setDraft","editorOpened","setEditorOpened","workflowDocs","readWorkflows","workflowOptionsTruncated","filter","workflow","deletedAt","name","map","id","$id","sort","a","b","localeCompare","variables","variable","String","page","setPage","pageSize","setPageSize","visibleVariables","slice","variableCountEpoch","setVariableCountEpoch","serverVariableCount","setServerVariableCount","active","then","snapshot","count","catch","variableCount","length","validName","test","nameTaken","Boolean","some","toLowerCase","trim","handleSave","fields","workflowId","workflowName","verdict","subject","unreadable","updatedAt","now","merge","ok","message","persist","resource","epoch","error","console","allowDuplicate","handleShowUsage","result","kind","handleDelete","scan","confirmed","title","description","total","confirmationText","confirmationButtonProps","color","header","help","anchor","contentGutterX","contentGutterY","flex","minWidth","noWrap","disabled","onClick","rowCount","onPageChange","onPageSizeChange","severity","alignSelf","quota","allowed","limit","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","pt","helperText","prev","autoFocus","mt","select","Object","entries","find","option","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/logic/src/lib/components/host-variables-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 formatVariableValue,\n HOST_VARIABLE_TYPE_LABELS,\n type HostVariable,\n type HostVariableType,\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 renders\n * this card mocks `@aglyn/tenant-feature-instance` wholesale to stage its\n * Firestore hooks, and a query builder imported through that barrel disappears\n * under the mock — which fails as \"not a function\" in the component rather than\n * as anything about the test's subject. 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 MenuItem,\n Stack,\n Switch,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, doc, getCountFromServer } 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 WhereUsedDialog from './where-used-dialog.component'\nimport {\n fetchWhereUsed,\n summarizeDependents,\n type WhereUsedResult,\n} from '@aglyn/aglyn/app-utils/where-used'\n\n/**\n * How many variables 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 VARIABLE_CEILING = 100\n\n/**\n * How many workflows the computed-variable picker offers.\n *\n * Paid for only while the editor is open, which is what makes a ceiling this\n * size affordable: it is one reader mid-edit rather than every visitor to the\n * page.\n */\nconst WORKFLOW_OPTION_CEILING = 100\n\nexport interface HostVariablesCardProps {\n hostId: string\n /** Resolved entitlement source for quota checks (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\ninterface VariableDraft {\n /** Computed-source workflow doc id (AGL-261); name is the display hint. */\n workflowId: string\n id: string | null\n name: string\n type: HostVariableType\n value: string\n /** Workflow (by name) computing this variable at render (AGL-129). */\n workflowName: string\n}\n\n/** Per-type value editor: mirrors the mockup's type list. */\nfunction VariableValueField(props: {\n draft: VariableDraft\n onChange: (value: string) => void\n}) {\n const { draft, onChange } = props\n switch (draft.type) {\n case 'boolean':\n return (\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center' }}>\n <Switch\n checked={draft.value === 'true'}\n onChange={(event) =>\n onChange(event.target.checked ? 'true' : 'false')\n }\n />\n <Typography variant=\"body2\">\n {draft.value === 'true' ? 'True' : 'False'}\n </Typography>\n </Stack>\n )\n case 'date':\n case 'time':\n return (\n <TextField\n label=\"Value\"\n type={draft.type}\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n slotProps={{ inputLabel: { shrink: true } }}\n />\n )\n case 'number':\n return (\n <TextField\n label=\"Value\"\n value={draft.value}\n onChange={(event) =>\n onChange(event.target.value.replace(/[^0-9.eE+-]/g, ''))\n }\n size=\"small\"\n />\n )\n case 'dictionary':\n case 'collection':\n return (\n <TextField\n label=\"Value (JSON)\"\n placeholder={\n draft.type === 'dictionary' ? '{\"key\": \"value\"}' : '[\"a\", \"b\"]'\n }\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n multiline\n minRows={3}\n />\n )\n default:\n return (\n <TextField\n label=\"Value\"\n value={draft.value}\n onChange={(event) => onChange(event.target.value)}\n size=\"small\"\n multiline\n />\n )\n }\n}\n\n/**\n * Host variables (Component Builder, AGL-91): the mockup's Edit Variable\n * dialog — name + typed value — persisted to `hosts/{hostId}/variables`.\n * Any string prop can reference a variable with `{{name}}`; the org\n * compose pipeline resolves it at render. Soft delete keeps old tokens\n * rendering literally rather than breaking published pages.\n */\nexport function HostVariablesCard(props: HostVariablesCardProps) {\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 // Where-used dependents dialog (AGL-187).\n const [usage, setUsage] = useState<{\n name: string\n result: WhereUsedResult\n } | null>(null)\n const [usageLoading, setUsageLoading] = useState<string | null>(null)\n const {\n data: variableDocs,\n status: variablesStatus,\n /**\n * The rows this editor is seeded from are unconfirmed by the server\n * (AGL-1358). Editing copies a whole stored variable into `draft` and\n * writes all of it back, so `merge: true` protects nothing — every field\n * is in the payload. `value` is the literal every `{{name}}` binding on\n * every published page resolves to, and `workflowId` is what rebinds a\n * computed variable to its source (AGL-261), so a cached seed can point\n * a live binding back at a value or a workflow the author replaced.\n */\n fromCache: variablesFromCache,\n } = useFirestoreCollection<any>(\n /*\n * ORDERED AND CEILINGED, deliberately not paged by the query (AGL-2501).\n *\n * `limit(100)` alone is answered in DOCUMENT-ID order, so the window is a\n * pseudo-random hundred that the `localeCompare` below arranges into a\n * convincing A-to-Z list. `variablesPerHost` runs to 5,000, so a Scale\n * site with three hundred variables sees a hundred of them and nothing\n * said so.\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 not\n * mis-sort this list, it would HIDE from it every variable written without\n * one, and `/api/hosts/resources` validates no field for presence while\n * `IMPORTABLE_FIELDS.variables` copies a name only if the exported\n * document carried it. The document name cannot be absent.\n *\n * The QUERY is not paged because `nameTaken` below tests the draft against\n * these rows. Case-insensitive uniqueness is what keeps legacy `{{name}}`\n * token resolution unambiguous (AGL-185), and on a ten-row server page\n * that check would compare a new variable against a tenth of the site and\n * cheerfully create the duplicate it exists to prevent.\n *\n * The check is still only as complete as the ceiling, and that is now\n * SAID rather than assumed: the notice under the list appears exactly when\n * the probe finds a variable this card did not read.\n */\n () =>\n collectionCeiling(\n collection(firestore, 'hosts', hostId, 'variables'),\n VARIABLE_CEILING,\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const { rows: readVariables, truncated: variablesTruncated } =\n ceilingedWindow<any>(variableDocs, VARIABLE_CEILING)\n const [draft, setDraft] = useState<VariableDraft | null>(null)\n /**\n * The editor has been opened at least once in this session.\n *\n * A LATCH rather than `draft` itself, because the workflow picker below keys its\n * listeners on it. Tracking the dialog would tear that subscription down\n * on Cancel and pay for them again on the next Edit, so a merchant working\n * through ten variables would buy the same window ten times — worse than\n * the mount-time read this replaces. Latched, a reader who never edits pays\n * nothing and a reader who edits pays once.\n */\n const [editorOpened, setEditorOpened] = useState(false)\n if (draft && !editorOpened) setEditorOpened(true)\n /*\n * Workflow picker options (AGL-261): computed variables reference the\n * workflow by doc id instead of a typed name.\n *\n * READ WHEN THE EDITOR OPENS, not when the card mounts (AGL-2501). Nothing\n * outside the dialog below touches these rows — the table shows a computed\n * variable's stored `workflowName`, never a name looked up here — so an\n * unconditional listener would charge every visitor to this page for a\n * hundred workflows to fill a select most of them never see.\n *\n * Ceilinged and ordered for the same reason as the variables above: a bare\n * `limit` is answered in document-id order, so the `localeCompare` below\n * would arrange a pseudo-random hundred into a convincing alphabet and a\n * workflow past it could not be picked, with nothing saying why.\n */\n const { data: workflowDocs } = useFirestoreCollection<any>(\n () =>\n editorOpened\n ? collectionCeiling(\n collection(firestore, 'hosts', hostId, 'workflows'),\n WORKFLOW_OPTION_CEILING,\n )\n : null,\n [firestore, hostId, editorOpened],\n { idField: '$id' },\n )\n const { rows: readWorkflows, truncated: workflowOptionsTruncated } =\n ceilingedWindow<any>(workflowDocs, WORKFLOW_OPTION_CEILING)\n // Sorting the whole ceiling, not a page of it.\n const workflowOptions = readWorkflows\n .filter((workflow: any) => !workflow.deletedAt && workflow.name)\n .map((workflow: any) => ({\n id: workflow.$id as string,\n name: workflow.name as string,\n }))\n .sort((a, b) => a.name.localeCompare(b.name))\n /*\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, so the order\n * on screen is the order of everything the card holds.\n */\n const variables = useMemo(\n () =>\n readVariables\n .filter((variable: any) => !variable.deletedAt)\n .sort((a: any, b: any) =>\n String(a.name ?? '').localeCompare(String(b.name ?? '')),\n ),\n [readVariables],\n )\n // The page is a SLICE, because the rows are already in hand and `nameTaken`\n // needs all of them. What the card lacked was not a cheaper read but a\n // control: a hundred variables rendered as one wall.\n const [page, setPage] = useState(0)\n const [pageSize, setPageSize] = useState(TABLE_PAGE_SIZE_DEFAULT)\n const visibleVariables = useMemo(\n () => variables.slice(page * pageSize, page * pageSize + pageSize),\n [variables, page, pageSize],\n )\n /**\n * The variable HEAD-COUNT is a server aggregate, not the length of the\n * capped listener (AGL-1716, the AGL-1706 shape).\n *\n * The listener is `limit(100)` and `variables.length` was handed to\n * `checkQuota(org, 'variablesPerHost', …)`. The bands are 3 / 25 / 100 /\n * 1,000 / 5,000, so the window ties Pro's 100 and hides Business's 1,000\n * and Scale's 5,000 entirely: on those plans the gate compared 100 against\n * thousands and could never refuse, while `api/hosts/resources` counted\n * the collection and did. The card offered headroom that did not exist and\n * then failed the create.\n *\n * UNFILTERED, matching the enforcing route: it runs a plain\n * `collection('variables').count()` for this quota — its `softDeletes`\n * branch governs only the flat per-host webhook cap — so a soft-deleted\n * variable has always counted toward `variablesPerHost` server-side while\n * this card excluded it. The card now asks the route's question in the\n * route's terms, which is the only thing that makes a console gate a\n * useful prediction of the route's verdict.\n *\n * THE LIST KEEPS ITS CAP. Only a create moves the number (deletes here are\n * soft, and the route counts them), so that is where it is re-read.\n */\n const [variableCountEpoch, setVariableCountEpoch] = useState(0)\n const [serverVariableCount, setServerVariableCount] = useState<number | null>(\n null,\n )\n useEffect(() => {\n let active = true\n void getCountFromServer(collection(firestore, 'hosts', hostId, 'variables'))\n .then((snapshot) => {\n if (active) setServerVariableCount(snapshot.data().count)\n })\n .catch(() => {\n // Falls back to the loaded rows below — a LOWER bound, and this\n // card's prior behaviour. Deliberately not 0: `checkQuota` answers\n // from whatever it is handed, and 0 used is a confident wrong\n // number in the flattering direction.\n })\n return () => {\n active = false\n }\n }, [firestore, hostId, variableCountEpoch])\n const variableCount = serverVariableCount ?? variables.length\n\n const validName = VARIABLE_NAME_PATTERN.test(draft?.name ?? '')\n // Case-insensitive (AGL-185): names must stay unambiguous for legacy\n // {{name}} token resolution and picker display.\n const nameTaken = Boolean(\n draft &&\n variables.some(\n (variable: any) =>\n String(variable.name ?? '').toLowerCase() ===\n draft.name.trim().toLowerCase() && variable.$id !== draft.id,\n ),\n )\n\n const handleSave = useCallback(async () => {\n if (!draft || !validName || nameTaken) return\n const fields = {\n name: draft.name,\n type: draft.type,\n value: draft.value,\n workflowId: draft.workflowId.trim(),\n workflowName: draft.workflowName.trim(),\n }\n try {\n if (draft.id) {\n /**\n * Edit stays client-direct (no quota consumed) — and is refused when\n * its seed was never confirmed by the server (AGL-1358). `merge:\n * true` protects nothing here: `fields` is every editable key of the\n * stored row, copied off the listener whether or not it was touched.\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: 'variable',\n unreadable: variablesStatus === 'error',\n fromCache: variablesFromCache,\n },\n async () => {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'variables', draft.id),\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 // what was typed. A save that silently does nothing sends the user\n // back to retype a form that will be refused again just as quietly.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n } else {\n // New variable rides the quota-enforcing resources API (AGL-473).\n await createHostResource({ hostId, resource: 'variable', data: fields })\n // A create moves the count and the aggregate is a one-shot — the\n // listener refreshes the ROWS for free, the count has to be asked\n // again or the cap drifts stale for the rest of the session.\n setVariableCountEpoch((epoch) => epoch + 1)\n }\n setDraft(null)\n enqueueSnackbar(\n `Saved — use {{${draft.name}}} in any text to bind it`,\n { variant: 'success', persist: false },\n )\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 validName,\n nameTaken,\n firestore,\n hostId,\n createHostResource,\n enqueueSnackbar,\n variablesStatus,\n variablesFromCache,\n ])\n\n const handleShowUsage = useCallback(\n (variable: any) => async () => {\n setUsageLoading(variable.$id)\n const result = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'variable',\n id: variable.$id,\n name: variable.name,\n })\n setUsageLoading(null)\n setUsage({ name: variable.name, result })\n },\n [user, hostId],\n )\n\n const handleDelete = useCallback(\n (variable: any) => async () => {\n // Real dependents warning (AGL-187) instead of the generic copy.\n const scan = await fetchWhereUsed(user as any, {\n hostId,\n kind: 'variable',\n id: variable.$id,\n name: variable.name,\n })\n const confirmed = await confirm({\n title: 'Delete this variable?',\n description: scan.total\n ? `\"${variable.name}\" is used in ${summarizeDependents(scan)}. ` +\n 'Those bindings will render as empty or literal tokens after ' +\n 'the next publish.'\n : `\"${variable.name}\" is not referenced by any published ` +\n 'screen, layout, or workflow.',\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, 'variables', variable.$id),\n { deletedAt: Timestamp.now() },\n ),\n })\n enqueueSnackbar('Variable deleted', {\n variant: 'success',\n persist: false,\n })\n },\n [user, confirm, firestore, hostId, enqueueSnackbar],\n )\n\n return (\n <CardDisplay\n header={'Variables'}\n help={pluginDocsHelp('bindings', { anchor: '#typed-variables' })}\n contentGutterX\n contentGutterY\n >\n <Stack spacing={1}>\n {variables.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Define typed values once and bind them anywhere with ' +\n '{{name}} — change the variable, every page updates on the ' +\n 'next publish.'}\n </Typography>\n ) : (\n visibleVariables.map((variable: any) => (\n <Stack\n key={variable.$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 {`{{${variable.name}}}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {`${HOST_VARIABLE_TYPE_LABELS[variable.type as HostVariableType] ?? variable.type} · ${\n formatVariableValue(variable as HostVariable) || '—'\n }`}\n </Typography>\n </Stack>\n <Button\n size=\"small\"\n disabled={usageLoading === variable.$id}\n onClick={handleShowUsage(variable)}\n >\n {usageLoading === variable.$id ? 'Scanning…' : 'Usage'}\n </Button>\n <Button\n size=\"small\"\n onClick={() =>\n setDraft({\n id: variable.$id,\n name: variable.name ?? '',\n type: variable.type ?? 'text',\n value: variable.value ?? '',\n workflowId: variable.workflowId ?? '',\n workflowName: variable.workflowName ?? '',\n })\n }\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={handleDelete(variable)}\n >\n {'Delete'}\n </Button>\n </Stack>\n ))\n )}\n {variables.length === 0 ? null : (\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={visibleVariables.length}\n // The variables the card HOLDS. Not `variableCount`, 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={variables.length}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n )}\n {variablesTruncated ? (\n <Alert severity=\"info\">\n {`Showing ${VARIABLE_CEILING} variables, 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 variables, not this page of them (AGL-1716).\n const quota = checkQuota(org, 'variablesPerHost', variableCount)\n if (!quota.allowed) {\n return void enqueueSnackbar(\n `Variable limit reached (${quota.limit}) — upgrade in Billing`,\n { variant: 'warning', persist: false },\n )\n }\n setDraft({\n id: null,\n name: '',\n type: 'text',\n value: '',\n workflowId: '',\n workflowName: '',\n })\n }}\n >\n {'Add variable'}\n </Button>\n </Stack>\n <Dialog\n open={Boolean(draft)}\n onClose={() => setDraft(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n {draft?.id ? 'Edit Variable' : 'Add Variable'}\n </DialogTitle>\n <DialogContent\n sx={{ display: 'flex', flexDirection: 'column', gap: 2, pt: 1 }}\n >\n <TextField\n label=\"Name\"\n helperText={\n nameTaken\n ? 'A variable with this name already exists'\n : 'Used to identify the variable'\n }\n error={(Boolean(draft?.name) && !validName) || nameTaken}\n value={draft?.name ?? ''}\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n name: event.target.value.replace(\n /[^a-zA-Z0-9_]/g,\n '',\n ),\n }\n : prev,\n )\n }\n size=\"small\"\n autoFocus\n sx={{ mt: 1 }}\n />\n <TextField\n label=\"Type\"\n value={draft?.type ?? 'text'}\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n type: event.target.value as HostVariableType,\n value: '',\n }\n : prev,\n )\n }\n size=\"small\"\n select\n >\n {Object.entries(HOST_VARIABLE_TYPE_LABELS).map(\n ([value, label]) => (\n <MenuItem key={value} value={value}>\n {label}\n </MenuItem>\n ),\n )}\n </TextField>\n {draft ? (\n <VariableValueField\n draft={draft}\n onChange={(value) =>\n setDraft((prev) => (prev ? { ...prev, value } : prev))\n }\n />\n ) : null}\n <TextField\n select\n label=\"Computed from workflow (optional)\"\n helperText={\n workflowOptionsTruncated\n ? `Showing ${WORKFLOW_OPTION_CEILING} workflows, ordered by ` +\n 'id. This site has more, so one of them is not offered here.'\n : 'Pick a workflow — its result becomes this ' +\n 'variable\\u2019s value at render; the value above is the ' +\n 'fallback (AGL-129)'\n }\n value={\n draft?.workflowId ||\n workflowOptions.find(\n (option) => option.name === draft?.workflowName,\n )?.id ||\n ''\n }\n onChange={(event) =>\n setDraft((prev) =>\n prev\n ? {\n ...prev,\n workflowId: event.target.value,\n workflowName:\n workflowOptions.find(\n (option) => option.id === event.target.value,\n )?.name ?? '',\n }\n : prev,\n )\n }\n size=\"small\"\n >\n <MenuItem value=\"\">{'None'}</MenuItem>\n {workflowOptions.map((option) => (\n <MenuItem key={option.id} value={option.id}>\n {option.name}\n </MenuItem>\n ))}\n </TextField>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDraft(null)}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n disabled={!validName || nameTaken}\n onClick={handleSave}\n >\n {'Save variable'}\n </Button>\n </DialogActions>\n </Dialog>\n <WhereUsedDialog\n hostId={hostId}\n usage={usage}\n onClose={() => setUsage(null)}\n />\n </CardDisplay>\n )\n}\nHostVariablesCard.displayName = 'HostVariablesCard'\n\nexport default HostVariablesCard\n"],"names":["checkQuota","formatVariableValue","HOST_VARIABLE_TYPE_LABELS","pluginDocsHelp","VARIABLE_NAME_PATTERN","ceilingedWindow","collectionCeiling","CardDisplay","useConfirmationContext","ListPagination","TABLE_PAGE_SIZE_DEFAULT","useSnackbar","Timestamp","Alert","Button","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","Switch","TextField","Typography","collection","doc","getCountFromServer","useCallback","useEffect","useMemo","useState","useFirestore","useFirestoreCollection","useHostResourceApi","useUser","writeGuardedBySeed","writeSiteWideChange","WhereUsedDialog","fetchWhereUsed","summarizeDependents","VARIABLE_CEILING","WORKFLOW_OPTION_CEILING","VariableValueField","props","draft","onChange","type","direction","spacing","sx","alignItems","checked","value","event","target","variant","label","size","slotProps","inputLabel","shrink","replace","placeholder","multiline","minRows","HostVariablesCard","workflowOptions","hostId","firestore","data","user","createHostResource","enqueueSnackbar","confirm","org","usage","setUsage","usageLoading","setUsageLoading","variableDocs","status","variablesStatus","fromCache","variablesFromCache","idField","rows","readVariables","truncated","variablesTruncated","setDraft","editorOpened","setEditorOpened","workflowDocs","readWorkflows","workflowOptionsTruncated","filter","workflow","deletedAt","name","map","id","$id","sort","a","b","localeCompare","variables","variable","String","page","setPage","pageSize","setPageSize","visibleVariables","slice","variableCountEpoch","setVariableCountEpoch","serverVariableCount","setServerVariableCount","active","then","snapshot","count","catch","variableCount","length","validName","test","nameTaken","Boolean","some","toLowerCase","trim","handleSave","fields","workflowId","workflowName","verdict","subject","unreadable","write","batch","set","updatedAt","now","merge","ok","message","persist","resource","epoch","error","console","allowDuplicate","handleShowUsage","result","kind","handleDelete","scan","confirmed","title","description","total","confirmationText","confirmationButtonProps","color","update","header","help","anchor","contentGutterX","contentGutterY","flex","minWidth","noWrap","disabled","onClick","rowCount","onPageChange","onPageSizeChange","severity","alignSelf","quota","allowed","limit","open","onClose","maxWidth","fullWidth","display","flexDirection","gap","pt","helperText","prev","autoFocus","mt","select","Object","entries","find","option","displayName"],"mappings":"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"}