@elevasis/ui 2.29.0 → 2.31.0

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 (125) hide show
  1. package/dist/{CoreAuthKitInner-QC62UHTZ.js → CoreAuthKitInner-KSEGSB67.js} +1 -1
  2. package/dist/api/index.js +3 -3
  3. package/dist/app/index.d.ts +176 -1
  4. package/dist/app/index.js +11 -11
  5. package/dist/auth/context.js +1 -1
  6. package/dist/auth/index.js +5 -5
  7. package/dist/charts/index.d.ts +2 -1
  8. package/dist/charts/index.js +9 -9
  9. package/dist/{chunk-XTVZFT7U.js → chunk-2Q2JQSQO.js} +1 -1
  10. package/dist/{chunk-LH4GPYDX.js → chunk-3BAPR3KA.js} +19 -3
  11. package/dist/{chunk-HLFFKKT3.js → chunk-3FV6HBXS.js} +17 -17
  12. package/dist/{chunk-WKJ47GIW.js → chunk-533DUEQY.js} +1 -1
  13. package/dist/{chunk-SZWXQHKO.js → chunk-542WPQU2.js} +9 -8
  14. package/dist/{chunk-5CW2HXQA.js → chunk-5LJAEZMA.js} +7 -28
  15. package/dist/{chunk-V3HUIZJX.js → chunk-6IXOKUBC.js} +1 -1
  16. package/dist/{chunk-VKMNWHTL.js → chunk-6YT4IKJ7.js} +3 -3
  17. package/dist/{chunk-CEHUFNAL.js → chunk-7HMCB26R.js} +12 -12
  18. package/dist/chunk-7KC4P3AU.js +357 -0
  19. package/dist/{chunk-OWESKPTJ.js → chunk-CQZ3DNQY.js} +30 -11
  20. package/dist/{chunk-ROSMICXG.js → chunk-CXY7FMUM.js} +35 -20
  21. package/dist/{chunk-I2KLQ2HA.js → chunk-DZTG5IAC.js} +7 -1
  22. package/dist/{chunk-JCGD4GM6.js → chunk-GRDLB6LM.js} +1 -0
  23. package/dist/{chunk-FGDUK74A.js → chunk-HQGF4ATG.js} +10 -56
  24. package/dist/{chunk-HOIT677G.js → chunk-HUJCU55S.js} +1 -1
  25. package/dist/{chunk-OIMPGKDB.js → chunk-HYNYEBHM.js} +4 -4
  26. package/dist/{chunk-GESXCQWY.js → chunk-JA5ECJJB.js} +1 -1
  27. package/dist/{chunk-KU7ZDWQ7.js → chunk-JBWJ6WHZ.js} +1 -1
  28. package/dist/{chunk-HNFQCOD2.js → chunk-JKSUN5GN.js} +1107 -370
  29. package/dist/{chunk-5WWZXCS5.js → chunk-KJ3QUBNU.js} +9 -2
  30. package/dist/{chunk-OHGNCWJP.js → chunk-L2NVFLXU.js} +3 -3
  31. package/dist/{chunk-6WXDE5LZ.js → chunk-L3BVJWML.js} +1 -1
  32. package/dist/{chunk-3DUOPXOJ.js → chunk-MVFCLZSK.js} +691 -222
  33. package/dist/{chunk-A7R2URMV.js → chunk-ND42LPY4.js} +44 -10
  34. package/dist/{chunk-CLUP5H3C.js → chunk-O2QOPJI5.js} +360 -126
  35. package/dist/{chunk-VMJVQAFZ.js → chunk-OAVTMITG.js} +1 -1
  36. package/dist/{chunk-X2SUMO3P.js → chunk-P55BJZZW.js} +2 -1
  37. package/dist/{chunk-QNL7UI5G.js → chunk-Q6OYNEGR.js} +6 -6
  38. package/dist/{chunk-Y3YJKKEB.js → chunk-QDEETKYT.js} +5 -2
  39. package/dist/{chunk-XBMCDGHA.js → chunk-QHEWXU7I.js} +1 -1
  40. package/dist/chunk-R2XR4FCV.js +48 -0
  41. package/dist/chunk-R66W5UDG.js +26 -0
  42. package/dist/{chunk-65RQE3XF.js → chunk-SHQXMW4F.js} +1051 -380
  43. package/dist/{chunk-AK5E6ILJ.js → chunk-T3IPHEYJ.js} +1893 -305
  44. package/dist/{chunk-7E3FUTND.js → chunk-TOIXUWR6.js} +1 -1
  45. package/dist/{chunk-FFDAE2QI.js → chunk-TVRQ6AQI.js} +172 -26
  46. package/dist/{chunk-CN2HC4D4.js → chunk-UFTM5SZZ.js} +2 -2
  47. package/dist/{chunk-WFTNY755.js → chunk-VKIZUUPM.js} +1 -1
  48. package/dist/{chunk-KVJ3LFH2.js → chunk-VNFR57DF.js} +4 -24
  49. package/dist/{chunk-S66IQSSR.js → chunk-WF227UBV.js} +1 -1
  50. package/dist/{chunk-6NHCE7JM.js → chunk-Y4FWCG7Y.js} +159 -314
  51. package/dist/components/chat/index.d.ts +2 -1
  52. package/dist/components/chat/index.js +2 -2
  53. package/dist/components/index.d.ts +205 -11
  54. package/dist/components/index.js +51 -48
  55. package/dist/components/navigation/index.js +9 -9
  56. package/dist/execution/index.d.ts +2 -1
  57. package/dist/execution/index.js +1 -1
  58. package/dist/features/auth/index.d.ts +121 -0
  59. package/dist/features/auth/index.js +6 -6
  60. package/dist/features/clients/index.css +611 -0
  61. package/dist/features/clients/index.d.ts +86 -0
  62. package/dist/features/clients/index.js +719 -0
  63. package/dist/features/crm/index.d.ts +148 -2
  64. package/dist/features/crm/index.js +27 -25
  65. package/dist/features/dashboard/index.d.ts +36 -1
  66. package/dist/features/dashboard/index.js +23 -23
  67. package/dist/features/delivery/index.d.ts +121 -0
  68. package/dist/features/delivery/index.js +27 -25
  69. package/dist/features/knowledge/index.js +52 -29
  70. package/dist/features/lead-gen/index.d.ts +116 -12
  71. package/dist/features/lead-gen/index.js +28 -26
  72. package/dist/features/monitoring/index.js +26 -25
  73. package/dist/features/monitoring/requests/index.js +23 -22
  74. package/dist/features/operations/index.d.ts +38 -2
  75. package/dist/features/operations/index.js +32 -31
  76. package/dist/features/seo/index.js +1 -1
  77. package/dist/features/settings/index.d.ts +121 -0
  78. package/dist/features/settings/index.js +25 -24
  79. package/dist/graph/index.js +1 -1
  80. package/dist/hooks/delivery/index.d.ts +140 -0
  81. package/dist/hooks/delivery/index.js +4 -4
  82. package/dist/hooks/index.d.ts +844 -21
  83. package/dist/hooks/index.js +21 -21
  84. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +82 -1
  85. package/dist/hooks/operations/command-view/utils/transformCommandViewData.js +1 -1
  86. package/dist/hooks/published.d.ts +844 -21
  87. package/dist/hooks/published.js +21 -21
  88. package/dist/index.d.ts +1056 -27
  89. package/dist/index.js +22 -22
  90. package/dist/initialization/index.d.ts +121 -0
  91. package/dist/initialization/index.js +5 -5
  92. package/dist/knowledge/index.d.ts +151 -1
  93. package/dist/knowledge/index.js +1692 -1039
  94. package/dist/layout/index.d.ts +6 -0
  95. package/dist/layout/index.js +4 -4
  96. package/dist/organization/index.js +5 -5
  97. package/dist/profile/index.d.ts +121 -0
  98. package/dist/profile/index.js +3 -3
  99. package/dist/provider/ElevasisServiceContext.d.ts +11 -5
  100. package/dist/provider/ElevasisServiceContext.js +2 -2
  101. package/dist/provider/index.d.ts +337 -7
  102. package/dist/provider/index.js +18 -18
  103. package/dist/provider/published.d.ts +337 -7
  104. package/dist/provider/published.js +14 -14
  105. package/dist/router/context.js +1 -1
  106. package/dist/router/index.js +1 -1
  107. package/dist/sse/index.js +1 -1
  108. package/dist/supabase/index.d.ts +232 -0
  109. package/dist/supabase/index.js +1 -1
  110. package/dist/test-utils/index.d.ts +3 -0
  111. package/dist/test-utils/index.js +31 -7
  112. package/dist/test-utils/setup-integration.js +1 -1
  113. package/dist/test-utils/setup.js +2 -2
  114. package/dist/theme/index.js +4 -4
  115. package/dist/theme/presets/index.js +2 -2
  116. package/dist/typeform/index.js +1 -1
  117. package/dist/typeform/schemas.js +1 -1
  118. package/dist/types/index.d.ts +204 -1
  119. package/dist/utils/index.d.ts +36 -1
  120. package/dist/utils/index.js +2 -2
  121. package/dist/vite/index.js +3 -3
  122. package/dist/vite-plugin-knowledge/index.js +2 -2
  123. package/dist/zustand/index.js +1 -1
  124. package/package.json +14 -5
  125. /package/dist/{chunk-HXZQWMKE.js → chunk-XQHZBA65.js} +0 -0
@@ -1,66 +1,36 @@
1
- import { DEFAULT_ORGANIZATION_MODEL_PROSPECTING, PROSPECTING_STEPS } from './chunk-FFDAE2QI.js';
1
+ import { SalesSidebar, LeadGenSidebarMiddle } from './chunk-7KC4P3AU.js';
2
+ import { DEFAULT_ORGANIZATION_MODEL_PROSPECTING, PROSPECTING_STEPS } from './chunk-TVRQ6AQI.js';
2
3
  import { sanitizeInput } from './chunk-3MEXPLWT.js';
4
+ import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
3
5
  import { PageContainer } from './chunk-BZZCNLT6.js';
4
6
  import { TableSelectionToolbar, SortableHeader } from './chunk-TUMSNGTX.js';
5
- import { SubshellNavItem } from './chunk-X4WBGKJQ.js';
6
- import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
7
7
  import { FilterBar } from './chunk-PDHTXPSF.js';
8
- import { CustomModal } from './chunk-KVJ3LFH2.js';
9
- import { acquisitionListKeys, useListsTelemetry, useLists, useCreateList, useTableSort, sortData, usePaginationState, useTableSelection, useWorkflowExecution, useList, useListProgress, useListExecutions, useDeleteList, useCompanyFacets, useCompanies, useDeleteCompanies, useContacts, useDeleteContacts, useListMembers, useListMember, useTransitionListMember, useDeriveActions, useArtifacts } from './chunk-HNFQCOD2.js';
10
- import { showApiErrorNotification, showSuccessNotification } from './chunk-CEHUFNAL.js';
11
- import { PageTitleCaption, CenteredErrorState, StatCard, CardHeader, EmptyState, JsonViewer } from './chunk-6WXDE5LZ.js';
12
- import { useListActions, LEAD_GEN_STAGE_CATALOG, LEAD_GEN_PIPELINE_DEFINITIONS, findPipeline } from './chunk-OWESKPTJ.js';
8
+ import { CustomModal } from './chunk-R66W5UDG.js';
9
+ import { acquisitionListKeys, useListsTelemetry, useLists, useCreateList, useTableSort, sortData, usePaginationState, useTableSelection, useWorkflowExecution, useList, useListProgress, useListExecutions, useDeleteList, useCompanyFacets, useCompanies, useDeleteCompanies, useContacts, useDeleteContacts, useCredentials, useVerifyCredential, useInFlightExecutions, useListRecords, useExecutionSSE, useListMembers, useListMember, useTransitionListMember, useDeriveActions, useArtifacts } from './chunk-JKSUN5GN.js';
10
+ import { showApiErrorNotification, showSuccessNotification } from './chunk-7HMCB26R.js';
11
+ import { PageTitleCaption, CenteredErrorState, StatCard, CardHeader, EmptyState, JsonViewer } from './chunk-L3BVJWML.js';
12
+ import { useListActions, LEAD_GEN_STAGE_CATALOG, LEAD_GEN_PIPELINE_DEFINITIONS, findPipeline } from './chunk-CQZ3DNQY.js';
13
13
  import { SubshellContentContainer } from './chunk-TKAYX2SP.js';
14
- import { useRouterContext } from './chunk-Q7DJKLEN.js';
15
- import { useElevasisServices } from './chunk-5WWZXCS5.js';
16
- import { Stack, Group, Title, Text, Alert, Button, Collapse, Paper, Anchor, ActionIcon, Divider, Box, SimpleGrid, Badge, Card, Center, Loader, Table, TextInput, Select, Checkbox, Pagination, Textarea, Tooltip, Tabs, ThemeIcon, Pill, SegmentedControl, UnstyledButton, Drawer, JsonInput, Switch, NumberInput, MultiSelect, TagsInput, ScrollArea } from '@mantine/core';
17
- import { IconLayoutGrid, IconList, IconBuilding, IconAddressBook, IconTarget, IconExternalLink, IconX, IconAlertCircle, IconPlayerPlay, IconArrowRight, IconSparkles, IconListDetails, IconPlus, IconSearch, IconAlertTriangle, IconLayoutDashboard, IconBolt, IconCopy, IconUsers, IconTrash, IconBuildingFactory2, IconArrowLeft, IconChevronDown, IconChevronRight, IconRefresh, IconSettings, IconMail, IconUser, IconDatabase } from '@tabler/icons-react';
14
+ import { isStepStartedContext, isStepCompletedContext, isStepFailedContext } from './chunk-KRWALB24.js';
15
+ import { useElevasisServices } from './chunk-KJ3QUBNU.js';
16
+ import { Stack, Group, Title, Text, Alert, Button, Collapse, Paper, Anchor, Center, Loader, SimpleGrid, Card, Table, Badge, TextInput, Select, Checkbox, Pagination, Textarea, ActionIcon, Tooltip, Tabs, ThemeIcon, Box, Pill, SegmentedControl, UnstyledButton, Drawer, JsonInput, Switch, NumberInput, MultiSelect, TagsInput, ScrollArea, Progress } from '@mantine/core';
17
+ import { IconTarget, IconAlertCircle, IconPlayerPlay, IconArrowRight, IconSparkles, IconListDetails, IconPlus, IconSearch, IconList, IconExternalLink, IconAlertTriangle, IconLayoutDashboard, IconBolt, IconCopy, IconBuilding, IconUsers, IconTrash, IconBuildingFactory2, IconArrowLeft, IconChevronDown, IconChevronRight, IconRefresh, IconAddressBook, IconSettings, IconCircleCheck, IconCircleDot, IconTerminal2, IconProgressCheck, IconMail, IconUser, IconDatabase } from '@tabler/icons-react';
18
18
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
19
- import { Link, useNavigate, useSearch } from '@tanstack/react-router';
20
- import { useState, useRef, useMemo, useEffect, Fragment as Fragment$1 } from 'react';
19
+ import { useState, useRef, useMemo, useEffect, Fragment as Fragment$1, useCallback } from 'react';
21
20
  import { useForm } from '@mantine/form';
22
21
  import { zod4Resolver } from 'mantine-form-zod-resolver';
22
+ import { Link, useNavigate, useSearch } from '@tanstack/react-router';
23
23
  import { useQueryClient, useMutation } from '@tanstack/react-query';
24
24
 
25
25
  var LeadGenSidebarTop = () => {
26
26
  return /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconTarget, label: "Lead Gen" });
27
27
  };
28
- var LEAD_GEN_ITEMS = [
29
- { label: "Overview", to: "/lead-gen", icon: IconLayoutGrid, exact: true },
30
- { label: "Lists", to: "/lead-gen/lists", icon: IconList, exact: false },
31
- { label: "Companies", to: "/lead-gen/companies", icon: IconBuilding, exact: false },
32
- { label: "Contacts", to: "/lead-gen/contacts", icon: IconAddressBook, exact: false }
33
- ];
34
- var LeadGenSidebarMiddle = ({ items = LEAD_GEN_ITEMS } = {}) => {
35
- const { currentPath, navigate } = useRouterContext();
36
- return /* @__PURE__ */ jsx(Stack, { gap: 0, style: { flex: 1, overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { gap: 0, p: "sm", children: items.map((item) => {
37
- const isActive = item.exact ? currentPath === item.to || currentPath === `${item.to}/` : currentPath.startsWith(item.to);
38
- return /* @__PURE__ */ jsx(
39
- SubshellNavItem,
40
- {
41
- icon: item.icon,
42
- label: item.label,
43
- isActive,
44
- href: item.to,
45
- onClick: () => navigate(item.to)
46
- },
47
- item.to
48
- );
49
- }) }) });
50
- };
51
28
  var LeadGenSidebar = ({ children } = {}) => {
52
29
  return /* @__PURE__ */ jsxs(Stack, { gap: 0, style: { height: "100%", display: "flex", flexDirection: "column" }, children: [
53
30
  /* @__PURE__ */ jsx(LeadGenSidebarTop, {}),
54
31
  children ?? /* @__PURE__ */ jsx(LeadGenSidebarMiddle, {})
55
32
  ] });
56
33
  };
57
- var leadGenManifest = {
58
- key: "lead-gen",
59
- featureId: "sales.lead-gen",
60
- capabilityIds: ["leadgen.lists.manage"],
61
- icon: IconTarget,
62
- sidebar: LeadGenSidebar
63
- };
64
34
 
65
35
  // ../core/src/business/acquisition/build-templates.ts
66
36
  var PROSPECTING_BUILD_TEMPLATE_OPTIONS = DEFAULT_ORGANIZATION_MODEL_PROSPECTING.buildTemplates.map(
@@ -84,13 +54,25 @@ function createBuildPlanSnapshotFromTemplateId(templateId) {
84
54
  primaryEntity: step.primaryEntity,
85
55
  outputs: [...step.outputs],
86
56
  stageKey: step.stageKey,
57
+ recordsStageKey: step.recordsStageKey ?? step.stageKey,
58
+ recordSourceStageKey: step.recordSourceStageKey ?? step.recordsStageKey ?? step.stageKey,
87
59
  dependencyMode: step.dependencyMode,
88
60
  capabilityKey: step.capabilityKey,
89
61
  defaultBatchSize: step.defaultBatchSize,
90
62
  maxBatchSize: step.maxBatchSize
91
63
  };
92
64
  if (step.description) snapshotStep.description = step.description;
65
+ if (step.recordEntity) snapshotStep.recordEntity = step.recordEntity;
93
66
  if (step.dependsOn?.length) snapshotStep.dependsOn = [...step.dependsOn];
67
+ if (step.credentialRequirements?.length) {
68
+ snapshotStep.credentialRequirements = step.credentialRequirements.map((requirement) => ({ ...requirement }));
69
+ }
70
+ if (step.recordColumns) {
71
+ snapshotStep.recordColumns = {
72
+ ...step.recordColumns.company ? { company: step.recordColumns.company.map((column) => ({ ...column })) } : {},
73
+ ...step.recordColumns.contact ? { contact: step.recordColumns.contact.map((column) => ({ ...column })) } : {}
74
+ };
75
+ }
94
76
  return snapshotStep;
95
77
  })
96
78
  };
@@ -388,6 +370,15 @@ function StepConfigForm({
388
370
  )) })
389
371
  ] });
390
372
  }
373
+
374
+ // src/features/lead-gen/manifest.ts
375
+ var leadGenManifest = {
376
+ key: "lead-gen",
377
+ featureId: "sales.lead-gen",
378
+ capabilityIds: ["leadgen.lists.manage"],
379
+ icon: IconTarget,
380
+ sidebar: SalesSidebar
381
+ };
391
382
  var LEAD_GEN_ROUTE_LINKS = [
392
383
  { label: "Overview", to: "/lead-gen" },
393
384
  { label: "Lists", to: "/lead-gen/lists" },
@@ -458,135 +449,8 @@ function getEnrichmentStatus(enrichmentData) {
458
449
  if (website === "failed" || linkedin === "failed") return "failed";
459
450
  return "pending";
460
451
  }
461
- function formatName(parts, fallback) {
462
- const name = parts.filter(Boolean).join(" ").trim();
463
- return name || fallback;
464
- }
465
- function CompanyDetailModal({
466
- company,
467
- onClose
468
- }) {
469
- return /* @__PURE__ */ jsx(CustomModal, { opened: !!company, onClose, size: "xl", children: company ? /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
470
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
471
- /* @__PURE__ */ jsxs("div", { children: [
472
- /* @__PURE__ */ jsx(Title, { order: 3, children: company.name }),
473
- company.domain ? /* @__PURE__ */ jsxs(Anchor, { href: `https://${company.domain}`, target: "_blank", size: "sm", c: "dimmed", children: [
474
- company.domain,
475
- " ",
476
- /* @__PURE__ */ jsx(IconExternalLink, { size: 12, style: { verticalAlign: "middle" } })
477
- ] }) : null
478
- ] }),
479
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", onClick: onClose, children: /* @__PURE__ */ jsx(IconX, { size: 18 }) })
480
- ] }),
481
- /* @__PURE__ */ jsx(Divider, {}),
482
- /* @__PURE__ */ jsxs(Box, { children: [
483
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Firmographics" }),
484
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 3, children: [
485
- /* @__PURE__ */ jsxs("div", { children: [
486
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Segment" }),
487
- /* @__PURE__ */ jsx(Text, { size: "sm", children: company.segment || "-" })
488
- ] }),
489
- /* @__PURE__ */ jsxs("div", { children: [
490
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Category" }),
491
- /* @__PURE__ */ jsx(Text, { size: "sm", children: company.category || "-" })
492
- ] }),
493
- /* @__PURE__ */ jsxs("div", { children: [
494
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Employees" }),
495
- /* @__PURE__ */ jsx(Text, { size: "sm", children: company.numEmployees || "-" })
496
- ] }),
497
- /* @__PURE__ */ jsxs("div", { children: [
498
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Founded" }),
499
- /* @__PURE__ */ jsx(Text, { size: "sm", children: company.foundedYear || "-" })
500
- ] }),
501
- /* @__PURE__ */ jsxs("div", { children: [
502
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Location" }),
503
- /* @__PURE__ */ jsx(Text, { size: "sm", children: [company.locationCity, company.locationState].filter(Boolean).join(", ") || "-" })
504
- ] }),
505
- /* @__PURE__ */ jsxs("div", { children: [
506
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Contacts" }),
507
- /* @__PURE__ */ jsx(Text, { size: "sm", children: company.contactCount })
508
- ] })
509
- ] })
510
- ] }),
511
- company.enrichmentData ? /* @__PURE__ */ jsxs(Box, { children: [
512
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Enrichment Data" }),
513
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", style: { whiteSpace: "pre-wrap" }, children: JSON.stringify(company.enrichmentData, null, 2) })
514
- ] }) : null,
515
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
516
- company.linkedinUrl ? /* @__PURE__ */ jsxs(Anchor, { href: company.linkedinUrl, target: "_blank", size: "sm", children: [
517
- "LinkedIn ",
518
- /* @__PURE__ */ jsx(IconExternalLink, { size: 12 })
519
- ] }) : null,
520
- company.website ? /* @__PURE__ */ jsxs(Anchor, { href: company.website, target: "_blank", size: "sm", children: [
521
- "Website ",
522
- /* @__PURE__ */ jsx(IconExternalLink, { size: 12 })
523
- ] }) : null
524
- ] }),
525
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
526
- "Created: ",
527
- formatDate(company.createdAt),
528
- company.updatedAt && ` | Updated: ${formatDate(company.updatedAt)}`
529
- ] })
530
- ] }) : null });
531
- }
532
- function ContactDetailModal({
533
- contact,
534
- onClose
535
- }) {
536
- return /* @__PURE__ */ jsx(CustomModal, { opened: !!contact, onClose, size: "xl", children: contact ? /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
537
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
538
- /* @__PURE__ */ jsxs("div", { children: [
539
- /* @__PURE__ */ jsx(Title, { order: 3, children: formatName([contact.firstName, contact.lastName], contact.email) }),
540
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: contact.email }),
541
- contact.title ? /* @__PURE__ */ jsx(Text, { size: "sm", children: contact.title }) : null
542
- ] }),
543
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", onClick: onClose, children: /* @__PURE__ */ jsx(IconX, { size: 18 }) })
544
- ] }),
545
- /* @__PURE__ */ jsx(Divider, {}),
546
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
547
- /* @__PURE__ */ jsx(Badge, { color: getStatusColor(contact.status), children: contact.status }),
548
- contact.openingLine ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Personalized" }) : null
549
- ] }),
550
- contact.company ? /* @__PURE__ */ jsxs(Box, { children: [
551
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Company" }),
552
- /* @__PURE__ */ jsxs(Card, { withBorder: true, children: [
553
- /* @__PURE__ */ jsx(Text, { fw: 500, children: contact.company.name }),
554
- contact.company.domain ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: contact.company.domain }) : null
555
- ] })
556
- ] }) : null,
557
- /* @__PURE__ */ jsxs(Box, { children: [
558
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Contact Information" }),
559
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
560
- /* @__PURE__ */ jsxs("div", { children: [
561
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Headline" }),
562
- /* @__PURE__ */ jsx(Text, { size: "sm", children: contact.headline || "-" })
563
- ] }),
564
- /* @__PURE__ */ jsxs("div", { children: [
565
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "LinkedIn" }),
566
- contact.linkedinUrl ? /* @__PURE__ */ jsxs(Anchor, { href: contact.linkedinUrl, target: "_blank", size: "sm", children: [
567
- "View Profile ",
568
- /* @__PURE__ */ jsx(IconExternalLink, { size: 12 })
569
- ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", children: "-" })
570
- ] })
571
- ] })
572
- ] }),
573
- contact.filterReason ? /* @__PURE__ */ jsxs(Box, { children: [
574
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Qualification" }),
575
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", children: contact.filterReason })
576
- ] }) : null,
577
- contact.openingLine ? /* @__PURE__ */ jsxs(Box, { children: [
578
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "xs", children: "Personalization" }),
579
- /* @__PURE__ */ jsx(Text, { size: "sm", children: contact.openingLine })
580
- ] }) : null,
581
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
582
- "Created: ",
583
- formatDate(contact.createdAt),
584
- contact.updatedAt && ` | Updated: ${formatDate(contact.updatedAt)}`
585
- ] })
586
- ] }) : null });
587
- }
588
452
  function useDeleteLists() {
589
- const { apiRequest, organizationId } = useElevasisServices();
453
+ const { apiRequest, workOSOrganizationId } = useElevasisServices();
590
454
  const queryClient = useQueryClient();
591
455
  return useMutation({
592
456
  mutationFn: async (listIds) => {
@@ -601,8 +465,8 @@ function useDeleteLists() {
601
465
  );
602
466
  },
603
467
  onSuccess: () => {
604
- queryClient.invalidateQueries({ queryKey: acquisitionListKeys.list(organizationId) });
605
- queryClient.invalidateQueries({ queryKey: acquisitionListKeys.telemetry(organizationId) });
468
+ queryClient.invalidateQueries({ queryKey: acquisitionListKeys.list(workOSOrganizationId) });
469
+ queryClient.invalidateQueries({ queryKey: acquisitionListKeys.telemetry(workOSOrganizationId) });
606
470
  showSuccessNotification("Lists deleted");
607
471
  },
608
472
  onError: (error) => {
@@ -1369,6 +1233,253 @@ function ListMemberDrawer({ memberId, memberKind, listId, onClose }) {
1369
1233
  }
1370
1234
  );
1371
1235
  }
1236
+ function formatEventTime(timestamp) {
1237
+ return new Date(timestamp).toLocaleTimeString("en-US", {
1238
+ hour12: false,
1239
+ hour: "2-digit",
1240
+ minute: "2-digit",
1241
+ second: "2-digit"
1242
+ });
1243
+ }
1244
+ function formatId(executionId) {
1245
+ return executionId.length > 10 ? `${executionId.slice(0, 8)}...` : executionId;
1246
+ }
1247
+ function getLogLevelColor(level) {
1248
+ switch (level) {
1249
+ case "error":
1250
+ return "red";
1251
+ case "warn":
1252
+ return "yellow";
1253
+ case "debug":
1254
+ return "gray";
1255
+ default:
1256
+ return "blue";
1257
+ }
1258
+ }
1259
+ function getStepStatusColor(status) {
1260
+ switch (status) {
1261
+ case "failed":
1262
+ return "red";
1263
+ case "done":
1264
+ return "green";
1265
+ default:
1266
+ return "blue";
1267
+ }
1268
+ }
1269
+ function getStepStatusLabel(status) {
1270
+ switch (status) {
1271
+ case "failed":
1272
+ return "Failed";
1273
+ case "done":
1274
+ return "Done";
1275
+ default:
1276
+ return "Running";
1277
+ }
1278
+ }
1279
+ function getEventColor(event) {
1280
+ switch (event.type) {
1281
+ case "new-execution":
1282
+ return "blue";
1283
+ case "execution-complete":
1284
+ return event.data.success ? "green" : "red";
1285
+ case "log":
1286
+ return getLogLevelColor(event.data.log.level);
1287
+ default:
1288
+ return "gray";
1289
+ }
1290
+ }
1291
+ function getEventLabel(event) {
1292
+ switch (event.type) {
1293
+ case "new-execution":
1294
+ return "Execution started";
1295
+ case "execution-complete":
1296
+ return event.data.success ? "Execution completed" : "Execution failed";
1297
+ case "log":
1298
+ return event.data.log.message;
1299
+ default:
1300
+ return "Stream connected";
1301
+ }
1302
+ }
1303
+ function hasExecutionId(event) {
1304
+ return event.type !== "connected" && typeof event.executionId === "string" && event.executionId.length > 0;
1305
+ }
1306
+ function toTimelineEvents(events) {
1307
+ return events.filter(hasExecutionId).map((event) => ({
1308
+ executionId: event.executionId,
1309
+ timestamp: event.timestamp,
1310
+ label: getEventLabel(event),
1311
+ color: getEventColor(event),
1312
+ detail: event.type === "execution-complete" ? event.data.error : void 0
1313
+ })).sort((a, b) => b.timestamp - a.timestamp).slice(0, 5);
1314
+ }
1315
+ function collectStepStatuses(events, streamingLogs) {
1316
+ const statuses = /* @__PURE__ */ new Map();
1317
+ const applyLog = (executionId, log) => {
1318
+ const context = log.context;
1319
+ if (!context || context.type !== "workflow") return;
1320
+ if (!("stepId" in context)) return;
1321
+ let status = null;
1322
+ if (isStepStartedContext(context)) status = "running";
1323
+ if (isStepCompletedContext(context)) status = "done";
1324
+ if (isStepFailedContext(context)) status = "failed";
1325
+ if (!status) return;
1326
+ statuses.set(executionId, {
1327
+ executionId,
1328
+ stepId: context.stepId,
1329
+ status,
1330
+ timestamp: log.timestamp,
1331
+ message: log.message
1332
+ });
1333
+ };
1334
+ events.forEach((event) => {
1335
+ if (event.type === "log") applyLog(event.executionId, event.data.log);
1336
+ });
1337
+ streamingLogs.forEach((logs, executionId) => {
1338
+ logs.forEach((log) => applyLog(executionId, log));
1339
+ });
1340
+ return Array.from(statuses.values()).sort((a, b) => b.timestamp - a.timestamp);
1341
+ }
1342
+ function getExecutionId(execution) {
1343
+ return "executionId" in execution ? execution.executionId : execution.id;
1344
+ }
1345
+ function getInFlightExecutions(data) {
1346
+ if (Array.isArray(data)) return data;
1347
+ if (data && typeof data === "object" && "executions" in data) {
1348
+ const executions = data.executions;
1349
+ return Array.isArray(executions) ? executions : [];
1350
+ }
1351
+ return [];
1352
+ }
1353
+ function getStageProgress(progress, stageKey) {
1354
+ return progress?.byCompanyStage[stageKey] ?? progress?.byContactStage[stageKey];
1355
+ }
1356
+ function getStageLabel(stageKey) {
1357
+ return LEAD_GEN_STAGE_CATALOG[stageKey]?.label ?? stageKey;
1358
+ }
1359
+ function getDoneCount(stageProgress) {
1360
+ return stageProgress?.attempted ?? 0;
1361
+ }
1362
+ function LeadGenLiveStatusPanel({
1363
+ listId,
1364
+ resourceId,
1365
+ stageKey,
1366
+ stepLabel,
1367
+ enabled = true,
1368
+ onRunningChange
1369
+ }) {
1370
+ const sse = useExecutionSSE(resourceId, {
1371
+ enabled: enabled && Boolean(resourceId),
1372
+ listId
1373
+ });
1374
+ const inFlightQuery = useInFlightExecutions(resourceId, {
1375
+ enabled: enabled && Boolean(resourceId),
1376
+ limit: 5,
1377
+ refetchInterval: enabled && Boolean(resourceId) ? 2e3 : false
1378
+ });
1379
+ const inFlightExecutions = useMemo(() => getInFlightExecutions(inFlightQuery.data), [inFlightQuery.data]);
1380
+ const activeExecutionIds = useMemo(() => {
1381
+ const ids = new Set(sse.liveExecutions);
1382
+ inFlightExecutions.forEach((execution) => {
1383
+ const executionId = getExecutionId(execution);
1384
+ if (executionId) ids.add(executionId);
1385
+ });
1386
+ return Array.from(ids);
1387
+ }, [inFlightExecutions, sse.liveExecutions]);
1388
+ const running = enabled && activeExecutionIds.length > 0;
1389
+ const [showCompletedActivity, setShowCompletedActivity] = useState(false);
1390
+ const progressQuery = useListProgress(listId, {
1391
+ enabled: enabled && Boolean(listId),
1392
+ refetchInterval: running ? 2e3 : false
1393
+ });
1394
+ useEffect(() => {
1395
+ onRunningChange?.(running);
1396
+ }, [onRunningChange, running]);
1397
+ const stepStatuses = useMemo(
1398
+ () => collectStepStatuses(sse.events, sse.streamingLogs),
1399
+ [sse.events, sse.streamingLogs]
1400
+ );
1401
+ const latestStepStatus = stepStatuses[0];
1402
+ const lastEvents = useMemo(() => toTimelineEvents(sse.events), [sse.events]);
1403
+ const stageProgress = getStageProgress(progressQuery.data, stageKey);
1404
+ const doneCount = getDoneCount(stageProgress);
1405
+ const totalCount = stageProgress?.total ?? 0;
1406
+ const failed = Boolean(sse.error) || sse.events.some((event) => event.type === "execution-complete" && !event.data.success);
1407
+ const latestEvent = sse.latestEvent;
1408
+ useEffect(() => {
1409
+ if (running || failed || sse.error) {
1410
+ setShowCompletedActivity(true);
1411
+ return;
1412
+ }
1413
+ if (latestEvent?.type !== "execution-complete") return;
1414
+ setShowCompletedActivity(true);
1415
+ const timeoutId = window.setTimeout(() => setShowCompletedActivity(false), 1e4);
1416
+ return () => window.clearTimeout(timeoutId);
1417
+ }, [failed, latestEvent, running, sse.error]);
1418
+ const hasActivity = activeExecutionIds.length > 0 || sse.streamingLogs.size > 0 || showCompletedActivity || Boolean(sse.error);
1419
+ if (!enabled || !hasActivity && !sse.error && !failed) {
1420
+ return null;
1421
+ }
1422
+ return /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1423
+ /* @__PURE__ */ jsx(
1424
+ CardHeader,
1425
+ {
1426
+ icon: /* @__PURE__ */ jsx(IconTerminal2, { size: 16 }),
1427
+ title: stepLabel ? `${stepLabel} status` : "Live status",
1428
+ rightSection: /* @__PURE__ */ jsxs(Group, { gap: 6, children: [
1429
+ /* @__PURE__ */ jsx(
1430
+ Badge,
1431
+ {
1432
+ size: "xs",
1433
+ variant: "light",
1434
+ color: sse.connected ? "green" : running ? "yellow" : "gray",
1435
+ leftSection: sse.connected ? /* @__PURE__ */ jsx(IconCircleCheck, { size: 9 }) : /* @__PURE__ */ jsx(IconCircleDot, { size: 9 }),
1436
+ children: sse.connected ? "Connected" : running ? "Reconnecting" : "Idle"
1437
+ }
1438
+ ),
1439
+ running ? /* @__PURE__ */ jsxs(Badge, { size: "xs", variant: "filled", color: "blue", leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 9 }), children: [
1440
+ activeExecutionIds.length,
1441
+ " running"
1442
+ ] }) : null
1443
+ ] })
1444
+ }
1445
+ ),
1446
+ sse.error ? /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 14 }), color: "red", variant: "light", p: "xs", children: /* @__PURE__ */ jsx(Text, { size: "xs", children: sse.error }) }) : null,
1447
+ activeExecutionIds.length > 0 ? /* @__PURE__ */ jsx(Group, { gap: 6, children: activeExecutionIds.map((executionId) => /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: "blue", ff: "monospace", children: formatId(executionId) }, executionId)) }) : null,
1448
+ /* @__PURE__ */ jsxs(Box, { p: "xs", bg: "var(--surface-primary-subtle)", style: { borderRadius: "var(--mantine-radius-sm)" }, children: [
1449
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
1450
+ /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", style: { minWidth: 0 }, children: [
1451
+ /* @__PURE__ */ jsx(IconProgressCheck, { size: 14 }),
1452
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, truncate: "end", children: getStageLabel(stageKey) })
1453
+ ] }),
1454
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", ff: "monospace", children: [
1455
+ doneCount,
1456
+ "/",
1457
+ totalCount,
1458
+ " done"
1459
+ ] })
1460
+ ] }),
1461
+ /* @__PURE__ */ jsx(
1462
+ Progress,
1463
+ {
1464
+ mt: 6,
1465
+ size: "xs",
1466
+ value: totalCount > 0 ? doneCount / totalCount * 100 : 0,
1467
+ color: stageProgress && stageProgress.error > 0 ? "red" : "blue"
1468
+ }
1469
+ )
1470
+ ] }),
1471
+ latestStepStatus ? /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", children: [
1472
+ /* @__PURE__ */ jsx(Badge, { size: "xs", color: getStepStatusColor(latestStepStatus.status), variant: "light", children: getStepStatusLabel(latestStepStatus.status) }),
1473
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, truncate: "end", children: latestStepStatus.stepId }),
1474
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", truncate: "end", style: { flex: 1 }, children: latestStepStatus.message })
1475
+ ] }) : running ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Waiting for workflow step events." }) : null,
1476
+ lastEvents.length > 0 ? /* @__PURE__ */ jsx(Stack, { gap: 4, children: lastEvents.map((event) => /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", children: [
1477
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "dot", color: event.color, miw: 68, children: formatEventTime(event.timestamp) }),
1478
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ff: "monospace", miw: 62, children: formatId(event.executionId) }),
1479
+ /* @__PURE__ */ jsx(Text, { size: "xs", truncate: "end", style: { flex: 1 }, children: event.detail ?? event.label })
1480
+ ] }, `${event.executionId}-${event.timestamp}-${event.label}`)) }) : null
1481
+ ] }) });
1482
+ }
1372
1483
  var panelStyle = {
1373
1484
  flex: 1,
1374
1485
  minHeight: 0,
@@ -1377,6 +1488,7 @@ var panelStyle = {
1377
1488
  };
1378
1489
  function StepDetailRightColumn({
1379
1490
  configuration,
1491
+ records,
1380
1492
  advanced,
1381
1493
  runs,
1382
1494
  action,
@@ -1397,7 +1509,7 @@ function StepDetailRightColumn({
1397
1509
  {
1398
1510
  value: activeTab,
1399
1511
  onChange: (value) => {
1400
- if (value === "configuration" || value === "advanced" || value === "runs") {
1512
+ if (value === "configuration" || value === "records" || value === "advanced" || value === "runs") {
1401
1513
  onTabChange(value);
1402
1514
  }
1403
1515
  },
@@ -1410,10 +1522,12 @@ function StepDetailRightColumn({
1410
1522
  children: [
1411
1523
  /* @__PURE__ */ jsxs(Tabs.List, { children: [
1412
1524
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "configuration", children: "Configuration" }),
1525
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "records", children: "Records" }),
1413
1526
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "advanced", children: "Advanced" }),
1414
1527
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "runs", children: "Runs" })
1415
1528
  ] }),
1416
1529
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "configuration", style: panelStyle, children: configuration }),
1530
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "records", style: panelStyle, children: records ?? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No records view configured for this step." }) }),
1417
1531
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "advanced", style: panelStyle, children: advanced ?? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No advanced settings for this step." }) }),
1418
1532
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "runs", style: panelStyle, children: runs })
1419
1533
  ]
@@ -1513,6 +1627,12 @@ var STAGE_COLOR_SETS = {
1513
1627
  border: "color-mix(in srgb, var(--color-border) 70%, var(--color-primary))",
1514
1628
  text: "var(--color-text)"
1515
1629
  },
1630
+ crawled: {
1631
+ accent: "color-mix(in srgb, var(--color-primary) 70%, var(--color-text-subtle))",
1632
+ background: "color-mix(in srgb, var(--color-primary) 9%, transparent)",
1633
+ border: "color-mix(in srgb, var(--color-border) 72%, var(--color-primary))",
1634
+ text: "var(--color-text)"
1635
+ },
1516
1636
  extracted: {
1517
1637
  accent: "color-mix(in srgb, var(--color-primary) 78%, var(--color-success))",
1518
1638
  background: "color-mix(in srgb, var(--color-primary) 10%, transparent)",
@@ -1628,7 +1748,7 @@ function buildLaneStages({
1628
1748
  })
1629
1749
  );
1630
1750
  }
1631
- function getStageProgress(progress, stageKey, entity) {
1751
+ function getStageProgress2(progress, stageKey, entity) {
1632
1752
  const stageProgress = entity === "company" ? progress.byCompanyStage[stageKey] : progress.byContactStage[stageKey];
1633
1753
  const total = stageProgress?.total ?? (entity === "company" ? progress.totalCompanies : progress.totalMembers);
1634
1754
  return {
@@ -1746,7 +1866,7 @@ function TimelineLane({
1746
1866
  position: "relative"
1747
1867
  },
1748
1868
  children: stages.map((stage, index) => {
1749
- const counts = getStageProgress(progress, stage.key, entity);
1869
+ const counts = getStageProgress2(progress, stage.key, entity);
1750
1870
  const accent = getLeadGenStageColorVar(stage.key);
1751
1871
  const completion = Math.round(percent(counts.success, counts.total));
1752
1872
  const attempted = Math.round(percent(counts.attempted, counts.total));
@@ -2416,7 +2536,7 @@ function sortStageKeys(keys) {
2416
2536
  return oa - ob || a.localeCompare(b);
2417
2537
  });
2418
2538
  }
2419
- function getStageProgress2(progress, step) {
2539
+ function getStageProgress3(progress, step) {
2420
2540
  return step.primaryEntity === "company" ? progress.byCompanyStage[step.stageKey] : progress.byContactStage[step.stageKey];
2421
2541
  }
2422
2542
  function getEntityTotal(progress, entity) {
@@ -2434,11 +2554,16 @@ function normalizeBuildPlanStep(step) {
2434
2554
  primaryEntity: step.primaryEntity,
2435
2555
  outputs: step.outputs,
2436
2556
  stageKey: step.stageKey,
2557
+ recordEntity: step.recordEntity,
2558
+ recordsStageKey: step.recordsStageKey,
2559
+ recordSourceStageKey: step.recordSourceStageKey,
2437
2560
  dependsOn: step.dependsOn,
2438
2561
  dependencyMode: step.dependencyMode,
2439
2562
  capabilityKey: step.capabilityKey,
2440
2563
  defaultBatchSize: step.defaultBatchSize,
2441
2564
  maxBatchSize: step.maxBatchSize,
2565
+ recordColumns: step.recordColumns,
2566
+ credentialRequirements: step.credentialRequirements,
2442
2567
  emptyBlockedText: fallback?.emptyBlockedText ?? "Complete prerequisite build steps before this action can run."
2443
2568
  };
2444
2569
  }
@@ -2563,7 +2688,7 @@ function getStepRecommendedAction(step, action, kind) {
2563
2688
  function deriveBuildStepStates(list, progress, actions) {
2564
2689
  const byStepId = /* @__PURE__ */ new Map();
2565
2690
  for (const step of resolveBuildPlanSteps(list)) {
2566
- const stageProgress = getStageProgress2(progress, step);
2691
+ const stageProgress = getStageProgress3(progress, step);
2567
2692
  const entityTotal = getEntityTotal(progress, step.primaryEntity);
2568
2693
  const prerequisites = getPrerequisiteSteps(step, byStepId);
2569
2694
  const hasDependencies = (step.dependsOn?.length ?? 0) > 0;
@@ -2652,6 +2777,101 @@ function displayMemberStageFor(row, kind) {
2652
2777
  function asRecord3(value) {
2653
2778
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2654
2779
  }
2780
+ function valueAtPath(source, path) {
2781
+ return path.split(".").reduce((current, segment) => {
2782
+ if (!current || typeof current !== "object") return void 0;
2783
+ return current[segment];
2784
+ }, source);
2785
+ }
2786
+ function compactText(value) {
2787
+ if (value === null || value === void 0 || value === "") return "-";
2788
+ if (Array.isArray(value)) {
2789
+ if (!value.length) return "-";
2790
+ return value.map((item) => {
2791
+ if (item && typeof item === "object") {
2792
+ const labelled = item;
2793
+ return String(labelled.name ?? labelled.label ?? labelled.title ?? labelled.id ?? JSON.stringify(item));
2794
+ }
2795
+ return String(item);
2796
+ }).join(", ");
2797
+ }
2798
+ if (typeof value === "object") return JSON.stringify(value);
2799
+ return String(value);
2800
+ }
2801
+ function getRecordDisplayName(row) {
2802
+ if (row.entity === "company") return row.company?.name ?? "Company";
2803
+ const contact = row.contact;
2804
+ const full = [contact?.firstName, contact?.lastName].filter(Boolean).join(" ").trim();
2805
+ return full || contact?.email || "Contact";
2806
+ }
2807
+ function getRecordColumnSource(row) {
2808
+ if (row.entity === "company") {
2809
+ return {
2810
+ ...row,
2811
+ company: row.company ? {
2812
+ ...row.company,
2813
+ enrichmentData: row.enrichmentData,
2814
+ processingState: row.processingState
2815
+ } : null
2816
+ };
2817
+ }
2818
+ return {
2819
+ ...row,
2820
+ contact: row.contact ? {
2821
+ ...row.contact,
2822
+ name: getRecordDisplayName(row),
2823
+ enrichmentData: row.enrichmentData,
2824
+ processingState: row.processingState
2825
+ } : null
2826
+ };
2827
+ }
2828
+ function getStageEntry(row, stageKey) {
2829
+ const entry = valueAtPath(row.processingState, stageKey);
2830
+ return asRecord3(entry);
2831
+ }
2832
+ function getRecordStageStatus(row, stageKey) {
2833
+ const status = getStageEntry(row, stageKey).status;
2834
+ return typeof status === "string" ? status : "pending";
2835
+ }
2836
+ function getStageFailureReason(row, stageKey) {
2837
+ const data = asRecord3(getStageEntry(row, stageKey).data);
2838
+ const error = data.error ?? data.reason ?? data.failureReason ?? data.disqualifiedReason;
2839
+ return compactText(error);
2840
+ }
2841
+ function getRecordStatusColor(status) {
2842
+ switch (status) {
2843
+ case "success":
2844
+ return "green";
2845
+ case "error":
2846
+ case "failed":
2847
+ return "red";
2848
+ case "skipped":
2849
+ case "no_result":
2850
+ return "yellow";
2851
+ case "pending":
2852
+ return "gray";
2853
+ default:
2854
+ return "blue";
2855
+ }
2856
+ }
2857
+ function renderRecordValue(value, column) {
2858
+ if (value === null || value === void 0 || value === "") {
2859
+ return /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "-" });
2860
+ }
2861
+ switch (column.renderType) {
2862
+ case "badge":
2863
+ return /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: column.badgeColor ?? getRecordStatusColor(String(value)), children: compactText(value) });
2864
+ case "datetime":
2865
+ return compactText(typeof value === "string" ? formatDateTime4(value) : value);
2866
+ case "count":
2867
+ return Array.isArray(value) ? value.length : compactText(value);
2868
+ case "json":
2869
+ return /* @__PURE__ */ jsx(Text, { size: "xs", lineClamp: 2, children: compactText(value) });
2870
+ case "text":
2871
+ default:
2872
+ return /* @__PURE__ */ jsx(Text, { size: "sm", lineClamp: 2, children: compactText(value) });
2873
+ }
2874
+ }
2655
2875
  function getRunStatusColor(status) {
2656
2876
  switch (status) {
2657
2877
  case "completed":
@@ -3090,20 +3310,364 @@ function getBuildTabDescription(steps, currentStep) {
3090
3310
  if (currentStep.status === "failed") return `${currentStep.label} needs attention.`;
3091
3311
  return `${currentStep.label} is waiting on earlier work.`;
3092
3312
  }
3313
+ var RECORDS_PAGE_SIZE = 25;
3314
+ var EXPORT_WORKFLOW_ID = "lgn-06-export-list-workflow";
3315
+ function setValueAtInputPath(source, path, value) {
3316
+ const segments = path.split(".").filter(Boolean);
3317
+ if (!segments.length) return source;
3318
+ const next = { ...source };
3319
+ let cursor = next;
3320
+ segments.forEach((segment, index) => {
3321
+ if (index === segments.length - 1) {
3322
+ cursor[segment] = value;
3323
+ return;
3324
+ }
3325
+ const current = cursor[segment];
3326
+ const child = current && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
3327
+ cursor[segment] = child;
3328
+ cursor = child;
3329
+ });
3330
+ return next;
3331
+ }
3332
+ function credentialMatchesRequirement(credential, requirement) {
3333
+ const provider = requirement.provider.toLowerCase();
3334
+ const credentialProvider = credential.provider?.toLowerCase() ?? "";
3335
+ const credentialType = credential.type.toLowerCase();
3336
+ const credentialName = credential.name.toLowerCase();
3337
+ if (credentialProvider === provider || credentialType === provider || credentialName.startsWith(`${provider}-`) || credentialName.includes(`-${provider}`) || credentialName.includes(`${provider}-`)) {
3338
+ return true;
3339
+ }
3340
+ return credentialType === requirement.credentialType;
3341
+ }
3342
+ function getMatchingCredentials(credentials, requirement) {
3343
+ return credentials.filter((credential) => credentialMatchesRequirement(credential, requirement));
3344
+ }
3345
+ function getSelectedCredential(credentials, selections, requirement) {
3346
+ const selectedId = selections[requirement.key];
3347
+ return credentials.find((credential) => credential.id === selectedId) ?? null;
3348
+ }
3349
+ function getClickUpRequirement(step) {
3350
+ return step.credentialRequirements?.find((requirement) => requirement.provider === "clickup") ?? null;
3351
+ }
3352
+ function filterCredentialRequirementFields(layout, requirements) {
3353
+ if (!layout || requirements.length === 0) return layout;
3354
+ const credentialInputPaths = new Set(requirements.map((requirement) => requirement.inputPath).filter(Boolean));
3355
+ if (!credentialInputPaths.size) return layout;
3356
+ const filterSection = (section) => {
3357
+ const fields = section.fields.filter((field) => !credentialInputPaths.has(field.path));
3358
+ return fields.length > 0 ? { ...section, fields } : null;
3359
+ };
3360
+ return {
3361
+ ...layout,
3362
+ sections: layout.sections.map(filterSection).filter((section) => section !== null),
3363
+ advanced: layout.advanced ? filterSection(layout.advanced) ?? void 0 : void 0
3364
+ };
3365
+ }
3366
+ function hasMainConfigFields(layout) {
3367
+ return Boolean(layout?.sections.some((section) => section.fields.length > 0));
3368
+ }
3369
+ function hasAdvancedConfigFields(layout) {
3370
+ return Boolean(layout?.advanced?.fields.length);
3371
+ }
3372
+ function formatCredentialVerificationDetails(details) {
3373
+ if (!details) return null;
3374
+ const entries = Object.entries(details).filter(([, value]) => value !== null && value !== void 0 && value !== "").slice(0, 4);
3375
+ if (!entries.length) return null;
3376
+ return entries.map(([key, value]) => `${key}: ${compactText(value)}`).join(" | ");
3377
+ }
3378
+ function CredentialRequirementsPanel({
3379
+ requirements,
3380
+ credentials,
3381
+ credentialsLoading,
3382
+ selections,
3383
+ verificationByCredentialId,
3384
+ verifyingCredentialId,
3385
+ onSelect,
3386
+ onVerify
3387
+ }) {
3388
+ if (!requirements.length) return null;
3389
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3390
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Credentials" }),
3391
+ requirements.map((requirement) => {
3392
+ const matchingCredentials = getMatchingCredentials(credentials, requirement);
3393
+ const selectedCredential = getSelectedCredential(credentials, selections, requirement);
3394
+ const verification = selectedCredential ? verificationByCredentialId[selectedCredential.id] : null;
3395
+ return /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
3396
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "flex-end", wrap: "nowrap", children: [
3397
+ /* @__PURE__ */ jsx(
3398
+ Select,
3399
+ {
3400
+ label: requirement.label,
3401
+ description: `${requirement.provider} credential for ${requirement.inputPath}`,
3402
+ placeholder: credentialsLoading ? "Loading credentials..." : "Select credential",
3403
+ data: matchingCredentials.map((credential) => ({
3404
+ value: credential.id,
3405
+ label: `${credential.name} (${credential.provider ?? credential.type})`
3406
+ })),
3407
+ value: selectedCredential?.id ?? null,
3408
+ onChange: (credentialId) => {
3409
+ onSelect(requirement, credentials.find((credential) => credential.id === credentialId) ?? null);
3410
+ },
3411
+ required: requirement.required,
3412
+ disabled: credentialsLoading || matchingCredentials.length === 0,
3413
+ style: { flex: 1 }
3414
+ }
3415
+ ),
3416
+ /* @__PURE__ */ jsx(
3417
+ Button,
3418
+ {
3419
+ size: "xs",
3420
+ variant: "light",
3421
+ disabled: !selectedCredential,
3422
+ loading: selectedCredential ? verifyingCredentialId === selectedCredential.id : false,
3423
+ onClick: () => selectedCredential && onVerify(selectedCredential),
3424
+ children: "Test credential"
3425
+ }
3426
+ )
3427
+ ] }),
3428
+ matchingCredentials.length === 0 ? /* @__PURE__ */ jsx(
3429
+ Alert,
3430
+ {
3431
+ color: requirement.required ? "yellow" : "gray",
3432
+ variant: "light",
3433
+ icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }),
3434
+ children: /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
3435
+ "No matching ",
3436
+ requirement.provider,
3437
+ " credentials found. Add one in",
3438
+ " ",
3439
+ /* @__PURE__ */ jsx(Text, { component: "a", href: "/settings/credentials", size: "sm", fw: 600, children: "Settings -> Credentials" }),
3440
+ "."
3441
+ ] })
3442
+ }
3443
+ ) : null,
3444
+ verification ? /* @__PURE__ */ jsx(
3445
+ Alert,
3446
+ {
3447
+ color: verification.status === "success" ? "green" : "red",
3448
+ variant: "light",
3449
+ icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }),
3450
+ children: /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
3451
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: verification.message }),
3452
+ verification.checkedAt ? /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
3453
+ "Checked ",
3454
+ formatDateTime4(verification.checkedAt)
3455
+ ] }) : null,
3456
+ formatCredentialVerificationDetails(verification.details) ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatCredentialVerificationDetails(verification.details) }) : null
3457
+ ] })
3458
+ }
3459
+ ) : null
3460
+ ] }, requirement.key);
3461
+ })
3462
+ ] });
3463
+ }
3464
+ function BuildStepRunningWatcher({
3465
+ resourceId,
3466
+ onRunningChange
3467
+ }) {
3468
+ const inFlightQuery = useInFlightExecutions(resourceId, {
3469
+ enabled: Boolean(resourceId),
3470
+ limit: 5,
3471
+ refetchInterval: 2e3
3472
+ });
3473
+ const isRunning = (inFlightQuery.data?.executions.length ?? 0) > 0;
3474
+ useEffect(() => {
3475
+ onRunningChange(resourceId, isRunning);
3476
+ return () => onRunningChange(resourceId, false);
3477
+ }, [isRunning, onRunningChange, resourceId]);
3478
+ return null;
3479
+ }
3480
+ function StepRecordsPanel({
3481
+ list,
3482
+ step,
3483
+ credentialSelections,
3484
+ credentials,
3485
+ clickupListId
3486
+ }) {
3487
+ const queryClient = useQueryClient();
3488
+ const [page, setPage] = useState(1);
3489
+ const [approvalByCompanyId, setApprovalByCompanyId] = useState({});
3490
+ const navigate = useNavigate();
3491
+ const recordsStageKey = step.recordSourceStageKey ?? step.recordsStageKey ?? step.stageKey;
3492
+ const recordsEntity = step.recordEntity ?? step.primaryEntity;
3493
+ const columns = step.recordColumns?.[recordsEntity] ?? [];
3494
+ const recordsQuery = useListRecords(list.id, {
3495
+ entity: recordsEntity,
3496
+ stage: recordsStageKey,
3497
+ limit: RECORDS_PAGE_SIZE,
3498
+ offset: (page - 1) * RECORDS_PAGE_SIZE
3499
+ });
3500
+ const exportWorkflowId = step.action?.resourceId ?? EXPORT_WORKFLOW_ID;
3501
+ const exportExecution = useWorkflowExecution({
3502
+ workflowId: exportWorkflowId,
3503
+ listId: list.id
3504
+ });
3505
+ useEffect(() => {
3506
+ setPage(1);
3507
+ setApprovalByCompanyId({});
3508
+ }, [step.id]);
3509
+ const rows = recordsQuery.data?.data ?? [];
3510
+ const total = recordsQuery.data?.total ?? 0;
3511
+ const totalPages = Math.max(1, Math.ceil(total / RECORDS_PAGE_SIZE));
3512
+ const isReviewExportStep = step.primaryEntity === "company" && (step.capabilityKey === "lead-gen.export.list" || exportWorkflowId === EXPORT_WORKFLOW_ID);
3513
+ const approvedCompanyIds = Object.entries(approvalByCompanyId).filter(([, status]) => status === "approved").map(([companyId]) => companyId);
3514
+ const rejectedCompanyIds = Object.entries(approvalByCompanyId).filter(([, status]) => status === "rejected").map(([companyId]) => companyId);
3515
+ const clickupRequirement = getClickUpRequirement(step);
3516
+ const clickupCredential = clickupRequirement ? getSelectedCredential(credentials, credentialSelections, clickupRequirement) : null;
3517
+ const isClickUpExportPath = isReviewExportStep && Boolean(clickupRequirement);
3518
+ const normalizedClickupListId = clickupListId.trim();
3519
+ const canExport = approvedCompanyIds.length > 0 && (!isClickUpExportPath || Boolean(clickupCredential) && normalizedClickupListId.length > 0);
3520
+ const exportDisabledReason = approvedCompanyIds.length === 0 ? "Approve at least one company before export." : isClickUpExportPath && !clickupCredential ? "Select a ClickUp credential in Configuration." : isClickUpExportPath && !normalizedClickupListId ? "Enter a ClickUp List ID in Configuration." : null;
3521
+ const setApproval = (companyId, status) => {
3522
+ setApprovalByCompanyId((current) => ({ ...current, [companyId]: status }));
3523
+ };
3524
+ const openRecordDetail = (row) => {
3525
+ if (row.entity === "company") {
3526
+ void navigate({ to: "/crm/companies/$companyId", params: { companyId: row.companyId } });
3527
+ return;
3528
+ }
3529
+ void navigate({ to: "/crm/contacts/$contactId", params: { contactId: row.contactId } });
3530
+ };
3531
+ const exportApproved = async () => {
3532
+ try {
3533
+ const result = await exportExecution.execute({
3534
+ input: {
3535
+ listId: list.id,
3536
+ mode: "export",
3537
+ approved: true,
3538
+ ...isClickUpExportPath ? {
3539
+ destination: "clickup",
3540
+ clickupCredential: clickupCredential?.name,
3541
+ clickupListId: normalizedClickupListId
3542
+ } : {},
3543
+ approvedCompanyIds,
3544
+ rejectedCompanyIds
3545
+ }
3546
+ });
3547
+ showSuccessNotification(`Export workflow run started: ${result.executionId}`);
3548
+ await queryClient.invalidateQueries({ queryKey: acquisitionListKeys.all });
3549
+ } catch (error) {
3550
+ showApiErrorNotification(error);
3551
+ }
3552
+ };
3553
+ if (!columns.length) {
3554
+ return /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No record columns are configured for this step." });
3555
+ }
3556
+ if (recordsQuery.isLoading) {
3557
+ return /* @__PURE__ */ jsx(Center, { p: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) });
3558
+ }
3559
+ if (recordsQuery.error) {
3560
+ return /* @__PURE__ */ jsx(CenteredErrorState, { error: recordsQuery.error, title: "Failed to load records" });
3561
+ }
3562
+ if (!rows.length) {
3563
+ return /* @__PURE__ */ jsx(Stack, { gap: "xs", children: /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
3564
+ "No records found for ",
3565
+ LEAD_GEN_STAGE_CATALOG[recordsStageKey]?.label ?? recordsStageKey,
3566
+ "."
3567
+ ] }) });
3568
+ }
3569
+ return /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
3570
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
3571
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
3572
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Records" }),
3573
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
3574
+ total,
3575
+ " ",
3576
+ recordsEntity,
3577
+ " records from ",
3578
+ LEAD_GEN_STAGE_CATALOG[recordsStageKey]?.label ?? recordsStageKey
3579
+ ] })
3580
+ ] }),
3581
+ recordsQuery.isFetching ? /* @__PURE__ */ jsx(Loader, { size: "xs" }) : null
3582
+ ] }),
3583
+ /* @__PURE__ */ jsx(Box, { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs(Table, { highlightOnHover: true, children: [
3584
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
3585
+ columns.map((column) => /* @__PURE__ */ jsx(Table.Th, { style: column.width ? { width: column.width } : void 0, children: column.label }, column.key)),
3586
+ /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
3587
+ /* @__PURE__ */ jsx(Table.Th, { children: "Failure reason" }),
3588
+ isReviewExportStep ? /* @__PURE__ */ jsx(Table.Th, { children: "Approval" }) : null
3589
+ ] }) }),
3590
+ /* @__PURE__ */ jsx(Table.Tbody, { children: rows.map((row) => {
3591
+ const columnSource = getRecordColumnSource(row);
3592
+ const status = getRecordStageStatus(row, recordsStageKey);
3593
+ const companyId = row.entity === "company" ? row.companyId : null;
3594
+ return /* @__PURE__ */ jsxs(Table.Tr, { onClick: () => openRecordDetail(row), style: { cursor: "pointer" }, children: [
3595
+ columns.map((column) => /* @__PURE__ */ jsx(Table.Td, { children: renderRecordValue(valueAtPath(columnSource, column.path), column) }, column.key)),
3596
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getRecordStatusColor(status), children: status }) }),
3597
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", lineClamp: 2, children: getStageFailureReason(row, recordsStageKey) }) }),
3598
+ isReviewExportStep ? /* @__PURE__ */ jsx(Table.Td, { children: companyId ? /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", "aria-label": `Approval for ${getRecordDisplayName(row)}`, children: [
3599
+ /* @__PURE__ */ jsx(
3600
+ Button,
3601
+ {
3602
+ size: "compact-xs",
3603
+ variant: approvalByCompanyId[companyId] === "approved" ? "filled" : "light",
3604
+ color: "green",
3605
+ onClick: (event) => {
3606
+ event.stopPropagation();
3607
+ setApproval(companyId, "approved");
3608
+ },
3609
+ children: "Approve"
3610
+ }
3611
+ ),
3612
+ /* @__PURE__ */ jsx(
3613
+ Button,
3614
+ {
3615
+ size: "compact-xs",
3616
+ variant: approvalByCompanyId[companyId] === "rejected" ? "filled" : "light",
3617
+ color: "red",
3618
+ onClick: (event) => {
3619
+ event.stopPropagation();
3620
+ setApproval(companyId, "rejected");
3621
+ },
3622
+ children: "Reject"
3623
+ }
3624
+ )
3625
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "-" }) }) : null
3626
+ ] }, row.id);
3627
+ }) })
3628
+ ] }) }),
3629
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
3630
+ /* @__PURE__ */ jsx(Pagination, { size: "sm", total: totalPages, value: page, onChange: setPage, disabled: recordsQuery.isFetching }),
3631
+ isReviewExportStep ? /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
3632
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
3633
+ approvedCompanyIds.length,
3634
+ " approved, ",
3635
+ rejectedCompanyIds.length,
3636
+ " rejected"
3637
+ ] }),
3638
+ exportDisabledReason ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: exportDisabledReason }) : null,
3639
+ /* @__PURE__ */ jsx(
3640
+ Button,
3641
+ {
3642
+ size: "xs",
3643
+ leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 }),
3644
+ loading: exportExecution.isPending,
3645
+ disabled: !canExport,
3646
+ onClick: () => void exportApproved(),
3647
+ children: isClickUpExportPath ? "Export to ClickUp" : "Export approved"
3648
+ }
3649
+ )
3650
+ ] }) : null
3651
+ ] })
3652
+ ] });
3653
+ }
3093
3654
  function BuildTab({
3094
3655
  list,
3095
3656
  steps,
3096
3657
  recommendedStep,
3097
3658
  onRunStep,
3098
3659
  onRetryStep,
3099
- onViewRunLog,
3100
- onViewRuns
3660
+ onViewRunLog
3101
3661
  }) {
3102
3662
  const [selectedStepId, setSelectedStepId] = useState(null);
3103
3663
  const [stepInputFormState, setStepInputFormState] = useState({});
3104
3664
  const [stepInputError, setStepInputError] = useState(null);
3105
3665
  const [stepInputInitialized, setStepInputInitialized] = useState(false);
3106
3666
  const [activeRightColumnTab, setActiveRightColumnTab] = useState("configuration");
3667
+ const [credentialSelections, setCredentialSelections] = useState({});
3668
+ const [credentialVerificationById, setCredentialVerificationById] = useState({});
3669
+ const [clickupListId, setClickupListId] = useState("");
3670
+ const [runningResources, setRunningResources] = useState({});
3107
3671
  const [stepInputResetKey, setStepInputResetKey] = useState(0);
3108
3672
  const currentStep = getDisplayStep(steps, recommendedStep);
3109
3673
  const selectedStep = steps.find((step) => step.id === selectedStepId) ?? currentStep;
@@ -3113,10 +3677,36 @@ function BuildTab({
3113
3677
  const selectedResourceId = selectedStep?.action?.resourceId ?? null;
3114
3678
  const stepSchema = selectedStep?.action?.schema;
3115
3679
  const stepLayout = selectedStep?.action?.layout;
3680
+ const credentialRequirements = selectedStep?.credentialRequirements ?? [];
3681
+ const visibleStepLayout = useMemo(
3682
+ () => filterCredentialRequirementFields(stepLayout, credentialRequirements),
3683
+ [stepLayout, credentialRequirements]
3684
+ );
3685
+ const showMainStepConfig = stepSchema && hasMainConfigFields(visibleStepLayout);
3686
+ const showAdvancedStepConfig = stepSchema && hasAdvancedConfigFields(visibleStepLayout);
3116
3687
  const recentRunsQuery = useListExecutions(list.id, { resourceId: selectedResourceId, limit: 5 });
3117
3688
  const recentRuns = useMemo(() => recentRunsQuery.data ?? [], [recentRunsQuery.data]);
3689
+ const credentialsQuery = useCredentials();
3690
+ const credentials = credentialsQuery.data ?? [];
3691
+ const verifyCredential = useVerifyCredential();
3118
3692
  const canRunSelectedAction = !!selectedStep?.action && (selectedActionKind === "retry_failed" || selectedActionKind === "run_next_batch");
3693
+ const selectedResourceIsRunning = selectedResourceId ? runningResources[selectedResourceId] ?? false : false;
3694
+ const selectedActionDisabled = !canRunSelectedAction || selectedResourceIsRunning;
3695
+ const selectedActionLabel = selectedResourceIsRunning ? "Running..." : selectedActionKind === "none" ? "No action" : getStepActionLabel(selectedActionKind);
3119
3696
  const selectedActionIcon = selectedActionKind === "retry_failed" ? /* @__PURE__ */ jsx(IconRefresh, { size: 14 }) : /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 });
3697
+ const handleResourceRunningChange = useCallback((resourceId, isRunning) => {
3698
+ setRunningResources((current) => {
3699
+ if (current[resourceId] === isRunning) return current;
3700
+ return { ...current, [resourceId]: isRunning };
3701
+ });
3702
+ }, []);
3703
+ const handleSelectedResourceRunningChange = useCallback(
3704
+ (isRunning) => {
3705
+ if (!selectedResourceId) return;
3706
+ handleResourceRunningChange(selectedResourceId, isRunning);
3707
+ },
3708
+ [handleResourceRunningChange, selectedResourceId]
3709
+ );
3120
3710
  useEffect(() => {
3121
3711
  setStepInputFormState(getInitialStepInput(list, selectedStep?.action));
3122
3712
  setStepInputError(null);
@@ -3139,8 +3729,45 @@ function BuildTab({
3139
3729
  setStepInputFormState(next);
3140
3730
  if (stepInputError) setStepInputError(null);
3141
3731
  };
3732
+ const handleCredentialSelect = (requirement, credential) => {
3733
+ setCredentialSelections((current) => ({
3734
+ ...current,
3735
+ [requirement.key]: credential?.id ?? null
3736
+ }));
3737
+ setStepInputFormState((current) => setValueAtInputPath(current, requirement.inputPath, credential?.name ?? ""));
3738
+ if (stepInputError) setStepInputError(null);
3739
+ };
3740
+ const handleVerifyCredential = (credential) => {
3741
+ verifyCredential.mutate(credential.id, {
3742
+ onSuccess: (result) => {
3743
+ setCredentialVerificationById((current) => ({
3744
+ ...current,
3745
+ [credential.id]: {
3746
+ status: result.ok ? "success" : "error",
3747
+ checkedAt: result.checkedAt,
3748
+ message: result.message ?? (result.ok ? "Credential verified." : "Credential verification failed."),
3749
+ details: result.details
3750
+ }
3751
+ }));
3752
+ },
3753
+ onError: (error) => {
3754
+ setCredentialVerificationById((current) => ({
3755
+ ...current,
3756
+ [credential.id]: {
3757
+ status: "error",
3758
+ message: error instanceof Error ? error.message : "Credential verification failed."
3759
+ }
3760
+ }));
3761
+ }
3762
+ });
3763
+ };
3764
+ const handleClickupListIdChange = (value) => {
3765
+ setClickupListId(value);
3766
+ setStepInputFormState((current) => setValueAtInputPath(current, "clickupListId", value));
3767
+ if (stepInputError) setStepInputError(null);
3768
+ };
3142
3769
  const handleSelectedAction = () => {
3143
- if (!selectedStep || !canRunSelectedAction) return;
3770
+ if (!selectedStep || selectedActionDisabled) return;
3144
3771
  if (stepSchema) {
3145
3772
  const parsed = stepSchema.safeParse(stepInputFormState);
3146
3773
  if (!parsed.success) {
@@ -3167,196 +3794,238 @@ function BuildTab({
3167
3794
  if (!resourceId) return;
3168
3795
  onViewRunLog(resourceId, run.executionId);
3169
3796
  };
3170
- return /* @__PURE__ */ jsx(
3171
- TabSection,
3172
- {
3173
- icon: /* @__PURE__ */ jsx(IconBolt, { size: 16 }),
3174
- title: "Build",
3175
- description: getBuildTabDescription(steps, currentStep),
3176
- children: /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
3177
- /* @__PURE__ */ jsx(Card, { withBorder: true, style: { height: "100%", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsx(Stack, { gap: "xs", style: { flex: 1, minHeight: 0 }, children: steps.map((step, index) => {
3178
- const isCurrent = currentStep?.id === step.id;
3179
- const isSelected = selectedStep?.id === step.id;
3180
- const isWaiting = step.status === "blocked";
3181
- const isPassiveWaiting = isWaiting && !isSelected && !isCurrent;
3182
- const stepTone = isSelected || isCurrent ? step.status : step.status === "complete" || isWaiting ? step.status : "neutral";
3183
- return /* @__PURE__ */ jsx(
3184
- UnstyledButton,
3185
- {
3186
- onClick: () => setSelectedStepId(step.id),
3187
- style: {
3188
- backgroundColor: isSelected ? "var(--surface-primary-strong)" : isPassiveWaiting ? "color-mix(in srgb, var(--color-surface-hover) 38%, transparent)" : "transparent",
3189
- border: isSelected ? "var(--active-border)" : "1px solid var(--color-border)",
3190
- borderStyle: isPassiveWaiting ? "dashed" : "solid",
3191
- borderRadius: 8,
3192
- display: "block",
3193
- opacity: isPassiveWaiting ? 0.72 : 1,
3194
- padding: 12,
3195
- textAlign: "left",
3196
- width: "100%"
3197
- },
3198
- children: /* @__PURE__ */ jsxs(Group, { gap: "sm", align: "flex-start", wrap: "nowrap", children: [
3199
- /* @__PURE__ */ jsx(
3200
- Box,
3201
- {
3202
- w: 28,
3203
- h: 28,
3204
- style: {
3205
- alignItems: "center",
3206
- ...getBuildToneStyle(stepTone),
3207
- borderRadius: 999,
3208
- borderStyle: "solid",
3209
- borderWidth: 1,
3210
- display: "flex",
3211
- flexShrink: 0,
3212
- fontWeight: 700,
3213
- justifyContent: "center"
3214
- },
3215
- children: index + 1
3216
- }
3217
- ),
3218
- /* @__PURE__ */ jsxs(Stack, { gap: 4, style: { minWidth: 0, flex: 1 }, children: [
3219
- /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", children: [
3220
- /* @__PURE__ */ jsx(Text, { fw: 700, c: isPassiveWaiting ? "dimmed" : void 0, truncate: true, children: step.label }),
3221
- isCurrent ? /* @__PURE__ */ jsx(StatusPill, { label: "Current", tone: step.status }) : null,
3222
- !isCurrent && isWaiting ? /* @__PURE__ */ jsx(StatusPill, { label: "Waiting", tone: "blocked" }) : null
3223
- ] }),
3224
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 2, children: step.description }),
3225
- /* @__PURE__ */ jsx(StepCounterLine, { step })
3226
- ] })
3227
- ] })
3797
+ return /* @__PURE__ */ jsx(TabSection, { icon: /* @__PURE__ */ jsx(IconBolt, { size: 16 }), title: "Build", description: getBuildTabDescription(steps, currentStep), children: /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
3798
+ /* @__PURE__ */ jsx(Card, { withBorder: true, style: { height: "100%", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", style: { flex: 1, minHeight: 0 }, children: [
3799
+ steps.map(
3800
+ (step) => step.action?.resourceId ? /* @__PURE__ */ jsx(
3801
+ BuildStepRunningWatcher,
3802
+ {
3803
+ resourceId: step.action.resourceId,
3804
+ onRunningChange: handleResourceRunningChange
3805
+ },
3806
+ `running-${step.id}`
3807
+ ) : null
3808
+ ),
3809
+ steps.map((step, index) => {
3810
+ const isCurrent = currentStep?.id === step.id;
3811
+ const isSelected = selectedStep?.id === step.id;
3812
+ const stepResourceId = step.action?.resourceId ?? null;
3813
+ const isStepRunning = stepResourceId ? runningResources[stepResourceId] ?? false : false;
3814
+ const isWaiting = step.status === "blocked";
3815
+ const isPassiveWaiting = isWaiting && !isSelected && !isCurrent;
3816
+ const stepTone = isStepRunning ? "ready" : isSelected || isCurrent ? step.status : step.status === "complete" || isWaiting ? step.status : "neutral";
3817
+ return /* @__PURE__ */ jsx(
3818
+ UnstyledButton,
3819
+ {
3820
+ onClick: () => setSelectedStepId(step.id),
3821
+ style: {
3822
+ backgroundColor: isSelected ? "var(--surface-primary-strong)" : isStepRunning ? "color-mix(in srgb, var(--color-primary) 12%, transparent)" : isPassiveWaiting ? "color-mix(in srgb, var(--color-surface-hover) 38%, transparent)" : "transparent",
3823
+ border: isSelected ? "var(--active-border)" : isStepRunning ? "1px solid var(--border-primary-muted)" : "1px solid var(--color-border)",
3824
+ borderStyle: isPassiveWaiting && !isStepRunning ? "dashed" : "solid",
3825
+ borderRadius: 8,
3826
+ display: "block",
3827
+ opacity: isPassiveWaiting && !isStepRunning ? 0.72 : 1,
3828
+ padding: 12,
3829
+ textAlign: "left",
3830
+ width: "100%"
3228
3831
  },
3229
- step.id
3230
- );
3231
- }) }) }),
3232
- selectedStep ? /* @__PURE__ */ jsx(Card, { withBorder: true, style: { height: "100%", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", style: { flex: 1, minHeight: 0 }, children: [
3233
- /* @__PURE__ */ jsxs(Stack, { gap: 2, style: { minWidth: 0, flexShrink: 0 }, children: [
3234
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: [
3235
- "Step ",
3236
- selectedStepIndex + 1,
3237
- " details"
3238
- ] }),
3239
- /* @__PURE__ */ jsx(Title, { order: 5, children: selectedStep.label })
3832
+ children: /* @__PURE__ */ jsxs(Group, { gap: "sm", align: "flex-start", wrap: "nowrap", children: [
3833
+ /* @__PURE__ */ jsx(
3834
+ Box,
3835
+ {
3836
+ w: 28,
3837
+ h: 28,
3838
+ style: {
3839
+ alignItems: "center",
3840
+ ...getBuildToneStyle(stepTone),
3841
+ borderRadius: 999,
3842
+ borderStyle: "solid",
3843
+ borderWidth: 1,
3844
+ display: "flex",
3845
+ flexShrink: 0,
3846
+ fontWeight: 700,
3847
+ justifyContent: "center"
3848
+ },
3849
+ children: index + 1
3850
+ }
3851
+ ),
3852
+ /* @__PURE__ */ jsxs(Stack, { gap: 4, style: { minWidth: 0, flex: 1 }, children: [
3853
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", children: [
3854
+ /* @__PURE__ */ jsx(Text, { fw: 700, c: isPassiveWaiting && !isStepRunning ? "dimmed" : void 0, truncate: true, children: step.label }),
3855
+ isStepRunning ? /* @__PURE__ */ jsx(StatusPill, { label: "Running", tone: "ready" }) : null,
3856
+ !isStepRunning && isCurrent ? /* @__PURE__ */ jsx(StatusPill, { label: "Current", tone: step.status }) : null,
3857
+ !isStepRunning && !isCurrent && isWaiting ? /* @__PURE__ */ jsx(StatusPill, { label: "Waiting", tone: "blocked" }) : null
3858
+ ] }),
3859
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 2, children: step.description }),
3860
+ /* @__PURE__ */ jsx(StepCounterLine, { step })
3861
+ ] })
3862
+ ] })
3863
+ },
3864
+ step.id
3865
+ );
3866
+ })
3867
+ ] }) }),
3868
+ selectedStep ? /* @__PURE__ */ jsx(Card, { withBorder: true, style: { height: "100%", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", style: { flex: 1, minHeight: 0 }, children: [
3869
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, style: { minWidth: 0, flexShrink: 0 }, children: [
3870
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: [
3871
+ "Step ",
3872
+ selectedStepIndex + 1,
3873
+ " details"
3874
+ ] }),
3875
+ /* @__PURE__ */ jsx(Title, { order: 5, children: selectedStep.label })
3876
+ ] }),
3877
+ /* @__PURE__ */ jsx(BuildStepProgressBar, { step: selectedStep }),
3878
+ /* @__PURE__ */ jsx(
3879
+ StepDetailRightColumn,
3880
+ {
3881
+ activeTab: activeRightColumnTab,
3882
+ onTabChange: setActiveRightColumnTab,
3883
+ configuration: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
3884
+ selectedResourceId && selectedStep.stageKey ? /* @__PURE__ */ jsx(
3885
+ LeadGenLiveStatusPanel,
3886
+ {
3887
+ listId: list.id,
3888
+ resourceId: selectedResourceId,
3889
+ stageKey: selectedStep.stageKey,
3890
+ stepLabel: selectedStep.label,
3891
+ enabled: true,
3892
+ onRunningChange: handleSelectedResourceRunningChange
3893
+ },
3894
+ selectedResourceId
3895
+ ) : null,
3896
+ selectedStep.status === "blocked" ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: selectedStep.emptyBlockedText }) : null,
3897
+ selectedStep.outputs.includes(selectedStep.primaryEntity) && selectedStep.ready === 0 && selectedStep.complete === 0 && selectedStep.failed === 0 && selectedStep.blocked === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Run this step to populate members." }) : null,
3898
+ !selectedStep.outputs.includes(selectedStep.primaryEntity) && selectedStep.recommendedAction?.defaultSize !== void 0 && selectedStep.recommendedAction.maxSize !== void 0 ? /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
3899
+ "Batch size: ",
3900
+ selectedStep.recommendedAction.defaultSize,
3901
+ " default,",
3902
+ " ",
3903
+ selectedStep.recommendedAction.maxSize,
3904
+ " max."
3905
+ ] }) : null,
3906
+ showMainStepConfig && visibleStepLayout ? /* @__PURE__ */ jsx(
3907
+ StepConfigForm,
3908
+ {
3909
+ slot: "main",
3910
+ schema: stepSchema,
3911
+ layout: visibleStepLayout,
3912
+ value: stepInputFormState,
3913
+ onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3914
+ disabled: !canRunSelectedAction
3915
+ },
3916
+ `${selectedResourceId ?? "none"}-main-${stepInputResetKey}`
3917
+ ) : !credentialRequirements.length ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No configuration for this step." }) : null,
3918
+ /* @__PURE__ */ jsx(
3919
+ CredentialRequirementsPanel,
3920
+ {
3921
+ requirements: credentialRequirements,
3922
+ credentials,
3923
+ credentialsLoading: credentialsQuery.isLoading,
3924
+ selections: credentialSelections,
3925
+ verificationByCredentialId: credentialVerificationById,
3926
+ verifyingCredentialId: verifyCredential.isPending ? verifyCredential.variables ?? null : null,
3927
+ onSelect: handleCredentialSelect,
3928
+ onVerify: handleVerifyCredential
3929
+ }
3930
+ ),
3931
+ selectedStep.capabilityKey === "lead-gen.export.list" || getClickUpRequirement(selectedStep) ? /* @__PURE__ */ jsx(
3932
+ TextInput,
3933
+ {
3934
+ label: "ClickUp List ID",
3935
+ description: "Destination List ID for approved company tasks.",
3936
+ placeholder: "123456789",
3937
+ value: clickupListId,
3938
+ onChange: (event) => handleClickupListIdChange(event.currentTarget.value)
3939
+ }
3940
+ ) : null
3240
3941
  ] }),
3241
- /* @__PURE__ */ jsx(BuildStepProgressBar, { step: selectedStep }),
3242
- /* @__PURE__ */ jsx(
3243
- StepDetailRightColumn,
3942
+ advanced: showAdvancedStepConfig && visibleStepLayout ? /* @__PURE__ */ jsx(
3943
+ StepConfigForm,
3244
3944
  {
3245
- activeTab: activeRightColumnTab,
3246
- onTabChange: setActiveRightColumnTab,
3247
- configuration: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
3248
- selectedStep.status === "blocked" ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: selectedStep.emptyBlockedText }) : null,
3249
- selectedStep.outputs.includes(selectedStep.primaryEntity) && selectedStep.ready === 0 && selectedStep.complete === 0 && selectedStep.failed === 0 && selectedStep.blocked === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Run this step to populate members." }) : null,
3250
- !selectedStep.outputs.includes(selectedStep.primaryEntity) && selectedStep.recommendedAction?.defaultSize !== void 0 && selectedStep.recommendedAction.maxSize !== void 0 ? /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
3251
- "Batch size: ",
3252
- selectedStep.recommendedAction.defaultSize,
3253
- " default,",
3254
- " ",
3255
- selectedStep.recommendedAction.maxSize,
3256
- " max."
3257
- ] }) : null,
3258
- stepSchema && stepLayout ? /* @__PURE__ */ jsx(
3259
- StepConfigForm,
3260
- {
3261
- slot: "main",
3262
- schema: stepSchema,
3263
- layout: stepLayout,
3264
- value: stepInputFormState,
3265
- onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3266
- disabled: !canRunSelectedAction
3267
- },
3268
- `${selectedResourceId ?? "none"}-main-${stepInputResetKey}`
3269
- ) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No configuration for this step." })
3270
- ] }),
3271
- advanced: stepSchema && stepLayout?.advanced ? /* @__PURE__ */ jsx(
3272
- StepConfigForm,
3945
+ slot: "advanced",
3946
+ schema: stepSchema,
3947
+ layout: visibleStepLayout,
3948
+ value: stepInputFormState,
3949
+ onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3950
+ disabled: !canRunSelectedAction
3951
+ },
3952
+ `${selectedResourceId ?? "none"}-advanced-${stepInputResetKey}`
3953
+ ) : void 0,
3954
+ records: /* @__PURE__ */ jsx(
3955
+ StepRecordsPanel,
3956
+ {
3957
+ list,
3958
+ step: selectedStep,
3959
+ credentialSelections,
3960
+ credentials,
3961
+ clickupListId
3962
+ },
3963
+ selectedStep.id
3964
+ ),
3965
+ runs: selectedResourceId ? /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3966
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
3967
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Recent runs" }),
3968
+ recentRunsQuery.isFetching ? /* @__PURE__ */ jsx(Loader, { size: "xs" }) : null
3969
+ ] }),
3970
+ !recentRuns.length && !recentRunsQuery.isLoading ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No runs yet for this step." }) : /* @__PURE__ */ jsx(Stack, { gap: 4, children: recentRuns.map((run) => {
3971
+ const canUseSettings = hasRunInput(run);
3972
+ return /* @__PURE__ */ jsx(
3973
+ Box,
3273
3974
  {
3274
- slot: "advanced",
3275
- schema: stepSchema,
3276
- layout: stepLayout,
3277
- value: stepInputFormState,
3278
- onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3279
- disabled: !canRunSelectedAction
3975
+ style: {
3976
+ border: "1px solid var(--color-border)",
3977
+ borderRadius: 8,
3978
+ padding: "8px 10px",
3979
+ width: "100%"
3980
+ },
3981
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
3982
+ /* @__PURE__ */ jsx(
3983
+ UnstyledButton,
3984
+ {
3985
+ onClick: () => openRecentRunLog(run),
3986
+ style: { flex: 1, minWidth: 0, textAlign: "left" },
3987
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
3988
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, style: { minWidth: 0 }, children: [
3989
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, truncate: true, children: formatDateTime4(run.createdAt) }),
3990
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ff: "monospace", truncate: true, children: run.executionId })
3991
+ ] }),
3992
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getRunStatusColor(run.status), children: run.status })
3993
+ ] })
3994
+ }
3995
+ ),
3996
+ /* @__PURE__ */ jsx(Tooltip, { label: "Use this run's settings", children: /* @__PURE__ */ jsx(
3997
+ Button,
3998
+ {
3999
+ size: "xs",
4000
+ variant: "subtle",
4001
+ leftSection: /* @__PURE__ */ jsx(IconSettings, { size: 12 }),
4002
+ disabled: !canUseSettings,
4003
+ onClick: () => loadRecentRunInput(run),
4004
+ children: "Use settings"
4005
+ }
4006
+ ) })
4007
+ ] })
3280
4008
  },
3281
- `${selectedResourceId ?? "none"}-advanced-${stepInputResetKey}`
3282
- ) : void 0,
3283
- runs: selectedResourceId ? /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3284
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
3285
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Recent runs" }),
3286
- recentRunsQuery.isFetching ? /* @__PURE__ */ jsx(Loader, { size: "xs" }) : null
3287
- ] }),
3288
- !recentRuns.length && !recentRunsQuery.isLoading ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No runs yet for this step." }) : /* @__PURE__ */ jsx(Stack, { gap: 4, children: recentRuns.map((run) => {
3289
- const canUseSettings = hasRunInput(run);
3290
- return /* @__PURE__ */ jsx(
3291
- Box,
3292
- {
3293
- style: {
3294
- border: "1px solid var(--color-border)",
3295
- borderRadius: 8,
3296
- padding: "8px 10px",
3297
- width: "100%"
3298
- },
3299
- children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
3300
- /* @__PURE__ */ jsx(
3301
- UnstyledButton,
3302
- {
3303
- onClick: () => openRecentRunLog(run),
3304
- style: { flex: 1, minWidth: 0, textAlign: "left" },
3305
- children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
3306
- /* @__PURE__ */ jsxs(Stack, { gap: 2, style: { minWidth: 0 }, children: [
3307
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, truncate: true, children: formatDateTime4(run.createdAt) }),
3308
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ff: "monospace", truncate: true, children: run.executionId })
3309
- ] }),
3310
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getRunStatusColor(run.status), children: run.status })
3311
- ] })
3312
- }
3313
- ),
3314
- /* @__PURE__ */ jsx(Tooltip, { label: "Use this run's settings", children: /* @__PURE__ */ jsx(
3315
- Button,
3316
- {
3317
- size: "xs",
3318
- variant: "subtle",
3319
- leftSection: /* @__PURE__ */ jsx(IconSettings, { size: 12 }),
3320
- disabled: !canUseSettings,
3321
- onClick: () => loadRecentRunInput(run),
3322
- children: "Use settings"
3323
- }
3324
- ) })
3325
- ] })
3326
- },
3327
- run.executionId
3328
- );
3329
- }) })
3330
- ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No runs available for this step." }),
3331
- action: /* @__PURE__ */ jsxs(Fragment, { children: [
3332
- stepInputError ? /* @__PURE__ */ jsx(Alert, { color: "red", icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), variant: "light", children: stepInputError }) : null,
3333
- /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "flex-end", wrap: "nowrap", children: [
3334
- /* @__PURE__ */ jsx(
3335
- Button,
3336
- {
3337
- leftSection: selectedActionIcon,
3338
- disabled: !canRunSelectedAction,
3339
- onClick: handleSelectedAction,
3340
- children: selectedActionKind === "none" ? "No action" : getStepActionLabel(selectedActionKind)
3341
- }
3342
- ),
3343
- recentRuns.length > 0 ? /* @__PURE__ */ jsx(
3344
- Button,
3345
- {
3346
- variant: "light",
3347
- leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 }),
3348
- onClick: () => onViewRuns(selectedResourceId),
3349
- children: "View runs"
3350
- }
3351
- ) : null
3352
- ] })
3353
- ] })
3354
- }
3355
- )
3356
- ] }) }) : null
3357
- ] })
3358
- }
3359
- );
4009
+ run.executionId
4010
+ );
4011
+ }) })
4012
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No runs available for this step." }),
4013
+ action: /* @__PURE__ */ jsxs(Fragment, { children: [
4014
+ stepInputError ? /* @__PURE__ */ jsx(Alert, { color: "red", icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), variant: "light", children: stepInputError }) : null,
4015
+ /* @__PURE__ */ jsx(Group, { gap: "xs", justify: "flex-end", wrap: "nowrap", children: /* @__PURE__ */ jsx(
4016
+ Button,
4017
+ {
4018
+ leftSection: selectedActionIcon,
4019
+ disabled: selectedActionDisabled,
4020
+ onClick: handleSelectedAction,
4021
+ children: selectedActionLabel
4022
+ }
4023
+ ) })
4024
+ ] })
4025
+ }
4026
+ )
4027
+ ] }) }) : null
4028
+ ] }) });
3360
4029
  }
3361
4030
  function MembersTab({
3362
4031
  listId,
@@ -3638,10 +4307,6 @@ function LeadGenListDetailPage({ listId }) {
3638
4307
  params: { workflowId: resourceId },
3639
4308
  search: { exec: executionId }
3640
4309
  });
3641
- },
3642
- onViewRuns: (resourceId) => {
3643
- setRunsResourceFilter(resourceId);
3644
- setActiveTab("runs");
3645
4310
  }
3646
4311
  }
3647
4312
  ) }),
@@ -3708,11 +4373,15 @@ function LeadGenCompaniesPage() {
3708
4373
  const [segmentFilter, setSegmentFilter] = useState(null);
3709
4374
  const [categoryFilter, setCategoryFilter] = useState(null);
3710
4375
  const [statusFilter, setStatusFilter] = useState(null);
3711
- const [selectedCompany, setSelectedCompany] = useState(null);
3712
4376
  const [showBatchDelete, setShowBatchDelete] = useState(false);
4377
+ const navigate = useNavigate();
3713
4378
  const pagination = usePaginationState(PAGE_SIZE_DEFAULT2, [companySearch, segmentFilter, categoryFilter, statusFilter]);
3714
4379
  const { data: companyFacets } = useCompanyFacets();
3715
- const { data: pagedCompanies, isLoading: pagedCompaniesLoading, error: pagedCompaniesError } = useCompanies({
4380
+ const {
4381
+ data: pagedCompanies,
4382
+ isLoading: pagedCompaniesLoading,
4383
+ error: pagedCompaniesError
4384
+ } = useCompanies({
3716
4385
  search: companySearch || void 0,
3717
4386
  segment: segmentFilter || void 0,
3718
4387
  category: categoryFilter || void 0,
@@ -3828,7 +4497,7 @@ function LeadGenCompaniesPage() {
3828
4497
  Table.Tr,
3829
4498
  {
3830
4499
  style: { cursor: "pointer" },
3831
- onClick: () => setSelectedCompany(company),
4500
+ onClick: () => navigate({ to: "/crm/companies/$companyId", params: { companyId: company.id } }),
3832
4501
  children: [
3833
4502
  /* @__PURE__ */ jsx(
3834
4503
  Table.Td,
@@ -3870,7 +4539,6 @@ function LeadGenCompaniesPage() {
3870
4539
  }
3871
4540
  ) }) : null
3872
4541
  ] }) }),
3873
- /* @__PURE__ */ jsx(CompanyDetailModal, { company: selectedCompany, onClose: () => setSelectedCompany(null) }),
3874
4542
  /* @__PURE__ */ jsx(CustomModal, { opened: showBatchDelete, onClose: () => setShowBatchDelete(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
3875
4543
  /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
3876
4544
  /* @__PURE__ */ jsx(IconAlertTriangle, { size: 20, color: "var(--mantine-color-red-6)" }),
@@ -3893,11 +4561,15 @@ function LeadGenContactsPage() {
3893
4561
  const [contactSearch, setContactSearch] = useState("");
3894
4562
  const [statusFilter, setStatusFilter] = useState(null);
3895
4563
  const [listFilter, setListFilter] = useState(null);
3896
- const [selectedContact, setSelectedContact] = useState(null);
3897
4564
  const [showBatchDelete, setShowBatchDelete] = useState(false);
4565
+ const navigate = useNavigate();
3898
4566
  const pagination = usePaginationState(PAGE_SIZE_DEFAULT3, [contactSearch, statusFilter, listFilter]);
3899
4567
  const { data: lists } = useLists();
3900
- const { data: contacts, isLoading: contactsLoading, error: contactsError } = useContacts({
4568
+ const {
4569
+ data: contacts,
4570
+ isLoading: contactsLoading,
4571
+ error: contactsError
4572
+ } = useContacts({
3901
4573
  search: contactSearch || void 0,
3902
4574
  contactStatus: statusFilter || void 0,
3903
4575
  listId: listFilter || void 0,
@@ -4000,7 +4672,7 @@ function LeadGenContactsPage() {
4000
4672
  Table.Tr,
4001
4673
  {
4002
4674
  style: { cursor: "pointer" },
4003
- onClick: () => setSelectedContact(contact),
4675
+ onClick: () => navigate({ to: "/crm/contacts/$contactId", params: { contactId: contact.id } }),
4004
4676
  children: [
4005
4677
  /* @__PURE__ */ jsx(
4006
4678
  Table.Td,
@@ -4041,7 +4713,6 @@ function LeadGenContactsPage() {
4041
4713
  }
4042
4714
  ) }) : null
4043
4715
  ] }) }),
4044
- /* @__PURE__ */ jsx(ContactDetailModal, { contact: selectedContact, onClose: () => setSelectedContact(null) }),
4045
4716
  /* @__PURE__ */ jsx(CustomModal, { opened: showBatchDelete, onClose: () => setShowBatchDelete(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4046
4717
  /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
4047
4718
  /* @__PURE__ */ jsx(IconAlertTriangle, { size: 20, color: "var(--mantine-color-red-6)" }),
@@ -4060,4 +4731,4 @@ function LeadGenContactsPage() {
4060
4731
  ] }) });
4061
4732
  }
4062
4733
 
4063
- export { CompanyDetailModal, ContactDetailModal, LEAD_GEN_ITEMS, LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, ListBuilderIndexPage, ListBuilderPage, ORPHAN_STAGE_ORDER, RunWorkflowModal, StepConfigForm, TabSection, deriveBusinessProgress, formatDate, getEnrichmentColor, getEnrichmentStatus, getStateKeyColor, getStatusColor, getStepActionLabel, leadGenManifest, resolveBuildPlanSteps, resolveBuildState, sortStageKeys, useDeleteLists };
4734
+ export { LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarTop, ListBuilderIndexPage, ListBuilderPage, ORPHAN_STAGE_ORDER, RunWorkflowModal, StepConfigForm, TabSection, deriveBusinessProgress, formatDate, getEnrichmentColor, getEnrichmentStatus, getStateKeyColor, getStatusColor, getStepActionLabel, leadGenManifest, resolveBuildPlanSteps, resolveBuildState, sortStageKeys, useDeleteLists };