@elevasis/ui 2.2.0 → 2.3.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 (43) hide show
  1. package/dist/{chunk-J5TBNCMD.js → chunk-2XWEOJSX.js} +3 -3
  2. package/dist/{chunk-RB34YOIX.js → chunk-47YILFON.js} +98 -70
  3. package/dist/{chunk-MZPVNRPL.js → chunk-ISHNN42L.js} +134 -10
  4. package/dist/{chunk-PFONCU6C.js → chunk-IWFIKQR5.js} +1 -1
  5. package/dist/{chunk-QITPFGWC.js → chunk-JT7WDIZI.js} +2 -2
  6. package/dist/{chunk-7IE3KXKV.js → chunk-NKV5MEWQ.js} +3877 -1543
  7. package/dist/{chunk-MXVA7U2I.js → chunk-PEATQEEP.js} +3 -3
  8. package/dist/{chunk-JT3FN6TE.js → chunk-Q3FTQP2M.js} +2 -2
  9. package/dist/{chunk-BIZNOFO4.js → chunk-SWIAK47F.js} +3 -3
  10. package/dist/{chunk-35QO7M43.js → chunk-VNUOQQNY.js} +1 -1
  11. package/dist/{chunk-2JTCPVZX.js → chunk-ZY4MWZW2.js} +2 -2
  12. package/dist/components/index.css +7 -0
  13. package/dist/components/index.d.ts +16 -4
  14. package/dist/components/index.js +1214 -120
  15. package/dist/features/auth/index.css +7 -0
  16. package/dist/features/dashboard/index.css +7 -0
  17. package/dist/features/dashboard/index.d.ts +4 -0
  18. package/dist/features/dashboard/index.js +6 -6
  19. package/dist/features/monitoring/index.css +7 -0
  20. package/dist/features/monitoring/index.d.ts +4 -0
  21. package/dist/features/monitoring/index.js +7 -7
  22. package/dist/features/operations/index.css +7 -0
  23. package/dist/features/operations/index.d.ts +26 -14
  24. package/dist/features/operations/index.js +8 -8
  25. package/dist/features/settings/index.css +7 -0
  26. package/dist/features/settings/index.d.ts +4 -0
  27. package/dist/features/settings/index.js +7 -7
  28. package/dist/hooks/index.css +7 -0
  29. package/dist/hooks/index.d.ts +4 -1
  30. package/dist/hooks/index.js +5 -5
  31. package/dist/hooks/published.css +7 -0
  32. package/dist/hooks/published.d.ts +4 -1
  33. package/dist/hooks/published.js +4 -4
  34. package/dist/index.css +7 -0
  35. package/dist/index.d.ts +307 -249
  36. package/dist/index.js +6 -6
  37. package/dist/provider/index.css +7 -0
  38. package/dist/provider/index.d.ts +58 -2
  39. package/dist/provider/index.js +3 -3
  40. package/dist/provider/published.d.ts +58 -2
  41. package/dist/provider/published.js +1 -1
  42. package/dist/theme/index.js +2 -2
  43. package/package.json +9 -3
@@ -1,32 +1,34 @@
1
1
  import { useBreadcrumbs } from '../chunk-MG3NF7QL.js';
2
2
  import '../chunk-SMJLS23U.js';
3
- import { NotificationList } from '../chunk-2JTCPVZX.js';
4
- export { ActivityCard, ActivityFilters as ActivityFiltersBar, ActivityTable, BusinessImpactCard, CostBreakdownCard, CostByModelTable, CostMetricsCard, ErrorAnalysisCard, ErrorBreakdownTable, ExecutionBreakdownTable, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, NotificationItem, NotificationList, monitoringManifest } from '../chunk-2JTCPVZX.js';
5
- export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipFeaturePanel, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, WebhookUrlDisplayModal, settingsManifest } from '../chunk-MXVA7U2I.js';
3
+ import { NotificationList } from '../chunk-ZY4MWZW2.js';
4
+ export { ActivityCard, ActivityFilters as ActivityFiltersBar, ActivityTable, BusinessImpactCard, CostBreakdownCard, CostByModelTable, CostMetricsCard, ErrorAnalysisCard, ErrorBreakdownTable, ExecutionBreakdownTable, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, NotificationItem, NotificationList, monitoringManifest } from '../chunk-ZY4MWZW2.js';
5
+ export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipFeaturePanel, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, WebhookUrlDisplayModal, settingsManifest } from '../chunk-PEATQEEP.js';
6
6
  import { FilterBar } from '../chunk-PDHTXPSF.js';
7
7
  export { FilterBar } from '../chunk-PDHTXPSF.js';
8
- import { ResourceExecuteDialog } from '../chunk-7IE3KXKV.js';
9
- export { ActionModal, AgentDefinitionDisplay, AgentExecutionLogs, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, CheckpointGroup, CollapsibleJsonSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, CommandQueueTaskRow, CommandViewEdge, CommandViewGraph, CommandViewNode, ConfigCard, ContentSections, ContextUsageBadge, ContractDisplay, ExecutionErrorSection, FormFieldRenderer, LogEntry, LogGroup, NewKnowledgeMapEdge, NewKnowledgeMapGraph, NewKnowledgeMapNode, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceNotFoundState, SessionMemory, ToolsListDisplay, WorkflowDefinitionDisplay, WorkflowExecutionLogs, getExecutionStatusConfig, getIcon, getLogLevelConfig, iconMap, operationsManifest, useNewKnowledgeMapLayout } from '../chunk-7IE3KXKV.js';
8
+ import { ResourceExecuteDialog } from '../chunk-NKV5MEWQ.js';
9
+ export { ActionModal, AgentDefinitionDisplay, AgentExecutionLogs, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, CheckpointGroup, CollapsibleJsonSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, CommandQueueTaskRow, ConfigCard, ContentSections, ContextUsageBadge, ContractDisplay, ExecutionErrorSection, FormFieldRenderer, LogEntry, LogGroup, NewKnowledgeMapEdge, NewKnowledgeMapGraph, NewKnowledgeMapNode, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceNotFoundState, SessionMemory, ToolsListDisplay, WorkflowDefinitionDisplay, WorkflowExecutionLogs, getExecutionStatusConfig, getIcon, getLogLevelConfig, iconMap, operationsManifest, useNewKnowledgeMapLayout } from '../chunk-NKV5MEWQ.js';
10
10
  import '../chunk-ROSMICXG.js';
11
11
  import { SubshellLoader, PageContainer, SubshellSidebarSection, SubshellNavItem, CollapsibleSidebarGroup } from '../chunk-OCP2MBTY.js';
12
- export { ResourceHealthPanel } from '../chunk-PFONCU6C.js';
12
+ export { ResourceHealthPanel } from '../chunk-IWFIKQR5.js';
13
13
  import { CustomModal } from '../chunk-GBMNCNHX.js';
14
14
  export { ConfirmationInputModal, ConfirmationModal, CustomModal } from '../chunk-GBMNCNHX.js';
15
- export { AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationEdge, AgentIterationNode, BaseEdge, BaseNode, EmptyVisualizer, ExecutionStats, ExecutionStatusBadge, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, VisualizerContainer, WorkflowExecutionTimeline, dashboardManifest, getGraphBackgroundStyles, useGraphBackgroundStyles, useGraphTheme } from '../chunk-BIZNOFO4.js';
15
+ import { BaseNode, useGraphTheme, BaseEdge, GraphBackground, GraphLegend, GraphFitViewButton } from '../chunk-SWIAK47F.js';
16
+ export { AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationEdge, AgentIterationNode, BaseEdge, BaseNode, EmptyVisualizer, ExecutionStats, ExecutionStatusBadge, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, VisualizerContainer, WorkflowExecutionTimeline, dashboardManifest, getGraphBackgroundStyles, useGraphBackgroundStyles, useGraphTheme } from '../chunk-SWIAK47F.js';
16
17
  export { ResourceHealthChart, getHealthColor } from '../chunk-LGKLC5MG.js';
17
18
  import '../chunk-KFICYU6S.js';
18
19
  import { AppShellLoader } from '../chunk-YEX4MQSY.js';
19
- import '../chunk-35QO7M43.js';
20
- import { useUpdateApiKey, useDeleteApiKey, useCreateApiKey, useListApiKeys, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments, useProjects } from '../chunk-JT3FN6TE.js';
21
- import { usePaginationState, useDeploymentDocs, useResources, useCreateSchedule, useListSchedules, usePauseSchedule, useResumeSchedule, useCancelSchedule, useDeleteSchedule, useDealNotes, useCreateDealNote, useDeals, useSyncDealStage, dealKeys, useDealTasksDue, useCreateDealTask, useDeleteDeal, useTableSort, sortData, useTableSelection, useDealDetail, showApiErrorNotification, acquisitionListKeys, showSuccessNotification, useListsTelemetry, useLists, useCreateList, useList, useListProgress, useListExecutions, useResourceDefinition, useCompanies, useDeleteCompanies, useContacts, useDeleteContacts, useDeleteProject, useMarkAllAsRead, useNotifications, showErrorNotification } from '../chunk-J5TBNCMD.js';
22
- export { showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification } from '../chunk-J5TBNCMD.js';
20
+ import '../chunk-VNUOQQNY.js';
21
+ import { useUpdateApiKey, useDeleteApiKey, useCreateApiKey, useListApiKeys, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments, useProjects, useProject, useProjectNotes, useDeleteProject as useDeleteProject$1, useUpdateMilestone, useCreateNote } from '../chunk-Q3FTQP2M.js';
22
+ import { useCommandViewLayout, usePaginationState, useDeploymentDocs, useResources, useCreateSchedule, useListSchedules, usePauseSchedule, useResumeSchedule, useCancelSchedule, useDeleteSchedule, useDealNotes, useCreateDealNote, useDeals, useSyncDealStage, dealKeys, useDealTasksDue, useCreateDealTask, useDeleteDeal, useTableSort, sortData, useTableSelection, useDealDetail, showApiErrorNotification, acquisitionListKeys, showSuccessNotification, useListsTelemetry, useLists, useCreateList, useList, useListProgress, useListExecutions, useResourceDefinition, useCompanies, useDeleteCompanies, useContacts, useDeleteContacts, useDeleteProject, useMarkAllAsRead, useNotifications, showErrorNotification } from '../chunk-2XWEOJSX.js';
23
+ export { showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification } from '../chunk-2XWEOJSX.js';
23
24
  import '../chunk-LXHZYSMQ.js';
25
+ import { Graph_module_css_default, useDirectedChainHighlighting, useNodeSelection, GRAPH_CONSTANTS } from '../chunk-F6RBK7NJ.js';
24
26
  export { Graph_module_css_default as graphStyles } from '../chunk-F6RBK7NJ.js';
25
27
  export { CONTAINER_CONSTANTS, SHARED_VIZ_CONSTANTS } from '../chunk-XA34RETF.js';
26
- import '../chunk-QITPFGWC.js';
27
- import '../chunk-RB34YOIX.js';
28
+ import '../chunk-JT7WDIZI.js';
29
+ import '../chunk-47YILFON.js';
28
30
  import '../chunk-CYXZHBP4.js';
29
- import '../chunk-MZPVNRPL.js';
31
+ import '../chunk-ISHNN42L.js';
30
32
  import { SubshellContainer, SubshellSidebar, SubshellRightSideContainer, SubshellContentContainer } from '../chunk-RX4UWZZR.js';
31
33
  import { ListSkeleton, EmptyState, PageTitleCaption, StatCard, CenteredErrorState, CardHeader, ActivityTimeline, StatusBadge } from '../chunk-Y3D3WFJG.js';
32
34
  export { APIErrorAlert, ActivityTimeline, CardHeader, CenteredErrorState, CollapsibleSection, ContextViewer, CustomSelector, DetailCardSkeleton, ElevasisLoader, EmptyState, FeatureUnavailableState, GlowDot, JsonViewer, ListSkeleton, PageNotFound, PageTitleCaption, ResourceCard, StatCard, StatCardSkeleton, StatsCardSkeleton, StatusBadge, TabCountBadge, TimeRangeSelector, TrendIndicator, catalogItemToResourceDefinition } from '../chunk-Y3D3WFJG.js';
@@ -40,21 +42,23 @@ import { useAppearance } from '../chunk-QJ2KCHKX.js';
40
42
  import '../chunk-DT3QYZVU.js';
41
43
  import '../chunk-SLVC5OJ2.js';
42
44
  import '../chunk-RNP5R5I3.js';
43
- import { formatDateTime, PAGE_SIZE_DEFAULT, formatTimeAgo } from '../chunk-IOKL7BKE.js';
45
+ import { getResourceIcon, getResourceColor, formatDateTime, PAGE_SIZE_DEFAULT, formatTimeAgo, formatDate } from '../chunk-IOKL7BKE.js';
44
46
  import '../chunk-MTJ43R2E.js';
45
47
  import { useInitialization } from '../chunk-TUXTSEAF.js';
46
48
  import '../chunk-DD3CCMCZ.js';
47
49
  import { useElevasisServices } from '../chunk-QEPXAWE2.js';
48
50
  import '../chunk-BRJ3QZ4E.js';
49
51
  import { useRouterContext } from '../chunk-Q7DJKLEN.js';
50
- import { Table, Group, Text, Button, Stack, Title, TextInput, Alert, Tooltip, ActionIcon, Paper, Code, CopyButton, SimpleGrid, Badge, Loader, Pagination, useMantineTheme, Box, ScrollArea, Select, Center, Card, SegmentedControl, Switch, Textarea, Divider, Menu, Timeline, ThemeIcon, Tabs, Anchor, Breadcrumbs as Breadcrumbs$1, Drawer, UnstyledButton, Modal, Checkbox, RingProgress, Collapse, Popover, Indicator } from '@mantine/core';
51
- import { IconAddressBook, IconBriefcase, IconTarget, IconChevronUp, IconChevronDown, IconSelector, IconTrash, IconPencil, IconAlertCircle, IconKey, IconCalendar, IconClock, IconAlertTriangle, IconExclamationMark, IconShieldLock, IconCheck, IconCopy, IconPlus, IconRocket, IconRefresh, IconPower, IconPlayerPlay, IconCircleCheck, IconTag, IconBook2, IconFileOff, IconList, IconCalendarRepeat, IconCalendarEvent, IconCalendarTime, IconRobot, IconGitBranch, IconSettings, IconExternalLink, IconDotsVertical, IconPlayerPause, IconPlayerStop, IconCalendarDue, IconCalendarStats, IconCalendarOff, IconListCheck, IconTrophy, IconClockExclamation, IconUser, IconLayoutGrid, IconColumns, IconFileInvoice, IconChecklist, IconHistory, IconSearch, IconTargetArrow, IconArrowLeft, IconFileText, IconX, IconBuilding, IconMailCheck, IconChartBar, IconBuildingFactory2, IconUsers, IconQuestionMark, IconSparkles, IconClockHour4, IconTrendingUp, IconHeartbeat, IconFlag, IconInbox, IconLock, IconChevronRight, IconDownload, IconMessageCircle, IconBell, IconNotes, IconFolderOpen, IconFolder, IconCheckbox, IconMail, IconPhone, IconArrowRight, IconNote } from '@tabler/icons-react';
52
+ import { Stack, Group, ThemeIcon, Text, Badge, Box, Table, Button, Title, TextInput, Alert, Tooltip, ActionIcon, Paper, Code, CopyButton, SimpleGrid, Loader, Pagination, useMantineTheme, ScrollArea, Select, Center, Card, SegmentedControl, Switch, Textarea, Divider, Menu, Timeline, Tabs, Breadcrumbs as Breadcrumbs$1, Drawer, UnstyledButton, Modal, Checkbox, Anchor, Progress, RingProgress, Collapse, Popover, Indicator } from '@mantine/core';
53
+ import { IconBrain, IconDatabase, IconMessage, IconAlertCircle, IconCircleX, IconCircleCheck, IconBolt, IconHandClick, IconClock, IconWebhook, IconExternalLink, IconAddressBook, IconBriefcase, IconTarget, IconChevronUp, IconChevronDown, IconSelector, IconTrash, IconPencil, IconKey, IconCalendar, IconAlertTriangle, IconExclamationMark, IconShieldLock, IconCheck, IconCopy, IconPlus, IconRocket, IconRefresh, IconPower, IconPlayerPlay, IconTag, IconBook2, IconFileOff, IconList, IconCalendarRepeat, IconCalendarEvent, IconCalendarTime, IconRobot, IconGitBranch, IconSettings, IconDotsVertical, IconPlayerPause, IconPlayerStop, IconCalendarDue, IconCalendarStats, IconCalendarOff, IconListCheck, IconTrophy, IconClockExclamation, IconUser, IconLayoutGrid, IconColumns, IconFileInvoice, IconChecklist, IconHistory, IconSearch, IconTargetArrow, IconArrowLeft, IconFileText, IconX, IconBuilding, IconMailCheck, IconArrowRight, IconQuestionMark, IconSparkles, IconClockHour4, IconBuildingFactory2, IconUsers, IconChartBar, IconTrendingUp, IconHeartbeat, IconFlag, IconInbox, IconLock, IconChevronRight, IconDownload, IconMessageCircle, IconBell, IconNotes, IconFolderOpen, IconFolder, IconCheckbox, IconMail, IconPhone, IconNote } from '@tabler/icons-react';
52
54
  import * as runtime from 'react/jsx-runtime';
53
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
55
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
54
56
  import { useDisclosure } from '@mantine/hooks';
55
57
  import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
56
- import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
58
+ import { memo, forwardRef, useMemo, useImperativeHandle, useState, useEffect, useCallback, useRef } from 'react';
57
59
  import { useForm } from '@mantine/form';
60
+ import { useReactFlow, ReactFlow, ReactFlowProvider } from '@xyflow/react';
61
+ import '@xyflow/react/dist/style.css';
58
62
  import { Link, RichTextEditor as RichTextEditor$1 } from '@mantine/tiptap';
59
63
  import { useEditor } from '@tiptap/react';
60
64
  import Placeholder from '@tiptap/extension-placeholder';
@@ -1737,7 +1741,7 @@ function getStatusColor(status) {
1737
1741
  return "gray";
1738
1742
  }
1739
1743
  }
1740
- function formatDate(date) {
1744
+ function formatDate2(date) {
1741
1745
  if (!date) return "N/A";
1742
1746
  const d = typeof date === "string" ? new Date(date) : date;
1743
1747
  return d.toLocaleString("en-US", {
@@ -1777,7 +1781,7 @@ function ScheduleConfigDetails({ schedule }) {
1777
1781
  ] }),
1778
1782
  config.endAt && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1779
1783
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Ends" }) }),
1780
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(config.endAt) }) })
1784
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate2(config.endAt) }) })
1781
1785
  ] }),
1782
1786
  /* @__PURE__ */ jsxs(Table.Tr, { children: [
1783
1787
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Overdue" }) }),
@@ -1799,7 +1803,7 @@ function ScheduleConfigDetails({ schedule }) {
1799
1803
  /* @__PURE__ */ jsxs(Table.Tr, { children: [
1800
1804
  /* @__PURE__ */ jsx(Table.Td, { w: 120, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Anchor" }) }),
1801
1805
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { children: [
1802
- formatDate(config.anchorAt),
1806
+ formatDate2(config.anchorAt),
1803
1807
  config.anchorLabel && ` (${config.anchorLabel})`
1804
1808
  ] }) })
1805
1809
  ] }),
@@ -1820,7 +1824,7 @@ function ScheduleConfigDetails({ schedule }) {
1820
1824
  ] }),
1821
1825
  /* @__PURE__ */ jsx(Stack, { gap: 4, children: config.items.map((item, i) => /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1822
1826
  /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: i === schedule.currentStep ? "blue" : "gray", children: i + 1 }),
1823
- /* @__PURE__ */ jsx(Text, { children: formatDate(item.runAt) }),
1827
+ /* @__PURE__ */ jsx(Text, { children: formatDate2(item.runAt) }),
1824
1828
  item.label && /* @__PURE__ */ jsxs(Text, { c: "dimmed", children: [
1825
1829
  "\u2014 ",
1826
1830
  item.label
@@ -1873,14 +1877,14 @@ function ScheduleDetailModal({ opened, onClose, schedule, resourceStatus }) {
1873
1877
  /* @__PURE__ */ jsx(IconClock, { size: 12, color: "var(--color-text-subtle)" }),
1874
1878
  /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Next Run" })
1875
1879
  ] }) }),
1876
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.nextRunAt) }) })
1880
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate2(schedule.nextRunAt) }) })
1877
1881
  ] }),
1878
1882
  /* @__PURE__ */ jsxs(Table.Tr, { children: [
1879
1883
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1880
1884
  /* @__PURE__ */ jsx(IconCalendar, { size: 12, color: "var(--color-text-subtle)" }),
1881
1885
  /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Last Run" })
1882
1886
  ] }) }),
1883
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.lastRunAt) }) })
1887
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate2(schedule.lastRunAt) }) })
1884
1888
  ] }),
1885
1889
  /* @__PURE__ */ jsxs(Table.Tr, { children: [
1886
1890
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
@@ -1907,11 +1911,11 @@ function ScheduleDetailModal({ opened, onClose, schedule, resourceStatus }) {
1907
1911
  /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
1908
1912
  /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1909
1913
  "Created ",
1910
- formatDate(schedule.createdAt)
1914
+ formatDate2(schedule.createdAt)
1911
1915
  ] }),
1912
1916
  /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1913
1917
  "Updated ",
1914
- formatDate(schedule.updatedAt)
1918
+ formatDate2(schedule.updatedAt)
1915
1919
  ] })
1916
1920
  ] }),
1917
1921
  /* @__PURE__ */ jsx(
@@ -2423,6 +2427,392 @@ var TaskScheduler = () => {
2423
2427
  )
2424
2428
  ] });
2425
2429
  };
2430
+ var triggerTypeIcons = {
2431
+ webhook: IconWebhook,
2432
+ schedule: IconClock,
2433
+ manual: IconHandClick,
2434
+ event: IconBolt
2435
+ };
2436
+ var connectionStatusIcons = {
2437
+ connected: IconCircleCheck,
2438
+ disconnected: IconCircleX,
2439
+ error: IconAlertCircle
2440
+ };
2441
+ var statBubbleBase = {
2442
+ minWidth: 20,
2443
+ height: 20,
2444
+ borderRadius: 10,
2445
+ display: "flex",
2446
+ alignItems: "center",
2447
+ justifyContent: "center",
2448
+ fontSize: 11,
2449
+ fontWeight: 600,
2450
+ padding: "0 6px",
2451
+ color: "white",
2452
+ boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
2453
+ };
2454
+ var CommandViewNode = memo(function CommandViewNode2({ data, selected }) {
2455
+ const Icon = getResourceIcon(data.type);
2456
+ const color = getResourceColor(data.type);
2457
+ const successCount = (data.type === "agent" || data.type === "workflow") && data.stats ? data.stats.successCount : 0;
2458
+ const failureCount = (data.type === "agent" || data.type === "workflow") && data.stats ? data.stats.failureCount : 0;
2459
+ const warningCount = (data.type === "agent" || data.type === "workflow") && data.stats ? data.stats.warningCount : 0;
2460
+ const pendingCount = data.type === "human" && data.stats ? data.stats.pendingCount : 0;
2461
+ const showBubbles = successCount > 0 || failureCount > 0 || warningCount > 0 || pendingCount > 0;
2462
+ return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
2463
+ showBubbles && /* @__PURE__ */ jsxs(
2464
+ "div",
2465
+ {
2466
+ style: {
2467
+ position: "absolute",
2468
+ top: -8,
2469
+ right: -8,
2470
+ display: "flex",
2471
+ gap: 4,
2472
+ zIndex: 10
2473
+ },
2474
+ children: [
2475
+ successCount > 0 && /* @__PURE__ */ jsx(
2476
+ "div",
2477
+ {
2478
+ style: {
2479
+ ...statBubbleBase,
2480
+ background: "linear-gradient(135deg, var(--mantine-color-green-5), var(--mantine-color-green-7))"
2481
+ },
2482
+ children: successCount
2483
+ }
2484
+ ),
2485
+ warningCount > 0 && /* @__PURE__ */ jsx(
2486
+ "div",
2487
+ {
2488
+ style: {
2489
+ ...statBubbleBase,
2490
+ background: "linear-gradient(135deg, var(--mantine-color-yellow-5), var(--mantine-color-yellow-7))"
2491
+ },
2492
+ children: warningCount
2493
+ }
2494
+ ),
2495
+ failureCount > 0 && /* @__PURE__ */ jsx(
2496
+ "div",
2497
+ {
2498
+ style: {
2499
+ ...statBubbleBase,
2500
+ background: "linear-gradient(135deg, var(--mantine-color-red-5), var(--mantine-color-red-7))"
2501
+ },
2502
+ children: failureCount
2503
+ }
2504
+ ),
2505
+ pendingCount > 0 && /* @__PURE__ */ jsx(
2506
+ "div",
2507
+ {
2508
+ style: {
2509
+ ...statBubbleBase,
2510
+ background: "linear-gradient(135deg, var(--mantine-color-orange-5), var(--mantine-color-orange-7))"
2511
+ },
2512
+ children: pendingCount
2513
+ }
2514
+ )
2515
+ ]
2516
+ }
2517
+ ),
2518
+ /* @__PURE__ */ jsx(BaseNode, { color, selected, highlighted: Boolean(data.highlighted), children: /* @__PURE__ */ jsxs(Stack, { gap: 8, children: [
2519
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
2520
+ /* @__PURE__ */ jsx(
2521
+ ThemeIcon,
2522
+ {
2523
+ size: "md",
2524
+ variant: "gradient",
2525
+ gradient: { from: `${color}.4`, to: `${color}.6`, deg: 135 },
2526
+ className: Graph_module_css_default.nodeIcon,
2527
+ children: /* @__PURE__ */ jsx(Icon, { size: 16 })
2528
+ }
2529
+ ),
2530
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, truncate: true, style: { flex: 1, fontFamily: "var(--elevasis-font-family-subtitle)" }, children: data.name })
2531
+ ] }),
2532
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 2, children: data.description }),
2533
+ /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "wrap", children: [
2534
+ /* @__PURE__ */ jsx(
2535
+ Badge,
2536
+ {
2537
+ size: "xs",
2538
+ variant: "gradient",
2539
+ gradient: data.status === "prod" ? { from: "green.5", to: "green.7", deg: 135 } : { from: "blue.5", to: "blue.7", deg: 135 },
2540
+ className: data.status === "prod" ? Graph_module_css_default.badgeProd : "",
2541
+ style: {
2542
+ textTransform: "uppercase",
2543
+ letterSpacing: "0.5px"
2544
+ },
2545
+ children: data.status
2546
+ }
2547
+ ),
2548
+ data.type === "agent" && /* @__PURE__ */ jsxs(Fragment, { children: [
2549
+ /* @__PURE__ */ jsxs(
2550
+ Badge,
2551
+ {
2552
+ size: "xs",
2553
+ variant: "outline",
2554
+ color: "gray",
2555
+ className: Graph_module_css_default.badge,
2556
+ style: { backdropFilter: "blur(4px)" },
2557
+ children: [
2558
+ data.toolCount,
2559
+ " tools"
2560
+ ]
2561
+ }
2562
+ ),
2563
+ data.hasKnowledgeMap && /* @__PURE__ */ jsx(
2564
+ Badge,
2565
+ {
2566
+ size: "xs",
2567
+ variant: "gradient",
2568
+ gradient: { from: "grape.5", to: "grape.7", deg: 135 },
2569
+ leftSection: /* @__PURE__ */ jsx(IconBrain, { size: 10 }),
2570
+ className: Graph_module_css_default.badge,
2571
+ children: "KM"
2572
+ }
2573
+ ),
2574
+ data.hasMemory && /* @__PURE__ */ jsx(
2575
+ Badge,
2576
+ {
2577
+ size: "xs",
2578
+ variant: "gradient",
2579
+ gradient: { from: "cyan.5", to: "cyan.7", deg: 135 },
2580
+ leftSection: /* @__PURE__ */ jsx(IconDatabase, { size: 10 }),
2581
+ className: Graph_module_css_default.badge,
2582
+ children: "Mem"
2583
+ }
2584
+ ),
2585
+ data.sessionCapable && /* @__PURE__ */ jsx(
2586
+ Badge,
2587
+ {
2588
+ size: "xs",
2589
+ variant: "gradient",
2590
+ gradient: { from: "blue.5", to: "blue.7", deg: 135 },
2591
+ leftSection: /* @__PURE__ */ jsx(IconMessage, { size: 10 }),
2592
+ className: Graph_module_css_default.badge,
2593
+ children: "Session"
2594
+ }
2595
+ )
2596
+ ] }),
2597
+ data.type === "workflow" && /* @__PURE__ */ jsxs(
2598
+ Badge,
2599
+ {
2600
+ size: "xs",
2601
+ variant: "outline",
2602
+ color: "gray",
2603
+ className: Graph_module_css_default.badge,
2604
+ style: { backdropFilter: "blur(4px)" },
2605
+ children: [
2606
+ data.stepCount,
2607
+ " steps"
2608
+ ]
2609
+ }
2610
+ ),
2611
+ data.type === "integration" && /* @__PURE__ */ jsx(
2612
+ Badge,
2613
+ {
2614
+ size: "xs",
2615
+ variant: "gradient",
2616
+ gradient: data.connectionStatus === "connected" ? { from: "green.5", to: "green.7", deg: 135 } : data.connectionStatus === "error" ? { from: "red.5", to: "red.7", deg: 135 } : { from: "gray.5", to: "gray.7", deg: 135 },
2617
+ leftSection: (() => {
2618
+ const StatusIcon = connectionStatusIcons[data.connectionStatus];
2619
+ return /* @__PURE__ */ jsx(StatusIcon, { size: 10 });
2620
+ })(),
2621
+ className: Graph_module_css_default.badge,
2622
+ children: data.connectionStatus
2623
+ }
2624
+ ),
2625
+ data.type === "trigger" && /* @__PURE__ */ jsx(
2626
+ Badge,
2627
+ {
2628
+ size: "xs",
2629
+ variant: "outline",
2630
+ color: "gray",
2631
+ leftSection: (() => {
2632
+ const TriggerIcon = triggerTypeIcons[data.triggerType] || IconBolt;
2633
+ return /* @__PURE__ */ jsx(TriggerIcon, { size: 10 });
2634
+ })(),
2635
+ className: Graph_module_css_default.badge,
2636
+ style: { backdropFilter: "blur(4px)" },
2637
+ children: data.triggerType
2638
+ }
2639
+ ),
2640
+ data.type === "external" && /* @__PURE__ */ jsx(
2641
+ Badge,
2642
+ {
2643
+ size: "xs",
2644
+ variant: "outline",
2645
+ color: "gray",
2646
+ leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 10 }),
2647
+ className: Graph_module_css_default.badge,
2648
+ style: { backdropFilter: "blur(4px)" },
2649
+ children: data.platform
2650
+ }
2651
+ ),
2652
+ data.type === "human" && /* @__PURE__ */ jsx(
2653
+ Badge,
2654
+ {
2655
+ size: "xs",
2656
+ variant: "gradient",
2657
+ gradient: { from: "yellow.5", to: "orange.6", deg: 135 },
2658
+ leftSection: /* @__PURE__ */ jsx(IconHandClick, { size: 10 }),
2659
+ className: Graph_module_css_default.badge,
2660
+ children: "Approval Required"
2661
+ }
2662
+ )
2663
+ ] })
2664
+ ] }) })
2665
+ ] });
2666
+ });
2667
+ var relationshipColorMap = {
2668
+ triggers: { color: "edgeTriggers", glow: "edgeTriggersGlow" },
2669
+ uses: { color: "edgeUses", glow: "edgeUsesGlow" },
2670
+ approval: { color: "edgeApproval", glow: "edgeApprovalGlow" }
2671
+ };
2672
+ function getEdgeColors(relationship, colors) {
2673
+ const mapping = relationshipColorMap[relationship] ?? relationshipColorMap.approval;
2674
+ return {
2675
+ edgeColor: colors[mapping.color],
2676
+ glowColor: colors[mapping.glow]
2677
+ };
2678
+ }
2679
+ var CommandViewEdge = memo(function CommandViewEdge2({
2680
+ id,
2681
+ sourceX,
2682
+ sourceY,
2683
+ targetX,
2684
+ targetY,
2685
+ sourcePosition,
2686
+ targetPosition,
2687
+ data,
2688
+ selected
2689
+ }) {
2690
+ const colors = useGraphTheme();
2691
+ const relationship = data?.relationship || "uses";
2692
+ const { edgeColor, glowColor } = getEdgeColors(relationship, colors);
2693
+ return /* @__PURE__ */ jsx(
2694
+ BaseEdge,
2695
+ {
2696
+ id,
2697
+ sourceX,
2698
+ sourceY,
2699
+ targetX,
2700
+ targetY,
2701
+ sourcePosition,
2702
+ targetPosition,
2703
+ color: edgeColor,
2704
+ glowColor,
2705
+ label: data?.label || relationship,
2706
+ animated: data?.animated ?? false,
2707
+ selected,
2708
+ dimmed: data?.dimmed,
2709
+ edgeIndex: data?.edgeIndex,
2710
+ totalEdges: data?.totalEdges
2711
+ }
2712
+ );
2713
+ });
2714
+ var nodeTypes = {
2715
+ commandView: CommandViewNode
2716
+ };
2717
+ var edgeTypes = {
2718
+ commandView: CommandViewEdge
2719
+ };
2720
+ var CommandViewGraphInner = forwardRef(function CommandViewGraphInner2({ graph, height, selectedNodeId, onNodeSelect }, ref) {
2721
+ const { fitView } = useReactFlow();
2722
+ const { nodes: layoutNodes, edges: layoutEdges } = useCommandViewLayout(graph);
2723
+ const { nodes, edges, handleNodeMouseEnter, handleNodeMouseLeave } = useDirectedChainHighlighting(
2724
+ layoutNodes,
2725
+ layoutEdges,
2726
+ { selectedNodeId }
2727
+ );
2728
+ const { handleNodeClick, handlePaneClick } = useNodeSelection(selectedNodeId ?? null, onNodeSelect ?? (() => {
2729
+ }));
2730
+ const nodesWithSelection = useMemo(
2731
+ () => nodes.map((node) => ({
2732
+ ...node,
2733
+ selected: node.id === selectedNodeId
2734
+ })),
2735
+ [nodes, selectedNodeId]
2736
+ );
2737
+ useImperativeHandle(ref, () => ({
2738
+ fitView: () => fitView({ padding: 0.15, duration: 300 })
2739
+ }));
2740
+ return /* @__PURE__ */ jsx(
2741
+ Box,
2742
+ {
2743
+ className: Graph_module_css_default.graphContainer,
2744
+ style: {
2745
+ width: "100%",
2746
+ height,
2747
+ border: "1px solid var(--color-border)",
2748
+ borderRadius: "var(--mantine-radius-default)",
2749
+ overflow: "hidden"
2750
+ },
2751
+ children: /* @__PURE__ */ jsxs(
2752
+ ReactFlow,
2753
+ {
2754
+ nodes: nodesWithSelection,
2755
+ edges,
2756
+ nodeTypes,
2757
+ edgeTypes,
2758
+ onNodeMouseEnter: handleNodeMouseEnter,
2759
+ onNodeMouseLeave: handleNodeMouseLeave,
2760
+ onNodeClick: onNodeSelect ? handleNodeClick : void 0,
2761
+ onPaneClick: onNodeSelect ? handlePaneClick : void 0,
2762
+ fitView: true,
2763
+ fitViewOptions: { padding: 0.15 },
2764
+ proOptions: { hideAttribution: true },
2765
+ minZoom: GRAPH_CONSTANTS.MIN_ZOOM,
2766
+ maxZoom: GRAPH_CONSTANTS.MAX_ZOOM,
2767
+ nodesDraggable: false,
2768
+ nodesConnectable: false,
2769
+ elementsSelectable: !!onNodeSelect,
2770
+ selectNodesOnDrag: false,
2771
+ panOnDrag: true,
2772
+ zoomOnScroll: true,
2773
+ zoomOnPinch: true,
2774
+ panOnScroll: false,
2775
+ children: [
2776
+ /* @__PURE__ */ jsx(GraphBackground, {}),
2777
+ /* @__PURE__ */ jsx(
2778
+ GraphLegend,
2779
+ {
2780
+ title: "",
2781
+ position: "bottom-right",
2782
+ items: [
2783
+ { color: "orange", label: "Triggers" },
2784
+ { color: "violet", label: "Agents" },
2785
+ { color: "blue", label: "Workflows" },
2786
+ { color: "teal", label: "Integrations" },
2787
+ { color: "yellow", label: "Human" },
2788
+ { color: "gray", label: "External" }
2789
+ ]
2790
+ }
2791
+ ),
2792
+ /* @__PURE__ */ jsx(
2793
+ GraphLegend,
2794
+ {
2795
+ title: "",
2796
+ position: "bottom-left",
2797
+ items: [
2798
+ { color: "blue", label: "Triggers", type: "line" },
2799
+ { color: "teal", label: "Uses", type: "line" },
2800
+ { color: "yellow", label: "Requires Approval", type: "line" }
2801
+ ]
2802
+ }
2803
+ ),
2804
+ /* @__PURE__ */ jsx(GraphFitViewButton, { padding: 0.15, variant: "mantine", duration: 300 })
2805
+ ]
2806
+ }
2807
+ )
2808
+ }
2809
+ );
2810
+ });
2811
+ var CommandViewGraph = forwardRef(
2812
+ function CommandViewGraph2(props, ref) {
2813
+ return /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(CommandViewGraphInner, { ref, ...props }) });
2814
+ }
2815
+ );
2426
2816
  var tokens = {
2427
2817
  cardBg: "rgba(16, 16, 20, 0.92)",
2428
2818
  cardBorder: "rgba(255, 255, 255, 0.06)",
@@ -3029,13 +3419,13 @@ var Breadcrumbs = ({ navItems }) => {
3029
3419
  return /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "var(--color-text)", children: item.label }, item.path || item.label);
3030
3420
  }
3031
3421
  return item.path ? /* @__PURE__ */ jsx(
3032
- Anchor,
3422
+ Text,
3033
3423
  {
3034
3424
  component: Link4,
3035
3425
  to: item.path,
3036
3426
  size: "sm",
3427
+ c: "var(--color-text-subtle)",
3037
3428
  style: {
3038
- color: "var(--color-text-subtle)",
3039
3429
  textDecoration: "none",
3040
3430
  fontWeight: 500
3041
3431
  },
@@ -3044,7 +3434,18 @@ var Breadcrumbs = ({ navItems }) => {
3044
3434
  item.path
3045
3435
  ) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "var(--color-text-subtle)", children: item.label }, item.label);
3046
3436
  });
3047
- return /* @__PURE__ */ jsx(Breadcrumbs$1, { separator: "/", children: items });
3437
+ return /* @__PURE__ */ jsx(
3438
+ Breadcrumbs$1,
3439
+ {
3440
+ separator: "/",
3441
+ styles: {
3442
+ separator: {
3443
+ color: "var(--color-text-subtle)"
3444
+ }
3445
+ },
3446
+ children: items
3447
+ }
3448
+ );
3048
3449
  };
3049
3450
  function DealKanbanCard({ deal, config, onClick, onDragStart, onDragEnd }) {
3050
3451
  const contactFirstName = deal.contact?.first_name || "";
@@ -3089,22 +3490,11 @@ function DealKanbanCard({ deal, config, onClick, onDragStart, onDragEnd }) {
3089
3490
  }
3090
3491
  );
3091
3492
  }
3092
-
3093
- // src/components/acquisition/kanban/constants.ts
3094
- var DEAL_STAGES = ["interested", "proposal", "closing", "closed_won", "closed_lost", "nurturing"];
3095
- var DEFAULT_KANBAN_CONFIG = {
3096
- interested: { color: "blue" },
3097
- proposal: { color: "yellow" },
3098
- closing: { color: "lime" },
3099
- closed_won: { color: "green" },
3100
- closed_lost: { color: "red" },
3101
- nurturing: { color: "grape" }
3102
- };
3103
3493
  function formatStageLabel(stage) {
3104
3494
  if (!stage) return "Unstaged";
3105
3495
  return stage.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3106
3496
  }
3107
- function DealDrawer({ deal, opened, onClose, renderActions }) {
3497
+ function DealDrawer({ deal, config, opened, onClose, renderActions }) {
3108
3498
  const [noteBody, setNoteBody] = useState("");
3109
3499
  const { data: notes, isLoading: notesLoading } = useDealNotes(deal?.id ?? "");
3110
3500
  const createNote = useCreateDealNote();
@@ -3116,7 +3506,7 @@ function DealDrawer({ deal, opened, onClose, renderActions }) {
3116
3506
  const email = deal.contact?.email || deal.contact_email || null;
3117
3507
  const companyName = deal.contact?.company?.name || deal.discovery_data?.company || null;
3118
3508
  const stage = deal.cached_stage;
3119
- const badgeColor = DEFAULT_KANBAN_CONFIG[stage]?.color ?? "gray";
3509
+ const badgeColor = (stage ? config?.[stage]?.color : null) ?? "gray";
3120
3510
  const activityLog = deal.activity_log || [];
3121
3511
  const hasInitialFee = typeof deal.initial_fee === "number" && deal.initial_fee > 0;
3122
3512
  const hasMonthlyFee = typeof deal.monthly_fee === "number" && deal.monthly_fee > 0;
@@ -3232,12 +3622,9 @@ function formatStageLabel2(stage) {
3232
3622
  if (stage === UNSTAGED_KEY) return "Unstaged";
3233
3623
  return stage.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3234
3624
  }
3235
- function groupDealsByStage(deals) {
3625
+ function groupDealsByStage(deals, columns) {
3236
3626
  const map = /* @__PURE__ */ new Map();
3237
- for (const stage of DEAL_STAGES) {
3238
- map.set(stage, []);
3239
- }
3240
- map.set(UNSTAGED_KEY, []);
3627
+ for (const stage of columns) map.set(stage, []);
3241
3628
  for (const deal of deals) {
3242
3629
  const key = deal.cached_stage ?? UNSTAGED_KEY;
3243
3630
  const bucket = map.get(key);
@@ -3249,7 +3636,7 @@ function groupDealsByStage(deals) {
3249
3636
  }
3250
3637
  return map;
3251
3638
  }
3252
- function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3639
+ function KanbanBoard({ config, renderDrawerActions }) {
3253
3640
  const { data: deals, isLoading, error } = useDeals();
3254
3641
  const syncStage = useSyncDealStage();
3255
3642
  const queryClient = useQueryClient();
@@ -3257,8 +3644,11 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3257
3644
  const [drawerOpen, setDrawerOpen] = useState(false);
3258
3645
  const [dragOverColumn, setDragOverColumn] = useState(null);
3259
3646
  const draggingDealRef = useRef(null);
3260
- const groupedDeals = groupDealsByStage(deals ?? []);
3261
- const columns = [...DEAL_STAGES, UNSTAGED_KEY];
3647
+ const resolvedConfig = config ?? {};
3648
+ const configuredStages = Object.keys(resolvedConfig).filter((stage) => Boolean(resolvedConfig[stage]));
3649
+ const columns = [...configuredStages, UNSTAGED_KEY];
3650
+ const hasConfig = configuredStages.length > 0;
3651
+ const groupedDeals = groupDealsByStage(deals ?? [], columns);
3262
3652
  const handleDragStart = useCallback((e, deal) => {
3263
3653
  draggingDealRef.current = deal;
3264
3654
  e.dataTransfer.effectAllowed = "move";
@@ -3307,6 +3697,15 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3307
3697
  if (error) {
3308
3698
  return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Alert, { color: "red", children: "Failed to load deals" }) });
3309
3699
  }
3700
+ if (!hasConfig) {
3701
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
3702
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Pipeline", caption: "Kanban view of your deal pipeline" }),
3703
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "xl", children: /* @__PURE__ */ jsx(Center, { py: "xl", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", align: "center", children: [
3704
+ /* @__PURE__ */ jsx(Text, { fw: 600, children: "Configuration Required" }),
3705
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", ta: "center", children: "Provide a kanban stage config before rendering the pipeline board." })
3706
+ ] }) }) })
3707
+ ] }) });
3708
+ }
3310
3709
  return /* @__PURE__ */ jsxs(SubshellContentContainer, { children: [
3311
3710
  /* @__PURE__ */ jsxs(Stack, { children: [
3312
3711
  /* @__PURE__ */ jsx(PageTitleCaption, { title: "Pipeline", caption: "Kanban view of your deal pipeline" }),
@@ -3322,7 +3721,7 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3322
3721
  const columnDeals = groupedDeals.get(columnKey) ?? [];
3323
3722
  const isUnstaged = columnKey === UNSTAGED_KEY;
3324
3723
  const isDragTarget = dragOverColumn === columnKey;
3325
- const badgeColor = isUnstaged ? "gray" : config[columnKey]?.color ?? "gray";
3724
+ const badgeColor = isUnstaged ? "gray" : resolvedConfig[columnKey]?.color ?? "gray";
3326
3725
  return /* @__PURE__ */ jsx(
3327
3726
  Box,
3328
3727
  {
@@ -3361,7 +3760,7 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3361
3760
  DealKanbanCard,
3362
3761
  {
3363
3762
  deal,
3364
- config,
3763
+ config: resolvedConfig,
3365
3764
  onClick: handleCardClick,
3366
3765
  onDragStart: handleDragStart,
3367
3766
  onDragEnd: handleDragEnd
@@ -3380,6 +3779,7 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3380
3779
  DealDrawer,
3381
3780
  {
3382
3781
  deal: selectedDeal,
3782
+ config: resolvedConfig,
3383
3783
  opened: drawerOpen,
3384
3784
  onClose: () => setDrawerOpen(false),
3385
3785
  renderActions: renderDrawerActions
@@ -3387,6 +3787,17 @@ function KanbanBoard({ config = DEFAULT_KANBAN_CONFIG, renderDrawerActions }) {
3387
3787
  )
3388
3788
  ] });
3389
3789
  }
3790
+
3791
+ // src/components/acquisition/kanban/constants.ts
3792
+ var DEAL_STAGES = ["interested", "proposal", "closing", "closed_won", "closed_lost", "nurturing"];
3793
+ var DEFAULT_KANBAN_CONFIG = {
3794
+ interested: { color: "blue" },
3795
+ proposal: { color: "yellow" },
3796
+ closing: { color: "lime" },
3797
+ closed_won: { color: "green" },
3798
+ closed_lost: { color: "red" },
3799
+ nurturing: { color: "grape" }
3800
+ };
3390
3801
  var CrmSidebarTop = () => {
3391
3802
  return /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconAddressBook, label: "CRM" });
3392
3803
  };
@@ -4546,7 +4957,7 @@ function LeadGenRouteShell({
4546
4957
  ] }) })
4547
4958
  ] }) }) });
4548
4959
  }
4549
- function formatDate2(dateValue) {
4960
+ function formatDate3(dateValue) {
4550
4961
  const date = typeof dateValue === "string" ? new Date(dateValue) : dateValue;
4551
4962
  return date.toLocaleDateString("en-US", {
4552
4963
  month: "short",
@@ -4640,8 +5051,8 @@ function CompanyDetailModal({ company, onClose }) {
4640
5051
  ] }),
4641
5052
  /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
4642
5053
  "Created: ",
4643
- formatDate2(company.createdAt),
4644
- company.updatedAt && ` | Updated: ${formatDate2(company.updatedAt)}`
5054
+ formatDate3(company.createdAt),
5055
+ company.updatedAt && ` | Updated: ${formatDate3(company.updatedAt)}`
4645
5056
  ] })
4646
5057
  ] }) : null });
4647
5058
  }
@@ -4693,8 +5104,8 @@ function ContactDetailModal({ contact, onClose }) {
4693
5104
  ] }) : null,
4694
5105
  /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
4695
5106
  "Created: ",
4696
- formatDate2(contact.createdAt),
4697
- contact.updatedAt && ` | Updated: ${formatDate2(contact.updatedAt)}`
5107
+ formatDate3(contact.createdAt),
5108
+ contact.updatedAt && ` | Updated: ${formatDate3(contact.updatedAt)}`
4698
5109
  ] })
4699
5110
  ] }) : null });
4700
5111
  }
@@ -4902,12 +5313,159 @@ function useDeleteLists() {
4902
5313
  });
4903
5314
  }
4904
5315
  var EM_DASH = "\u2014";
5316
+ function computeCompletionRatio(populated, personalized) {
5317
+ if (populated === 0) return null;
5318
+ return personalized / populated;
5319
+ }
5320
+ function formatPercentage(ratio, fractionDigits = 0) {
5321
+ if (ratio == null) return EM_DASH;
5322
+ return `${(ratio * 100).toFixed(fractionDigits)}%`;
5323
+ }
4905
5324
  function computeCompletionPercentage(populated, personalized) {
4906
- if (populated === 0) return EM_DASH;
4907
- return `${Math.round(personalized / populated * 100)}%`;
5325
+ return formatPercentage(computeCompletionRatio(populated, personalized));
5326
+ }
5327
+ function computeBounceRate(d) {
5328
+ const denominator = d.valid + d.risky + d.invalid + d.bounced;
5329
+ if (denominator === 0) return EM_DASH;
5330
+ return `${(d.bounced / denominator * 100).toFixed(1)}%`;
5331
+ }
5332
+ function computeBacklog(current, completed) {
5333
+ return Math.max(current - completed, 0);
5334
+ }
5335
+ function getOverviewStatus(list) {
5336
+ if ((list.activeWorkflows?.length ?? 0) > 0) {
5337
+ return { label: "Active Work", color: "green" };
5338
+ }
5339
+ if (list.stageCounts.personalized > 0 && list.stageCounts.personalized === list.stageCounts.uploaded) {
5340
+ return { label: "Complete", color: "blue" };
5341
+ }
5342
+ return { label: "Idle", color: "gray" };
5343
+ }
5344
+ function getNextFocus(list) {
5345
+ if ((list.activeWorkflows?.length ?? 0) > 0) {
5346
+ return { label: "Workflow running", count: list.activeWorkflows?.length ?? 0 };
5347
+ }
5348
+ if (list.totalCompanies === 0 && list.totalContacts === 0) {
5349
+ return { label: "Populate list", count: null };
5350
+ }
5351
+ const extractGap = computeBacklog(list.stageCounts.populated, list.stageCounts.extracted);
5352
+ if (extractGap > 0) {
5353
+ return { label: "Extract website data", count: extractGap };
5354
+ }
5355
+ const qualifyGap = computeBacklog(list.stageCounts.extracted, list.stageCounts.qualified);
5356
+ if (qualifyGap > 0) {
5357
+ return { label: "Qualify companies", count: qualifyGap };
5358
+ }
5359
+ const discoverGap = computeBacklog(list.stageCounts.qualified, list.stageCounts.discovered);
5360
+ if (discoverGap > 0) {
5361
+ return { label: "Discover contacts", count: discoverGap };
5362
+ }
5363
+ const verifyGap = computeBacklog(list.stageCounts.discovered, list.stageCounts.verified);
5364
+ if (verifyGap > 0) {
5365
+ return { label: "Verify emails", count: verifyGap };
5366
+ }
5367
+ const personalizeGap = computeBacklog(list.stageCounts.verified, list.stageCounts.personalized);
5368
+ if (personalizeGap > 0) {
5369
+ return { label: "Personalize outreach", count: personalizeGap };
5370
+ }
5371
+ const uploadGap = computeBacklog(list.stageCounts.personalized, list.stageCounts.uploaded);
5372
+ if (uploadGap > 0) {
5373
+ return { label: "Upload contacts", count: uploadGap };
5374
+ }
5375
+ return { label: "Complete", count: null };
5376
+ }
5377
+ function formatCountLabel(value, noun) {
5378
+ return `${value} ${noun}${value === 1 ? "" : "s"}`;
5379
+ }
5380
+ function getPrimaryAction({
5381
+ uploadBacklog,
5382
+ personalizationBacklog,
5383
+ verificationBacklog,
5384
+ deliverabilityRiskCount,
5385
+ activeListCount,
5386
+ totalLists
5387
+ }) {
5388
+ if (uploadBacklog > 0) {
5389
+ return {
5390
+ title: `Upload ${formatCountLabel(uploadBacklog, "personalized contact")}`,
5391
+ detail: "No verification blockers are left on the contacts already ready for outreach.",
5392
+ buttonLabel: "Review lists",
5393
+ buttonTo: "/lead-gen/lists",
5394
+ tone: "blue"
5395
+ };
5396
+ }
5397
+ if (personalizationBacklog > 0) {
5398
+ return {
5399
+ title: `Personalize ${formatCountLabel(personalizationBacklog, "verified contact")}`,
5400
+ detail: "Verification is done. The next bottleneck is drafting outreach copy.",
5401
+ buttonLabel: "Open lists",
5402
+ buttonTo: "/lead-gen/lists",
5403
+ tone: "blue"
5404
+ };
5405
+ }
5406
+ if (verificationBacklog > 0) {
5407
+ return {
5408
+ title: `Verify ${formatCountLabel(verificationBacklog, "discovered contact")}`,
5409
+ detail: "Email validation is the main blocker before personalization can continue.",
5410
+ buttonLabel: "Open lists",
5411
+ buttonTo: "/lead-gen/lists",
5412
+ tone: "orange"
5413
+ };
5414
+ }
5415
+ if (deliverabilityRiskCount > 0) {
5416
+ return {
5417
+ title: `Resolve ${formatCountLabel(deliverabilityRiskCount, "deliverability risk")}`,
5418
+ detail: "Risky, invalid, or bounced records are the main campaign health issue right now.",
5419
+ buttonLabel: "View deliverability",
5420
+ buttonTo: "/lead-gen/deliverability",
5421
+ tone: "orange"
5422
+ };
5423
+ }
5424
+ if (activeListCount > 0) {
5425
+ return {
5426
+ title: `Monitor ${formatCountLabel(activeListCount, "active list")}`,
5427
+ detail: "Workflows are running and there are no immediate contact-stage backlogs to clear.",
5428
+ buttonLabel: "Open lists",
5429
+ buttonTo: "/lead-gen/lists",
5430
+ tone: "green"
5431
+ };
5432
+ }
5433
+ if (totalLists > 0) {
5434
+ return {
5435
+ title: "No blockers right now",
5436
+ detail: "Lists are idle and the current pipeline does not show an urgent follow-up step.",
5437
+ buttonLabel: "Review lists",
5438
+ buttonTo: "/lead-gen/lists",
5439
+ tone: "gray"
5440
+ };
5441
+ }
5442
+ return {
5443
+ title: "Create your first list",
5444
+ detail: "Lead gen telemetry will appear here once a list starts moving through the pipeline.",
5445
+ buttonLabel: "Open lists",
5446
+ buttonTo: "/lead-gen/lists",
5447
+ tone: "gray"
5448
+ };
5449
+ }
5450
+ function CompactPipelineStage({
5451
+ label,
5452
+ value,
5453
+ ratio
5454
+ }) {
5455
+ return /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
5456
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", wrap: "nowrap", children: [
5457
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", tt: "uppercase", fw: 600, children: label }),
5458
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: "blue", children: formatPercentage(ratio) })
5459
+ ] }),
5460
+ /* @__PURE__ */ jsx(Title, { order: 4, children: value }),
5461
+ /* @__PURE__ */ jsx(Progress, { value: ratio == null ? 0 : ratio * 100, size: "sm", radius: "xl", color: "blue" })
5462
+ ] }) });
4908
5463
  }
4909
5464
  function LeadGenOverviewPage() {
4910
- const { data, isLoading, isError, error } = useListsTelemetry();
5465
+ const telemetryQuery = useListsTelemetry();
5466
+ const listsQuery = useLists();
5467
+ const data = telemetryQuery.data;
5468
+ const listMetaById = new Map((listsQuery.data ?? []).map((list) => [list.id, list]));
4911
5469
  const totalCompanies = data?.reduce((sum, list) => sum + list.totalCompanies, 0) ?? 0;
4912
5470
  const totalContacts = data?.reduce((sum, list) => sum + list.totalContacts, 0) ?? 0;
4913
5471
  const stageTotals = data?.reduce(
@@ -4922,82 +5480,210 @@ function LeadGenOverviewPage() {
4922
5480
  }),
4923
5481
  { populated: 0, extracted: 0, qualified: 0, discovered: 0, verified: 0, personalized: 0, uploaded: 0 }
4924
5482
  ) ?? { populated: 0, extracted: 0, qualified: 0, discovered: 0, verified: 0, personalized: 0, uploaded: 0 };
4925
- const completionLabel = (() => {
4926
- if (!data?.length) return EM_DASH;
4927
- return computeCompletionPercentage(stageTotals.populated, stageTotals.personalized);
4928
- })();
4929
- const stageTiles = [
4930
- { label: "Populated", value: stageTotals.populated },
4931
- { label: "Extracted", value: stageTotals.extracted },
4932
- { label: "Qualified", value: stageTotals.qualified },
4933
- { label: "Discovered", value: stageTotals.discovered },
4934
- { label: "Verified", value: stageTotals.verified },
4935
- { label: "Personalized", value: stageTotals.personalized },
4936
- { label: "Uploaded", value: stageTotals.uploaded }
5483
+ const deliverabilityTotals = data?.reduce(
5484
+ (acc, list) => ({
5485
+ valid: acc.valid + list.deliverability.valid,
5486
+ risky: acc.risky + list.deliverability.risky,
5487
+ invalid: acc.invalid + list.deliverability.invalid,
5488
+ unknown: acc.unknown + list.deliverability.unknown,
5489
+ bounced: acc.bounced + list.deliverability.bounced
5490
+ }),
5491
+ { valid: 0, risky: 0, invalid: 0, unknown: 0, bounced: 0 }
5492
+ ) ?? { risky: 0, invalid: 0, bounced: 0 };
5493
+ const activeListCount = data?.filter((list) => (list.activeWorkflows?.length ?? 0) > 0).length ?? 0;
5494
+ const verificationBacklog = computeBacklog(stageTotals.discovered, stageTotals.verified);
5495
+ const personalizationBacklog = computeBacklog(stageTotals.verified, stageTotals.personalized);
5496
+ const uploadBacklog = computeBacklog(stageTotals.personalized, stageTotals.uploaded);
5497
+ const deliverabilityRiskCount = deliverabilityTotals.risky + deliverabilityTotals.invalid + deliverabilityTotals.bounced;
5498
+ const totalLists = data?.length ?? 0;
5499
+ const summaryLine = [
5500
+ `${totalLists} ${totalLists === 1 ? "list" : "lists"} active`,
5501
+ `${formatCountLabel(uploadBacklog, "contact")} ready for upload`,
5502
+ deliverabilityRiskCount === 0 ? "no risks" : `${formatCountLabel(deliverabilityRiskCount, "risk")}`
5503
+ ].join(" \u2022 ");
5504
+ const primaryAction = getPrimaryAction({
5505
+ uploadBacklog,
5506
+ personalizationBacklog,
5507
+ verificationBacklog,
5508
+ deliverabilityRiskCount,
5509
+ activeListCount,
5510
+ totalLists
5511
+ });
5512
+ const pipelineStages = [
5513
+ {
5514
+ label: "Populated",
5515
+ value: stageTotals.populated,
5516
+ ratio: totalCompanies === 0 ? null : stageTotals.populated / totalCompanies
5517
+ },
5518
+ {
5519
+ label: "Qualified",
5520
+ value: stageTotals.qualified,
5521
+ ratio: totalCompanies === 0 ? null : stageTotals.qualified / totalCompanies
5522
+ },
5523
+ {
5524
+ label: "Verified",
5525
+ value: stageTotals.verified,
5526
+ ratio: totalContacts === 0 ? null : stageTotals.verified / totalContacts
5527
+ },
5528
+ {
5529
+ label: "Personalized",
5530
+ value: stageTotals.personalized,
5531
+ ratio: totalContacts === 0 ? null : stageTotals.personalized / totalContacts
5532
+ },
5533
+ {
5534
+ label: "Uploaded",
5535
+ value: stageTotals.uploaded,
5536
+ ratio: totalContacts === 0 ? null : stageTotals.uploaded / totalContacts
5537
+ }
4937
5538
  ];
5539
+ const overviewRows = data?.map((list) => {
5540
+ const listMeta = listMetaById.get(list.listId);
5541
+ const completionRatio = computeCompletionRatio(list.stageCounts.populated, list.stageCounts.personalized);
5542
+ const nextFocus = getNextFocus(list);
5543
+ return {
5544
+ ...list,
5545
+ name: listMeta?.name ?? `List ${list.listId.slice(0, 8)}`,
5546
+ completionRatio,
5547
+ nextFocus,
5548
+ status: getOverviewStatus(list)
5549
+ };
5550
+ }).sort((a, b) => {
5551
+ const aActive = a.status.label === "Active Work" ? 1 : 0;
5552
+ const bActive = b.status.label === "Active Work" ? 1 : 0;
5553
+ if (aActive !== bActive) return bActive - aActive;
5554
+ const aBacklog = computeBacklog(a.stageCounts.discovered, a.stageCounts.verified) + computeBacklog(a.stageCounts.verified, a.stageCounts.personalized) + computeBacklog(a.stageCounts.personalized, a.stageCounts.uploaded);
5555
+ const bBacklog = computeBacklog(b.stageCounts.discovered, b.stageCounts.verified) + computeBacklog(b.stageCounts.verified, b.stageCounts.personalized) + computeBacklog(b.stageCounts.personalized, b.stageCounts.uploaded);
5556
+ if (aBacklog !== bBacklog) return bBacklog - aBacklog;
5557
+ return b.totalContacts - a.totalContacts;
5558
+ }) ?? [];
4938
5559
  return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
4939
5560
  /* @__PURE__ */ jsx(
4940
5561
  PageTitleCaption,
4941
5562
  {
4942
5563
  title: "Lead Gen Overview",
4943
- caption: "Pipeline health, list roll-up, and active work at a glance"
5564
+ caption: summaryLine,
5565
+ rightSection: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
5566
+ /* @__PURE__ */ jsx(Button, { component: Link$1, to: "/lead-gen/lists", size: "sm", variant: "light", children: "Lists" }),
5567
+ /* @__PURE__ */ jsx(Button, { component: Link$1, to: "/lead-gen/deliverability", size: "sm", variant: "light", children: "Deliverability" })
5568
+ ] })
4944
5569
  }
4945
5570
  ),
4946
- isLoading ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) }) : isError ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load list telemetry" }) }) : !data?.length ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { h: 300, children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "No lists yet." }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4947
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 2, sm: 4 }, children: [
4948
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChartBar, value: data.length, label: "Total Lists" }),
4949
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconBuildingFactory2, value: totalCompanies, label: "Total Companies" }),
4950
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconUsers, value: totalContacts, label: "Total Contacts" }),
4951
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChecklist, value: completionLabel, label: "Overall Completion" })
4952
- ] }),
4953
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
4954
- "View per-list detail on the",
4955
- " ",
4956
- /* @__PURE__ */ jsx(Anchor, { component: Link$1, to: "/lead-gen/lists", size: "sm", children: "Lists" }),
4957
- " ",
4958
- "page."
5571
+ telemetryQuery.isLoading ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) }) : telemetryQuery.isError ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(CenteredErrorState, { error: telemetryQuery.error, title: "Failed to load list telemetry" }) }) : !data?.length ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Center, { h: 300, children: /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "gray", variant: "light", children: "No lists yet." }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5572
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 3 }, children: [
5573
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconPlayerPlay, value: activeListCount, label: "Active Lists" }),
5574
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconArrowRight, value: uploadBacklog, label: "Ready Contacts" }),
5575
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconAlertCircle, value: deliverabilityRiskCount, label: "At Risk" })
4959
5576
  ] }),
4960
5577
  /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4961
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Pipeline Roll-Up" }),
4962
- /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 2, sm: 3, lg: 7 }, children: stageTiles.map((tile) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
4963
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: tile.label }),
4964
- /* @__PURE__ */ jsx(Title, { order: 4, children: tile.value })
4965
- ] }, tile.label)) })
5578
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", gap: "md", children: [
5579
+ /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
5580
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", tt: "uppercase", fw: 700, children: "Next Action" }),
5581
+ /* @__PURE__ */ jsx(Title, { order: 3, children: primaryAction.title }),
5582
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", maw: 620, children: primaryAction.detail })
5583
+ ] }),
5584
+ /* @__PURE__ */ jsx(Button, { component: Link$1, to: primaryAction.buttonTo, size: "sm", variant: "light", children: primaryAction.buttonLabel })
5585
+ ] }),
5586
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, md: 3 }, children: [
5587
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
5588
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", tt: "uppercase", fw: 600, children: "Verification" }),
5589
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-end", mt: 6, children: [
5590
+ /* @__PURE__ */ jsx(Title, { order: 4, children: verificationBacklog }),
5591
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "waiting" })
5592
+ ] })
5593
+ ] }),
5594
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
5595
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", tt: "uppercase", fw: 600, children: "Personalization" }),
5596
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-end", mt: 6, children: [
5597
+ /* @__PURE__ */ jsx(Title, { order: 4, children: personalizationBacklog }),
5598
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "ready" })
5599
+ ] })
5600
+ ] }),
5601
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, p: "sm", children: [
5602
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", tt: "uppercase", fw: 600, children: "Completion" }),
5603
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-end", mt: 6, children: [
5604
+ /* @__PURE__ */ jsx(Title, { order: 4, children: computeCompletionPercentage(stageTotals.populated, stageTotals.personalized) }),
5605
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "personalized" })
5606
+ ] })
5607
+ ] })
5608
+ ] })
5609
+ ] }) }),
5610
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
5611
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-end", children: [
5612
+ /* @__PURE__ */ jsxs("div", { children: [
5613
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Pipeline" }),
5614
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Keep the funnel visible without giving every zero state its own section." })
5615
+ ] }),
5616
+ /* @__PURE__ */ jsxs(Badge, { variant: "light", color: "blue", children: [
5617
+ stageTotals.extracted,
5618
+ " extracted \u2022 ",
5619
+ stageTotals.discovered,
5620
+ " discovered"
5621
+ ] })
5622
+ ] }),
5623
+ /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 1, sm: 2, xl: 5 }, children: pipelineStages.map((stage) => /* @__PURE__ */ jsx(
5624
+ CompactPipelineStage,
5625
+ {
5626
+ label: stage.label,
5627
+ value: stage.value,
5628
+ ratio: stage.ratio
5629
+ },
5630
+ stage.label
5631
+ )) })
4966
5632
  ] }) }),
4967
5633
  /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
4968
- /* @__PURE__ */ jsx(Title, { order: 3, children: "List Snapshot" }),
5634
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-end", children: [
5635
+ /* @__PURE__ */ jsxs("div", { children: [
5636
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "List Snapshot" }),
5637
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Ranked to surface active work first, then the largest unresolved backlogs." })
5638
+ ] }),
5639
+ /* @__PURE__ */ jsx(Button, { component: Link$1, to: "/lead-gen/lists", size: "sm", variant: "subtle", children: "Open lists" })
5640
+ ] }),
4969
5641
  /* @__PURE__ */ jsxs(Table, { children: [
4970
5642
  /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
4971
5643
  /* @__PURE__ */ jsx(Table.Th, { children: "List" }),
4972
5644
  /* @__PURE__ */ jsx(Table.Th, { children: "Companies" }),
4973
5645
  /* @__PURE__ */ jsx(Table.Th, { children: "Contacts" }),
4974
- /* @__PURE__ */ jsx(Table.Th, { children: "Completion" }),
5646
+ /* @__PURE__ */ jsx(Table.Th, { children: "Next Focus" }),
5647
+ /* @__PURE__ */ jsx(Table.Th, { children: "Progress" }),
4975
5648
  /* @__PURE__ */ jsx(Table.Th, { children: "Status" })
4976
5649
  ] }) }),
4977
- /* @__PURE__ */ jsx(Table.Tbody, { children: data.map((list) => {
4978
- const completion = computeCompletionPercentage(
4979
- list.stageCounts.populated,
4980
- list.stageCounts.personalized
4981
- );
4982
- const isActive = (list.activeWorkflows?.length ?? 0) > 0;
4983
- return /* @__PURE__ */ jsxs(Table.Tr, { children: [
4984
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: list.listId }) }),
4985
- /* @__PURE__ */ jsx(Table.Td, { children: list.totalCompanies }),
4986
- /* @__PURE__ */ jsx(Table.Td, { children: list.totalContacts }),
4987
- /* @__PURE__ */ jsx(Table.Td, { children: completion }),
4988
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: isActive ? "light" : "outline", color: isActive ? "green" : "gray", children: isActive ? "Active Work" : "Idle" }) })
4989
- ] }, list.listId);
4990
- }) })
5650
+ /* @__PURE__ */ jsx(Table.Tbody, { children: overviewRows.map((list) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
5651
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
5652
+ /* @__PURE__ */ jsx(Link$1, { to: "/lead-gen/lists/$listId", params: { listId: list.listId }, children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, component: "span", c: "blue.4", children: list.name }) }),
5653
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: list.listId })
5654
+ ] }) }),
5655
+ /* @__PURE__ */ jsx(Table.Td, { children: list.totalCompanies }),
5656
+ /* @__PURE__ */ jsx(Table.Td, { children: list.totalContacts }),
5657
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
5658
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: list.nextFocus.label }),
5659
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: list.nextFocus.count == null ? "No outstanding count" : `${list.nextFocus.count} item${list.nextFocus.count === 1 ? "" : "s"} queued` })
5660
+ ] }) }),
5661
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", miw: 150, children: [
5662
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "xs", children: [
5663
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatPercentage(list.completionRatio) }),
5664
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
5665
+ list.stageCounts.personalized,
5666
+ "/",
5667
+ list.stageCounts.populated || 0
5668
+ ] })
5669
+ ] }),
5670
+ /* @__PURE__ */ jsx(
5671
+ Progress,
5672
+ {
5673
+ value: list.completionRatio == null ? 0 : list.completionRatio * 100,
5674
+ size: "sm",
5675
+ radius: "xl",
5676
+ color: "blue"
5677
+ }
5678
+ )
5679
+ ] }) }),
5680
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: list.status.color, children: list.status.label }) })
5681
+ ] }, list.listId)) })
4991
5682
  ] })
4992
5683
  ] }) })
4993
5684
  ] })
4994
5685
  ] }) }) });
4995
5686
  }
4996
- function computeBounceRate(d) {
4997
- const denominator = d.valid + d.risky + d.invalid + d.bounced;
4998
- if (denominator === 0) return EM_DASH;
4999
- return `${(d.bounced / denominator * 100).toFixed(1)}%`;
5000
- }
5001
5687
  function LeadGenDeliverabilityPage() {
5002
5688
  const { data, isLoading, error } = useListsTelemetry();
5003
5689
  if (isLoading) {
@@ -5218,7 +5904,7 @@ function LeadGenListsPage() {
5218
5904
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { fw: 500, children: list.name }) }),
5219
5905
  /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: list.description || "-" }) }),
5220
5906
  /* @__PURE__ */ jsx(Table.Td, { children: contactCountByListId.get(list.id) ?? 0 }),
5221
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDate2(list.createdAt) }) })
5907
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDate3(list.createdAt) }) })
5222
5908
  ]
5223
5909
  },
5224
5910
  list.id
@@ -6073,7 +6759,7 @@ function ringValue(completed, total) {
6073
6759
  if (total === 0) return 0;
6074
6760
  return Math.round(completed / total * 100);
6075
6761
  }
6076
- function formatDate3(iso) {
6762
+ function formatDate4(iso) {
6077
6763
  return new Date(iso).toLocaleDateString();
6078
6764
  }
6079
6765
  function daysRelative(targetEndDate) {
@@ -6161,17 +6847,17 @@ function HealthStatusCard({
6161
6847
  ] }),
6162
6848
  /* @__PURE__ */ jsx(Stack, { gap: 2, children: startDate && targetEndDate ? /* @__PURE__ */ jsxs(Fragment, { children: [
6163
6849
  /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
6164
- formatDate3(startDate),
6850
+ formatDate4(startDate),
6165
6851
  " \u2192 ",
6166
- formatDate3(targetEndDate)
6852
+ formatDate4(targetEndDate)
6167
6853
  ] }),
6168
6854
  timeInfo && /* @__PURE__ */ jsx(Text, { size: "xs", c: timeInfo.overdue ? "red" : "dimmed", children: timeInfo.label })
6169
6855
  ] }) : startDate ? /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
6170
6856
  "Started ",
6171
- formatDate3(startDate)
6857
+ formatDate4(startDate)
6172
6858
  ] }) : targetEndDate ? /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
6173
6859
  "Due ",
6174
- formatDate3(targetEndDate)
6860
+ formatDate4(targetEndDate)
6175
6861
  ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No dates set" }) })
6176
6862
  ] }) })
6177
6863
  ] });
@@ -6557,6 +7243,414 @@ function ProjectsListPage({ onProjectClick } = {}) {
6557
7243
  )
6558
7244
  ] });
6559
7245
  }
7246
+ var noteTypeOptions = [
7247
+ { value: "call_note", label: "Call Note" },
7248
+ { value: "status_update", label: "Status Update" },
7249
+ { value: "issue", label: "Issue" },
7250
+ { value: "blocker", label: "Blocker" }
7251
+ ];
7252
+ function parseChecklist(milestone) {
7253
+ const raw = milestone.checklist;
7254
+ if (!Array.isArray(raw)) return [];
7255
+ return raw;
7256
+ }
7257
+ function MilestoneChecklist({ milestone }) {
7258
+ const items = parseChecklist(milestone);
7259
+ const { mutate: updateMilestone } = useUpdateMilestone();
7260
+ const [newItemLabel, setNewItemLabel] = useState("");
7261
+ const [adding, setAdding] = useState(false);
7262
+ function saveChecklist(updated) {
7263
+ const allComplete = updated.length > 0 && updated.every((item) => item.completed);
7264
+ const wasComplete = milestone.status === "completed";
7265
+ const updates = {
7266
+ checklist: updated
7267
+ };
7268
+ if (allComplete && !wasComplete) {
7269
+ updates.status = "completed";
7270
+ updates.completed_at = (/* @__PURE__ */ new Date()).toISOString();
7271
+ } else if (!allComplete && wasComplete) {
7272
+ updates.status = "in_progress";
7273
+ updates.completed_at = null;
7274
+ }
7275
+ updateMilestone({ id: milestone.id, updates });
7276
+ }
7277
+ function toggleItem(itemId) {
7278
+ const updated = items.map((item) => item.id === itemId ? { ...item, completed: !item.completed } : item);
7279
+ saveChecklist(updated);
7280
+ }
7281
+ function addItem() {
7282
+ const label = newItemLabel.trim();
7283
+ if (!label) return;
7284
+ const newItem = { id: crypto.randomUUID(), label, completed: false };
7285
+ saveChecklist([...items, newItem]);
7286
+ setNewItemLabel("");
7287
+ }
7288
+ function removeItem(itemId) {
7289
+ saveChecklist(items.filter((item) => item.id !== itemId));
7290
+ }
7291
+ const completedCount = items.filter((item) => item.completed).length;
7292
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", mt: "sm", children: [
7293
+ items.length > 0 && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
7294
+ completedCount,
7295
+ "/",
7296
+ items.length,
7297
+ " complete"
7298
+ ] }),
7299
+ items.map((item) => /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
7300
+ /* @__PURE__ */ jsx(
7301
+ Checkbox,
7302
+ {
7303
+ size: "xs",
7304
+ checked: item.completed,
7305
+ onChange: () => toggleItem(item.id),
7306
+ label: /* @__PURE__ */ jsx(
7307
+ Text,
7308
+ {
7309
+ size: "sm",
7310
+ td: item.completed ? "line-through" : void 0,
7311
+ c: item.completed ? "dimmed" : "var(--color-text-subtle)",
7312
+ children: item.label
7313
+ }
7314
+ ),
7315
+ styles: { input: { cursor: "pointer" }, label: { cursor: "pointer" } }
7316
+ }
7317
+ ),
7318
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "xs", onClick: () => removeItem(item.id), style: { opacity: 0.4 }, children: /* @__PURE__ */ jsx(IconX, { size: 12 }) })
7319
+ ] }, item.id)),
7320
+ adding ? /* @__PURE__ */ jsx(
7321
+ TextInput,
7322
+ {
7323
+ size: "xs",
7324
+ placeholder: "Item label...",
7325
+ value: newItemLabel,
7326
+ onChange: (event) => setNewItemLabel(event.target.value),
7327
+ onKeyDown: (event) => {
7328
+ if (event.key === "Enter") {
7329
+ addItem();
7330
+ setAdding(false);
7331
+ }
7332
+ if (event.key === "Escape") {
7333
+ setNewItemLabel("");
7334
+ setAdding(false);
7335
+ }
7336
+ },
7337
+ onBlur: () => {
7338
+ if (newItemLabel.trim()) addItem();
7339
+ setAdding(false);
7340
+ },
7341
+ autoFocus: true,
7342
+ style: { maxWidth: 250 }
7343
+ }
7344
+ ) : /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Button, { variant: "subtle", size: "compact-xs", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 12 }), onClick: () => setAdding(true), children: "Add item" }) })
7345
+ ] });
7346
+ }
7347
+ function AddNoteModal({ opened, onClose, projectId }) {
7348
+ const [noteType, setNoteType] = useState("call_note");
7349
+ const [content, setContent] = useState("");
7350
+ const [summary, setSummary] = useState("");
7351
+ const { mutate: createNote, isPending } = useCreateNote();
7352
+ function handleSubmit() {
7353
+ if (!content.trim() || !noteType) return;
7354
+ createNote(
7355
+ {
7356
+ project_id: projectId,
7357
+ type: noteType,
7358
+ content: content.trim(),
7359
+ summary: summary.trim() || null
7360
+ },
7361
+ {
7362
+ onSuccess: () => {
7363
+ setContent("");
7364
+ setSummary("");
7365
+ setNoteType("call_note");
7366
+ onClose();
7367
+ }
7368
+ }
7369
+ );
7370
+ }
7371
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "md", loading: isPending, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7372
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
7373
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Add Note" }),
7374
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", onClick: onClose, disabled: isPending, children: /* @__PURE__ */ jsx(IconX, { size: 18 }) })
7375
+ ] }),
7376
+ /* @__PURE__ */ jsx(Select, { label: "Type", data: noteTypeOptions, value: noteType, onChange: setNoteType, required: true }),
7377
+ /* @__PURE__ */ jsx(
7378
+ TextInput,
7379
+ {
7380
+ label: "Summary",
7381
+ placeholder: "Brief summary (optional)",
7382
+ value: summary,
7383
+ onChange: (event) => setSummary(event.target.value)
7384
+ }
7385
+ ),
7386
+ /* @__PURE__ */ jsx(
7387
+ Textarea,
7388
+ {
7389
+ label: "Content",
7390
+ placeholder: "Note content...",
7391
+ minRows: 4,
7392
+ value: content,
7393
+ onChange: (event) => setContent(event.target.value),
7394
+ required: true
7395
+ }
7396
+ ),
7397
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
7398
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: onClose, disabled: isPending, children: "Cancel" }),
7399
+ /* @__PURE__ */ jsx(Button, { onClick: handleSubmit, loading: isPending, disabled: !content.trim() || !noteType, children: "Add Note" })
7400
+ ] })
7401
+ ] }) });
7402
+ }
7403
+ function ProjectDetailPage({ projectId, onBack, backLabel = "Projects" }) {
7404
+ const { data: project, isLoading, error } = useProject(projectId);
7405
+ const { data: notes } = useProjectNotes({ projectId });
7406
+ const { mutate: deleteProject, isPending: isDeleting } = useDeleteProject$1();
7407
+ const [addNoteOpen, setAddNoteOpen] = useState(false);
7408
+ const [deleteModalOpen, setDeleteModalOpen] = useState(false);
7409
+ if (isLoading) {
7410
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Loader, {}) }) });
7411
+ }
7412
+ if (error) {
7413
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Alert, { color: "red", children: "Error loading project" }) }) });
7414
+ }
7415
+ if (!project) {
7416
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Alert, { color: "yellow", children: "Project not found" }) }) });
7417
+ }
7418
+ const milestones = project.milestones ?? [];
7419
+ const tasks = project.tasks ?? [];
7420
+ const totalMilestones = milestones.length;
7421
+ const completedMilestones = milestones.filter((milestone) => milestone.status === "completed").length;
7422
+ const totalTasks = tasks.length;
7423
+ const approvedTasks = tasks.filter((task) => task.status === "approved").length;
7424
+ const milestoneProgress = calculateProgress(completedMilestones, totalMilestones);
7425
+ const taskProgress = calculateProgress(approvedTasks, totalTasks);
7426
+ const companyName = project.company?.name ?? null;
7427
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
7428
+ /* @__PURE__ */ jsx(
7429
+ PageTitleCaption,
7430
+ {
7431
+ title: project.name,
7432
+ caption: [companyName, formatStatusLabel(project.status || "unknown")].filter(Boolean).join(" - "),
7433
+ rightSection: /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onBack, children: backLabel }) })
7434
+ }
7435
+ ),
7436
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 4, children: [
7437
+ /* @__PURE__ */ jsx(
7438
+ StatCard,
7439
+ {
7440
+ variant: "hero",
7441
+ icon: IconHeartbeat,
7442
+ value: formatStatusLabel(project.status || "unknown"),
7443
+ label: "Status",
7444
+ valueColor: `var(--mantine-color-${projectStatusColors[project.status || ""] || "gray"}-6)`
7445
+ }
7446
+ ),
7447
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconFlag, value: `${completedMilestones}/${totalMilestones}`, label: "Milestones", children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
7448
+ milestoneProgress,
7449
+ "% complete"
7450
+ ] }) }),
7451
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconChecklist, value: `${approvedTasks}/${totalTasks}`, label: "Tasks", children: /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
7452
+ taskProgress,
7453
+ "% complete"
7454
+ ] }) }),
7455
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconCalendar, value: project.start_date ? formatDate(project.start_date) : "-", label: "Timeline", children: project.target_end_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
7456
+ "to ",
7457
+ formatDate(project.target_end_date)
7458
+ ] }) })
7459
+ ] }),
7460
+ /* @__PURE__ */ jsxs(
7461
+ Paper,
7462
+ {
7463
+ p: "md",
7464
+ style: {
7465
+ border: "1px solid var(--color-border)",
7466
+ borderRadius: "var(--mantine-radius-default)"
7467
+ },
7468
+ children: [
7469
+ /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7470
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "wrap", children: [
7471
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
7472
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Project Details" }),
7473
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: projectStatusColors[project.status || ""] || "gray", children: formatStatusLabel(project.status || "unknown") })
7474
+ ] }),
7475
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
7476
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: project.id }),
7477
+ /* @__PURE__ */ jsx(CopyButton, { value: project.id, children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, { label: copied ? "Copied!" : "Copy ID", withArrow: true, children: /* @__PURE__ */ jsx(ActionIcon, { onClick: copy, variant: "subtle", size: "xs", color: copied ? "green" : "var(--color-text-subtle)", children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 }) }) }) })
7478
+ ] })
7479
+ ] }),
7480
+ /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
7481
+ project.start_date && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
7482
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Started:" }),
7483
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDate(project.start_date) })
7484
+ ] }),
7485
+ project.target_end_date && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
7486
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Target:" }),
7487
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDate(project.target_end_date) })
7488
+ ] }),
7489
+ project.contract_value != null && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
7490
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Contract:" }),
7491
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
7492
+ "$",
7493
+ project.contract_value.toLocaleString(),
7494
+ project.metadata && project.metadata.rate_type === "hourly" ? "/hr" : ""
7495
+ ] })
7496
+ ] }),
7497
+ project.company && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
7498
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Company:" }),
7499
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: project.company.name })
7500
+ ] })
7501
+ ] })
7502
+ ] }),
7503
+ /* @__PURE__ */ jsx(Divider, { my: "md" }),
7504
+ /* @__PURE__ */ jsxs(Tabs, { defaultValue: "status", children: [
7505
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
7506
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "status", children: "Status" }),
7507
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "details", children: "Details" }),
7508
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "notes", children: "Notes" }),
7509
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "activity", children: "Activity" })
7510
+ ] }),
7511
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "status", pt: "md", children: milestones.length === 0 ? /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "No milestones yet." }) : /* @__PURE__ */ jsx(
7512
+ Timeline,
7513
+ {
7514
+ active: completedMilestones,
7515
+ bulletSize: 20,
7516
+ color: "var(--color-primary)",
7517
+ styles: {
7518
+ itemBullet: {
7519
+ borderColor: "color-mix(in srgb, var(--color-primary) 40%, transparent)",
7520
+ backgroundColor: "var(--color-surface)"
7521
+ },
7522
+ item: {
7523
+ "--_item-border-color": "color-mix(in srgb, var(--color-primary) 25%, transparent)"
7524
+ },
7525
+ itemTitle: {
7526
+ color: "var(--color-text)"
7527
+ }
7528
+ },
7529
+ children: milestones.map((milestone) => {
7530
+ const milestoneTasks = tasks.filter((task) => task.milestone_id === milestone.id);
7531
+ return /* @__PURE__ */ jsxs(
7532
+ Timeline.Item,
7533
+ {
7534
+ bullet: milestone.status === "completed" ? /* @__PURE__ */ jsx(
7535
+ "div",
7536
+ {
7537
+ style: {
7538
+ width: 12,
7539
+ height: 12,
7540
+ borderRadius: "50%",
7541
+ backgroundColor: "var(--color-primary)",
7542
+ boxShadow: "0 0 8px var(--color-primary), 0 0 16px color-mix(in srgb, var(--color-primary) 50%, transparent)"
7543
+ }
7544
+ }
7545
+ ) : void 0,
7546
+ title: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
7547
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: milestone.name }),
7548
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: milestoneStatusColors[milestone.status || ""] || "gray", size: "sm", children: formatStatusLabel(milestone.status || "unknown") }),
7549
+ milestone.due_date && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
7550
+ "Due ",
7551
+ formatDate(milestone.due_date)
7552
+ ] })
7553
+ ] }),
7554
+ children: [
7555
+ milestone.description && /* @__PURE__ */ jsx(Text, { size: "sm", mt: "xs", children: milestone.description }),
7556
+ /* @__PURE__ */ jsx(MilestoneChecklist, { milestone }),
7557
+ milestoneTasks.length > 0 && /* @__PURE__ */ jsx(Stack, { gap: "xs", mt: "sm", children: milestoneTasks.map((task) => /* @__PURE__ */ jsx(Card, { withBorder: true, p: "xs", children: /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", children: [
7558
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: task.name }),
7559
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
7560
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: taskTypeColors[task.type || ""] || "gray", size: "xs", children: formatStatusLabel(task.type || "other") }),
7561
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: taskStatusColors[task.status || ""] || "gray", size: "xs", children: formatStatusLabel(task.status || "pending") })
7562
+ ] })
7563
+ ] }) }, task.id)) })
7564
+ ]
7565
+ },
7566
+ milestone.id
7567
+ );
7568
+ })
7569
+ }
7570
+ ) }),
7571
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "details", pt: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7572
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
7573
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Project Details" }),
7574
+ project.description && /* @__PURE__ */ jsxs("div", { children: [
7575
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Description" }),
7576
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: project.description })
7577
+ ] }),
7578
+ project.contract_value != null && /* @__PURE__ */ jsxs("div", { children: [
7579
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Contract Value" }),
7580
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
7581
+ "$",
7582
+ project.contract_value.toLocaleString()
7583
+ ] })
7584
+ ] }),
7585
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 3, children: [
7586
+ /* @__PURE__ */ jsxs("div", { children: [
7587
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Start Date" }),
7588
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDate(project.start_date) })
7589
+ ] }),
7590
+ /* @__PURE__ */ jsxs("div", { children: [
7591
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Target End Date" }),
7592
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDate(project.target_end_date) })
7593
+ ] }),
7594
+ /* @__PURE__ */ jsxs("div", { children: [
7595
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Actual End Date" }),
7596
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDate(project.actual_end_date) })
7597
+ ] })
7598
+ ] })
7599
+ ] }) }),
7600
+ project.company && /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
7601
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Company" }),
7602
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: project.company.name }),
7603
+ project.company.domain && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: project.company.domain })
7604
+ ] }) })
7605
+ ] }) }),
7606
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "notes", pt: "md", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7607
+ /* @__PURE__ */ jsx(Group, { justify: "flex-end", children: /* @__PURE__ */ jsx(Button, { variant: "light", size: "sm", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setAddNoteOpen(true), children: "Add Note" }) }),
7608
+ !notes?.length ? /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "No notes yet." }) : /* @__PURE__ */ jsx(Stack, { gap: "sm", children: notes.map((note) => /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
7609
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
7610
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: noteTypeColors[note.type || ""] || "gray", size: "sm", children: formatStatusLabel(note.type || "note") }),
7611
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatTimeAgo(note.occurred_at) })
7612
+ ] }),
7613
+ note.summary && /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: note.summary }),
7614
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: note.content })
7615
+ ] }) }, note.id)) })
7616
+ ] }) }),
7617
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "activity", pt: "md", children: /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "Activity feed coming soon." }) })
7618
+ ] })
7619
+ ]
7620
+ }
7621
+ ),
7622
+ /* @__PURE__ */ jsx(AddNoteModal, { opened: addNoteOpen, onClose: () => setAddNoteOpen(false), projectId }),
7623
+ /* @__PURE__ */ jsx(CustomModal, { opened: deleteModalOpen, onClose: () => setDeleteModalOpen(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7624
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
7625
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete project" }),
7626
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", onClick: () => setDeleteModalOpen(false), children: /* @__PURE__ */ jsx(IconX, { size: 18 }) })
7627
+ ] }),
7628
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
7629
+ "Are you sure you want to delete ",
7630
+ /* @__PURE__ */ jsx("strong", { children: project.name }),
7631
+ "? This cannot be undone."
7632
+ ] }),
7633
+ /* @__PURE__ */ jsx(Divider, {}),
7634
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
7635
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setDeleteModalOpen(false), disabled: isDeleting, children: "Cancel" }),
7636
+ /* @__PURE__ */ jsx(
7637
+ Button,
7638
+ {
7639
+ color: "red",
7640
+ loading: isDeleting,
7641
+ onClick: () => deleteProject(project.id, {
7642
+ onSuccess: () => {
7643
+ setDeleteModalOpen(false);
7644
+ onBack();
7645
+ }
7646
+ }),
7647
+ children: "Delete project"
7648
+ }
7649
+ )
7650
+ ] })
7651
+ ] }) })
7652
+ ] }) }) });
7653
+ }
6560
7654
  function NotificationPanel({ notifications, isLoading, onClose, onNavigate }) {
6561
7655
  const markAllAsRead = useMarkAllAsRead();
6562
7656
  const hasUnread = notifications.some((n) => !n.read);
@@ -6609,4 +7703,4 @@ function NotificationBell({ unreadCount, onNavigate }) {
6609
7703
  ] });
6610
7704
  }
6611
7705
 
6612
- export { AbsoluteScheduleForm, ActivityFeedWidget, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CrashErrorFallback, CreateApiKeyModal, CreateScheduleModal, CrmOverview, CrmSidebar, CrmSidebarMiddle, CrmSidebarTop, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealDetailPage, DealDrawer, DealKanbanCard, DealsListPage, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, DocTreeNav, EditApiKeyModal, ErrorReportCard, HealthStatusCard, KanbanBoard, KnowledgeBasePage, LEAD_GEN_ROUTE_LINKS, LIST_TEMPLATE_OPTIONS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenDeliverabilityPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, MdxRenderer, MetricsStrip, MilestoneTimeline, MyTasksPanel, NotificationBell, NotificationPanel, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, QuickCreateActions, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, SAVED_VIEW_PRESETS, SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, SavedViewsPanel, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, SortableHeader, TableSelectionToolbar, TaskCard, TaskScheduler, TasksDueWidget, buildErrorReport, buildListConfig, calculateProgress, crmManifest, deliveryManifest, formatStatusLabel, getEnrichmentColor, getStatusColor3 as getStatusColor, leadGenManifest, mdxComponents, milestoneStatusColors, noteTypeColors, projectStatusColors, seoManifest, taskStatusColors, taskTypeColors, useCrmPipelineSummary, useCrmQuickMetrics, useDeleteLists, useRecentCrmActivity };
7706
+ export { AbsoluteScheduleForm, ActivityFeedWidget, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CommandViewEdge, CommandViewGraph, CommandViewNode, CrashErrorFallback, CreateApiKeyModal, CreateScheduleModal, CrmOverview, CrmSidebar, CrmSidebarMiddle, CrmSidebarTop, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealDetailPage, DealDrawer, DealKanbanCard, DealsListPage, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, DocTreeNav, EditApiKeyModal, ErrorReportCard, HealthStatusCard, KanbanBoard, KnowledgeBasePage, LEAD_GEN_ROUTE_LINKS, LIST_TEMPLATE_OPTIONS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenDeliverabilityPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, MdxRenderer, MetricsStrip, MilestoneTimeline, MyTasksPanel, NotificationBell, NotificationPanel, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, QuickCreateActions, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, SAVED_VIEW_PRESETS, SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, SavedViewsPanel, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, SortableHeader, TableSelectionToolbar, TaskCard, TaskScheduler, TasksDueWidget, buildErrorReport, buildListConfig, calculateProgress, crmManifest, deliveryManifest, formatStatusLabel, getEnrichmentColor, getStatusColor3 as getStatusColor, leadGenManifest, mdxComponents, milestoneStatusColors, noteTypeColors, projectStatusColors, seoManifest, taskStatusColors, taskTypeColors, useCrmPipelineSummary, useCrmQuickMetrics, useDeleteLists, useRecentCrmActivity };