@burdenoff/fluidgrids-fe-sdk 2026.1107.1 → 2026.1108.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/{ExecutionDetailPage-TQST7JKC.js → ExecutionDetailPage-PY5OE2RJ.js} +16 -15
  2. package/dist/{ExecutionsListPage-QQKEGXSC.js → ExecutionsListPage-LKNYPXNZ.js} +12 -11
  3. package/dist/{MissingNodesInstallModal-OSAJLIBE.js → MissingNodesInstallModal-Q6OPULJU.js} +2 -1
  4. package/dist/{TemplateConfigurationModal-SILENYXX.js → TemplateConfigurationModal-PWCDDPKT.js} +2 -1
  5. package/dist/{TemplateDetailPanel-7MPY5MYT.js → TemplateDetailPanel-5WY75DVB.js} +3 -2
  6. package/dist/WorkflowBuilder-YFPBMOWZ.js +37 -0
  7. package/dist/{WorkflowsList-2WX7N526.js → WorkflowsList-TETNEMYP.js} +11 -11
  8. package/dist/{agentTools-MEEGOAE2.js → agentTools-BW2XMHRV.js} +7 -7
  9. package/dist/{chunk-KE677WYY.js → chunk-2CXUTQUH.js} +1 -1
  10. package/dist/{chunk-H4ERTSMX.js → chunk-2VSYOGNI.js} +1948 -35
  11. package/dist/{chunk-NZMUKAXG.js → chunk-54NXUOHI.js} +1 -1
  12. package/dist/{chunk-E3PNEIBJ.js → chunk-62RJORF7.js} +5 -5
  13. package/dist/{chunk-4F54UT62.js → chunk-66AKFXP7.js} +21 -18
  14. package/dist/{chunk-MESGVHUU.js → chunk-7SSMRID2.js} +5 -5
  15. package/dist/{chunk-752BT4WM.js → chunk-7XW6BC4B.js} +1 -1
  16. package/dist/{chunk-5375NUIO.js → chunk-AR22A74Y.js} +11 -0
  17. package/dist/{chunk-5KK3ALQ4.js → chunk-D5Y3DHGJ.js} +1 -1
  18. package/dist/{chunk-NSDBXKIC.js → chunk-DG4UO5OY.js} +5 -5
  19. package/dist/{chunk-NMYENCP2.js → chunk-E7KIH3CF.js} +1 -1
  20. package/dist/{chunk-HUCRE45R.js → chunk-GI6BQIQA.js} +127 -42
  21. package/dist/{chunk-Z3ABLERJ.js → chunk-GOZR72NK.js} +64 -1
  22. package/dist/{chunk-KHS2DZHH.js → chunk-HICQ4J4W.js} +1 -1
  23. package/dist/chunk-HPNZ3PYU.js +1448 -0
  24. package/dist/{chunk-RI4NFNDX.js → chunk-HQSSW7K3.js} +8 -8
  25. package/dist/{chunk-CTKWMPQQ.js → chunk-HSOSMPRC.js} +3 -1
  26. package/dist/{chunk-JRSCUUBT.js → chunk-IPJV2IOH.js} +1 -1
  27. package/dist/{chunk-PYSEOWLW.js → chunk-IWLNBDR2.js} +5 -5
  28. package/dist/{chunk-MYAFMXFI.js → chunk-IZOPKR64.js} +3 -3
  29. package/dist/{chunk-ZWDKN6PU.js → chunk-JRR4VKYD.js} +95 -6
  30. package/dist/{chunk-TDFC5U66.js → chunk-JSJSBB76.js} +2 -2
  31. package/dist/{chunk-V2K4HJY4.js → chunk-KJB3WZVD.js} +2 -2
  32. package/dist/{chunk-OHKSDHNC.js → chunk-L7PHZ7RY.js} +2 -2
  33. package/dist/{chunk-JOOGRWYY.js → chunk-LOMLLWHD.js} +705 -12
  34. package/dist/{chunk-ZTZNQ5GF.js → chunk-MYPB2KTJ.js} +13 -6
  35. package/dist/{chunk-HY3XCZLB.js → chunk-N2QXEV5Y.js} +8 -8
  36. package/dist/{chunk-EXJW7EKR.js → chunk-OJHBCOBA.js} +164 -1
  37. package/dist/{chunk-BLLBUHVF.js → chunk-POYMF7L6.js} +1 -1
  38. package/dist/{chunk-BQXVT32O.js → chunk-QJAZXCFQ.js} +1 -23
  39. package/dist/{chunk-GA3V3X7Q.js → chunk-RNYFPG7R.js} +4 -4
  40. package/dist/chunk-TFCIZFDM.js +28 -0
  41. package/dist/{chunk-PASKZCII.js → chunk-TN3NGTF7.js} +3 -3
  42. package/dist/{chunk-KXCJPWYE.js → chunk-VH3EET6H.js} +2 -2
  43. package/dist/{chunk-UZJKX5FN.js → chunk-X3F5IQBP.js} +5 -3
  44. package/dist/chunk-XRGAH6IQ.js +110 -0
  45. package/dist/chunk-YASVILWQ.js +398 -0
  46. package/dist/{chunk-WBVBRXDI.js → chunk-ZHXJYOOG.js} +2115 -25
  47. package/dist/executions.js +17 -16
  48. package/dist/history.js +9 -9
  49. package/dist/index.d.ts +15474 -238
  50. package/dist/index.js +1064 -58
  51. package/dist/{node-detail-view-AQCGO4XQ.js → node-detail-view-BGWKE6KW.js} +490 -22
  52. package/dist/nodes.js +5 -2
  53. package/dist/observability.js +9 -9
  54. package/dist/{quick-config-panel-G3T4JCF6.js → quick-config-panel-67BU4I23.js} +9 -9
  55. package/dist/settings.js +11 -9
  56. package/dist/templates.js +19 -17
  57. package/dist/{workflow-builder-C261exmL.d.ts → workflow-builder-D7eMRluc.d.ts} +3 -1
  58. package/dist/workflow-builder.d.ts +1 -1
  59. package/dist/workflow-builder.js +21 -19
  60. package/dist/workflow-preview.js +2 -2
  61. package/dist/workflows-list.js +11 -11
  62. package/package.json +2 -2
  63. package/dist/WorkflowBuilder-R7VIOVRO.js +0 -35
  64. package/dist/chunk-VKC3ICRA.js +0 -529
@@ -1,12 +1,13 @@
1
- import { AgentsTab } from './chunk-5KK3ALQ4.js';
2
- import { ActionPoliciesTab } from './chunk-EXJW7EKR.js';
3
- import { LogStreamingTab } from './chunk-BLLBUHVF.js';
1
+ import { AgentsTab } from './chunk-D5Y3DHGJ.js';
2
+ import { ActionPoliciesTab, checkCodecServerUrl } from './chunk-OJHBCOBA.js';
3
+ import { useResource, fetchPauseRules, FieldError, fetchSearchAttributes, StatusPill, NativeSelect, fetchArchiveSettings, fetchCodecServerSettings, deletePauseRule, createPauseRule, deleteSearchAttribute, createSearchAttribute, saveArchiveSettings, clearArchiveSettings, saveCodecServerSettings } from './chunk-YASVILWQ.js';
4
+ import { LogStreamingTab } from './chunk-POYMF7L6.js';
4
5
  import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
5
- import { useFluidGridsFlag, FLUIDGRIDS_FLAGS, useSaveStatusStore, findSaveConflict, useDurableParityEnabled, useConnections } from './chunk-HUCRE45R.js';
6
- import { useFluidGridsPermission, FLUIDGRIDS_PERMISSIONS } from './chunk-5375NUIO.js';
7
- import { useFlowStore } from './chunk-UZJKX5FN.js';
6
+ import { useFluidGridsFlag, FLUIDGRIDS_FLAGS, usePhaseCFlags, useSaveStatusStore, findSaveConflict, useDurableParityEnabled, useConnections } from './chunk-GI6BQIQA.js';
7
+ import { useFluidGridsPermission, FLUIDGRIDS_PERMISSIONS } from './chunk-AR22A74Y.js';
8
+ import { useFlowStore } from './chunk-X3F5IQBP.js';
8
9
  import { getGlobalStoreClient } from './chunk-TYI2XOSI.js';
9
- import { useWorkflowDefinitionQuery, useUpdateWorkflowDefinitionMutation, useWorkflowDefinitionsQuery, DurableHistoryCapsDocument, UpdateDurableHistoryCapsDocument } from './chunk-Z3ABLERJ.js';
10
+ import { useWorkflowDefinitionQuery, useUpdateWorkflowDefinitionMutation, useWorkflowDefinitionsQuery, DurableHistoryCapsDocument, UpdateDurableHistoryCapsDocument } from './chunk-GOZR72NK.js';
10
11
  import { useTr } from './chunk-UULVIT25.js';
11
12
  import { getFluidGridsClient } from './chunk-PDODDDHY.js';
12
13
  import { throwIfResultError, describeOperationError } from './chunk-JKLZ6YZ3.js';
@@ -15,7 +16,7 @@ import { useState, useMemo, useEffect, useCallback } from 'react';
15
16
  import { useNavigate, useParams } from 'react-router';
16
17
  import { Icon } from '@iconify/react';
17
18
  import { Button } from '@burdenoff/fe-libs/button';
18
- import { Tabs, TabsList, TabsTrigger, TabsContent, Input, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Label, Card, CardHeader, Badge, Checkbox, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@burdenoff/fe-libs/ui';
19
+ import { Tabs, TabsList, TabsTrigger, TabsContent, Input, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Label, Card as Card$1, CardHeader, Badge, Checkbox, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@burdenoff/fe-libs/ui';
19
20
  import { toast } from 'sonner';
20
21
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
21
22
  import { gql } from '@apollo/client';
@@ -628,6 +629,691 @@ function RunDataTab() {
628
629
  parityEnabled && /* @__PURE__ */ jsx(DurableHistoryCapsCard, { canEdit })
629
630
  ] });
630
631
  }
632
+ function hasRunControlSettings(flags) {
633
+ return flags.runControlDurable || flags.searchAttributes || flags.runArchival || flags.selfHostedWorkers;
634
+ }
635
+ function RunControlTab({ flags }) {
636
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", "data-testid": "settings-run-control", children: [
637
+ flags.runControlDurable && /* @__PURE__ */ jsx(PauseRulesCard, {}),
638
+ flags.searchAttributes && /* @__PURE__ */ jsx(SearchAttributeDefinitionsCard, {}),
639
+ flags.runArchival && /* @__PURE__ */ jsx(ArchiveSettingsCard, {}),
640
+ flags.selfHostedWorkers && /* @__PURE__ */ jsx(CodecServerCard, {})
641
+ ] });
642
+ }
643
+ function Card({
644
+ icon,
645
+ title,
646
+ description,
647
+ children,
648
+ testId
649
+ }) {
650
+ return /* @__PURE__ */ jsxs(
651
+ "section",
652
+ {
653
+ className: "rounded-lg border border-border-secondary bg-background-secondary p-4 sm:p-6",
654
+ "data-testid": testId,
655
+ children: [
656
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center gap-2", children: [
657
+ /* @__PURE__ */ jsx(Icon, { icon, width: 18, className: "text-text-secondary" }),
658
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-text-primary", children: title })
659
+ ] }),
660
+ /* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-text-secondary", children: description }),
661
+ children
662
+ ]
663
+ }
664
+ );
665
+ }
666
+ function PauseRulesCard() {
667
+ const tr = useTr();
668
+ const rules = useResource("pause-rules", true, fetchPauseRules);
669
+ const { allowed: canEdit } = useFluidGridsPermission(
670
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_UPDATE
671
+ );
672
+ const [form, setForm] = useState({
673
+ activityType: "",
674
+ workflowKey: "",
675
+ reason: "",
676
+ expiresAt: ""
677
+ });
678
+ const [busy, setBusy] = useState(false);
679
+ const [error, setError] = useState(null);
680
+ const expires = form.expiresAt ? new Date(form.expiresAt) : null;
681
+ const valid = (form.activityType.trim() || form.workflowKey.trim()) && form.reason.trim() && (!expires || !Number.isNaN(expires.getTime()) && expires.getTime() > Date.now());
682
+ const create = async () => {
683
+ if (!valid) return;
684
+ setBusy(true);
685
+ setError(null);
686
+ try {
687
+ await createPauseRule({
688
+ activityType: form.activityType.trim() || null,
689
+ workflowKey: form.workflowKey.trim() || null,
690
+ reason: form.reason.trim(),
691
+ expiresAt: expires ? expires.toISOString() : null
692
+ });
693
+ setForm({ activityType: "", workflowKey: "", reason: "", expiresAt: "" });
694
+ await rules.refetch();
695
+ } catch (err) {
696
+ setError(describeOperationError(err));
697
+ } finally {
698
+ setBusy(false);
699
+ }
700
+ };
701
+ const remove = async (id) => {
702
+ try {
703
+ await deletePauseRule(id);
704
+ toast.success(
705
+ tr(
706
+ "fluidgrids.settings.pauseRules.deleted",
707
+ "Rule deleted; what it paused is unpaused"
708
+ )
709
+ );
710
+ await rules.refetch();
711
+ } catch (err) {
712
+ toast.error(describeOperationError(err));
713
+ }
714
+ };
715
+ return /* @__PURE__ */ jsxs(
716
+ Card,
717
+ {
718
+ icon: "mdi:pause-octagon-outline",
719
+ title: tr("fluidgrids.settings.pauseRules.title", "Activity pause rules"),
720
+ description: tr(
721
+ "fluidgrids.settings.pauseRules.description",
722
+ "A rule pauses matching durable activities when they are scheduled or retried, for example while a downstream system is down. Deleting it unpauses them."
723
+ ),
724
+ testId: "settings-pause-rules",
725
+ children: [
726
+ /* @__PURE__ */ jsx(FieldError, { message: rules.error }),
727
+ rules.data && rules.data.length === 0 && /* @__PURE__ */ jsx("p", { className: "mb-3 text-sm text-text-secondary", children: tr("fluidgrids.settings.pauseRules.empty", "No pause rules.") }),
728
+ rules.data && rules.data.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mb-4 divide-y divide-border-secondary rounded-md border border-border-secondary", children: rules.data.map((rule) => /* @__PURE__ */ jsxs(
729
+ "li",
730
+ {
731
+ className: "flex flex-wrap items-center gap-3 px-3 py-2 text-sm",
732
+ "data-testid": `pause-rule-${rule.id}`,
733
+ children: [
734
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-xs text-text-primary", children: rule.activityType ?? rule.nodeType ?? "*" }),
735
+ rule.workflowKey && /* @__PURE__ */ jsx("span", { className: "text-xs text-text-secondary", children: rule.workflowKey }),
736
+ /* @__PURE__ */ jsx("span", { className: "text-text-primary", children: rule.reason }),
737
+ rule.expiresAt && /* @__PURE__ */ jsx("span", { className: "text-xs text-text-secondary", children: tr(
738
+ "fluidgrids.settings.pauseRules.until",
739
+ "until {{date}}",
740
+ { date: new Date(rule.expiresAt).toLocaleString() }
741
+ ) }),
742
+ canEdit && /* @__PURE__ */ jsx(
743
+ Button,
744
+ {
745
+ size: "sm",
746
+ variant: "ghost",
747
+ className: "ml-auto text-[var(--color-status-error-text)]",
748
+ onClick: () => void remove(rule.id),
749
+ "data-testid": `pause-rule-delete-${rule.id}`,
750
+ children: tr("fluidgrids.settings.common.delete", "Delete")
751
+ }
752
+ )
753
+ ]
754
+ },
755
+ rule.id
756
+ )) }),
757
+ canEdit && /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
758
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
759
+ /* @__PURE__ */ jsx(Label, { htmlFor: "pause-rule-type", children: tr(
760
+ "fluidgrids.settings.pauseRules.activityType",
761
+ "Activity or node type"
762
+ ) }),
763
+ /* @__PURE__ */ jsx(
764
+ Input,
765
+ {
766
+ id: "pause-rule-type",
767
+ value: form.activityType,
768
+ placeholder: "store/crm",
769
+ onChange: (event) => setForm({ ...form, activityType: event.target.value }),
770
+ "data-testid": "pause-rule-type"
771
+ }
772
+ )
773
+ ] }),
774
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
775
+ /* @__PURE__ */ jsx(Label, { htmlFor: "pause-rule-workflow", children: tr(
776
+ "fluidgrids.settings.pauseRules.workflowKey",
777
+ "Workflow key (optional)"
778
+ ) }),
779
+ /* @__PURE__ */ jsx(
780
+ Input,
781
+ {
782
+ id: "pause-rule-workflow",
783
+ value: form.workflowKey,
784
+ onChange: (event) => setForm({ ...form, workflowKey: event.target.value }),
785
+ "data-testid": "pause-rule-workflow"
786
+ }
787
+ )
788
+ ] }),
789
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
790
+ /* @__PURE__ */ jsx(Label, { htmlFor: "pause-rule-reason", children: tr("fluidgrids.settings.pauseRules.reason", "Reason") }),
791
+ /* @__PURE__ */ jsx(
792
+ Input,
793
+ {
794
+ id: "pause-rule-reason",
795
+ value: form.reason,
796
+ onChange: (event) => setForm({ ...form, reason: event.target.value }),
797
+ "data-testid": "pause-rule-reason"
798
+ }
799
+ )
800
+ ] }),
801
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
802
+ /* @__PURE__ */ jsx(Label, { htmlFor: "pause-rule-expires", children: tr(
803
+ "fluidgrids.settings.pauseRules.expiresAt",
804
+ "Ends at (optional)"
805
+ ) }),
806
+ /* @__PURE__ */ jsx(
807
+ Input,
808
+ {
809
+ id: "pause-rule-expires",
810
+ type: "datetime-local",
811
+ value: form.expiresAt,
812
+ onChange: (event) => setForm({ ...form, expiresAt: event.target.value }),
813
+ "data-testid": "pause-rule-expires"
814
+ }
815
+ )
816
+ ] }),
817
+ /* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
818
+ /* @__PURE__ */ jsx(FieldError, { message: error, testId: "pause-rule-error" }),
819
+ /* @__PURE__ */ jsx(
820
+ Button,
821
+ {
822
+ onClick: () => void create(),
823
+ disabled: !valid || busy,
824
+ "data-testid": "pause-rule-create",
825
+ children: tr("fluidgrids.settings.pauseRules.create", "Add rule")
826
+ }
827
+ )
828
+ ] })
829
+ ] })
830
+ ]
831
+ }
832
+ );
833
+ }
834
+ var ATTRIBUTE_TYPES = [
835
+ "KEYWORD" /* Keyword */,
836
+ "TEXT" /* Text */,
837
+ "INT" /* Int */,
838
+ "DOUBLE" /* Double */,
839
+ "BOOL" /* Bool */,
840
+ "DATETIME" /* Datetime */,
841
+ "KEYWORD_LIST" /* KeywordList */
842
+ ];
843
+ var SEARCH_ATTRIBUTE_NAME = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
844
+ function SearchAttributeDefinitionsCard() {
845
+ const tr = useTr();
846
+ const definitions = useResource(
847
+ "search-attributes",
848
+ true,
849
+ fetchSearchAttributes
850
+ );
851
+ const { allowed: canEdit } = useFluidGridsPermission(
852
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_UPDATE
853
+ );
854
+ const [name, setName] = useState("");
855
+ const [type, setType] = useState(
856
+ "KEYWORD" /* Keyword */
857
+ );
858
+ const [description, setDescription] = useState("");
859
+ const [busy, setBusy] = useState(false);
860
+ const [error, setError] = useState(null);
861
+ const validName = SEARCH_ATTRIBUTE_NAME.test(name.trim());
862
+ const create = async () => {
863
+ if (!validName) return;
864
+ setBusy(true);
865
+ setError(null);
866
+ try {
867
+ await createSearchAttribute({ name, type, description });
868
+ setName("");
869
+ setDescription("");
870
+ await definitions.refetch();
871
+ } catch (err) {
872
+ setError(describeOperationError(err));
873
+ } finally {
874
+ setBusy(false);
875
+ }
876
+ };
877
+ const remove = async (id) => {
878
+ try {
879
+ await deleteSearchAttribute(id);
880
+ await definitions.refetch();
881
+ } catch (err) {
882
+ toast.error(describeOperationError(err));
883
+ }
884
+ };
885
+ return /* @__PURE__ */ jsxs(
886
+ Card,
887
+ {
888
+ icon: "mdi:tag-search-outline",
889
+ title: tr(
890
+ "fluidgrids.settings.searchAttributes.title",
891
+ "Search attributes"
892
+ ),
893
+ description: tr(
894
+ "fluidgrids.settings.searchAttributes.description",
895
+ "Typed values runs carry so the Runs list can filter on them (at most 50). Deleting one leaves the runs' values in place."
896
+ ),
897
+ testId: "settings-search-attributes",
898
+ children: [
899
+ /* @__PURE__ */ jsx(FieldError, { message: definitions.error }),
900
+ definitions.data && definitions.data.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mb-4 divide-y divide-border-secondary rounded-md border border-border-secondary", children: definitions.data.map((definition) => /* @__PURE__ */ jsxs(
901
+ "li",
902
+ {
903
+ className: "flex flex-wrap items-center gap-3 px-3 py-2 text-sm",
904
+ "data-testid": `search-attribute-${definition.name}`,
905
+ children: [
906
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-xs text-text-primary", children: definition.name }),
907
+ /* @__PURE__ */ jsx(StatusPill, { tone: "neutral", children: definition.type }),
908
+ definition.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-text-secondary", children: definition.description }),
909
+ canEdit && /* @__PURE__ */ jsx(
910
+ Button,
911
+ {
912
+ size: "sm",
913
+ variant: "ghost",
914
+ className: "ml-auto text-[var(--color-status-error-text)]",
915
+ onClick: () => void remove(definition.id),
916
+ children: tr("fluidgrids.settings.common.delete", "Delete")
917
+ }
918
+ )
919
+ ]
920
+ },
921
+ definition.id
922
+ )) }),
923
+ canEdit && /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [
924
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
925
+ /* @__PURE__ */ jsx(Label, { htmlFor: "search-attribute-name", children: tr("fluidgrids.settings.searchAttributes.name", "Name") }),
926
+ /* @__PURE__ */ jsx(
927
+ Input,
928
+ {
929
+ id: "search-attribute-name",
930
+ value: name,
931
+ placeholder: "customerId",
932
+ onChange: (event) => setName(event.target.value),
933
+ "data-testid": "search-attribute-name"
934
+ }
935
+ )
936
+ ] }),
937
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
938
+ /* @__PURE__ */ jsx(Label, { htmlFor: "search-attribute-type", children: tr("fluidgrids.settings.searchAttributes.type", "Type") }),
939
+ /* @__PURE__ */ jsx(
940
+ NativeSelect,
941
+ {
942
+ id: "search-attribute-type",
943
+ value: type,
944
+ onChange: (value) => setType(
945
+ ATTRIBUTE_TYPES.find((item) => item === value) ?? "KEYWORD" /* Keyword */
946
+ ),
947
+ testId: "search-attribute-type",
948
+ children: ATTRIBUTE_TYPES.map((item) => /* @__PURE__ */ jsx("option", { value: item, children: item }, item))
949
+ }
950
+ )
951
+ ] }),
952
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
953
+ /* @__PURE__ */ jsx(Label, { htmlFor: "search-attribute-description", children: tr(
954
+ "fluidgrids.settings.searchAttributes.descriptionField",
955
+ "Description (optional)"
956
+ ) }),
957
+ /* @__PURE__ */ jsx(
958
+ Input,
959
+ {
960
+ id: "search-attribute-description",
961
+ value: description,
962
+ maxLength: 1e3,
963
+ onChange: (event) => setDescription(event.target.value)
964
+ }
965
+ )
966
+ ] }),
967
+ /* @__PURE__ */ jsxs("div", { className: "sm:col-span-3", children: [
968
+ name && !validName && /* @__PURE__ */ jsx(
969
+ FieldError,
970
+ {
971
+ message: tr(
972
+ "fluidgrids.settings.searchAttributes.badName",
973
+ "Start with a letter; use letters, digits and underscores (at most 64)."
974
+ )
975
+ }
976
+ ),
977
+ /* @__PURE__ */ jsx(FieldError, { message: error, testId: "search-attribute-error" }),
978
+ /* @__PURE__ */ jsx(
979
+ Button,
980
+ {
981
+ onClick: () => void create(),
982
+ disabled: !validName || busy,
983
+ "data-testid": "search-attribute-create",
984
+ children: tr(
985
+ "fluidgrids.settings.searchAttributes.create",
986
+ "Add attribute"
987
+ )
988
+ }
989
+ )
990
+ ] })
991
+ ] })
992
+ ]
993
+ }
994
+ );
995
+ }
996
+ var ROLE_ARN = /^arn:aws[a-z-]*:iam::\d{12}:role\/[\w+=,.@/-]{1,512}$/;
997
+ var BUCKET_NAME = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
998
+ function ArchiveSettingsCard() {
999
+ const tr = useTr();
1000
+ const archive = useResource("archive-settings", true, fetchArchiveSettings);
1001
+ const { allowed: canEdit } = useFluidGridsPermission(
1002
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_DELETE
1003
+ );
1004
+ const [form, setForm] = useState({
1005
+ enabled: false,
1006
+ bucket: "",
1007
+ prefix: "",
1008
+ region: "",
1009
+ roleArn: "",
1010
+ includePayloads: true
1011
+ });
1012
+ const [busy, setBusy] = useState(false);
1013
+ const [error, setError] = useState(null);
1014
+ useEffect(() => {
1015
+ const current = archive.data;
1016
+ if (current)
1017
+ setForm({
1018
+ enabled: current.enabled,
1019
+ bucket: current.bucket,
1020
+ prefix: current.prefix,
1021
+ region: current.region,
1022
+ roleArn: current.roleArn,
1023
+ includePayloads: current.includePayloads
1024
+ });
1025
+ }, [archive.data]);
1026
+ const valid = BUCKET_NAME.test(form.bucket.trim()) && /^[a-z]{2}-[a-z]+-\d$/.test(form.region.trim()) && ROLE_ARN.test(form.roleArn.trim());
1027
+ const save = async () => {
1028
+ if (!valid) return;
1029
+ setBusy(true);
1030
+ setError(null);
1031
+ try {
1032
+ archive.set(
1033
+ await saveArchiveSettings({
1034
+ enabled: form.enabled,
1035
+ bucket: form.bucket.trim(),
1036
+ prefix: form.prefix.trim().replace(/^\/+|\/+$/g, ""),
1037
+ region: form.region.trim(),
1038
+ roleArn: form.roleArn.trim(),
1039
+ includePayloads: form.includePayloads
1040
+ })
1041
+ );
1042
+ toast.success(
1043
+ tr("fluidgrids.settings.archive.saved", "Archive destination saved")
1044
+ );
1045
+ } catch (err) {
1046
+ setError(describeOperationError(err));
1047
+ } finally {
1048
+ setBusy(false);
1049
+ }
1050
+ };
1051
+ const clear = async () => {
1052
+ setBusy(true);
1053
+ setError(null);
1054
+ try {
1055
+ await clearArchiveSettings();
1056
+ archive.set(null);
1057
+ setForm({
1058
+ enabled: false,
1059
+ bucket: "",
1060
+ prefix: "",
1061
+ region: "",
1062
+ roleArn: "",
1063
+ includePayloads: true
1064
+ });
1065
+ } catch (err) {
1066
+ setError(describeOperationError(err));
1067
+ } finally {
1068
+ setBusy(false);
1069
+ }
1070
+ };
1071
+ return /* @__PURE__ */ jsxs(
1072
+ Card,
1073
+ {
1074
+ icon: "mdi:archive-arrow-down-outline",
1075
+ title: tr("fluidgrids.settings.archive.title", "Run archive"),
1076
+ description: tr(
1077
+ "fluidgrids.settings.archive.description",
1078
+ "Before retention deletes a finished run, it is written to an S3 bucket in your AWS account. The service assumes your role with this workspace's id as the external id, and checks the destination with a probe object when you enable it."
1079
+ ),
1080
+ testId: "settings-archive",
1081
+ children: [
1082
+ archive.data && archive.data.failingRuns > 0 && /* @__PURE__ */ jsx(
1083
+ "div",
1084
+ {
1085
+ role: "status",
1086
+ className: "mb-4 rounded-md border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bg-subtle)] p-3 text-sm text-[var(--color-status-warning-text)]",
1087
+ "data-testid": "archive-failing",
1088
+ children: tr(
1089
+ "fluidgrids.settings.archive.failing",
1090
+ "{{count}} runs could not be archived, so their purge waits. Last error: {{error}}",
1091
+ {
1092
+ count: archive.data.failingRuns,
1093
+ error: archive.data.lastError ?? "\u2014"
1094
+ }
1095
+ )
1096
+ }
1097
+ ),
1098
+ /* @__PURE__ */ jsx(FieldError, { message: archive.error }),
1099
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
1100
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1101
+ /* @__PURE__ */ jsx(Label, { htmlFor: "archive-bucket", children: tr("fluidgrids.settings.archive.bucket", "Bucket") }),
1102
+ /* @__PURE__ */ jsx(
1103
+ Input,
1104
+ {
1105
+ id: "archive-bucket",
1106
+ value: form.bucket,
1107
+ disabled: !canEdit,
1108
+ onChange: (event) => setForm({ ...form, bucket: event.target.value }),
1109
+ "data-testid": "archive-bucket"
1110
+ }
1111
+ )
1112
+ ] }),
1113
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1114
+ /* @__PURE__ */ jsx(Label, { htmlFor: "archive-prefix", children: tr("fluidgrids.settings.archive.prefix", "Key prefix (optional)") }),
1115
+ /* @__PURE__ */ jsx(
1116
+ Input,
1117
+ {
1118
+ id: "archive-prefix",
1119
+ value: form.prefix,
1120
+ disabled: !canEdit,
1121
+ onChange: (event) => setForm({ ...form, prefix: event.target.value }),
1122
+ "data-testid": "archive-prefix"
1123
+ }
1124
+ )
1125
+ ] }),
1126
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1127
+ /* @__PURE__ */ jsx(Label, { htmlFor: "archive-region", children: tr("fluidgrids.settings.archive.region", "Region") }),
1128
+ /* @__PURE__ */ jsx(
1129
+ Input,
1130
+ {
1131
+ id: "archive-region",
1132
+ value: form.region,
1133
+ placeholder: "ap-south-1",
1134
+ disabled: !canEdit,
1135
+ onChange: (event) => setForm({ ...form, region: event.target.value }),
1136
+ "data-testid": "archive-region"
1137
+ }
1138
+ )
1139
+ ] }),
1140
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1141
+ /* @__PURE__ */ jsx(Label, { htmlFor: "archive-role", children: tr("fluidgrids.settings.archive.roleArn", "Role ARN") }),
1142
+ /* @__PURE__ */ jsx(
1143
+ Input,
1144
+ {
1145
+ id: "archive-role",
1146
+ value: form.roleArn,
1147
+ placeholder: "arn:aws:iam::123456789012:role/fluidgrids-archive",
1148
+ disabled: !canEdit,
1149
+ onChange: (event) => setForm({ ...form, roleArn: event.target.value }),
1150
+ "data-testid": "archive-role"
1151
+ }
1152
+ )
1153
+ ] }),
1154
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-3 text-sm sm:col-span-2", children: [
1155
+ tr(
1156
+ "fluidgrids.settings.archive.includePayloads",
1157
+ "Include payloads, inputs and outputs"
1158
+ ),
1159
+ /* @__PURE__ */ jsx(
1160
+ Switch,
1161
+ {
1162
+ checked: form.includePayloads,
1163
+ disabled: !canEdit,
1164
+ onCheckedChange: (includePayloads) => setForm({ ...form, includePayloads })
1165
+ }
1166
+ )
1167
+ ] }),
1168
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-3 text-sm sm:col-span-2", children: [
1169
+ tr(
1170
+ "fluidgrids.settings.archive.enabled",
1171
+ "Archive runs before they are purged"
1172
+ ),
1173
+ /* @__PURE__ */ jsx(
1174
+ Switch,
1175
+ {
1176
+ checked: form.enabled,
1177
+ disabled: !canEdit,
1178
+ onCheckedChange: (enabled) => setForm({ ...form, enabled }),
1179
+ "data-testid": "archive-enabled"
1180
+ }
1181
+ )
1182
+ ] })
1183
+ ] }),
1184
+ /* @__PURE__ */ jsx(FieldError, { message: error, testId: "archive-error" }),
1185
+ canEdit && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex gap-2", children: [
1186
+ /* @__PURE__ */ jsx(
1187
+ Button,
1188
+ {
1189
+ onClick: () => void save(),
1190
+ disabled: !valid || busy,
1191
+ "data-testid": "archive-save",
1192
+ children: tr("fluidgrids.settings.common.save", "Save")
1193
+ }
1194
+ ),
1195
+ archive.data && /* @__PURE__ */ jsx(
1196
+ Button,
1197
+ {
1198
+ variant: "outline",
1199
+ onClick: () => void clear(),
1200
+ disabled: busy,
1201
+ "data-testid": "archive-clear",
1202
+ children: tr("fluidgrids.settings.archive.remove", "Remove destination")
1203
+ }
1204
+ )
1205
+ ] })
1206
+ ]
1207
+ }
1208
+ );
1209
+ }
1210
+ function CodecServerCard() {
1211
+ const tr = useTr();
1212
+ const settings = useResource("codec-server", true, fetchCodecServerSettings);
1213
+ const { allowed: canEdit } = useFluidGridsPermission(
1214
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_DELETE
1215
+ );
1216
+ const [url, setUrl] = useState("");
1217
+ const [includeCredentials, setIncludeCredentials] = useState(false);
1218
+ const [busy, setBusy] = useState(false);
1219
+ const [error, setError] = useState(null);
1220
+ useEffect(() => {
1221
+ if (!settings.data) return;
1222
+ setUrl(settings.data.codecServerUrl ?? "");
1223
+ setIncludeCredentials(settings.data.codecServerIncludeCredentials);
1224
+ }, [settings.data]);
1225
+ const check = url.trim() ? checkCodecServerUrl(url) : null;
1226
+ const save = async () => {
1227
+ if (check && !check.ok) return;
1228
+ setBusy(true);
1229
+ setError(null);
1230
+ try {
1231
+ settings.set(
1232
+ await saveCodecServerSettings({
1233
+ codecServerUrl: url.trim(),
1234
+ codecServerIncludeCredentials: includeCredentials
1235
+ })
1236
+ );
1237
+ toast.success(
1238
+ tr("fluidgrids.settings.codec.saved", "Codec server saved")
1239
+ );
1240
+ } catch (err) {
1241
+ setError(describeOperationError(err));
1242
+ } finally {
1243
+ setBusy(false);
1244
+ }
1245
+ };
1246
+ return /* @__PURE__ */ jsxs(
1247
+ Card,
1248
+ {
1249
+ icon: "mdi:lock-open-outline",
1250
+ title: tr("fluidgrids.settings.codec.title", "Codec server"),
1251
+ description: tr(
1252
+ "fluidgrids.settings.codec.description",
1253
+ "Payloads your self-hosted workers encode stay encoded in FluidGrids. The run page can send them to your codec server (Temporal's codec-server protocol) to show them decoded. No FluidGrids token is ever sent there."
1254
+ ),
1255
+ testId: "settings-codec",
1256
+ children: [
1257
+ /* @__PURE__ */ jsx(FieldError, { message: settings.error }),
1258
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1259
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1260
+ /* @__PURE__ */ jsx(Label, { htmlFor: "codec-url", children: tr("fluidgrids.settings.codec.url", "Codec server URL") }),
1261
+ /* @__PURE__ */ jsx(
1262
+ Input,
1263
+ {
1264
+ id: "codec-url",
1265
+ value: url,
1266
+ disabled: !canEdit,
1267
+ placeholder: "https://codec.example.com",
1268
+ onChange: (event) => setUrl(event.target.value),
1269
+ "data-testid": "codec-url"
1270
+ }
1271
+ ),
1272
+ check && !check.ok && /* @__PURE__ */ jsx(
1273
+ FieldError,
1274
+ {
1275
+ message: tr(
1276
+ "fluidgrids.settings.codec.badUrl",
1277
+ "Use an https URL (http only for localhost)."
1278
+ ),
1279
+ testId: "codec-url-error"
1280
+ }
1281
+ ),
1282
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: tr(
1283
+ "fluidgrids.settings.codec.empty",
1284
+ "Leave it empty to show encoded payloads as encoded."
1285
+ ) })
1286
+ ] }),
1287
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-3 text-sm", children: [
1288
+ tr(
1289
+ "fluidgrids.settings.codec.credentials",
1290
+ "Send my browser's own credentials (cookies) to it"
1291
+ ),
1292
+ /* @__PURE__ */ jsx(
1293
+ Switch,
1294
+ {
1295
+ checked: includeCredentials,
1296
+ disabled: !canEdit,
1297
+ onCheckedChange: setIncludeCredentials,
1298
+ "data-testid": "codec-credentials"
1299
+ }
1300
+ )
1301
+ ] }),
1302
+ /* @__PURE__ */ jsx(FieldError, { message: error, testId: "codec-error" }),
1303
+ canEdit && /* @__PURE__ */ jsx(
1304
+ Button,
1305
+ {
1306
+ onClick: () => void save(),
1307
+ disabled: busy || check !== null && !check.ok,
1308
+ "data-testid": "codec-save",
1309
+ children: tr("fluidgrids.settings.common.save", "Save")
1310
+ }
1311
+ )
1312
+ ] })
1313
+ ]
1314
+ }
1315
+ );
1316
+ }
631
1317
 
632
1318
  // src/modules/settings/utils/error-trigger.ts
633
1319
  var ERROR_TRIGGER_NODE_TYPE = "internal:error-trigger";
@@ -2727,7 +3413,7 @@ function ApiTab() {
2727
3413
  const tr = useTr();
2728
3414
  const settings = DEFAULT_SETTINGS.api;
2729
3415
  return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
2730
- /* @__PURE__ */ jsx(Card, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
3416
+ /* @__PURE__ */ jsx(Card$1, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
2731
3417
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
2732
3418
  /* @__PURE__ */ jsx(Icon, { icon: "mdi:api", width: 20, className: "text-text-secondary" }),
2733
3419
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-text-primary", children: tr(
@@ -2753,7 +3439,7 @@ function ApiTab() {
2753
3439
  )
2754
3440
  ] })
2755
3441
  ] }) }),
2756
- /* @__PURE__ */ jsx(Card, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
3442
+ /* @__PURE__ */ jsx(Card$1, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
2757
3443
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
2758
3444
  /* @__PURE__ */ jsx(
2759
3445
  Icon,
@@ -2795,7 +3481,7 @@ function ApiTab() {
2795
3481
  )
2796
3482
  ] })
2797
3483
  ] }) }),
2798
- /* @__PURE__ */ jsx(Card, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
3484
+ /* @__PURE__ */ jsx(Card$1, { className: "border border-border-secondary bg-background-secondary", children: /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
2799
3485
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
2800
3486
  /* @__PURE__ */ jsx(
2801
3487
  Icon,
@@ -2842,7 +3528,9 @@ function SettingsPage({
2842
3528
  const workflowKey = workflowKeyProp || routeParams.workflowKey || routeParams.id || activeWorkflowKey || void 0;
2843
3529
  const [activeTab, setActiveTab] = useState("general");
2844
3530
  const logStreamsEnabled = useFluidGridsFlag(FLUIDGRIDS_FLAGS.logStreams);
2845
- const visibleTab = !logStreamsEnabled && activeTab === "log-streaming" ? "general" : activeTab;
3531
+ const phaseC = usePhaseCFlags();
3532
+ const runControlSettings = hasRunControlSettings(phaseC);
3533
+ const visibleTab = !logStreamsEnabled && activeTab === "log-streaming" || !runControlSettings && activeTab === "run-control" ? "general" : activeTab;
2846
3534
  return /* @__PURE__ */ jsxs("div", { className: "p-4 sm:p-6 bg-background-primary min-h-screen", children: [
2847
3535
  /* @__PURE__ */ jsxs(
2848
3536
  "div",
@@ -2892,6 +3580,10 @@ function SettingsPage({
2892
3580
  /* @__PURE__ */ jsx(Icon, { icon: "mdi:database-clock-outline", width: 16 }),
2893
3581
  tr("fluidgrids.settings.page.runDataTab", "Run data")
2894
3582
  ] }),
3583
+ runControlSettings ? /* @__PURE__ */ jsxs(TabsTrigger, { value: "run-control", className: "gap-1.5", children: [
3584
+ /* @__PURE__ */ jsx(Icon, { icon: "mdi:tune-variant", width: 16 }),
3585
+ tr("fluidgrids.settings.page.runControlTab", "Run control")
3586
+ ] }) : null,
2895
3587
  /* @__PURE__ */ jsxs(
2896
3588
  TabsTrigger,
2897
3589
  {
@@ -2954,6 +3646,7 @@ function SettingsPage({
2954
3646
  /* @__PURE__ */ jsx(TabsContent, { value: "general", children: /* @__PURE__ */ jsx(GeneralTab, {}) }),
2955
3647
  /* @__PURE__ */ jsx(TabsContent, { value: "execution", children: /* @__PURE__ */ jsx(ExecutionTab, { workflowKey }) }),
2956
3648
  /* @__PURE__ */ jsx(TabsContent, { value: "run-data", children: /* @__PURE__ */ jsx(RunDataTab, {}) }),
3649
+ runControlSettings ? /* @__PURE__ */ jsx(TabsContent, { value: "run-control", children: /* @__PURE__ */ jsx(RunControlTab, { flags: phaseC }) }) : null,
2957
3650
  /* @__PURE__ */ jsx(TabsContent, { value: "policies", children: /* @__PURE__ */ jsx(ActionPoliciesTab, {}) }),
2958
3651
  /* @__PURE__ */ jsx(TabsContent, { value: "agents", children: /* @__PURE__ */ jsx(AgentsTab, {}) }),
2959
3652
  /* @__PURE__ */ jsx(TabsContent, { value: "mcp", children: /* @__PURE__ */ jsx(McpGatewayTab, { workflowKey }) }),