@elevasis/ui 2.28.0 → 2.29.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 (72) hide show
  1. package/dist/api/index.js +2 -2
  2. package/dist/app/index.d.ts +6 -12
  3. package/dist/app/index.js +4 -4
  4. package/dist/charts/index.js +3 -3
  5. package/dist/{chunk-OHXU5WWK.js → chunk-3DUOPXOJ.js} +146 -9
  6. package/dist/{chunk-LWKZ3BCC.js → chunk-5CW2HXQA.js} +4 -4
  7. package/dist/{chunk-JKBGDFX2.js → chunk-65RQE3XF.js} +378 -254
  8. package/dist/{chunk-XZSEPJZQ.js → chunk-6NHCE7JM.js} +49 -28
  9. package/dist/{chunk-RIFTUOPE.js → chunk-6WXDE5LZ.js} +1 -1
  10. package/dist/{chunk-SGS4CQ2B.js → chunk-7E3FUTND.js} +1 -1
  11. package/dist/{chunk-UPMX5GJI.js → chunk-A7R2URMV.js} +88 -26
  12. package/dist/{chunk-UY5I2KOZ.js → chunk-AK5E6ILJ.js} +9 -8
  13. package/dist/{chunk-G26INIF3.js → chunk-CEHUFNAL.js} +1 -1
  14. package/dist/{chunk-ONFKASZI.js → chunk-CLUP5H3C.js} +7 -10
  15. package/dist/{chunk-MYEOTM7D.js → chunk-CN2HC4D4.js} +5 -1
  16. package/dist/chunk-FFDAE2QI.js +330 -0
  17. package/dist/{chunk-WUVR4QY6.js → chunk-FGDUK74A.js} +4 -4
  18. package/dist/{chunk-YHBPR67D.js → chunk-HNFQCOD2.js} +4 -4
  19. package/dist/{chunk-QD4X4H5A.js → chunk-HXZQWMKE.js} +2 -3
  20. package/dist/{chunk-KEFWANZY.js → chunk-JCGD4GM6.js} +5 -1
  21. package/dist/{chunk-YO2YORW4.js → chunk-OHGNCWJP.js} +3 -3
  22. package/dist/{chunk-JPGX3533.js → chunk-OIMPGKDB.js} +2 -2
  23. package/dist/{chunk-W2ZTLH7Y.js → chunk-OWESKPTJ.js} +85 -26
  24. package/dist/{chunk-G66QFZXD.js → chunk-QNL7UI5G.js} +15 -9
  25. package/dist/{chunk-OGXKOMUT.js → chunk-SZWXQHKO.js} +2 -2
  26. package/dist/{chunk-ZFLM2YVW.js → chunk-Y3YJKKEB.js} +1 -1
  27. package/dist/components/index.d.ts +16 -14
  28. package/dist/components/index.js +26 -26
  29. package/dist/features/auth/index.d.ts +6 -12
  30. package/dist/features/auth/index.js +1 -0
  31. package/dist/features/crm/index.d.ts +16 -14
  32. package/dist/features/crm/index.js +9 -9
  33. package/dist/features/dashboard/index.d.ts +16 -3
  34. package/dist/features/dashboard/index.js +10 -10
  35. package/dist/features/delivery/index.d.ts +6 -12
  36. package/dist/features/delivery/index.js +9 -9
  37. package/dist/features/knowledge/index.js +42 -20
  38. package/dist/features/lead-gen/index.d.ts +187 -24
  39. package/dist/features/lead-gen/index.js +10 -10
  40. package/dist/features/monitoring/index.js +11 -11
  41. package/dist/features/monitoring/requests/index.js +8 -8
  42. package/dist/features/operations/index.d.ts +16 -3
  43. package/dist/features/operations/index.js +15 -15
  44. package/dist/features/settings/index.d.ts +6 -12
  45. package/dist/features/settings/index.js +9 -9
  46. package/dist/hooks/delivery/index.d.ts +6 -12
  47. package/dist/hooks/delivery/index.js +2 -2
  48. package/dist/hooks/index.d.ts +110 -28
  49. package/dist/hooks/index.js +8 -8
  50. package/dist/hooks/published.d.ts +110 -28
  51. package/dist/hooks/published.js +8 -8
  52. package/dist/index.d.ts +149 -31
  53. package/dist/index.js +8 -8
  54. package/dist/initialization/index.d.ts +6 -12
  55. package/dist/knowledge/index.d.ts +44 -1
  56. package/dist/knowledge/index.js +149 -12
  57. package/dist/profile/index.d.ts +6 -12
  58. package/dist/provider/index.d.ts +44 -12
  59. package/dist/provider/index.js +6 -6
  60. package/dist/provider/published.d.ts +44 -12
  61. package/dist/provider/published.js +5 -5
  62. package/dist/supabase/index.d.ts +12 -24
  63. package/dist/test-utils/index.js +2 -2
  64. package/dist/typeform/index.d.ts +5 -1
  65. package/dist/typeform/index.js +52 -7
  66. package/dist/types/index.d.ts +7 -13
  67. package/dist/utils/index.d.ts +1 -3
  68. package/dist/utils/index.js +1 -1
  69. package/dist/vite/index.js +2 -2
  70. package/dist/vite-plugin-knowledge/index.js +1 -1
  71. package/package.json +5 -5
  72. package/dist/chunk-4KTLOK7K.js +0 -230
@@ -1,4 +1,4 @@
1
- import { DEFAULT_ORGANIZATION_MODEL_PROSPECTING } from './chunk-4KTLOK7K.js';
1
+ import { DEFAULT_ORGANIZATION_MODEL_PROSPECTING, PROSPECTING_STEPS } from './chunk-FFDAE2QI.js';
2
2
  import { sanitizeInput } from './chunk-3MEXPLWT.js';
3
3
  import { PageContainer } from './chunk-BZZCNLT6.js';
4
4
  import { TableSelectionToolbar, SortableHeader } from './chunk-TUMSNGTX.js';
@@ -6,15 +6,15 @@ import { SubshellNavItem } from './chunk-X4WBGKJQ.js';
6
6
  import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
7
7
  import { FilterBar } from './chunk-PDHTXPSF.js';
8
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-YHBPR67D.js';
10
- import { showApiErrorNotification, showSuccessNotification } from './chunk-G26INIF3.js';
11
- import { PageTitleCaption, CenteredErrorState, StatCard, CardHeader, EmptyState, JsonViewer } from './chunk-RIFTUOPE.js';
12
- import { useListActions, LEAD_GEN_STAGE_CATALOG, LEAD_GEN_PIPELINE_DEFINITIONS, findPipeline } from './chunk-W2ZTLH7Y.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';
13
13
  import { SubshellContentContainer } from './chunk-TKAYX2SP.js';
14
14
  import { useRouterContext } from './chunk-Q7DJKLEN.js';
15
15
  import { useElevasisServices } from './chunk-5WWZXCS5.js';
16
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, IconMail, IconUser, IconDatabase } from '@tabler/icons-react';
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';
18
18
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
19
19
  import { Link, useNavigate, useSearch } from '@tanstack/react-router';
20
20
  import { useState, useRef, useMemo, useEffect, Fragment as Fragment$1 } from 'react';
@@ -1208,17 +1208,9 @@ function LeadGenListsPage() {
1208
1208
  )
1209
1209
  ] }) });
1210
1210
  }
1211
- function formatDateTime(value) {
1212
- if (!value) return "Not yet";
1213
- return new Date(value).toLocaleString("en-US", {
1214
- month: "short",
1215
- day: "numeric",
1216
- year: "numeric",
1217
- hour: "numeric",
1218
- minute: "2-digit"
1219
- });
1220
- }
1221
- function resolveMemberStateLabel(member) {
1211
+
1212
+ // src/lib/lead-gen/legacy-pipeline.ts
1213
+ function resolveLegacyListMemberPipelineLabel(member) {
1222
1214
  const defs = LEAD_GEN_PIPELINE_DEFINITIONS["acq.list-member"];
1223
1215
  if (!defs) return null;
1224
1216
  const pipeline = findPipeline(defs, member.pipelineKey);
@@ -1231,23 +1223,21 @@ function resolveMemberStateLabel(member) {
1231
1223
  stateLabel: state?.label ?? member.stateKey
1232
1224
  };
1233
1225
  }
1226
+ function formatDateTime(value) {
1227
+ if (!value) return "Not yet";
1228
+ return new Date(value).toLocaleString("en-US", {
1229
+ month: "short",
1230
+ day: "numeric",
1231
+ year: "numeric",
1232
+ hour: "numeric",
1233
+ minute: "2-digit"
1234
+ });
1235
+ }
1234
1236
  function getMemberStateColor(stateKey) {
1235
- switch (stateKey) {
1236
- case "personalized":
1237
- case "verified":
1238
- case "qualified":
1239
- case "interested":
1240
- return "green";
1241
- case "uploaded":
1242
- case "discovered":
1243
- case "extracted":
1244
- case "populated":
1245
- return "blue";
1246
- case "pending":
1247
- return "gray";
1248
- default:
1249
- return "gray";
1250
- }
1237
+ const stage = LEAD_GEN_STAGE_CATALOG[stateKey];
1238
+ if (stage?.entity === "contact") return "green";
1239
+ if (stage?.entity === "company") return "blue";
1240
+ return "gray";
1251
1241
  }
1252
1242
  function ArtifactsPanel({ listMemberId }) {
1253
1243
  const { data, isLoading, error } = useArtifacts({ ownerKind: "list_member", ownerId: listMemberId });
@@ -1288,7 +1278,7 @@ function ListMemberDrawerContent({ member, listId }) {
1288
1278
  [member]
1289
1279
  );
1290
1280
  const derivedActions = useDeriveActions(statefulItem);
1291
- const resolved = resolveMemberStateLabel(member);
1281
+ const resolved = resolveLegacyListMemberPipelineLabel(member);
1292
1282
  const contactName = [member.contact?.firstName, member.contact?.lastName].filter(Boolean).join(" ").trim() || member.contact?.email || "\u2014";
1293
1283
  return /* @__PURE__ */ jsxs(Stack, { gap: "md", p: "md", children: [
1294
1284
  /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
@@ -1535,6 +1525,12 @@ var STAGE_COLOR_SETS = {
1535
1525
  border: "color-mix(in srgb, var(--color-border) 68%, var(--color-success))",
1536
1526
  text: "var(--color-text)"
1537
1527
  },
1528
+ "decision-makers-enriched": {
1529
+ accent: "color-mix(in srgb, var(--color-primary) 66%, var(--color-warning))",
1530
+ background: "color-mix(in srgb, var(--color-primary) 12%, transparent)",
1531
+ border: "color-mix(in srgb, var(--color-border) 66%, var(--color-primary))",
1532
+ text: "var(--color-text)"
1533
+ },
1538
1534
  discovered: {
1539
1535
  accent: "color-mix(in srgb, var(--color-primary) 70%, var(--color-warning))",
1540
1536
  background: "color-mix(in srgb, var(--color-warning) 10%, transparent)",
@@ -2298,197 +2294,120 @@ function ListBuilderPage({ listId }) {
2298
2294
  )
2299
2295
  ] });
2300
2296
  }
2301
- function formatDateTime4(value) {
2302
- if (!value) return "Not yet";
2303
- return new Date(value).toLocaleString("en-US", {
2304
- month: "short",
2305
- day: "numeric",
2306
- year: "numeric",
2307
- hour: "numeric",
2308
- minute: "2-digit"
2297
+
2298
+ // src/lib/lead-gen/processing-state.ts
2299
+ function isRecord(value) {
2300
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2301
+ }
2302
+ function parseProcessingStageStatus(value) {
2303
+ if (value === true || value === "success") return "success";
2304
+ if (value === "no_result" || value === "noResult") return "noResult";
2305
+ if (value === "skipped") return "skipped";
2306
+ if (value === "error") return "error";
2307
+ if (isRecord(value)) return parseProcessingStageStatus(value.status);
2308
+ if (typeof value === "string") return "other";
2309
+ return null;
2310
+ }
2311
+ function parseProcessingState(value) {
2312
+ const parsed = {};
2313
+ const stageStatuses = {};
2314
+ const knownStageStatuses = {};
2315
+ const unknownFields = {};
2316
+ if (!isRecord(value)) {
2317
+ Object.defineProperties(parsed, {
2318
+ stageStatuses: { value: stageStatuses },
2319
+ knownStageStatuses: { value: knownStageStatuses },
2320
+ unknownFields: { value: unknownFields }
2321
+ });
2322
+ return parsed;
2323
+ }
2324
+ for (const [key, rawStatus] of Object.entries(value)) {
2325
+ const parsedStatus = parseProcessingStageStatus(rawStatus);
2326
+ const isKnownStage = Boolean(LEAD_GEN_STAGE_CATALOG[key]);
2327
+ if (!parsedStatus) {
2328
+ unknownFields[key] = rawStatus;
2329
+ continue;
2330
+ }
2331
+ stageStatuses[key] = parsedStatus;
2332
+ parsed[key] = parsedStatus;
2333
+ if (isKnownStage) {
2334
+ knownStageStatuses[key] = parsedStatus;
2335
+ } else {
2336
+ unknownFields[key] = rawStatus;
2337
+ }
2338
+ }
2339
+ Object.defineProperties(parsed, {
2340
+ stageStatuses: { value: stageStatuses },
2341
+ knownStageStatuses: { value: knownStageStatuses },
2342
+ unknownFields: { value: unknownFields }
2309
2343
  });
2344
+ return parsed;
2310
2345
  }
2311
- function contactDisplayName(firstName, lastName) {
2312
- const full = [firstName, lastName].filter(Boolean).join(" ").trim();
2313
- return full || "\u2014";
2346
+ function readLeadGenProcessingState(row) {
2347
+ if (!isRecord(row)) return null;
2348
+ return row.processingState ?? row.processing_state ?? row.pipelineStatus ?? null;
2314
2349
  }
2315
- function getStatusColor4(status) {
2316
- switch (status) {
2317
- case "draft":
2318
- return "gray";
2319
- case "enriching":
2320
- return "blue";
2321
- case "launched":
2322
- return "green";
2323
- case "closing":
2324
- return "yellow";
2325
- case "archived":
2326
- return "red";
2327
- default:
2328
- return "gray";
2329
- }
2350
+ function readLeadGenStateKey(row) {
2351
+ if (!isRecord(row)) return null;
2352
+ const stateKey = row.stateKey ?? row.state_key;
2353
+ return typeof stateKey === "string" && stateKey.length > 0 ? stateKey : null;
2330
2354
  }
2331
- function getMemberStateColor2(stateKey) {
2332
- switch (stateKey) {
2333
- case "personalized":
2334
- case "verified":
2335
- case "qualified":
2336
- case "interested":
2337
- return "green";
2338
- case "uploaded":
2339
- case "discovered":
2340
- case "extracted":
2341
- case "populated":
2342
- return "blue";
2343
- case "pending":
2344
- return "gray";
2345
- default:
2346
- return "gray";
2355
+ function getDisplayLeadGenStageStateFor(row, entity) {
2356
+ const parsed = parseProcessingState(readLeadGenProcessingState(row));
2357
+ const latest = Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity && parsed.knownStageStatuses[stage.key]).sort((a, b) => b.order - a.order)[0];
2358
+ if (latest) {
2359
+ return {
2360
+ stageKey: latest.key,
2361
+ stageStatus: parsed.knownStageStatuses[latest.key]
2362
+ };
2347
2363
  }
2364
+ const unknownStageKey = Object.keys(parsed.stageStatuses).find((stageKey) => !LEAD_GEN_STAGE_CATALOG[stageKey]);
2365
+ if (unknownStageKey) {
2366
+ return {
2367
+ stageKey: unknownStageKey,
2368
+ stageStatus: parsed.stageStatuses[unknownStageKey]
2369
+ };
2370
+ }
2371
+ const stateKey = readLeadGenStateKey(row);
2372
+ return stateKey && LEAD_GEN_STAGE_CATALOG[stateKey] ? { stageKey: stateKey, stageStatus: null } : { stageKey: null, stageStatus: null };
2348
2373
  }
2374
+
2375
+ // src/features/lead-gen/build-state.ts
2376
+ var ORPHAN_STAGE_ORDER = 9999;
2349
2377
  function asRecord2(value) {
2350
2378
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2351
2379
  }
2352
- function getRunStatusColor(status) {
2353
- switch (status) {
2354
- case "completed":
2355
- case "success":
2356
- case "succeeded":
2357
- return "green";
2358
- case "running":
2359
- case "pending":
2360
- case "queued":
2361
- return "blue";
2362
- case "failed":
2363
- case "error":
2364
- case "cancelled":
2365
- return "red";
2366
- default:
2367
- return "gray";
2368
- }
2369
- }
2370
- function getRunInput(run) {
2371
- const payload = asRecord2(run.payload);
2372
- return run.input ?? run.inputs ?? payload.input ?? payload.inputs;
2373
- }
2374
- function sanitizeStepInput(value, _capabilityKey) {
2375
- return value;
2376
- }
2377
- function getDefaultStepInput(list, action) {
2378
- return asRecord2(action?.defaultInput?.(list));
2379
- }
2380
- function getInitialStepInput(list, action) {
2381
- return getDefaultStepInput(list, action);
2382
- }
2383
- function mergeStepRunInput(list, action, inputAtSubmit) {
2380
+ function defineMvpBuildStep(step, emptyBlockedText) {
2381
+ const description = "description" in step && typeof step.description === "string" ? step.description : `Run ${step.label.toLowerCase()} for this list.`;
2384
2382
  return {
2385
- ...getDefaultStepInput(list, action),
2386
- ...inputAtSubmit
2383
+ ...step,
2384
+ description,
2385
+ emptyBlockedText
2387
2386
  };
2388
2387
  }
2389
- var ORPHAN_STAGE_ORDER = 9999;
2390
- var EMPTY_SELECTION2 = {
2391
- selectedCompanyIds: [],
2392
- selectedContactIds: []
2393
- };
2394
2388
  var MVP_BUILD_STEPS = [
2395
- {
2396
- id: "source-companies",
2397
- label: "Source companies",
2398
- description: "Add or import the company cohort for this list.",
2399
- primaryEntity: "company",
2400
- outputs: ["company"],
2401
- stageKey: "populated",
2402
- dependencyMode: "per-record-eligibility",
2403
- capabilityKey: "lead-gen.company.source",
2404
- defaultBatchSize: 100,
2405
- maxBatchSize: 250,
2406
- emptyBlockedText: "No company source has been configured or populated yet."
2407
- },
2408
- {
2409
- id: "analyze-websites",
2410
- label: "Analyze websites",
2411
- description: "Extract website intelligence for sourced companies.",
2412
- primaryEntity: "company",
2413
- outputs: ["company"],
2414
- stageKey: "extracted",
2415
- dependsOn: ["source-companies"],
2416
- dependencyMode: "per-record-eligibility",
2417
- capabilityKey: "lead-gen.company.website-extract",
2418
- defaultBatchSize: 50,
2419
- maxBatchSize: 100,
2420
- emptyBlockedText: "Source companies before website analysis can run."
2421
- },
2422
- {
2423
- id: "qualify-companies",
2424
- label: "Qualify companies",
2425
- description: "Apply the ICP rubric to companies with enough context.",
2426
- primaryEntity: "company",
2427
- outputs: ["company"],
2428
- stageKey: "qualified",
2429
- dependsOn: ["analyze-websites"],
2430
- dependencyMode: "per-record-eligibility",
2431
- capabilityKey: "lead-gen.company.qualify",
2432
- defaultBatchSize: 100,
2433
- maxBatchSize: 250,
2434
- emptyBlockedText: "Analyze websites before qualification can run."
2435
- },
2436
- {
2437
- id: "find-contacts",
2438
- label: "Find contacts",
2439
- description: "Discover contacts for qualified companies.",
2440
- primaryEntity: "contact",
2441
- outputs: ["contact"],
2442
- stageKey: "discovered",
2443
- dependsOn: ["qualify-companies"],
2444
- dependencyMode: "per-record-eligibility",
2445
- capabilityKey: "lead-gen.contact.discover",
2446
- defaultBatchSize: 50,
2447
- maxBatchSize: 100,
2448
- emptyBlockedText: "Qualify companies before contact discovery can run."
2449
- },
2450
- {
2451
- id: "verify-emails",
2452
- label: "Verify emails",
2453
- description: "Verify deliverability for discovered contact emails.",
2454
- primaryEntity: "contact",
2455
- outputs: ["contact"],
2456
- stageKey: "verified",
2457
- dependsOn: ["find-contacts"],
2458
- dependencyMode: "per-record-eligibility",
2459
- capabilityKey: "lead-gen.contact.verify-email",
2460
- defaultBatchSize: 100,
2461
- maxBatchSize: 500,
2462
- emptyBlockedText: "Find contacts before email verification can run."
2463
- },
2464
- {
2465
- id: "personalize",
2466
- label: "Personalize",
2467
- description: "Generate outreach personalization for verified contacts.",
2468
- primaryEntity: "contact",
2469
- outputs: ["contact"],
2470
- stageKey: "personalized",
2471
- dependsOn: ["verify-emails"],
2472
- dependencyMode: "per-record-eligibility",
2473
- capabilityKey: "lead-gen.contact.personalize",
2474
- defaultBatchSize: 25,
2475
- maxBatchSize: 100,
2476
- emptyBlockedText: "Verify emails before personalization can run."
2477
- },
2478
- {
2479
- id: "review",
2480
- label: "Review",
2481
- description: "Review personalized records before outreach handoff.",
2482
- primaryEntity: "contact",
2483
- outputs: ["export"],
2484
- stageKey: "uploaded",
2485
- dependsOn: ["personalize"],
2486
- dependencyMode: "per-record-eligibility",
2487
- capabilityKey: "lead-gen.review.outreach-ready",
2488
- defaultBatchSize: 25,
2489
- maxBatchSize: 100,
2490
- emptyBlockedText: "Personalize contacts before records are ready for review."
2491
- }
2389
+ defineMvpBuildStep(
2390
+ PROSPECTING_STEPS.localServices.sourceCompanies,
2391
+ "No company source has been configured or populated yet."
2392
+ ),
2393
+ defineMvpBuildStep(
2394
+ PROSPECTING_STEPS.localServices.analyzeWebsites,
2395
+ "Source companies before website analysis can run."
2396
+ ),
2397
+ defineMvpBuildStep(
2398
+ PROSPECTING_STEPS.localServices.qualifyCompanies,
2399
+ "Analyze websites before qualification can run."
2400
+ ),
2401
+ defineMvpBuildStep(
2402
+ PROSPECTING_STEPS.localServices.findContacts,
2403
+ "Qualify companies before contact discovery can run."
2404
+ ),
2405
+ defineMvpBuildStep(PROSPECTING_STEPS.localServices.verifyEmails, "Find contacts before email verification can run."),
2406
+ defineMvpBuildStep(PROSPECTING_STEPS.localServices.personalize, "Verify emails before personalization can run."),
2407
+ defineMvpBuildStep(
2408
+ PROSPECTING_STEPS.localServices.review,
2409
+ "Personalize contacts before records are ready for review."
2410
+ )
2492
2411
  ];
2493
2412
  function sortStageKeys(keys) {
2494
2413
  return keys.slice().sort((a, b) => {
@@ -2567,6 +2486,70 @@ function getStepActionLabel(kind) {
2567
2486
  return "No action";
2568
2487
  }
2569
2488
  }
2489
+ function createCompleteStageCounts(total) {
2490
+ return {
2491
+ total,
2492
+ attempted: total,
2493
+ success: total,
2494
+ noResult: 0,
2495
+ skipped: 0,
2496
+ error: 0,
2497
+ other: 0,
2498
+ notAttempted: 0
2499
+ };
2500
+ }
2501
+ function isStageComplete(entry) {
2502
+ if (!entry || entry.total <= 0) return false;
2503
+ return entry.error === 0 && entry.attempted >= entry.total && entry.success + entry.noResult + entry.skipped + entry.other >= entry.total;
2504
+ }
2505
+ function getExecutionInput(run) {
2506
+ return asRecord2(run.input);
2507
+ }
2508
+ function isCompletedRun(run) {
2509
+ return run.status === "completed" || run.status === "success" || run.status === "succeeded";
2510
+ }
2511
+ function getApprovedCompanyIds(run) {
2512
+ const input = getExecutionInput(run);
2513
+ const raw = input.approvedCompanyIds;
2514
+ return Array.isArray(raw) ? raw.filter((value) => typeof value === "string") : [];
2515
+ }
2516
+ function hasApprovedExportRun(executions) {
2517
+ return executions.some((run) => {
2518
+ if (!isCompletedRun(run) || run.resourceId !== "lgn-06-export-list-workflow") return false;
2519
+ const input = getExecutionInput(run);
2520
+ return input.approved === true || getApprovedCompanyIds(run).length > 0;
2521
+ });
2522
+ }
2523
+ function hasCompletedSourcingRun(step, action, executions) {
2524
+ return executions.some((run) => isCompletedRun(run) && run.resourceId === (action?.resourceId ?? step.capabilityKey));
2525
+ }
2526
+ function deriveBusinessProgress(list, progress, actions = [], executions = []) {
2527
+ const byCompanyStage = { ...progress.byCompanyStage };
2528
+ const byContactStage = { ...progress.byContactStage };
2529
+ const steps = resolveBuildPlanSteps(list);
2530
+ for (const step of steps) {
2531
+ const stageProgress = step.primaryEntity === "company" ? byCompanyStage[step.stageKey] : byContactStage[step.stageKey];
2532
+ if (stageProgress || (step.dependsOn?.length ?? 0) > 0 || !step.outputs.includes("company")) continue;
2533
+ if (progress.totalCompanies <= 0) continue;
2534
+ const action = findActionForStep(actions, step);
2535
+ if (hasCompletedSourcingRun(step, action, executions) || step.stageKey === "populated") {
2536
+ byCompanyStage[step.stageKey] = createCompleteStageCounts(progress.totalCompanies);
2537
+ }
2538
+ }
2539
+ if (!isStageComplete(byCompanyStage.uploaded) && hasApprovedExportRun(executions)) {
2540
+ const exportedCount = Math.max(
2541
+ ...executions.filter((run) => isCompletedRun(run) && run.resourceId === "lgn-06-export-list-workflow").map((run) => getApprovedCompanyIds(run).length),
2542
+ 0
2543
+ );
2544
+ const total = exportedCount > 0 ? exportedCount : progress.totalCompanies;
2545
+ if (total > 0) byCompanyStage.uploaded = createCompleteStageCounts(total);
2546
+ }
2547
+ return {
2548
+ ...progress,
2549
+ byCompanyStage,
2550
+ byContactStage
2551
+ };
2552
+ }
2570
2553
  function getStepRecommendedAction(step, action, kind) {
2571
2554
  if (!action || kind === "none") return void 0;
2572
2555
  return {
@@ -2584,12 +2567,13 @@ function deriveBuildStepStates(list, progress, actions) {
2584
2567
  const entityTotal = getEntityTotal(progress, step.primaryEntity);
2585
2568
  const prerequisites = getPrerequisiteSteps(step, byStepId);
2586
2569
  const hasDependencies = (step.dependsOn?.length ?? 0) > 0;
2587
- const eligibleTotal = hasDependencies ? prerequisites.reduce((sum, prerequisite) => sum + prerequisite.complete, 0) : entityTotal > 0 ? entityTotal : 0;
2570
+ const prerequisiteEligibleTotal = prerequisites.reduce((sum, prerequisite) => sum + prerequisite.complete, 0);
2571
+ const eligibleTotal = hasDependencies ? entityTotal > 0 ? Math.min(entityTotal, prerequisiteEligibleTotal) : prerequisiteEligibleTotal : entityTotal > 0 ? entityTotal : 0;
2588
2572
  const total = Math.max(stageProgress?.total ?? 0, entityTotal, eligibleTotal);
2589
2573
  const complete = stageProgress ? stageProgress.success + stageProgress.noResult + stageProgress.skipped + stageProgress.other : 0;
2590
2574
  const failed = stageProgress?.error ?? 0;
2591
2575
  const ready = Math.max(0, eligibleTotal - complete - failed);
2592
- const blocked = hasDependencies ? Math.max(entityTotal - eligibleTotal, 0) : 0;
2576
+ const blocked = hasDependencies ? Math.max(total - eligibleTotal - complete - failed, 0) : 0;
2593
2577
  const status = failed > 0 ? "failed" : ready > 0 ? "ready" : blocked > 0 || total === 0 ? "blocked" : "complete";
2594
2578
  const action = findActionForStep(actions, step);
2595
2579
  const nextActionKind = getStepActionKind(step, ready, failed, action);
@@ -2620,6 +2604,99 @@ function resolveBuildState(list, progress, actions) {
2620
2604
  recommendedAction: recommendedStep?.recommendedAction ?? null
2621
2605
  };
2622
2606
  }
2607
+ function formatDateTime4(value) {
2608
+ if (!value) return "Not yet";
2609
+ return new Date(value).toLocaleString("en-US", {
2610
+ month: "short",
2611
+ day: "numeric",
2612
+ year: "numeric",
2613
+ hour: "numeric",
2614
+ minute: "2-digit"
2615
+ });
2616
+ }
2617
+ function contactDisplayName(firstName, lastName) {
2618
+ const full = [firstName, lastName].filter(Boolean).join(" ").trim();
2619
+ return full || "\u2014";
2620
+ }
2621
+ function getStatusColor4(status) {
2622
+ switch (status) {
2623
+ case "draft":
2624
+ return "gray";
2625
+ case "enriching":
2626
+ return "blue";
2627
+ case "launched":
2628
+ return "green";
2629
+ case "closing":
2630
+ return "yellow";
2631
+ case "archived":
2632
+ return "red";
2633
+ default:
2634
+ return "gray";
2635
+ }
2636
+ }
2637
+ function getMemberStateColor2(stateKey) {
2638
+ const stage = LEAD_GEN_STAGE_CATALOG[stateKey];
2639
+ if (stage?.entity === "contact") return "green";
2640
+ if (stage?.entity === "company") return "blue";
2641
+ return "gray";
2642
+ }
2643
+ function displayMemberStageFor(row, kind) {
2644
+ const stage = getDisplayLeadGenStageStateFor(row, kind);
2645
+ if (!stage.stageKey) return null;
2646
+ const catalogStage = LEAD_GEN_STAGE_CATALOG[stage.stageKey];
2647
+ return {
2648
+ key: stage.stageKey,
2649
+ label: catalogStage?.label ?? stage.stageKey
2650
+ };
2651
+ }
2652
+ function asRecord3(value) {
2653
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2654
+ }
2655
+ function getRunStatusColor(status) {
2656
+ switch (status) {
2657
+ case "completed":
2658
+ case "success":
2659
+ case "succeeded":
2660
+ return "green";
2661
+ case "running":
2662
+ case "pending":
2663
+ case "queued":
2664
+ return "blue";
2665
+ case "failed":
2666
+ case "error":
2667
+ case "cancelled":
2668
+ return "red";
2669
+ default:
2670
+ return "gray";
2671
+ }
2672
+ }
2673
+ function getRunInput(run) {
2674
+ const payload = asRecord3(run.payload);
2675
+ return run.input ?? run.inputs ?? payload.input ?? payload.inputs;
2676
+ }
2677
+ function hasRunInput(run) {
2678
+ const input = getRunInput(run);
2679
+ return input !== void 0 && input !== null;
2680
+ }
2681
+ function sanitizeStepInput(value, _capabilityKey) {
2682
+ return value;
2683
+ }
2684
+ function getDefaultStepInput(list, action) {
2685
+ return asRecord3(action?.defaultInput?.(list));
2686
+ }
2687
+ function getInitialStepInput(list, action) {
2688
+ return getDefaultStepInput(list, action);
2689
+ }
2690
+ function mergeStepRunInput(list, action, inputAtSubmit) {
2691
+ return {
2692
+ ...getDefaultStepInput(list, action),
2693
+ ...inputAtSubmit
2694
+ };
2695
+ }
2696
+ var EMPTY_SELECTION2 = {
2697
+ selectedCompanyIds: [],
2698
+ selectedContactIds: []
2699
+ };
2623
2700
  function getStageStatus(entry) {
2624
2701
  if (!entry || (entry.total ?? 0) === 0) return "not-started";
2625
2702
  if ((entry.error ?? 0) > 0) return "errors";
@@ -2673,6 +2750,8 @@ function StageNode({
2673
2750
  const total = entry?.total ?? 0;
2674
2751
  const attempted = entry?.attempted ?? 0;
2675
2752
  const success = entry?.success ?? 0;
2753
+ const done = entry ? entry.success + entry.noResult + entry.skipped + entry.other : 0;
2754
+ const summary = entry ? status === "complete" ? `${done}/${total} done` : status === "errors" ? `${entry.error} failed` : `${attempted}/${total} started` : "Not started";
2676
2755
  const tooltipLines = entry ? [
2677
2756
  `${attempted} / ${total} attempted`,
2678
2757
  `${success} success`,
@@ -2709,7 +2788,7 @@ function StageNode({
2709
2788
  boxShadow: `0 0 0 4px ${colors.ring}`,
2710
2789
  transition: "all var(--duration-normal) var(--easing)"
2711
2790
  },
2712
- children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: status === "not-started" ? 500 : 700, style: { color: colors.fg, lineHeight: 1 }, children: status === "complete" ? "\u2713" : index + 1 })
2791
+ children: /* @__PURE__ */ jsx(Box, { style: { color: colors.fg, lineHeight: 1, display: "flex", alignItems: "center" }, children: status === "complete" ? "OK" : index + 1 })
2713
2792
  }
2714
2793
  ) }),
2715
2794
  /* @__PURE__ */ jsxs(Stack, { gap: 2, align: "center", style: { minWidth: 0, maxWidth: "100%" }, children: [
@@ -2728,7 +2807,7 @@ function StageNode({
2728
2807
  children: label
2729
2808
  }
2730
2809
  ),
2731
- /* @__PURE__ */ jsx(Text, { size: "xs", style: { color: "var(--color-text-subtle)", fontVariantNumeric: "tabular-nums" }, children: entry ? `${attempted}/${total}` : "Pending" })
2810
+ /* @__PURE__ */ jsx(Text, { size: "xs", style: { color: "var(--color-text-subtle)", fontVariantNumeric: "tabular-nums" }, children: summary })
2732
2811
  ] })
2733
2812
  ]
2734
2813
  }
@@ -2774,14 +2853,14 @@ function PipelineStepper({
2774
2853
  ) });
2775
2854
  }
2776
2855
  function PipelineStagesCard({ list, progress }) {
2777
- const plannedSteps = list.metadata.buildPlanSnapshot?.steps ?? [];
2856
+ const plannedSteps = resolveBuildPlanSteps(list);
2778
2857
  const templateLabel = list.metadata.buildPlanSnapshot?.templateLabel;
2779
2858
  const combinedByStage = { ...progress.byCompanyStage, ...progress.byContactStage };
2780
2859
  const hasAnyContent = plannedSteps.length > 0 || Object.keys(combinedByStage).length > 0;
2781
2860
  return /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
2782
2861
  /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
2783
2862
  /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
2784
- /* @__PURE__ */ jsx(Title, { order: 5, children: "Pipeline Stages" }),
2863
+ /* @__PURE__ */ jsx(Title, { order: 5, children: "List Build Progress" }),
2785
2864
  templateLabel && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2786
2865
  "Template: ",
2787
2866
  templateLabel
@@ -2893,7 +2972,7 @@ function OverviewTab({ list, progress }) {
2893
2972
  {
2894
2973
  icon: /* @__PURE__ */ jsx(IconBuilding, { size: 16 }),
2895
2974
  title: "Overview",
2896
- description: "Configuration, progress, and source metadata for this list.",
2975
+ description: "Build status and source details for this list.",
2897
2976
  children: [
2898
2977
  /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, children: [
2899
2978
  /* @__PURE__ */ jsx(StatCard, { label: "Companies", value: progress.totalCompanies, icon: IconBuilding }),
@@ -3003,12 +3082,21 @@ function BuildStepProgressBar({ step }) {
3003
3082
  function getDisplayStep(steps, recommendedStep) {
3004
3083
  return recommendedStep ?? steps.find((step) => step.status !== "complete") ?? steps[steps.length - 1] ?? null;
3005
3084
  }
3085
+ function getBuildTabDescription(steps, currentStep) {
3086
+ if (!steps.length) return "No build steps are available for this list.";
3087
+ if (steps.every((step) => step.status === "complete")) return "List build complete.";
3088
+ if (!currentStep) return "No build steps need attention right now.";
3089
+ if (currentStep.status === "ready") return `${currentStep.label} is ready to run.`;
3090
+ if (currentStep.status === "failed") return `${currentStep.label} needs attention.`;
3091
+ return `${currentStep.label} is waiting on earlier work.`;
3092
+ }
3006
3093
  function BuildTab({
3007
3094
  list,
3008
3095
  steps,
3009
3096
  recommendedStep,
3010
3097
  onRunStep,
3011
3098
  onRetryStep,
3099
+ onViewRunLog,
3012
3100
  onViewRuns
3013
3101
  }) {
3014
3102
  const [selectedStepId, setSelectedStepId] = useState(null);
@@ -3041,7 +3129,7 @@ function BuildTab({
3041
3129
  if (recentRuns.length > 0) {
3042
3130
  const lastInput = getRunInput(recentRuns[0]);
3043
3131
  if (lastInput) {
3044
- setStepInputFormState(sanitizeStepInput(asRecord2(lastInput)));
3132
+ setStepInputFormState(sanitizeStepInput(asRecord3(lastInput)));
3045
3133
  setStepInputResetKey((k) => k + 1);
3046
3134
  }
3047
3135
  }
@@ -3070,16 +3158,21 @@ function BuildTab({
3070
3158
  onRunStep(selectedStep, submittedInput);
3071
3159
  };
3072
3160
  const loadRecentRunInput = (run) => {
3073
- setStepInputFormState(sanitizeStepInput(asRecord2(getRunInput(run))));
3161
+ setStepInputFormState(sanitizeStepInput(asRecord3(getRunInput(run))));
3074
3162
  setStepInputResetKey((k) => k + 1);
3075
3163
  setActiveRightColumnTab("configuration");
3076
3164
  };
3165
+ const openRecentRunLog = (run) => {
3166
+ const resourceId = run.resourceId ?? selectedResourceId;
3167
+ if (!resourceId) return;
3168
+ onViewRunLog(resourceId, run.executionId);
3169
+ };
3077
3170
  return /* @__PURE__ */ jsx(
3078
3171
  TabSection,
3079
3172
  {
3080
3173
  icon: /* @__PURE__ */ jsx(IconBolt, { size: 16 }),
3081
3174
  title: "Build",
3082
- description: currentStep ? `${currentStep.label} is the current step in this list build.` : "No build steps are available for this list.",
3175
+ description: getBuildTabDescription(steps, currentStep),
3083
3176
  children: /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 2 }, spacing: "md", children: [
3084
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) => {
3085
3178
  const isCurrent = currentStep?.id === step.id;
@@ -3169,7 +3262,7 @@ function BuildTab({
3169
3262
  schema: stepSchema,
3170
3263
  layout: stepLayout,
3171
3264
  value: stepInputFormState,
3172
- onChange: (v) => handleStepInputChange(asRecord2(v) ?? {}),
3265
+ onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3173
3266
  disabled: !canRunSelectedAction
3174
3267
  },
3175
3268
  `${selectedResourceId ?? "none"}-main-${stepInputResetKey}`
@@ -3182,7 +3275,7 @@ function BuildTab({
3182
3275
  schema: stepSchema,
3183
3276
  layout: stepLayout,
3184
3277
  value: stepInputFormState,
3185
- onChange: (v) => handleStepInputChange(asRecord2(v) ?? {}),
3278
+ onChange: (v) => handleStepInputChange(asRecord3(v) ?? {}),
3186
3279
  disabled: !canRunSelectedAction
3187
3280
  },
3188
3281
  `${selectedResourceId ?? "none"}-advanced-${stepInputResetKey}`
@@ -3192,27 +3285,48 @@ function BuildTab({
3192
3285
  /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 700, tt: "uppercase", children: "Recent runs" }),
3193
3286
  recentRunsQuery.isFetching ? /* @__PURE__ */ jsx(Loader, { size: "xs" }) : null
3194
3287
  ] }),
3195
- !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) => /* @__PURE__ */ jsx(
3196
- UnstyledButton,
3197
- {
3198
- onClick: () => loadRecentRunInput(run),
3199
- style: {
3200
- border: "1px solid var(--color-border)",
3201
- borderRadius: 8,
3202
- padding: "8px 10px",
3203
- textAlign: "left",
3204
- width: "100%"
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
+ ] })
3205
3326
  },
3206
- children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
3207
- /* @__PURE__ */ jsxs(Stack, { gap: 2, style: { minWidth: 0 }, children: [
3208
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, truncate: true, children: formatDateTime4(run.createdAt) }),
3209
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ff: "monospace", truncate: true, children: run.executionId })
3210
- ] }),
3211
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getRunStatusColor(run.status), children: run.status })
3212
- ] })
3213
- },
3214
- run.executionId
3215
- )) })
3327
+ run.executionId
3328
+ );
3329
+ }) })
3216
3330
  ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No runs available for this step." }),
3217
3331
  action: /* @__PURE__ */ jsxs(Fragment, { children: [
3218
3332
  stepInputError ? /* @__PURE__ */ jsx(Alert, { color: "red", icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), variant: "light", children: stepInputError }) : null,
@@ -3285,14 +3399,14 @@ function MembersTab({
3285
3399
  ] }) }),
3286
3400
  /* @__PURE__ */ jsx(Table.Tbody, { children: contacts.map((contact) => {
3287
3401
  const handleRowClick = () => onMemberClick?.(contact.id, "contact");
3288
- const memberState = contact.stateKey ?? null;
3402
+ const memberStage = displayMemberStageFor(contact, "contact");
3289
3403
  return /* @__PURE__ */ jsxs(Table.Tr, { onClick: handleRowClick, style: { cursor: "pointer" }, children: [
3290
3404
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: contactDisplayName(contact.firstName, contact.lastName) }) }),
3291
3405
  /* @__PURE__ */ jsx(Table.Td, { children: contact.email }),
3292
3406
  /* @__PURE__ */ jsx(Table.Td, { children: contact.title ?? "\u2014" }),
3293
3407
  /* @__PURE__ */ jsx(Table.Td, { children: contact.company?.name ?? "\u2014" }),
3294
3408
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor4(contact.status), children: contact.status }) }),
3295
- /* @__PURE__ */ jsx(Table.Td, { children: memberState ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberState), children: memberState }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
3409
+ /* @__PURE__ */ jsx(Table.Td, { children: memberStage ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberStage.key), children: memberStage.label }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
3296
3410
  /* @__PURE__ */ jsx(Table.Td, { children: formatDateTime4(contact.createdAt) })
3297
3411
  ] }, contact.id);
3298
3412
  }) })
@@ -3309,14 +3423,14 @@ function MembersTab({
3309
3423
  ] }) }),
3310
3424
  /* @__PURE__ */ jsx(Table.Tbody, { children: companies.map((company) => {
3311
3425
  const handleRowClick = () => onMemberClick?.(company.id, "company");
3312
- const memberState = company.stateKey ?? null;
3426
+ const memberStage = displayMemberStageFor(company, "company");
3313
3427
  return /* @__PURE__ */ jsxs(Table.Tr, { onClick: handleRowClick, style: { cursor: "pointer" }, children: [
3314
3428
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: company.name }) }),
3315
3429
  /* @__PURE__ */ jsx(Table.Td, { children: company.domain ?? "\u2014" }),
3316
3430
  /* @__PURE__ */ jsx(Table.Td, { children: company.segment ?? "\u2014" }),
3317
3431
  /* @__PURE__ */ jsx(Table.Td, { children: company.contactCount }),
3318
3432
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor4(company.status), children: company.status }) }),
3319
- /* @__PURE__ */ jsx(Table.Td, { children: memberState ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberState), children: memberState }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
3433
+ /* @__PURE__ */ jsx(Table.Td, { children: memberStage ? /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "dot", color: getMemberStateColor2(memberStage.key), children: memberStage.label }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\u2014" }) }),
3320
3434
  /* @__PURE__ */ jsx(Table.Td, { children: formatDateTime4(company.createdAt) })
3321
3435
  ] }, company.id);
3322
3436
  }) })
@@ -3353,6 +3467,7 @@ function LeadGenListDetailPage({ listId }) {
3353
3467
  };
3354
3468
  const listQuery = useList(listId);
3355
3469
  const progressQuery = useListProgress(listId);
3470
+ const executionsQuery = useListExecutions(listId);
3356
3471
  const deleteListMutation = useDeleteList();
3357
3472
  const [deleteModalOpen, setDeleteModalOpen] = useState(false);
3358
3473
  const [runModalOpen, setRunModalOpen] = useState(false);
@@ -3370,8 +3485,8 @@ function LeadGenListDetailPage({ listId }) {
3370
3485
  };
3371
3486
  });
3372
3487
  }, [actions, pendingStepRunInput]);
3373
- const isLoading = listQuery.isLoading || progressQuery.isLoading;
3374
- const error = listQuery.error ?? progressQuery.error;
3488
+ const isLoading = listQuery.isLoading || progressQuery.isLoading || executionsQuery.isLoading;
3489
+ const error = listQuery.error ?? progressQuery.error ?? executionsQuery.error;
3375
3490
  const backButton = /* @__PURE__ */ jsx(
3376
3491
  Button,
3377
3492
  {
@@ -3423,8 +3538,10 @@ function LeadGenListDetailPage({ listId }) {
3423
3538
  }
3424
3539
  const list = listQuery.data;
3425
3540
  const progress = progressQuery.data;
3541
+ const executions = executionsQuery.data ?? [];
3542
+ const businessProgress = deriveBusinessProgress(list, progress, actions, executions);
3426
3543
  const currentBuildTemplateLabel = list.metadata.buildPlanSnapshot?.templateLabel ?? "Default lead generation";
3427
- const buildResolution = resolveBuildState(list, progress, actions);
3544
+ const buildResolution = resolveBuildState(list, businessProgress, actions);
3428
3545
  const buildSteps = buildResolution.steps;
3429
3546
  const recommendedBuildStep = buildResolution.recommendedStep;
3430
3547
  const openRunModal = (resourceId) => {
@@ -3505,8 +3622,8 @@ function LeadGenListDetailPage({ listId }) {
3505
3622
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "build", leftSection: /* @__PURE__ */ jsx(IconBolt, { size: 14 }), children: "Build" }),
3506
3623
  /* @__PURE__ */ jsx(Tabs.Tab, { value: "runs", leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 }), children: "Runs" })
3507
3624
  ] }),
3508
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "overview", pt: "sm", children: /* @__PURE__ */ jsx(OverviewTab, { list, progress }) }),
3509
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "members", pt: "sm", children: /* @__PURE__ */ jsx(MembersTab, { listId, progress, onMemberClick: handleMemberClick }) }),
3625
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "overview", pt: "sm", children: /* @__PURE__ */ jsx(OverviewTab, { list, progress: businessProgress }) }),
3626
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "members", pt: "sm", children: /* @__PURE__ */ jsx(MembersTab, { listId, progress: businessProgress, onMemberClick: handleMemberClick }) }),
3510
3627
  /* @__PURE__ */ jsx(Tabs.Panel, { value: "build", pt: "sm", children: /* @__PURE__ */ jsx(
3511
3628
  BuildTab,
3512
3629
  {
@@ -3515,6 +3632,13 @@ function LeadGenListDetailPage({ listId }) {
3515
3632
  recommendedStep: recommendedBuildStep,
3516
3633
  onRunStep: openStepRun,
3517
3634
  onRetryStep: openStepRun,
3635
+ onViewRunLog: (resourceId, executionId) => {
3636
+ void navigate({
3637
+ to: "/operations/resources/workflow/$workflowId",
3638
+ params: { workflowId: resourceId },
3639
+ search: { exec: executionId }
3640
+ });
3641
+ },
3518
3642
  onViewRuns: (resourceId) => {
3519
3643
  setRunsResourceFilter(resourceId);
3520
3644
  setActiveTab("runs");
@@ -3936,4 +4060,4 @@ function LeadGenContactsPage() {
3936
4060
  ] }) });
3937
4061
  }
3938
4062
 
3939
- export { CompanyDetailModal, ContactDetailModal, LEAD_GEN_ITEMS, LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, ListBuilderIndexPage, ListBuilderPage, RunWorkflowModal, StepConfigForm, TabSection, formatDate, getEnrichmentColor, getEnrichmentStatus, getStateKeyColor, getStatusColor, leadGenManifest, useDeleteLists };
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 };