@burdenoff/microfe-bigconsole 2026.805.2 → 2026.805.3

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 (134) hide show
  1. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +109 -113
  2. package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
  3. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +115 -113
  4. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
  5. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +71 -62
  6. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  7. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +90 -89
  8. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  9. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +56 -54
  10. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
  11. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +126 -125
  12. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
  13. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +151 -150
  14. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
  15. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +77 -76
  16. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
  17. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +97 -96
  18. package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
  19. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +172 -191
  20. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  21. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +75 -83
  22. package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js.map +1 -1
  23. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +151 -154
  24. package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
  25. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +181 -190
  26. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  27. package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -0
  28. package/dist/bigconsole/components/dashboard/WidgetPalette.js +110 -108
  29. package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
  30. package/dist/bigconsole/components/datasink/CacheTTLSelector.js +102 -103
  31. package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
  32. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +36 -41
  33. package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
  34. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +38 -37
  35. package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
  36. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +113 -117
  37. package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -1
  38. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +182 -197
  39. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
  40. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +166 -168
  41. package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
  42. package/dist/bigconsole/components/parser/DataSinkSelector.js +87 -86
  43. package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
  44. package/dist/bigconsole/components/parser/ImportParserDialog.js +196 -211
  45. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  46. package/dist/bigconsole/components/parser/ParserSelector.js +130 -128
  47. package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
  48. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +66 -63
  49. package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
  50. package/dist/bigconsole/components/preview/AiPreviewPanel.js +95 -91
  51. package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
  52. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +222 -215
  53. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  54. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +149 -145
  55. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  56. package/dist/bigconsole/components/widgets/PropertiesPanel.js +504 -470
  57. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  58. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +44 -47
  59. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  60. package/dist/bigconsole/components/widgets/chart/ChartConfig.js +143 -142
  61. package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
  62. package/dist/bigconsole/components/widgets/comments/WidgetComments.js +101 -88
  63. package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
  64. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +135 -134
  65. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  66. package/dist/bigconsole/components/widgets/form/FormWidget.js +167 -159
  67. package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
  68. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +69 -68
  69. package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
  70. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +64 -72
  71. package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
  72. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +60 -59
  73. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  74. package/dist/bigconsole/components/widgets/list/ListConfig.js +57 -56
  75. package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
  76. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +70 -69
  77. package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
  78. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +35 -34
  79. package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
  80. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +20 -19
  81. package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
  82. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +178 -177
  83. package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
  84. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +76 -75
  85. package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
  86. package/dist/bigconsole/components/widgets/table/TableConfig.js +183 -168
  87. package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
  88. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +187 -180
  89. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  90. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +40 -38
  91. package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
  92. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +150 -148
  93. package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
  94. package/dist/bigconsole/pages/DashboardBuilderPage.js +181 -176
  95. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  96. package/dist/bigconsole/pages/DashboardViewPage.js +196 -192
  97. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  98. package/dist/bigconsole/pages/DashboardsPage.js +223 -219
  99. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  100. package/dist/bigconsole/pages/DataParsersPage.js +167 -170
  101. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  102. package/dist/bigconsole/pages/DataSinkBuilderPage.js +204 -189
  103. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  104. package/dist/bigconsole/pages/DataSinkViewPage.js +175 -169
  105. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  106. package/dist/bigconsole/pages/DataSourcesPage.js +8 -7
  107. package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
  108. package/dist/bigconsole/pages/InsightsPage.js +238 -208
  109. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  110. package/dist/bigconsole/pages/ParserBuilderPage.js +464 -412
  111. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  112. package/dist/bigconsole/pages/ParserViewPage.js +92 -90
  113. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  114. package/dist/bigconsole/pages/PipelineBuilderPage.js +221 -194
  115. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  116. package/dist/bigconsole/pages/PipelineViewPage.js +181 -184
  117. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  118. package/dist/bigconsole/pages/PipelinesPage.js +128 -127
  119. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  120. package/dist/bigconsole/pages/SettingsPage.js +177 -172
  121. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  122. package/dist/bigconsole/pages/WidgetDemoPage.js +121 -83
  123. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  124. package/dist/bigconsole/pages/WorkflowViewPage.js +199 -193
  125. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  126. package/dist/bigconsole/pages/WorkflowsPage.js +129 -128
  127. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  128. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +111 -109
  129. package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
  130. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +127 -126
  131. package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
  132. package/dist/bigconsole/renderers/adapters/CustomRenderer.js +103 -103
  133. package/dist/bigconsole/renderers/adapters/CustomRenderer.js.map +1 -1
  134. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ParserSelector.js","names":[],"sources":["../../../../src/bigconsole/components/parser/ParserSelector.tsx"],"sourcesContent":["/**\n * Parser Selector\n *\n * Dropdown component for selecting a parser.\n * Shows both dashboard-specific parsers and global parsers.\n */\n\nimport { memo, useState, useEffect, useCallback, Fragment, useMemo } from 'react';\nimport { Plus } from 'lucide-react';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { useBuildPath } from '../../contexts';\nimport { ParserTypeBadge } from './ParserTypeBadge';\nimport { ParserStatusBadge } from './ParserStatusBadge';\nimport type { ParserType, ParserStatus } from '../../types';\n\n// Default console ID for global parsers\nconst DEFAULT_CONSOLE_ID = 'default';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ParserSelectorProps {\n /** Console ID */\n consoleId: string;\n /** Currently selected parser ID */\n value: string | null;\n /** Callback when selection changes */\n onChange: (id: string | null) => void;\n /** Filter by type */\n filterType?: ParserType;\n /** Filter by status */\n filterStatus?: ParserStatus;\n /** Filter by input DataSink key */\n filterInputSinkKey?: string | null;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Whether to show error state */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst ChevronDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst GlobeIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 21a9 9 0 100-18 9 9 0 000 18z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M3.6 9h16.8M3.6 15h16.8\" />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 3a15 15 0 014 9 15 15 0 01-4 9 15 15 0 01-4-9 15 15 0 014-9z\"\n />\n </svg>\n);\n\n// ============================================================================\n// PARSER OPTION BUTTON\n// ============================================================================\n\ninterface ParserOptionButtonProps {\n parser: {\n id: string;\n name: string;\n description: string | null;\n type: 'jq' | 'jsonata';\n inputSinkKey: string;\n outputKey: string;\n status: 'active' | 'inactive';\n };\n isSelected: boolean;\n onSelect: (id: string) => void;\n isGlobal?: boolean;\n}\n\nconst ParserOptionButton = memo(function ParserOptionButton({\n parser,\n isSelected,\n onSelect,\n isGlobal = false,\n}: ParserOptionButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(parser.id)}\n className={`\n w-full px-3 py-2.5\n text-left\n hover:bg-bg-sunken\n transition-colors\n border-b border-border-default last:border-b-0\n ${isSelected ? 'bg-action-primary-bg/10' : ''}\n `}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n {/* Name and type */}\n <div className=\"flex items-center gap-2 mb-1\">\n <ParserTypeBadge type={parser.type} size=\"sm\" />\n <span className=\"text-sm font-medium text-text-primary truncate\">{parser.name}</span>\n {isGlobal && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n <GlobeIcon className=\"w-3 h-3\" />\n Global\n </span>\n )}\n </div>\n\n {/* Description */}\n {parser.description && <p className=\"text-xs text-text-secondary line-clamp-1 mb-1\">{parser.description}</p>}\n\n {/* Data flow */}\n <div className=\"flex items-center gap-2 text-xs text-text-tertiary\">\n <span>\n {parser.inputSinkKey} → {parser.outputKey}\n </span>\n </div>\n </div>\n\n {/* Status badge */}\n <div>\n <ParserStatusBadge status={parser.status} size=\"sm\" showIcon={false} />\n </div>\n </div>\n </button>\n );\n});\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport const ParserSelector = memo(function ParserSelector({\n consoleId,\n value,\n onChange,\n filterType,\n filterStatus = 'active',\n filterInputSinkKey,\n placeholder = 'Select a parser...',\n disabled = false,\n error = false,\n errorMessage,\n}: ParserSelectorProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n\n const buildPath = useBuildPath();\n\n // Determine if we need to fetch global parsers separately\n const isGlobalConsole = consoleId === DEFAULT_CONSOLE_ID;\n\n // Fetch dashboard-specific parsers\n const {\n parsers: dashboardParsers,\n loading: dashboardLoading,\n fetchParsers: fetchDashboardParsers,\n } = useParserOperations({\n consoleId,\n skipFetch: isGlobalConsole, // Skip if already fetching global\n });\n\n // Fetch global parsers (only if consoleId is not already 'default')\n const {\n parsers: globalParsers,\n loading: globalLoading,\n fetchParsers: fetchGlobalParsers,\n } = useParserOperations({\n consoleId: DEFAULT_CONSOLE_ID,\n skipFetch: isGlobalConsole, // Skip if consoleId is already 'default'\n });\n\n // Combine parsers: dashboard-specific + global (avoiding duplicates)\n const allParsers = useMemo(() => {\n if (isGlobalConsole) {\n // If we're already on global console, just return dashboard parsers\n return dashboardParsers;\n }\n\n // Combine both, with dashboard parsers first\n const parserIds = new Set(dashboardParsers.map((p) => p.id));\n const uniqueGlobalParsers = globalParsers.filter((p) => !parserIds.has(p.id));\n\n return [...dashboardParsers, ...uniqueGlobalParsers];\n }, [dashboardParsers, globalParsers, isGlobalConsole]);\n\n // Combined loading state\n const loading = dashboardLoading || globalLoading;\n\n // Filter parsers\n const filteredParsers = useMemo(() => {\n return allParsers.filter((p) => {\n // Filter by type if specified\n if (filterType && p.type !== filterType) return false;\n\n // Filter by status if specified\n if (filterStatus && p.status !== filterStatus) return false;\n\n // Filter by input DataSink key if specified\n if (filterInputSinkKey && p.inputSinkKey !== filterInputSinkKey) return false;\n\n // Filter by search query\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return (\n p.name.toLowerCase().includes(query) ||\n p.description?.toLowerCase().includes(query) ||\n p.inputSinkKey.toLowerCase().includes(query) ||\n p.outputKey.toLowerCase().includes(query)\n );\n }\n\n return true;\n });\n }, [allParsers, filterType, filterStatus, filterInputSinkKey, searchQuery]);\n\n // Group parsers by scope for display\n const { dashboardScopedParsers, globalScopedParsers } = useMemo(() => {\n const dashboard = filteredParsers.filter((p) => p.consoleId !== DEFAULT_CONSOLE_ID);\n const global = filteredParsers.filter((p) => p.consoleId === DEFAULT_CONSOLE_ID);\n return { dashboardScopedParsers: dashboard, globalScopedParsers: global };\n }, [filteredParsers]);\n\n // Find selected parser\n const selectedParser = allParsers.find((p) => p.id === value);\n\n // Fetch parsers when console changes or DataSink filter changes\n useEffect(() => {\n if (consoleId) {\n fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n\n // Also fetch global parsers if not already on global console\n if (!isGlobalConsole) {\n fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n }, [\n consoleId,\n filterType,\n filterStatus,\n filterInputSinkKey,\n fetchDashboardParsers,\n fetchGlobalParsers,\n isGlobalConsole,\n ]);\n\n // Handle selection\n const handleSelect = useCallback(\n (id: string | null) => {\n onChange(id);\n setIsOpen(false);\n setSearchQuery('');\n },\n [onChange]\n );\n\n // Toggle dropdown\n const handleToggle = useCallback(() => {\n if (disabled) return;\n const next = !isOpen;\n // Refetch on open so a parser created via the \"Create new\" tab shows\n // up here without needing a full page reload.\n if (next) {\n void fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n if (!isGlobalConsole) {\n void fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n setIsOpen(next);\n }, [disabled, isOpen, fetchDashboardParsers, fetchGlobalParsers, filterType, filterStatus, isGlobalConsole]);\n\n // Close dropdown\n const handleClose = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n // Open the create-Parser page in a new tab so the current editing\n // context (e.g. an unsaved widget in the dashboard builder) is preserved.\n // Preserve the dashboard scope so the new parser is created for this\n // console rather than as a global parser.\n const handleCreateNew = useCallback(() => {\n setIsOpen(false);\n const path = isGlobalConsole ? '/parsers/new' : `/dashboards/${consoleId}/parsers/new`;\n window.open(buildPath(path), '_blank', 'noopener,noreferrer');\n }, [buildPath, consoleId, isGlobalConsole]);\n\n return (\n <div className=\"relative\">\n {/* Trigger button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={`\n w-full\n px-3 py-2\n bg-bg-surface\n border rounded-md\n text-left\n flex items-center justify-between gap-2\n transition-colors\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:border-action-primary-bg cursor-pointer'}\n ${error ? 'border-status-error-border' : 'border-border-default'}\n ${isOpen ? 'border-action-primary-bg ring-2 ring-action-primary-bg/20' : ''}\n `}\n >\n <div className=\"flex-1 min-w-0\">\n {selectedParser ? (\n <div className=\"flex items-center gap-2\">\n <ParserTypeBadge type={selectedParser.type} size=\"sm\" />\n <span className=\"text-sm text-text-primary truncate\">{selectedParser.name}</span>\n </div>\n ) : (\n <span className=\"text-sm text-text-tertiary\">{placeholder}</span>\n )}\n </div>\n\n <ChevronDownIcon\n className={`w-4 h-4 text-text-secondary transition-transform ${isOpen ? 'transform rotate-180' : ''}`}\n />\n </button>\n\n {/* Error message */}\n {error && errorMessage && <p className=\"mt-1 text-xs text-status-error-text\">{errorMessage}</p>}\n\n {/* Dropdown */}\n {isOpen && (\n <Fragment>\n {/* Backdrop */}\n <div className=\"fixed inset-0 z-10\" onClick={handleClose} />\n\n {/* Dropdown content */}\n <div className=\"absolute left-0 right-0 top-full mt-1 z-20 bg-bg-surface border border-border-default rounded-md shadow-lg max-h-80 flex flex-col overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-border-default\">\n <input\n type=\"text\"\n placeholder=\"Search parsers...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={`\n w-full px-3 py-2\n bg-bg-sunken\n border border-border-default\n rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n `}\n />\n </div>\n\n {/* Options list */}\n <div className=\"overflow-y-auto flex-1\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">Loading parsers...</div>\n ) : filteredParsers.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">No parsers found</div>\n ) : (\n <Fragment>\n {/* None option */}\n <button\n type=\"button\"\n onClick={() => handleSelect(null)}\n className={`\n w-full px-3 py-2\n text-left text-sm\n hover:bg-bg-sunken\n transition-colors\n ${value === null ? 'bg-action-primary-bg/10 text-action-primary-bg' : 'text-text-secondary'}\n `}\n >\n <span className=\"italic\">None</span>\n </button>\n\n {/* Dashboard-scoped parsers section */}\n {dashboardScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Dashboard Parsers\n </span>\n </div>\n {dashboardScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n />\n ))}\n </Fragment>\n )}\n\n {/* Global parsers section */}\n {globalScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n Global Parsers\n </span>\n </div>\n {globalScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n isGlobal\n />\n ))}\n </Fragment>\n )}\n </Fragment>\n )}\n </div>\n\n {/* Create new — persistent footer action (opens in a new tab) */}\n <div className=\"p-2 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={handleCreateNew}\n className=\"\n w-full flex items-center gap-2\n px-3 py-2\n text-sm font-medium text-action-primary-bg\n rounded-md\n hover:bg-action-primary-bg/10\n transition-colors\n \"\n >\n <Plus className=\"w-4 h-4\" />\n Create new parser\n </button>\n </div>\n </div>\n </Fragment>\n )}\n </div>\n );\n});\n\nexport default ParserSelector;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ParserSelector.js","names":[],"sources":["../../../../src/bigconsole/components/parser/ParserSelector.tsx"],"sourcesContent":["/**\n * Parser Selector\n *\n * Dropdown component for selecting a parser.\n * Shows both dashboard-specific parsers and global parsers.\n */\n\nimport { memo, useState, useEffect, useCallback, Fragment, useMemo } from 'react';\nimport { Plus } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { useBuildPath } from '../../contexts';\nimport { ParserTypeBadge } from './ParserTypeBadge';\nimport { ParserStatusBadge } from './ParserStatusBadge';\nimport type { ParserType, ParserStatus } from '../../types';\n\n// Default console ID for global parsers\nconst DEFAULT_CONSOLE_ID = 'default';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface ParserSelectorProps {\n /** Console ID */\n consoleId: string;\n /** Currently selected parser ID */\n value: string | null;\n /** Callback when selection changes */\n onChange: (id: string | null) => void;\n /** Filter by type */\n filterType?: ParserType;\n /** Filter by status */\n filterStatus?: ParserStatus;\n /** Filter by input DataSink key */\n filterInputSinkKey?: string | null;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Whether to show error state */\n error?: boolean;\n /** Error message to display */\n errorMessage?: string;\n}\n\n// ============================================================================\n// ICONS\n// ============================================================================\n\nconst ChevronDownIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\nconst GlobeIcon = ({ className }: { className?: string }) => (\n <svg className={className} fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 21a9 9 0 100-18 9 9 0 000 18z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M3.6 9h16.8M3.6 15h16.8\" />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 3a15 15 0 014 9 15 15 0 01-4 9 15 15 0 01-4-9 15 15 0 014-9z\"\n />\n </svg>\n);\n\n// ============================================================================\n// PARSER OPTION BUTTON\n// ============================================================================\n\ninterface ParserOptionButtonProps {\n parser: {\n id: string;\n name: string;\n description: string | null;\n type: 'jq' | 'jsonata';\n inputSinkKey: string;\n outputKey: string;\n status: 'active' | 'inactive';\n };\n isSelected: boolean;\n onSelect: (id: string) => void;\n isGlobal?: boolean;\n}\n\nconst ParserOptionButton = memo(function ParserOptionButton({\n parser,\n isSelected,\n onSelect,\n isGlobal = false,\n}: ParserOptionButtonProps) {\n const { t } = useI18n();\n return (\n <button\n type=\"button\"\n onClick={() => onSelect(parser.id)}\n className={`\n w-full px-3 py-2.5\n text-left\n hover:bg-bg-sunken\n transition-colors\n border-b border-border-default last:border-b-0\n ${isSelected ? 'bg-action-primary-bg/10' : ''}\n `}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\n {/* Name and type */}\n <div className=\"flex items-center gap-2 mb-1\">\n <ParserTypeBadge type={parser.type} size=\"sm\" />\n <span className=\"text-sm font-medium text-text-primary truncate\">{parser.name}</span>\n {isGlobal && (\n <span className=\"inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n <GlobeIcon className=\"w-3 h-3\" />\n {t('bigconsole.parsers.selector.globalBadge', 'Global')}\n </span>\n )}\n </div>\n\n {/* Description */}\n {parser.description && <p className=\"text-xs text-text-secondary line-clamp-1 mb-1\">{parser.description}</p>}\n\n {/* Data flow */}\n <div className=\"flex items-center gap-2 text-xs text-text-tertiary\">\n <span>\n {parser.inputSinkKey} → {parser.outputKey}\n </span>\n </div>\n </div>\n\n {/* Status badge */}\n <div>\n <ParserStatusBadge status={parser.status} size=\"sm\" showIcon={false} />\n </div>\n </div>\n </button>\n );\n});\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport const ParserSelector = memo(function ParserSelector({\n consoleId,\n value,\n onChange,\n filterType,\n filterStatus = 'active',\n filterInputSinkKey,\n placeholder,\n disabled = false,\n error = false,\n errorMessage,\n}: ParserSelectorProps) {\n const { t } = useI18n();\n const [isOpen, setIsOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n\n const resolvedPlaceholder = placeholder ?? t('bigconsole.parsers.selector.placeholder', 'Select a parser...');\n\n const buildPath = useBuildPath();\n\n // Determine if we need to fetch global parsers separately\n const isGlobalConsole = consoleId === DEFAULT_CONSOLE_ID;\n\n // Fetch dashboard-specific parsers\n const {\n parsers: dashboardParsers,\n loading: dashboardLoading,\n fetchParsers: fetchDashboardParsers,\n } = useParserOperations({\n consoleId,\n skipFetch: isGlobalConsole, // Skip if already fetching global\n });\n\n // Fetch global parsers (only if consoleId is not already 'default')\n const {\n parsers: globalParsers,\n loading: globalLoading,\n fetchParsers: fetchGlobalParsers,\n } = useParserOperations({\n consoleId: DEFAULT_CONSOLE_ID,\n skipFetch: isGlobalConsole, // Skip if consoleId is already 'default'\n });\n\n // Combine parsers: dashboard-specific + global (avoiding duplicates)\n const allParsers = useMemo(() => {\n if (isGlobalConsole) {\n // If we're already on global console, just return dashboard parsers\n return dashboardParsers;\n }\n\n // Combine both, with dashboard parsers first\n const parserIds = new Set(dashboardParsers.map((p) => p.id));\n const uniqueGlobalParsers = globalParsers.filter((p) => !parserIds.has(p.id));\n\n return [...dashboardParsers, ...uniqueGlobalParsers];\n }, [dashboardParsers, globalParsers, isGlobalConsole]);\n\n // Combined loading state\n const loading = dashboardLoading || globalLoading;\n\n // Filter parsers\n const filteredParsers = useMemo(() => {\n return allParsers.filter((p) => {\n // Filter by type if specified\n if (filterType && p.type !== filterType) return false;\n\n // Filter by status if specified\n if (filterStatus && p.status !== filterStatus) return false;\n\n // Filter by input DataSink key if specified\n if (filterInputSinkKey && p.inputSinkKey !== filterInputSinkKey) return false;\n\n // Filter by search query\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n return (\n p.name.toLowerCase().includes(query) ||\n p.description?.toLowerCase().includes(query) ||\n p.inputSinkKey.toLowerCase().includes(query) ||\n p.outputKey.toLowerCase().includes(query)\n );\n }\n\n return true;\n });\n }, [allParsers, filterType, filterStatus, filterInputSinkKey, searchQuery]);\n\n // Group parsers by scope for display\n const { dashboardScopedParsers, globalScopedParsers } = useMemo(() => {\n const dashboard = filteredParsers.filter((p) => p.consoleId !== DEFAULT_CONSOLE_ID);\n const global = filteredParsers.filter((p) => p.consoleId === DEFAULT_CONSOLE_ID);\n return { dashboardScopedParsers: dashboard, globalScopedParsers: global };\n }, [filteredParsers]);\n\n // Find selected parser\n const selectedParser = allParsers.find((p) => p.id === value);\n\n // Fetch parsers when console changes or DataSink filter changes\n useEffect(() => {\n if (consoleId) {\n fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n\n // Also fetch global parsers if not already on global console\n if (!isGlobalConsole) {\n fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n }, [\n consoleId,\n filterType,\n filterStatus,\n filterInputSinkKey,\n fetchDashboardParsers,\n fetchGlobalParsers,\n isGlobalConsole,\n ]);\n\n // Handle selection\n const handleSelect = useCallback(\n (id: string | null) => {\n onChange(id);\n setIsOpen(false);\n setSearchQuery('');\n },\n [onChange]\n );\n\n // Toggle dropdown\n const handleToggle = useCallback(() => {\n if (disabled) return;\n const next = !isOpen;\n // Refetch on open so a parser created via the \"Create new\" tab shows\n // up here without needing a full page reload.\n if (next) {\n void fetchDashboardParsers({ type: filterType, status: filterStatus ?? undefined });\n if (!isGlobalConsole) {\n void fetchGlobalParsers({ type: filterType, status: filterStatus ?? undefined });\n }\n }\n setIsOpen(next);\n }, [disabled, isOpen, fetchDashboardParsers, fetchGlobalParsers, filterType, filterStatus, isGlobalConsole]);\n\n // Close dropdown\n const handleClose = useCallback(() => {\n setIsOpen(false);\n }, []);\n\n // Open the create-Parser page in a new tab so the current editing\n // context (e.g. an unsaved widget in the dashboard builder) is preserved.\n // Preserve the dashboard scope so the new parser is created for this\n // console rather than as a global parser.\n const handleCreateNew = useCallback(() => {\n setIsOpen(false);\n const path = isGlobalConsole ? '/parsers/new' : `/dashboards/${consoleId}/parsers/new`;\n window.open(buildPath(path), '_blank', 'noopener,noreferrer');\n }, [buildPath, consoleId, isGlobalConsole]);\n\n return (\n <div className=\"relative\">\n {/* Trigger button */}\n <button\n type=\"button\"\n onClick={handleToggle}\n disabled={disabled}\n className={`\n w-full\n px-3 py-2\n bg-bg-surface\n border rounded-md\n text-left\n flex items-center justify-between gap-2\n transition-colors\n ${disabled ? 'opacity-50 cursor-not-allowed' : 'hover:border-action-primary-bg cursor-pointer'}\n ${error ? 'border-status-error-border' : 'border-border-default'}\n ${isOpen ? 'border-action-primary-bg ring-2 ring-action-primary-bg/20' : ''}\n `}\n >\n <div className=\"flex-1 min-w-0\">\n {selectedParser ? (\n <div className=\"flex items-center gap-2\">\n <ParserTypeBadge type={selectedParser.type} size=\"sm\" />\n <span className=\"text-sm text-text-primary truncate\">{selectedParser.name}</span>\n </div>\n ) : (\n <span className=\"text-sm text-text-tertiary\">{resolvedPlaceholder}</span>\n )}\n </div>\n\n <ChevronDownIcon\n className={`w-4 h-4 text-text-secondary transition-transform ${isOpen ? 'transform rotate-180' : ''}`}\n />\n </button>\n\n {/* Error message */}\n {error && errorMessage && <p className=\"mt-1 text-xs text-status-error-text\">{errorMessage}</p>}\n\n {/* Dropdown */}\n {isOpen && (\n <Fragment>\n {/* Backdrop */}\n <div className=\"fixed inset-0 z-10\" onClick={handleClose} />\n\n {/* Dropdown content */}\n <div className=\"absolute left-0 right-0 top-full mt-1 z-20 bg-bg-surface border border-border-default rounded-md shadow-lg max-h-80 flex flex-col overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-border-default\">\n <input\n type=\"text\"\n placeholder={t('bigconsole.parsers.selector.searchPlaceholder', 'Search parsers...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={`\n w-full px-3 py-2\n bg-bg-sunken\n border border-border-default\n rounded-md\n text-sm text-text-primary\n placeholder-text-tertiary\n focus:outline-none\n focus:border-action-primary-bg\n focus:ring-2\n focus:ring-action-primary-bg/20\n `}\n />\n </div>\n\n {/* Options list */}\n <div className=\"overflow-y-auto flex-1\">\n {loading ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">\n {t('bigconsole.parsers.selector.loading', 'Loading parsers...')}\n </div>\n ) : filteredParsers.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-text-secondary\">\n {t('bigconsole.parsers.selector.empty', 'No parsers found')}\n </div>\n ) : (\n <Fragment>\n {/* None option */}\n <button\n type=\"button\"\n onClick={() => handleSelect(null)}\n className={`\n w-full px-3 py-2\n text-left text-sm\n hover:bg-bg-sunken\n transition-colors\n ${value === null ? 'bg-action-primary-bg/10 text-action-primary-bg' : 'text-text-secondary'}\n `}\n >\n <span className=\"italic\">{t('bigconsole.parsers.selector.none', 'None')}</span>\n </button>\n\n {/* Dashboard-scoped parsers section */}\n {dashboardScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n {t('bigconsole.parsers.selector.dashboardParsers', 'Dashboard Parsers')}\n </span>\n </div>\n {dashboardScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n />\n ))}\n </Fragment>\n )}\n\n {/* Global parsers section */}\n {globalScopedParsers.length > 0 && (\n <Fragment>\n <div className=\"px-3 py-1.5 bg-bg-sunken border-y border-border-default\">\n <span className=\"text-xs font-medium text-text-secondary uppercase tracking-wide\">\n {t('bigconsole.parsers.selector.globalParsers', 'Global Parsers')}\n </span>\n </div>\n {globalScopedParsers.map((parser) => (\n <ParserOptionButton\n key={parser.id}\n parser={parser}\n isSelected={value === parser.id}\n onSelect={handleSelect}\n isGlobal\n />\n ))}\n </Fragment>\n )}\n </Fragment>\n )}\n </div>\n\n {/* Create new — persistent footer action (opens in a new tab) */}\n <div className=\"p-2 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={handleCreateNew}\n className=\"\n w-full flex items-center gap-2\n px-3 py-2\n text-sm font-medium text-action-primary-bg\n rounded-md\n hover:bg-action-primary-bg/10\n transition-colors\n \"\n >\n <Plus className=\"w-4 h-4\" />\n {t('bigconsole.parsers.selector.createNew', 'Create new parser')}\n </button>\n </div>\n </div>\n </Fragment>\n )}\n </div>\n );\n});\n\nexport default ParserSelector;\n"],"mappings":"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"}
@@ -2,132 +2,135 @@ import { useAssistantRunStore as e } from "../../assistant/assistantRunStore.js"
2
2
  import { StepRail as t, formatAgo as n, useAssistantSidebarWidth as r } from "./previewShared.js";
3
3
  import { useEffect as i, useState as a } from "react";
4
4
  import { ArrowUpRight as o, Loader2 as s, Sparkles as c, X as l } from "lucide-react";
5
- import { Button as u } from "@burdenoff/fe-libs/ui";
6
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
5
+ import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
+ import { Button as d } from "@burdenoff/fe-libs/ui";
7
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
8
  //#region src/bigconsole/components/preview/AiPreviewMiniPanel.tsx
8
- function p({ onNavigate: p }) {
9
- let m = e((e) => e.isRunning), h = e((e) => e.previewOpen), g = e((e) => e.hasRun), _ = e((e) => e.richMounted), v = e((e) => e.steps), y = e((e) => e.entityIds), b = e((e) => e.caption), x = e((e) => e.error), S = e((e) => e.updatedAt), C = e((e) => e.openPreview), w = e((e) => e.closePreview), [T, E] = a(() => Date.now());
9
+ function m({ onNavigate: m }) {
10
+ let { t: h } = u(), g = e((e) => e.isRunning), _ = e((e) => e.previewOpen), v = e((e) => e.hasRun), y = e((e) => e.richMounted), b = e((e) => e.steps), x = e((e) => e.entityIds), S = e((e) => e.caption), C = e((e) => e.error), w = e((e) => e.updatedAt), T = e((e) => e.openPreview), E = e((e) => e.closePreview), [D, O] = a(() => Date.now());
10
11
  i(() => {
11
- if (!m) return;
12
- let e = window.setInterval(() => E(Date.now()), 1e3);
12
+ if (!g) return;
13
+ let e = window.setInterval(() => O(Date.now()), 1e3);
13
14
  return () => window.clearInterval(e);
14
- }, [m]);
15
- let D = r(), O = (e) => {
16
- p ? p(e) : typeof window < "u" && window.location.assign(e);
15
+ }, [g]);
16
+ let k = r(), A = (e) => {
17
+ m ? m(e) : typeof window < "u" && window.location.assign(e);
17
18
  };
18
- if (!g || _) return null;
19
- if (!h) return /* @__PURE__ */ d("div", {
19
+ if (!v || y) return null;
20
+ if (!_) return /* @__PURE__ */ f("div", {
20
21
  className: "flex justify-end px-4 pt-1 md:px-6",
21
- style: { marginRight: D },
22
- children: /* @__PURE__ */ f(u, {
22
+ style: { marginRight: k },
23
+ children: /* @__PURE__ */ p(d, {
23
24
  size: "sm",
24
25
  variant: "outline",
25
- onClick: C,
26
+ onClick: T,
26
27
  "data-testid": "ai-preview-open",
27
28
  children: [
28
- /* @__PURE__ */ d(c, { className: "mr-1.5 size-4" }),
29
- "Preview",
30
- m ? /* @__PURE__ */ d(s, { className: "ml-1.5 size-3.5 animate-spin" }) : null
29
+ /* @__PURE__ */ f(c, { className: "mr-1.5 size-4" }),
30
+ h("bigconsole.widget.aiPreviewMini.previewButton", "Preview"),
31
+ g ? /* @__PURE__ */ f(s, { className: "ml-1.5 size-3.5 animate-spin" }) : null
31
32
  ]
32
33
  })
33
34
  });
34
- let k = S ? Math.max(0, Math.floor((T - S) / 1e3)) : 0, A = [];
35
- return y.datasink && A.push({
35
+ let j = w ? Math.max(0, Math.floor((D - w) / 1e3)) : 0, M = [];
36
+ return x.datasink && M.push({
36
37
  key: "datasink",
37
- label: "Data Sink",
38
- path: `/bigconsole/datasinks/${y.datasink}`
39
- }), y.dashboard && A.push({
38
+ label: h("bigconsole.widget.aiPreviewMini.link.dataSink", "Data Sink"),
39
+ path: `/bigconsole/datasinks/${x.datasink}`
40
+ }), x.dashboard && M.push({
40
41
  key: "dashboard",
41
- label: "Dashboard",
42
- path: `/bigconsole/dashboards/${y.dashboard}`
43
- }), y.parser && A.push({
42
+ label: h("bigconsole.widget.aiPreviewMini.link.dashboard", "Dashboard"),
43
+ path: `/bigconsole/dashboards/${x.dashboard}`
44
+ }), x.parser && M.push({
44
45
  key: "parser",
45
- label: "Parser",
46
- path: `/bigconsole/parsers/${y.parser}`
47
- }), /* @__PURE__ */ f("section", {
46
+ label: h("bigconsole.widget.aiPreviewMini.link.parser", "Parser"),
47
+ path: `/bigconsole/parsers/${x.parser}`
48
+ }), /* @__PURE__ */ p("section", {
48
49
  "data-testid": "ai-preview-panel",
49
50
  "data-variant": "mini",
50
- "aria-label": "AI preview",
51
- style: { marginRight: D ? D + 16 : void 0 },
51
+ "aria-label": h("bigconsole.widget.aiPreviewMini.ariaLabel", "AI preview"),
52
+ style: { marginRight: k ? k + 16 : void 0 },
52
53
  className: "mx-4 mt-1 mb-3 overflow-hidden rounded-lg border border-border-default bg-bg-sunken shadow-sm md:mx-6",
53
54
  children: [
54
- /* @__PURE__ */ f("div", {
55
+ /* @__PURE__ */ p("div", {
55
56
  className: "flex items-center justify-between gap-3 border-b border-border-subtle bg-bg-surface px-3 py-2",
56
- children: [/* @__PURE__ */ f("div", {
57
+ children: [/* @__PURE__ */ p("div", {
57
58
  className: "flex min-w-0 items-center gap-2",
58
59
  children: [
59
- /* @__PURE__ */ d(c, { className: "size-4 shrink-0 text-action-primary-bg" }),
60
- /* @__PURE__ */ d("h2", {
60
+ /* @__PURE__ */ f(c, { className: "size-4 shrink-0 text-action-primary-bg" }),
61
+ /* @__PURE__ */ f("h2", {
61
62
  className: "truncate text-sm font-semibold text-text-primary",
62
- children: "AI Preview"
63
+ children: h("bigconsole.widget.aiPreviewMini.title", "AI Preview")
63
64
  }),
64
- m ? /* @__PURE__ */ f("span", {
65
+ g ? /* @__PURE__ */ p("span", {
65
66
  className: "inline-flex items-center gap-1.5 rounded-full bg-status-success-bg px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-status-success-text",
66
67
  "data-testid": "ai-preview-live",
67
- children: [/* @__PURE__ */ f("span", {
68
+ children: [/* @__PURE__ */ p("span", {
68
69
  className: "relative flex size-2",
69
- children: [/* @__PURE__ */ d("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-status-success-text opacity-75" }), /* @__PURE__ */ d("span", { className: "relative inline-flex size-2 rounded-full bg-status-success-text" })]
70
- }), "Live"]
70
+ children: [/* @__PURE__ */ f("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-status-success-text opacity-75" }), /* @__PURE__ */ f("span", { className: "relative inline-flex size-2 rounded-full bg-status-success-text" })]
71
+ }), h("bigconsole.widget.aiPreviewMini.live", "Live")]
71
72
  }) : null,
72
- /* @__PURE__ */ f("span", {
73
+ /* @__PURE__ */ p("span", {
73
74
  className: "truncate text-xs text-text-muted",
74
75
  "data-testid": "ai-preview-ago",
75
76
  children: [
76
- m ? b || "Working…" : x ? "Stopped" : "Done",
77
- " · updated",
77
+ g ? S || h("bigconsole.widget.aiPreviewMini.working", "Working…") : C ? h("bigconsole.widget.aiPreviewMini.stopped", "Stopped") : h("bigconsole.widget.aiPreviewMini.done", "Done"),
78
+ " ",
79
+ "· ",
80
+ h("bigconsole.widget.aiPreviewMini.updated", "updated"),
78
81
  " ",
79
- n(k)
82
+ n(j)
80
83
  ]
81
84
  })
82
85
  ]
83
- }), /* @__PURE__ */ d(u, {
86
+ }), /* @__PURE__ */ f(d, {
84
87
  size: "sm",
85
88
  variant: "ghost",
86
- onClick: w,
87
- "aria-label": "Close preview",
89
+ onClick: E,
90
+ "aria-label": h("bigconsole.widget.aiPreviewMini.closeAriaLabel", "Close preview"),
88
91
  "data-testid": "ai-preview-close",
89
- children: /* @__PURE__ */ d(l, { className: "size-4" })
92
+ children: /* @__PURE__ */ f(l, { className: "size-4" })
90
93
  })]
91
94
  }),
92
- /* @__PURE__ */ d("div", {
95
+ /* @__PURE__ */ f("div", {
93
96
  className: "border-b border-border-subtle px-3 py-2",
94
- children: /* @__PURE__ */ d(t, { steps: v })
97
+ children: /* @__PURE__ */ f(t, { steps: b })
95
98
  }),
96
- /* @__PURE__ */ f("div", {
99
+ /* @__PURE__ */ p("div", {
97
100
  className: "space-y-2 p-3",
98
- children: [A.length === 0 ? /* @__PURE__ */ d("p", {
101
+ children: [M.length === 0 ? /* @__PURE__ */ f("p", {
99
102
  className: "px-1 py-4 text-sm text-text-muted",
100
- children: m ? "Building… links appear here as each piece is created." : "Nothing built yet."
101
- }) : A.map((e) => /* @__PURE__ */ f("div", {
103
+ children: g ? h("bigconsole.widget.aiPreviewMini.building", "Building… links appear here as each piece is created.") : h("bigconsole.widget.aiPreviewMini.nothingBuilt", "Nothing built yet.")
104
+ }) : M.map((e) => /* @__PURE__ */ p("div", {
102
105
  "data-testid": "ai-preview-row",
103
106
  className: "flex items-center justify-between gap-3 rounded-md border border-border-subtle bg-bg-surface px-3 py-2",
104
107
  children: [/* @__PURE__ */ f("p", {
105
108
  className: "truncate text-sm font-medium text-text-primary",
106
- children: [e.label, " ready"]
107
- }), /* @__PURE__ */ f(u, {
109
+ children: h("bigconsole.widget.aiPreviewMini.linkReady", "{{label}} ready", { label: e.label })
110
+ }), /* @__PURE__ */ p(d, {
108
111
  size: "sm",
109
112
  variant: "ghost",
110
- onClick: () => O(e.path),
111
- children: ["Open", /* @__PURE__ */ d(o, { className: "ml-1 size-3.5" })]
113
+ onClick: () => A(e.path),
114
+ children: [h("bigconsole.widget.aiPreviewMini.open", "Open"), /* @__PURE__ */ f(o, { className: "ml-1 size-3.5" })]
112
115
  })]
113
- }, e.key)), y.dashboard ? /* @__PURE__ */ f(u, {
116
+ }, e.key)), x.dashboard ? /* @__PURE__ */ p(d, {
114
117
  size: "sm",
115
118
  variant: "outline",
116
119
  className: "w-full",
117
120
  "data-testid": "ai-preview-open-in-bigconsole",
118
- onClick: () => O(`/bigconsole/dashboards/${y.dashboard ?? ""}`),
119
- children: ["Open in BigConsole for the live view", /* @__PURE__ */ d(o, { className: "ml-1 size-3.5" })]
121
+ onClick: () => A(`/bigconsole/dashboards/${x.dashboard ?? ""}`),
122
+ children: [h("bigconsole.widget.aiPreviewMini.openInBigConsole", "Open in BigConsole for the live view"), /* @__PURE__ */ f(o, { className: "ml-1 size-3.5" })]
120
123
  }) : null]
121
124
  }),
122
- x ? /* @__PURE__ */ d("p", {
125
+ C ? /* @__PURE__ */ f("p", {
123
126
  className: "border-t border-border-subtle px-3 py-2 text-xs text-status-error-text",
124
127
  "data-testid": "ai-preview-error",
125
- children: x
128
+ children: C
126
129
  }) : null
127
130
  ]
128
131
  });
129
132
  }
130
133
  //#endregion
131
- export { p as default };
134
+ export { m as default };
132
135
 
133
136
  //# sourceMappingURL=AiPreviewMiniPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiPreviewMiniPanel.js","names":[],"sources":["../../../../src/bigconsole/components/preview/AiPreviewMiniPanel.tsx"],"sourcesContent":["/**\n * AI Preview — the app-shell copy.\n *\n * The full <AiPreviewPanel> lives inside BigConsoleRoot and only exists on\n * /bigconsole pages, but the assistant widget is global: you can start a build\n * from anywhere. This lightweight panel is mounted by the app shell so the build\n * is visible on WHATEVER page you are on — workflows, store, workspaces, search.\n *\n * It is deliberately store-only: no Apollo, no BigConsole context, no data\n * fetching. That is what lets it mount above the router. It shows the same live\n * step rail and caption as the full panel, plus click-through links to each\n * entity as it lands. The rich per-entity tabs stay on the /bigconsole pages,\n * where the data layer actually exists.\n *\n * It renders nothing while the full panel is up (`richMounted`), so the two\n * never stack. Leave a /bigconsole page mid-run and the full panel unmounts,\n * `richMounted` flips false, and this one takes over without a flicker.\n */\nimport { useEffect, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { ArrowUpRight, Loader2, Sparkles, X } from 'lucide-react';\n\nimport { useAssistantRunStore } from '../../assistant/assistantRunStore';\nimport { StepRail, formatAgo, useAssistantSidebarWidth } from './previewShared';\n\ninterface AiPreviewMiniPanelProps {\n /**\n * Route to an in-app path. The links are absolute (`/bigconsole/...`) because\n * this panel renders outside the BigConsole router. Falls back to a full\n * navigation when the host does not supply a handler.\n */\n onNavigate?: (path: string) => void;\n}\n\ninterface QuickLink {\n key: string;\n label: string;\n path: string;\n}\n\nexport function AiPreviewMiniPanel({ onNavigate }: AiPreviewMiniPanelProps) {\n const isRunning = useAssistantRunStore((state) => state.isRunning);\n const previewOpen = useAssistantRunStore((state) => state.previewOpen);\n const hasRun = useAssistantRunStore((state) => state.hasRun);\n const richMounted = useAssistantRunStore((state) => state.richMounted);\n const steps = useAssistantRunStore((state) => state.steps);\n const entityIds = useAssistantRunStore((state) => state.entityIds);\n const caption = useAssistantRunStore((state) => state.caption);\n const error = useAssistantRunStore((state) => state.error);\n const updatedAt = useAssistantRunStore((state) => state.updatedAt);\n const openPreview = useAssistantRunStore((state) => state.openPreview);\n const closePreview = useAssistantRunStore((state) => state.closePreview);\n\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (!isRunning) return;\n const id = window.setInterval(() => setNow(Date.now()), 1000);\n return () => window.clearInterval(id);\n }, [isRunning]);\n\n const assistantWidth = useAssistantSidebarWidth();\n\n const go = (path: string) => {\n if (onNavigate) onNavigate(path);\n else if (typeof window !== 'undefined') window.location.assign(path);\n };\n\n // Nothing has run, or the full in-context panel is already on screen.\n if (!hasRun || richMounted) return null;\n\n if (!previewOpen) {\n return (\n <div className=\"flex justify-end px-4 pt-1 md:px-6\" style={{ marginRight: assistantWidth }}>\n <Button size=\"sm\" variant=\"outline\" onClick={openPreview} data-testid=\"ai-preview-open\">\n <Sparkles className=\"mr-1.5 size-4\" />\n Preview\n {isRunning ? <Loader2 className=\"ml-1.5 size-3.5 animate-spin\" /> : null}\n </Button>\n </div>\n );\n }\n\n const agoSeconds = updatedAt ? Math.max(0, Math.floor((now - updatedAt) / 1000)) : 0;\n\n const links: QuickLink[] = [];\n if (entityIds.datasink)\n links.push({ key: 'datasink', label: 'Data Sink', path: `/bigconsole/datasinks/${entityIds.datasink}` });\n if (entityIds.dashboard)\n links.push({ key: 'dashboard', label: 'Dashboard', path: `/bigconsole/dashboards/${entityIds.dashboard}` });\n if (entityIds.parser) links.push({ key: 'parser', label: 'Parser', path: `/bigconsole/parsers/${entityIds.parser}` });\n\n return (\n <section\n data-testid=\"ai-preview-panel\"\n data-variant=\"mini\"\n aria-label=\"AI preview\"\n style={{ marginRight: assistantWidth ? assistantWidth + 16 : undefined }}\n className=\"mx-4 mt-1 mb-3 overflow-hidden rounded-lg border border-border-default bg-bg-sunken shadow-sm md:mx-6\"\n >\n {/* Header + live strip */}\n <div className=\"flex items-center justify-between gap-3 border-b border-border-subtle bg-bg-surface px-3 py-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Sparkles className=\"size-4 shrink-0 text-action-primary-bg\" />\n <h2 className=\"truncate text-sm font-semibold text-text-primary\">AI Preview</h2>\n {isRunning ? (\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full bg-status-success-bg px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-status-success-text\"\n data-testid=\"ai-preview-live\"\n >\n <span className=\"relative flex size-2\">\n <span className=\"absolute inline-flex size-full animate-ping rounded-full bg-status-success-text opacity-75\" />\n <span className=\"relative inline-flex size-2 rounded-full bg-status-success-text\" />\n </span>\n Live\n </span>\n ) : null}\n <span className=\"truncate text-xs text-text-muted\" data-testid=\"ai-preview-ago\">\n {isRunning ? (caption ? caption : 'Working…') : error ? 'Stopped' : 'Done'} · updated{' '}\n {formatAgo(agoSeconds)}\n </span>\n </div>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={closePreview}\n aria-label=\"Close preview\"\n data-testid=\"ai-preview-close\"\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n\n {/* Step rail */}\n <div className=\"border-b border-border-subtle px-3 py-2\">\n <StepRail steps={steps} />\n </div>\n\n {/* Quick links to what has been built so far. The full per-entity tabs live\n on the /bigconsole pages; here we surface the direct links instead. */}\n <div className=\"space-y-2 p-3\">\n {links.length === 0 ? (\n <p className=\"px-1 py-4 text-sm text-text-muted\">\n {isRunning ? 'Building… links appear here as each piece is created.' : 'Nothing built yet.'}\n </p>\n ) : (\n links.map((link) => (\n <div\n key={link.key}\n data-testid=\"ai-preview-row\"\n className=\"flex items-center justify-between gap-3 rounded-md border border-border-subtle bg-bg-surface px-3 py-2\"\n >\n <p className=\"truncate text-sm font-medium text-text-primary\">{link.label} ready</p>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => go(link.path)}>\n Open\n <ArrowUpRight className=\"ml-1 size-3.5\" />\n </Button>\n </div>\n ))\n )}\n {entityIds.dashboard ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n data-testid=\"ai-preview-open-in-bigconsole\"\n onClick={() => go(`/bigconsole/dashboards/${entityIds.dashboard ?? ''}`)}\n >\n Open in BigConsole for the live view\n <ArrowUpRight className=\"ml-1 size-3.5\" />\n </Button>\n ) : null}\n </div>\n\n {error ? (\n <p\n className=\"border-t border-border-subtle px-3 py-2 text-xs text-status-error-text\"\n data-testid=\"ai-preview-error\"\n >\n {error}\n </p>\n ) : null}\n </section>\n );\n}\n\nexport default AiPreviewMiniPanel;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AiPreviewMiniPanel.js","names":[],"sources":["../../../../src/bigconsole/components/preview/AiPreviewMiniPanel.tsx"],"sourcesContent":["/**\n * AI Preview — the app-shell copy.\n *\n * The full <AiPreviewPanel> lives inside BigConsoleRoot and only exists on\n * /bigconsole pages, but the assistant widget is global: you can start a build\n * from anywhere. This lightweight panel is mounted by the app shell so the build\n * is visible on WHATEVER page you are on — workflows, store, workspaces, search.\n *\n * It is deliberately store-only: no Apollo, no BigConsole context, no data\n * fetching. That is what lets it mount above the router. It shows the same live\n * step rail and caption as the full panel, plus click-through links to each\n * entity as it lands. The rich per-entity tabs stay on the /bigconsole pages,\n * where the data layer actually exists.\n *\n * It renders nothing while the full panel is up (`richMounted`), so the two\n * never stack. Leave a /bigconsole page mid-run and the full panel unmounts,\n * `richMounted` flips false, and this one takes over without a flicker.\n */\nimport { useEffect, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowUpRight, Loader2, Sparkles, X } from 'lucide-react';\n\nimport { useAssistantRunStore } from '../../assistant/assistantRunStore';\nimport { StepRail, formatAgo, useAssistantSidebarWidth } from './previewShared';\n\ninterface AiPreviewMiniPanelProps {\n /**\n * Route to an in-app path. The links are absolute (`/bigconsole/...`) because\n * this panel renders outside the BigConsole router. Falls back to a full\n * navigation when the host does not supply a handler.\n */\n onNavigate?: (path: string) => void;\n}\n\ninterface QuickLink {\n key: string;\n label: string;\n path: string;\n}\n\nexport function AiPreviewMiniPanel({ onNavigate }: AiPreviewMiniPanelProps) {\n const { t } = useI18n();\n const isRunning = useAssistantRunStore((state) => state.isRunning);\n const previewOpen = useAssistantRunStore((state) => state.previewOpen);\n const hasRun = useAssistantRunStore((state) => state.hasRun);\n const richMounted = useAssistantRunStore((state) => state.richMounted);\n const steps = useAssistantRunStore((state) => state.steps);\n const entityIds = useAssistantRunStore((state) => state.entityIds);\n const caption = useAssistantRunStore((state) => state.caption);\n const error = useAssistantRunStore((state) => state.error);\n const updatedAt = useAssistantRunStore((state) => state.updatedAt);\n const openPreview = useAssistantRunStore((state) => state.openPreview);\n const closePreview = useAssistantRunStore((state) => state.closePreview);\n\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n if (!isRunning) return;\n const id = window.setInterval(() => setNow(Date.now()), 1000);\n return () => window.clearInterval(id);\n }, [isRunning]);\n\n const assistantWidth = useAssistantSidebarWidth();\n\n const go = (path: string) => {\n if (onNavigate) onNavigate(path);\n else if (typeof window !== 'undefined') window.location.assign(path);\n };\n\n // Nothing has run, or the full in-context panel is already on screen.\n if (!hasRun || richMounted) return null;\n\n if (!previewOpen) {\n return (\n <div className=\"flex justify-end px-4 pt-1 md:px-6\" style={{ marginRight: assistantWidth }}>\n <Button size=\"sm\" variant=\"outline\" onClick={openPreview} data-testid=\"ai-preview-open\">\n <Sparkles className=\"mr-1.5 size-4\" />\n {t('bigconsole.widget.aiPreviewMini.previewButton', 'Preview')}\n {isRunning ? <Loader2 className=\"ml-1.5 size-3.5 animate-spin\" /> : null}\n </Button>\n </div>\n );\n }\n\n const agoSeconds = updatedAt ? Math.max(0, Math.floor((now - updatedAt) / 1000)) : 0;\n\n const links: QuickLink[] = [];\n if (entityIds.datasink)\n links.push({\n key: 'datasink',\n label: t('bigconsole.widget.aiPreviewMini.link.dataSink', 'Data Sink'),\n path: `/bigconsole/datasinks/${entityIds.datasink}`,\n });\n if (entityIds.dashboard)\n links.push({\n key: 'dashboard',\n label: t('bigconsole.widget.aiPreviewMini.link.dashboard', 'Dashboard'),\n path: `/bigconsole/dashboards/${entityIds.dashboard}`,\n });\n if (entityIds.parser)\n links.push({\n key: 'parser',\n label: t('bigconsole.widget.aiPreviewMini.link.parser', 'Parser'),\n path: `/bigconsole/parsers/${entityIds.parser}`,\n });\n\n return (\n <section\n data-testid=\"ai-preview-panel\"\n data-variant=\"mini\"\n aria-label={t('bigconsole.widget.aiPreviewMini.ariaLabel', 'AI preview')}\n style={{ marginRight: assistantWidth ? assistantWidth + 16 : undefined }}\n className=\"mx-4 mt-1 mb-3 overflow-hidden rounded-lg border border-border-default bg-bg-sunken shadow-sm md:mx-6\"\n >\n {/* Header + live strip */}\n <div className=\"flex items-center justify-between gap-3 border-b border-border-subtle bg-bg-surface px-3 py-2\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Sparkles className=\"size-4 shrink-0 text-action-primary-bg\" />\n <h2 className=\"truncate text-sm font-semibold text-text-primary\">\n {t('bigconsole.widget.aiPreviewMini.title', 'AI Preview')}\n </h2>\n {isRunning ? (\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full bg-status-success-bg px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-status-success-text\"\n data-testid=\"ai-preview-live\"\n >\n <span className=\"relative flex size-2\">\n <span className=\"absolute inline-flex size-full animate-ping rounded-full bg-status-success-text opacity-75\" />\n <span className=\"relative inline-flex size-2 rounded-full bg-status-success-text\" />\n </span>\n {t('bigconsole.widget.aiPreviewMini.live', 'Live')}\n </span>\n ) : null}\n <span className=\"truncate text-xs text-text-muted\" data-testid=\"ai-preview-ago\">\n {isRunning\n ? caption\n ? caption\n : t('bigconsole.widget.aiPreviewMini.working', 'Working…')\n : error\n ? t('bigconsole.widget.aiPreviewMini.stopped', 'Stopped')\n : t('bigconsole.widget.aiPreviewMini.done', 'Done')}{' '}\n · {t('bigconsole.widget.aiPreviewMini.updated', 'updated')} {formatAgo(agoSeconds)}\n </span>\n </div>\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={closePreview}\n aria-label={t('bigconsole.widget.aiPreviewMini.closeAriaLabel', 'Close preview')}\n data-testid=\"ai-preview-close\"\n >\n <X className=\"size-4\" />\n </Button>\n </div>\n\n {/* Step rail */}\n <div className=\"border-b border-border-subtle px-3 py-2\">\n <StepRail steps={steps} />\n </div>\n\n {/* Quick links to what has been built so far. The full per-entity tabs live\n on the /bigconsole pages; here we surface the direct links instead. */}\n <div className=\"space-y-2 p-3\">\n {links.length === 0 ? (\n <p className=\"px-1 py-4 text-sm text-text-muted\">\n {isRunning\n ? t('bigconsole.widget.aiPreviewMini.building', 'Building… links appear here as each piece is created.')\n : t('bigconsole.widget.aiPreviewMini.nothingBuilt', 'Nothing built yet.')}\n </p>\n ) : (\n links.map((link) => (\n <div\n key={link.key}\n data-testid=\"ai-preview-row\"\n className=\"flex items-center justify-between gap-3 rounded-md border border-border-subtle bg-bg-surface px-3 py-2\"\n >\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {t('bigconsole.widget.aiPreviewMini.linkReady', '{{label}} ready', { label: link.label })}\n </p>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => go(link.path)}>\n {t('bigconsole.widget.aiPreviewMini.open', 'Open')}\n <ArrowUpRight className=\"ml-1 size-3.5\" />\n </Button>\n </div>\n ))\n )}\n {entityIds.dashboard ? (\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n data-testid=\"ai-preview-open-in-bigconsole\"\n onClick={() => go(`/bigconsole/dashboards/${entityIds.dashboard ?? ''}`)}\n >\n {t('bigconsole.widget.aiPreviewMini.openInBigConsole', 'Open in BigConsole for the live view')}\n <ArrowUpRight className=\"ml-1 size-3.5\" />\n </Button>\n ) : null}\n </div>\n\n {error ? (\n <p\n className=\"border-t border-border-subtle px-3 py-2 text-xs text-status-error-text\"\n data-testid=\"ai-preview-error\"\n >\n {error}\n </p>\n ) : null}\n </section>\n );\n}\n\nexport default AiPreviewMiniPanel;\n"],"mappings":"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"}