@burdenoff/microfe-bigconsole 2026.610.1 → 2026.612.1

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 (23) hide show
  1. package/dist/bigconsole/components/widgets/WidgetRegistry.js +2 -1
  2. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  3. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +4 -4
  4. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  5. package/dist/bigconsole/components/widgets/form/FormWidget.js +20 -20
  6. package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
  7. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +1 -1
  8. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  9. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +2 -2
  10. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  11. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +2 -2
  12. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  13. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +37 -37
  14. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  15. package/dist/bigconsole/hooks/useDashboardOperations.js +92 -70
  16. package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
  17. package/dist/bigconsole/pages/DashboardsPage.js +109 -72
  18. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  19. package/dist/bigconsole/pages/InsightsPage.js +783 -395
  20. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  21. package/dist/generated/wspace-operations.js +105 -107
  22. package/dist/generated/wspace-operations.js.map +1 -1
  23. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MapWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/map-widget/MapWidget.tsx"],"sourcesContent":["/**\n * MapWidget Component\n *\n * Displays geographic data with markers (placeholder implementation).\n */\n\nimport { type FC, memo, useCallback } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MapWidgetProps {\n widget: Widget;\n data?: MapData;\n onClick?: (marker: MapMarker) => void;\n /** Drilldown handler - receives selected marker data */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\nexport interface MapMarker {\n name: string;\n lat: number;\n lng: number;\n value?: number;\n popup?: string;\n color?: string;\n}\n\nexport interface MapData {\n center?: { lat: number; lng: number };\n zoom?: number;\n markers?: MapMarker[];\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const MapWidget: FC<MapWidgetProps> = memo(function MapWidget({ widget: _widget, data, onClick, onDrilldown }) {\n const markers = data?.markers || [];\n const center = data?.center || { lat: 0, lng: 0 };\n\n // Handle marker click with drilldown support\n const handleMarkerClick = useCallback(\n (marker: MapMarker) => {\n if (onDrilldown) {\n onDrilldown(marker as unknown as Record<string, unknown>);\n } else if (onClick) {\n onClick(marker);\n }\n },\n [onClick, onDrilldown]\n );\n\n const isClickable = Boolean(onDrilldown || onClick);\n\n if (!markers.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n <p>No map data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4\">\n {/* Map placeholder with markers list */}\n <div className=\"flex-1 relative bg-bg-muted rounded-lg overflow-hidden\">\n {/* Simulated map background */}\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <svg className=\"w-32 h-32 text-text-tertiary/30\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={0.5}\n d=\"M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n </div>\n\n {/* Markers overlay */}\n <div className=\"absolute inset-0 p-4\">\n <div className=\"flex flex-wrap gap-2 justify-center\">\n {markers.slice(0, 8).map((marker, index) => (\n <div\n key={index}\n className={`\n flex items-center gap-1.5 px-2 py-1 rounded-full\n bg-bg-surface border border-border-default shadow-sm\n ${isClickable ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => handleMarkerClick(marker)}\n title={marker.popup || marker.name}\n >\n <div className=\"w-2 h-2 rounded-full\" style={{ backgroundColor: marker.color || '#3b82f6' }} />\n <span className=\"text-xs text-text-primary truncate max-w-[80px]\">{marker.name}</span>\n {marker.value !== undefined && (\n <span className=\"text-xs text-text-secondary\">{marker.value.toLocaleString()}</span>\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Location list */}\n <div className=\"mt-3 space-y-1 max-h-[120px] overflow-auto\">\n {markers.map((marker, index) => (\n <div\n key={index}\n className={`\n flex items-center justify-between p-2 rounded\n hover:bg-bg-muted/50 transition-colors\n ${isClickable ? 'cursor-pointer' : ''}\n `}\n onClick={() => handleMarkerClick(marker)}\n >\n <div className=\"flex items-center gap-2\">\n <div\n className=\"w-2 h-2 rounded-full flex-shrink-0\"\n style={{ backgroundColor: marker.color || '#3b82f6' }}\n />\n <span className=\"text-xs text-text-primary\">{marker.name}</span>\n </div>\n {marker.value !== undefined && (\n <span className=\"text-xs font-medium text-text-secondary\">{marker.value.toLocaleString()}</span>\n )}\n </div>\n ))}\n </div>\n\n {/* Center coordinates */}\n <div className=\"mt-2 pt-2 border-t border-border-default\">\n <p className=\"text-[10px] text-text-tertiary text-center\">\n Center: {center.lat.toFixed(2)}, {center.lng.toFixed(2)}\n </p>\n </div>\n </div>\n );\n});\n\nexport default MapWidget;\n"],"mappings":";;;AAwCA,IAAa,IAAgC,EAAK,SAAmB,EAAE,QAAQ,GAAS,SAAM,YAAS,kBAAe;CACpH,IAAM,IAAU,GAAM,WAAW,EAAE,EAC7B,IAAS,GAAM,UAAU;EAAE,KAAK;EAAG,KAAK;EAAG,EAG3C,IAAoB,GACvB,MAAsB;AACrB,EAAI,IACF,EAAY,EAA6C,GAChD,KACT,EAAQ,EAAO;IAGnB,CAAC,GAAS,EAAY,CACvB,EAEK,IAAc,GAAQ,KAAe;AA0B3C,QAxBK,EAAQ,SAyBX,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;MAAkC,MAAK;MAAO,QAAO;MAAe,SAAQ;gBACzF,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA;KACF,CAAA,EAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,GAAQ,MAChC,kBAAC,OAAD;OAEE,WAAW;;;sBAGL,IAAc,kDAAkD,GAAG;;;OAGzE,eAAe,EAAkB,EAAO;OACxC,OAAO,EAAO,SAAS,EAAO;iBAThC;QAWE,kBAAC,OAAD;SAAK,WAAU;SAAuB,OAAO,EAAE,iBAAiB,EAAO,SAAS,WAAW;SAAI,CAAA;QAC/F,kBAAC,QAAD;SAAM,WAAU;mBAAmD,EAAO;SAAY,CAAA;QACrF,EAAO,UAAU,KAAA,KAChB,kBAAC,QAAD;SAAM,WAAU;mBAA+B,EAAO,MAAM,gBAAgB;SAAQ,CAAA;QAElF;SAfC,EAeD,CACN;MACE,CAAA;KACF,CAAA,CACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,GAAQ,MACpB,kBAAC,OAAD;KAEE,WAAW;;;kBAGL,IAAc,mBAAmB,GAAG;;KAE1C,eAAe,EAAkB,EAAO;eAP1C,CASE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,WAAW;OACrD,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA6B,EAAO;OAAY,CAAA,CAC5D;SACL,EAAO,UAAU,KAAA,KAChB,kBAAC,QAAD;MAAM,WAAU;gBAA2C,EAAO,MAAM,gBAAgB;MAAQ,CAAA,CAE9F;OAlBC,EAkBD,CACN;IACE,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA0D;MAC/C,EAAO,IAAI,QAAQ,EAAE;MAAC;MAAG,EAAO,IAAI,QAAQ,EAAE;MACrD;;IACA,CAAA;GACF;MAhGJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAJV,CAME,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA,EACF,kBAAC,QAAD;KAAM,eAAc;KAAQ,gBAAe;KAAQ,aAAa;KAAK,GAAE;KAAqC,CAAA,CACxG;OACN,kBAAC,KAAD,EAAA,UAAG,eAAe,CAAA,CACd;;EACF,CAAA;EAgFV"}
1
+ {"version":3,"file":"MapWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/map-widget/MapWidget.tsx"],"sourcesContent":["/**\n * MapWidget Component\n *\n * Displays geographic data with markers (placeholder implementation).\n */\n\nimport { type FC, memo, useCallback } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MapWidgetProps {\n widget: Widget;\n data?: MapData;\n onClick?: (marker: MapMarker) => void;\n /** Drilldown handler - receives selected marker data */\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n}\n\nexport interface MapMarker {\n name: string;\n lat: number;\n lng: number;\n value?: number;\n popup?: string;\n color?: string;\n}\n\nexport interface MapData {\n center?: { lat: number; lng: number };\n zoom?: number;\n markers?: MapMarker[];\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const MapWidget: FC<MapWidgetProps> = memo(function MapWidget({ widget: _widget, data, onClick, onDrilldown }) {\n const markers = data?.markers || [];\n const center = data?.center || { lat: 0, lng: 0 };\n\n // Handle marker click with drilldown support\n const handleMarkerClick = useCallback(\n (marker: MapMarker) => {\n if (onDrilldown) {\n onDrilldown(marker as unknown as Record<string, unknown>);\n } else if (onClick) {\n onClick(marker);\n }\n },\n [onClick, onDrilldown]\n );\n\n const isClickable = Boolean(onDrilldown || onClick);\n\n if (!markers.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n <p>No map data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4\">\n {/* Map placeholder with markers list */}\n <div className=\"flex-1 relative bg-bg-muted rounded-lg overflow-hidden\">\n {/* Simulated map background */}\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <svg className=\"w-32 h-32 text-text-tertiary/30\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={0.5}\n d=\"M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n </div>\n\n {/* Markers overlay */}\n <div className=\"absolute inset-0 p-4\">\n <div className=\"flex flex-wrap gap-2 justify-center\">\n {markers.slice(0, 8).map((marker, index) => (\n <div\n key={index}\n className={`\n flex items-center gap-1.5 px-2 py-1 rounded-full\n bg-bg-surface border border-border-default shadow-sm\n ${isClickable ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => handleMarkerClick(marker)}\n title={marker.popup || marker.name}\n >\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: marker.color || 'var(--color-chart-1)' }}\n />\n <span className=\"text-xs text-text-primary truncate max-w-[80px]\">{marker.name}</span>\n {marker.value !== undefined && (\n <span className=\"text-xs text-text-secondary\">{marker.value.toLocaleString()}</span>\n )}\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Location list */}\n <div className=\"mt-3 space-y-1 max-h-[120px] overflow-auto\">\n {markers.map((marker, index) => (\n <div\n key={index}\n className={`\n flex items-center justify-between p-2 rounded\n hover:bg-bg-muted/50 transition-colors\n ${isClickable ? 'cursor-pointer' : ''}\n `}\n onClick={() => handleMarkerClick(marker)}\n >\n <div className=\"flex items-center gap-2\">\n <div\n className=\"w-2 h-2 rounded-full flex-shrink-0\"\n style={{ backgroundColor: marker.color || 'var(--color-chart-1)' }}\n />\n <span className=\"text-xs text-text-primary\">{marker.name}</span>\n </div>\n {marker.value !== undefined && (\n <span className=\"text-xs font-medium text-text-secondary\">{marker.value.toLocaleString()}</span>\n )}\n </div>\n ))}\n </div>\n\n {/* Center coordinates */}\n <div className=\"mt-2 pt-2 border-t border-border-default\">\n <p className=\"text-[10px] text-text-tertiary text-center\">\n Center: {center.lat.toFixed(2)}, {center.lng.toFixed(2)}\n </p>\n </div>\n </div>\n );\n});\n\nexport default MapWidget;\n"],"mappings":";;;AAwCA,IAAa,IAAgC,EAAK,SAAmB,EAAE,QAAQ,GAAS,SAAM,YAAS,kBAAe;CACpH,IAAM,IAAU,GAAM,WAAW,EAAE,EAC7B,IAAS,GAAM,UAAU;EAAE,KAAK;EAAG,KAAK;EAAG,EAG3C,IAAoB,GACvB,MAAsB;AACrB,EAAI,IACF,EAAY,EAA6C,GAChD,KACT,EAAQ,EAAO;IAGnB,CAAC,GAAS,EAAY,CACvB,EAEK,IAAc,GAAQ,KAAe;AA0B3C,QAxBK,EAAQ,SAyBX,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;MAAkC,MAAK;MAAO,QAAO;MAAe,SAAQ;gBACzF,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA;KACF,CAAA,EAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,GAAQ,MAChC,kBAAC,OAAD;OAEE,WAAW;;;sBAGL,IAAc,kDAAkD,GAAG;;;OAGzE,eAAe,EAAkB,EAAO;OACxC,OAAO,EAAO,SAAS,EAAO;iBAThC;QAWE,kBAAC,OAAD;SACE,WAAU;SACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,wBAAwB;SAClE,CAAA;QACF,kBAAC,QAAD;SAAM,WAAU;mBAAmD,EAAO;SAAY,CAAA;QACrF,EAAO,UAAU,KAAA,KAChB,kBAAC,QAAD;SAAM,WAAU;mBAA+B,EAAO,MAAM,gBAAgB;SAAQ,CAAA;QAElF;SAlBC,EAkBD,CACN;MACE,CAAA;KACF,CAAA,CACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAQ,KAAK,GAAQ,MACpB,kBAAC,OAAD;KAEE,WAAW;;;kBAGL,IAAc,mBAAmB,GAAG;;KAE1C,eAAe,EAAkB,EAAO;eAP1C,CASE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,wBAAwB;OAClE,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA6B,EAAO;OAAY,CAAA,CAC5D;SACL,EAAO,UAAU,KAAA,KAChB,kBAAC,QAAD;MAAM,WAAU;gBAA2C,EAAO,MAAM,gBAAgB;MAAQ,CAAA,CAE9F;OAlBC,EAkBD,CACN;IACE,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA0D;MAC/C,EAAO,IAAI,QAAQ,EAAE;MAAC;MAAG,EAAO,IAAI,QAAQ,EAAE;MACrD;;IACA,CAAA;GACF;MAnGJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAJV,CAME,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA,EACF,kBAAC,QAAD;KAAM,eAAc;KAAQ,gBAAe;KAAQ,aAAa;KAAK,GAAE;KAAqC,CAAA,CACxG;OACN,kBAAC,KAAD,EAAA,UAAG,eAAe,CAAA,CACd;;EACF,CAAA;EAmFV"}
@@ -68,7 +68,7 @@ var a = e(function({ widget: e, data: a, onClick: o }) {
68
68
  style: {
69
69
  left: `${f}%`,
70
70
  width: `${Math.max(p, 5)}%`,
71
- backgroundColor: e.color || "#3b82f6",
71
+ backgroundColor: e.color || "var(--color-chart-1)",
72
72
  opacity: .3
73
73
  }
74
74
  }),
@@ -104,7 +104,7 @@ var a = e(function({ widget: e, data: a, onClick: o }) {
104
104
  children: [
105
105
  /* @__PURE__ */ n("div", {
106
106
  className: "w-2 h-2 rounded-full",
107
- style: { backgroundColor: e.color || "#ef4444" }
107
+ style: { backgroundColor: e.color || "var(--color-chart-negative)" }
108
108
  }),
109
109
  /* @__PURE__ */ n("span", {
110
110
  className: "text-[10px] text-text-primary",
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/timeline/TimelineWidget.tsx"],"sourcesContent":["/**\n * TimelineWidget Component\n *\n * Simple timeline/gantt view showing project tasks and milestones.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TimelineWidgetProps {\n widget: Widget;\n data?: TimelineData;\n onClick?: (task: TimelineTask) => void;\n}\n\nexport interface TimelineTask {\n id: string;\n name: string;\n start: string;\n end: string;\n progress?: number;\n color?: string;\n duration?: number;\n dependencies?: string[];\n}\n\nexport interface TimelineMilestone {\n id: string;\n name: string;\n date: string;\n color?: string;\n}\n\nexport interface TimelineData {\n tasks?: TimelineTask[];\n milestones?: TimelineMilestone[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getProgressColor(progress: number): string {\n if (progress >= 100) return 'bg-state-success';\n if (progress >= 50) return 'bg-action-primary-bg';\n if (progress > 0) return 'bg-state-warning';\n return 'bg-bg-muted';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TimelineWidget: FC<TimelineWidgetProps> = memo(function TimelineWidget({\n widget: _widget,\n data,\n onClick,\n}) {\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n const milestones = data?.milestones || [];\n\n // Calculate date range\n const { minDate, maxDate, totalDays } = useMemo(() => {\n if (!tasks.length) {\n return { minDate: new Date(), maxDate: new Date(), totalDays: 1 };\n }\n\n const dates = tasks.flatMap((t) => [new Date(t.start), new Date(t.end)]);\n const min = new Date(Math.min(...dates.map((d) => d.getTime())));\n const max = new Date(Math.max(...dates.map((d) => d.getTime())));\n const days = Math.ceil((max.getTime() - min.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n\n return { minDate: min, maxDate: max, totalDays: days };\n }, [tasks]);\n\n if (!tasks.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n <p>No timeline data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4 overflow-auto\">\n {/* Header with date range */}\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">Project Timeline</h3>\n <span className=\"text-xs text-text-secondary\">\n {minDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} -{' '}\n {maxDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n\n {/* Timeline content */}\n <div className=\"flex-1 space-y-3 overflow-auto\">\n {tasks.map((task) => {\n const startDate = new Date(task.start);\n const endDate = new Date(task.end);\n const taskDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n const startOffset = Math.ceil((startDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24));\n const progress = task.progress ?? 0;\n\n // Calculate bar position and width as percentages\n const leftPercent = (startOffset / totalDays) * 100;\n const widthPercent = (taskDays / totalDays) * 100;\n\n return (\n <div\n key={task.id}\n className={`\n ${onClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onClick?.(task)}\n >\n {/* Task name and progress */}\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-primary truncate max-w-[60%]\">{task.name}</span>\n <span className=\"text-[10px] text-text-secondary\">{progress}%</span>\n </div>\n\n {/* Timeline bar */}\n <div className=\"relative h-6 bg-bg-muted rounded overflow-hidden\">\n {/* Task bar */}\n <div\n className=\"absolute top-1 bottom-1 rounded\"\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 5)}%`,\n backgroundColor: task.color || '#3b82f6',\n opacity: 0.3,\n }}\n />\n\n {/* Progress fill */}\n <div\n className={`absolute top-1 bottom-1 rounded ${getProgressColor(progress)}`}\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max((widthPercent * progress) / 100, 2)}%`,\n }}\n />\n\n {/* Date labels */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 text-[9px] text-text-tertiary\"\n style={{ left: `${leftPercent + 1}%` }}\n >\n {startDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Milestones */}\n {milestones.length > 0 && (\n <div className=\"mt-4 pt-3 border-t border-border-default\">\n <p className=\"text-xs font-medium text-text-secondary mb-2\">Milestones</p>\n <div className=\"flex flex-wrap gap-2\">\n {milestones.map((milestone) => (\n <div key={milestone.id} className=\"flex items-center gap-1.5 px-2 py-1 rounded bg-bg-muted\">\n <div className=\"w-2 h-2 rounded-full\" style={{ backgroundColor: milestone.color || '#ef4444' }} />\n <span className=\"text-[10px] text-text-primary\">{milestone.name}</span>\n <span className=\"text-[10px] text-text-tertiary\">\n {new Date(milestone.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport default TimelineWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TimelineWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/timeline/TimelineWidget.tsx"],"sourcesContent":["/**\n * TimelineWidget Component\n *\n * Simple timeline/gantt view showing project tasks and milestones.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TimelineWidgetProps {\n widget: Widget;\n data?: TimelineData;\n onClick?: (task: TimelineTask) => void;\n}\n\nexport interface TimelineTask {\n id: string;\n name: string;\n start: string;\n end: string;\n progress?: number;\n color?: string;\n duration?: number;\n dependencies?: string[];\n}\n\nexport interface TimelineMilestone {\n id: string;\n name: string;\n date: string;\n color?: string;\n}\n\nexport interface TimelineData {\n tasks?: TimelineTask[];\n milestones?: TimelineMilestone[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getProgressColor(progress: number): string {\n if (progress >= 100) return 'bg-state-success';\n if (progress >= 50) return 'bg-action-primary-bg';\n if (progress > 0) return 'bg-state-warning';\n return 'bg-bg-muted';\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TimelineWidget: FC<TimelineWidgetProps> = memo(function TimelineWidget({\n widget: _widget,\n data,\n onClick,\n}) {\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n const milestones = data?.milestones || [];\n\n // Calculate date range\n const { minDate, maxDate, totalDays } = useMemo(() => {\n if (!tasks.length) {\n return { minDate: new Date(), maxDate: new Date(), totalDays: 1 };\n }\n\n const dates = tasks.flatMap((t) => [new Date(t.start), new Date(t.end)]);\n const min = new Date(Math.min(...dates.map((d) => d.getTime())));\n const max = new Date(Math.max(...dates.map((d) => d.getTime())));\n const days = Math.ceil((max.getTime() - min.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n\n return { minDate: min, maxDate: max, totalDays: days };\n }, [tasks]);\n\n if (!tasks.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg\n className=\"w-12 h-12 mx-auto mb-2 text-text-tertiary\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n <p>No timeline data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4 overflow-auto\">\n {/* Header with date range */}\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">Project Timeline</h3>\n <span className=\"text-xs text-text-secondary\">\n {minDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} -{' '}\n {maxDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n\n {/* Timeline content */}\n <div className=\"flex-1 space-y-3 overflow-auto\">\n {tasks.map((task) => {\n const startDate = new Date(task.start);\n const endDate = new Date(task.end);\n const taskDays = Math.ceil((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)) + 1;\n const startOffset = Math.ceil((startDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24));\n const progress = task.progress ?? 0;\n\n // Calculate bar position and width as percentages\n const leftPercent = (startOffset / totalDays) * 100;\n const widthPercent = (taskDays / totalDays) * 100;\n\n return (\n <div\n key={task.id}\n className={`\n ${onClick ? 'cursor-pointer' : ''}\n `}\n onClick={() => onClick?.(task)}\n >\n {/* Task name and progress */}\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-primary truncate max-w-[60%]\">{task.name}</span>\n <span className=\"text-[10px] text-text-secondary\">{progress}%</span>\n </div>\n\n {/* Timeline bar */}\n <div className=\"relative h-6 bg-bg-muted rounded overflow-hidden\">\n {/* Task bar */}\n <div\n className=\"absolute top-1 bottom-1 rounded\"\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 5)}%`,\n backgroundColor: task.color || 'var(--color-chart-1)',\n opacity: 0.3,\n }}\n />\n\n {/* Progress fill */}\n <div\n className={`absolute top-1 bottom-1 rounded ${getProgressColor(progress)}`}\n style={{\n left: `${leftPercent}%`,\n width: `${Math.max((widthPercent * progress) / 100, 2)}%`,\n }}\n />\n\n {/* Date labels */}\n <div\n className=\"absolute top-1/2 -translate-y-1/2 text-[9px] text-text-tertiary\"\n style={{ left: `${leftPercent + 1}%` }}\n >\n {startDate.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Milestones */}\n {milestones.length > 0 && (\n <div className=\"mt-4 pt-3 border-t border-border-default\">\n <p className=\"text-xs font-medium text-text-secondary mb-2\">Milestones</p>\n <div className=\"flex flex-wrap gap-2\">\n {milestones.map((milestone) => (\n <div key={milestone.id} className=\"flex items-center gap-1.5 px-2 py-1 rounded bg-bg-muted\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: milestone.color || 'var(--color-chart-negative)' }}\n />\n <span className=\"text-[10px] text-text-primary\">{milestone.name}</span>\n <span className=\"text-[10px] text-text-tertiary\">\n {new Date(milestone.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n});\n\nexport default TimelineWidget;\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
5
5
  var s = {
6
6
  container: {
7
7
  padding: "16px",
8
- backgroundColor: "#ffffff",
8
+ backgroundColor: "var(--color-bg-surface)",
9
9
  borderRadius: "8px"
10
10
  },
11
11
  header: {
@@ -17,13 +17,13 @@ var s = {
17
17
  title: {
18
18
  fontSize: "16px",
19
19
  fontWeight: 600,
20
- color: "#111827",
20
+ color: "var(--color-text-primary)",
21
21
  margin: 0
22
22
  },
23
23
  addButton: {
24
24
  padding: "8px 16px",
25
- backgroundColor: "#2563eb",
26
- color: "#ffffff",
25
+ backgroundColor: "var(--color-action-primary-bg)",
26
+ color: "var(--color-text-inverse)",
27
27
  border: "none",
28
28
  borderRadius: "6px",
29
29
  fontSize: "14px",
@@ -37,9 +37,9 @@ var s = {
37
37
  },
38
38
  webhookCard: {
39
39
  padding: "16px",
40
- backgroundColor: "#f9fafb",
40
+ backgroundColor: "var(--color-bg-subtle)",
41
41
  borderRadius: "8px",
42
- border: "1px solid #e5e7eb"
42
+ border: "1px solid var(--color-border-subtle)"
43
43
  },
44
44
  webhookHeader: {
45
45
  display: "flex",
@@ -55,7 +55,7 @@ var s = {
55
55
  webhookName: {
56
56
  fontSize: "14px",
57
57
  fontWeight: 600,
58
- color: "#111827"
58
+ color: "var(--color-text-primary)"
59
59
  },
60
60
  statusBadge: {
61
61
  padding: "2px 8px",
@@ -64,21 +64,21 @@ var s = {
64
64
  fontWeight: 500
65
65
  },
66
66
  activeBadge: {
67
- backgroundColor: "#d1fae5",
68
- color: "#065f46"
67
+ backgroundColor: "var(--color-status-success-bgSubtle)",
68
+ color: "var(--color-status-success-text)"
69
69
  },
70
70
  inactiveBadge: {
71
- backgroundColor: "#fef3c7",
72
- color: "#92400e"
71
+ backgroundColor: "var(--color-status-warning-bgSubtle)",
72
+ color: "var(--color-status-warning-text)"
73
73
  },
74
74
  webhookDetails: {
75
75
  fontSize: "13px",
76
- color: "#6b7280",
76
+ color: "var(--color-text-muted)",
77
77
  marginBottom: "4px"
78
78
  },
79
79
  webhookUrl: {
80
80
  fontSize: "12px",
81
- color: "#9ca3af",
81
+ color: "var(--color-text-placeholder)",
82
82
  fontFamily: "monospace",
83
83
  wordBreak: "break-all"
84
84
  },
@@ -96,29 +96,29 @@ var s = {
96
96
  cursor: "pointer"
97
97
  },
98
98
  editButton: {
99
- backgroundColor: "#e5e7eb",
100
- color: "#374151"
99
+ backgroundColor: "var(--color-bg-sunken)",
100
+ color: "var(--color-text-primary)"
101
101
  },
102
102
  testButton: {
103
- backgroundColor: "#dbeafe",
104
- color: "#1d4ed8"
103
+ backgroundColor: "var(--color-status-info-bgSubtle)",
104
+ color: "var(--color-status-info-text)"
105
105
  },
106
106
  deleteButton: {
107
- backgroundColor: "#fee2e2",
108
- color: "#dc2626"
107
+ backgroundColor: "var(--color-status-error-bgSubtle)",
108
+ color: "var(--color-status-error-text)"
109
109
  },
110
110
  toggleButton: {
111
- backgroundColor: "#f3f4f6",
112
- color: "#6b7280"
111
+ backgroundColor: "var(--color-bg-sunken)",
112
+ color: "var(--color-text-muted)"
113
113
  },
114
114
  emptyState: {
115
115
  textAlign: "center",
116
116
  padding: "32px",
117
- color: "#9ca3af"
117
+ color: "var(--color-text-placeholder)"
118
118
  },
119
119
  form: {
120
120
  padding: "16px",
121
- backgroundColor: "#f9fafb",
121
+ backgroundColor: "var(--color-bg-subtle)",
122
122
  borderRadius: "8px",
123
123
  marginBottom: "16px"
124
124
  },
@@ -127,14 +127,14 @@ var s = {
127
127
  display: "block",
128
128
  fontSize: "13px",
129
129
  fontWeight: 500,
130
- color: "#374151",
130
+ color: "var(--color-text-primary)",
131
131
  marginBottom: "4px"
132
132
  },
133
133
  input: {
134
134
  width: "100%",
135
135
  padding: "8px 12px",
136
136
  fontSize: "14px",
137
- border: "1px solid #d1d5db",
137
+ border: "1px solid var(--color-border-default)",
138
138
  borderRadius: "6px",
139
139
  boxSizing: "border-box"
140
140
  },
@@ -142,16 +142,16 @@ var s = {
142
142
  width: "100%",
143
143
  padding: "8px 12px",
144
144
  fontSize: "14px",
145
- border: "1px solid #d1d5db",
145
+ border: "1px solid var(--color-border-default)",
146
146
  borderRadius: "6px",
147
147
  boxSizing: "border-box",
148
- backgroundColor: "#ffffff"
148
+ backgroundColor: "var(--color-bg-surface)"
149
149
  },
150
150
  textarea: {
151
151
  width: "100%",
152
152
  padding: "8px 12px",
153
153
  fontSize: "14px",
154
- border: "1px solid #d1d5db",
154
+ border: "1px solid var(--color-border-default)",
155
155
  borderRadius: "6px",
156
156
  boxSizing: "border-box",
157
157
  fontFamily: "monospace",
@@ -166,8 +166,8 @@ var s = {
166
166
  },
167
167
  cancelButton: {
168
168
  padding: "8px 16px",
169
- backgroundColor: "#f3f4f6",
170
- color: "#374151",
169
+ backgroundColor: "var(--color-bg-sunken)",
170
+ color: "var(--color-text-primary)",
171
171
  border: "none",
172
172
  borderRadius: "6px",
173
173
  fontSize: "14px",
@@ -175,8 +175,8 @@ var s = {
175
175
  },
176
176
  saveButton: {
177
177
  padding: "8px 16px",
178
- backgroundColor: "#2563eb",
179
- color: "#ffffff",
178
+ backgroundColor: "var(--color-action-primary-bg)",
179
+ color: "var(--color-text-inverse)",
180
180
  border: "none",
181
181
  borderRadius: "6px",
182
182
  fontSize: "14px",
@@ -190,16 +190,16 @@ var s = {
190
190
  fontSize: "13px"
191
191
  },
192
192
  testSuccess: {
193
- backgroundColor: "#d1fae5",
194
- color: "#065f46"
193
+ backgroundColor: "var(--color-status-success-bgSubtle)",
194
+ color: "var(--color-status-success-text)"
195
195
  },
196
196
  testFailure: {
197
- backgroundColor: "#fee2e2",
198
- color: "#991b1b"
197
+ backgroundColor: "var(--color-status-error-bgSubtle)",
198
+ color: "var(--color-status-error-text)"
199
199
  },
200
200
  helpText: {
201
201
  fontSize: "12px",
202
- color: "#9ca3af",
202
+ color: "var(--color-text-placeholder)",
203
203
  marginTop: "4px"
204
204
  }
205
205
  }, c = t(function({ webhook: e, dashboardId: t, widgetId: n, onSave: i, onCancel: c, loading: l }) {
@@ -1 +1 @@
1
- {"version":3,"file":"WebhookConfigPanel.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.tsx"],"sourcesContent":["/**\n * WebhookConfigPanel Component (v2.0)\n *\n * Panel for managing event webhook mappings.\n * Allows creating, editing, testing, and deleting webhooks.\n */\n\nimport React, { memo, useState, useCallback } from 'react';\nimport {\n useEventWebhooks,\n type HttpMethod,\n type EventWebhookMapping,\n type CreateEventWebhookMappingInput,\n type UpdateEventWebhookMappingInput,\n type WebhookTestResult,\n} from '../../../hooks/useEventWebhooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WebhookConfigPanelProps {\n /** Dashboard ID for webhook scope */\n dashboardId?: string;\n /** Widget ID for webhook scope */\n widgetId?: string;\n /** Callback when webhook is created */\n onWebhookCreated?: (webhook: EventWebhookMapping) => void;\n /** Callback when webhook is deleted */\n onWebhookDeleted?: (id: string) => void;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n padding: '16px',\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n } as React.CSSProperties,\n header: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '16px',\n } as React.CSSProperties,\n title: {\n fontSize: '16px',\n fontWeight: 600,\n color: '#111827',\n margin: 0,\n } as React.CSSProperties,\n addButton: {\n padding: '8px 16px',\n backgroundColor: '#2563eb',\n color: '#ffffff',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: 500,\n cursor: 'pointer',\n } as React.CSSProperties,\n webhookList: {\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n } as React.CSSProperties,\n webhookCard: {\n padding: '16px',\n backgroundColor: '#f9fafb',\n borderRadius: '8px',\n border: '1px solid #e5e7eb',\n } as React.CSSProperties,\n webhookHeader: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: '8px',\n } as React.CSSProperties,\n webhookTitle: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n } as React.CSSProperties,\n webhookName: {\n fontSize: '14px',\n fontWeight: 600,\n color: '#111827',\n } as React.CSSProperties,\n statusBadge: {\n padding: '2px 8px',\n borderRadius: '12px',\n fontSize: '12px',\n fontWeight: 500,\n } as React.CSSProperties,\n activeBadge: {\n backgroundColor: '#d1fae5',\n color: '#065f46',\n } as React.CSSProperties,\n inactiveBadge: {\n backgroundColor: '#fef3c7',\n color: '#92400e',\n } as React.CSSProperties,\n webhookDetails: {\n fontSize: '13px',\n color: '#6b7280',\n marginBottom: '4px',\n } as React.CSSProperties,\n webhookUrl: {\n fontSize: '12px',\n color: '#9ca3af',\n fontFamily: 'monospace',\n wordBreak: 'break-all',\n } as React.CSSProperties,\n webhookActions: {\n display: 'flex',\n gap: '8px',\n marginTop: '12px',\n } as React.CSSProperties,\n actionButton: {\n padding: '6px 12px',\n fontSize: '12px',\n fontWeight: 500,\n borderRadius: '4px',\n border: 'none',\n cursor: 'pointer',\n } as React.CSSProperties,\n editButton: {\n backgroundColor: '#e5e7eb',\n color: '#374151',\n } as React.CSSProperties,\n testButton: {\n backgroundColor: '#dbeafe',\n color: '#1d4ed8',\n } as React.CSSProperties,\n deleteButton: {\n backgroundColor: '#fee2e2',\n color: '#dc2626',\n } as React.CSSProperties,\n toggleButton: {\n backgroundColor: '#f3f4f6',\n color: '#6b7280',\n } as React.CSSProperties,\n emptyState: {\n textAlign: 'center',\n padding: '32px',\n color: '#9ca3af',\n } as React.CSSProperties,\n form: {\n padding: '16px',\n backgroundColor: '#f9fafb',\n borderRadius: '8px',\n marginBottom: '16px',\n } as React.CSSProperties,\n formGroup: {\n marginBottom: '12px',\n } as React.CSSProperties,\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: '#374151',\n marginBottom: '4px',\n } as React.CSSProperties,\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n boxSizing: 'border-box',\n } as React.CSSProperties,\n select: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n boxSizing: 'border-box',\n backgroundColor: '#ffffff',\n } as React.CSSProperties,\n textarea: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n boxSizing: 'border-box',\n fontFamily: 'monospace',\n minHeight: '80px',\n resize: 'vertical',\n } as React.CSSProperties,\n formActions: {\n display: 'flex',\n gap: '8px',\n justifyContent: 'flex-end',\n marginTop: '16px',\n } as React.CSSProperties,\n cancelButton: {\n padding: '8px 16px',\n backgroundColor: '#f3f4f6',\n color: '#374151',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n cursor: 'pointer',\n } as React.CSSProperties,\n saveButton: {\n padding: '8px 16px',\n backgroundColor: '#2563eb',\n color: '#ffffff',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: 500,\n cursor: 'pointer',\n } as React.CSSProperties,\n testResult: {\n marginTop: '12px',\n padding: '12px',\n borderRadius: '6px',\n fontSize: '13px',\n } as React.CSSProperties,\n testSuccess: {\n backgroundColor: '#d1fae5',\n color: '#065f46',\n } as React.CSSProperties,\n testFailure: {\n backgroundColor: '#fee2e2',\n color: '#991b1b',\n } as React.CSSProperties,\n helpText: {\n fontSize: '12px',\n color: '#9ca3af',\n marginTop: '4px',\n } as React.CSSProperties,\n};\n\n// ============================================================================\n// Webhook Form Component\n// ============================================================================\n\ninterface WebhookFormProps {\n webhook?: EventWebhookMapping;\n dashboardId?: string;\n widgetId?: string;\n onSave: (data: CreateEventWebhookMappingInput | UpdateEventWebhookMappingInput) => Promise<void>;\n onCancel: () => void;\n loading?: boolean;\n}\n\nconst WebhookForm: React.FC<WebhookFormProps> = memo(function WebhookForm({\n webhook,\n dashboardId,\n widgetId,\n onSave,\n onCancel,\n loading,\n}) {\n const [eventPattern, setEventPattern] = useState(webhook?.eventPattern || 'widget:*:clicked');\n const [webhookUrl, setWebhookUrl] = useState(webhook?.webhookUrl || '');\n const [method, setMethod] = useState(webhook?.method || 'POST');\n const [headers, setHeaders] = useState(webhook?.headers ? JSON.stringify(webhook.headers, null, 2) : '');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n let parsedHeaders: Record<string, string> | undefined;\n if (headers.trim()) {\n try {\n parsedHeaders = JSON.parse(headers);\n } catch {\n alert('Invalid JSON in headers field');\n return;\n }\n }\n\n if (webhook) {\n // Update\n await onSave({\n id: webhook.id,\n eventPattern,\n webhookUrl,\n method: method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n headers: parsedHeaders || null,\n });\n } else {\n // Create\n await onSave({\n dashboardId,\n widgetId,\n eventPattern,\n webhookUrl,\n method: method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n headers: parsedHeaders,\n });\n }\n };\n\n return (\n <form style={styles.form} onSubmit={handleSubmit}>\n <div style={styles.formGroup}>\n <label style={styles.label}>Event Pattern *</label>\n <input\n type=\"text\"\n value={eventPattern}\n onChange={(e) => setEventPattern(e.target.value)}\n placeholder=\"widget:*:clicked\"\n style={styles.input}\n required\n />\n <p style={styles.helpText}>Use * as wildcard. Examples: widget:*:clicked, *:submit, button:save:*</p>\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>Webhook URL *</label>\n <input\n type=\"url\"\n value={webhookUrl}\n onChange={(e) => setWebhookUrl(e.target.value)}\n placeholder=\"https://your-api.com/webhooks/bigconsole\"\n style={styles.input}\n required\n />\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>HTTP Method</label>\n <select value={method} onChange={(e) => setMethod(e.target.value as HttpMethod)} style={styles.select}>\n <option value=\"POST\">POST</option>\n <option value=\"PUT\">PUT</option>\n <option value=\"PATCH\">PATCH</option>\n <option value=\"GET\">GET</option>\n <option value=\"DELETE\">DELETE</option>\n </select>\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>Custom Headers (JSON)</label>\n <textarea\n value={headers}\n onChange={(e) => setHeaders(e.target.value)}\n placeholder={'{\\n \"Authorization\": \"Bearer your-token\"\\n}'}\n style={styles.textarea as React.CSSProperties}\n />\n </div>\n\n <div style={styles.formActions}>\n <button type=\"button\" onClick={onCancel} style={styles.cancelButton}>\n Cancel\n </button>\n <button type=\"submit\" disabled={loading} style={styles.saveButton}>\n {loading ? 'Saving...' : webhook ? 'Update Webhook' : 'Create Webhook'}\n </button>\n </div>\n </form>\n );\n});\n\n// ============================================================================\n// Webhook Card Component\n// ============================================================================\n\ninterface WebhookCardProps {\n webhook: EventWebhookMapping;\n onEdit: () => void;\n onDelete: () => void;\n onToggle: () => void;\n onTest: () => void;\n testResult?: WebhookTestResult | null;\n testing?: boolean;\n}\n\nconst WebhookCard: React.FC<WebhookCardProps> = memo(function WebhookCard({\n webhook,\n onEdit,\n onDelete,\n onToggle,\n onTest,\n testResult,\n testing,\n}) {\n return (\n <div style={styles.webhookCard}>\n <div style={styles.webhookHeader}>\n <div style={styles.webhookTitle}>\n <span style={{ fontSize: '16px' }}>📡</span>\n <span style={styles.webhookName}>{webhook.eventPattern}</span>\n <span\n style={{\n ...styles.statusBadge,\n ...(webhook.isActive ? styles.activeBadge : styles.inactiveBadge),\n }}\n >\n {webhook.isActive ? 'Active' : 'Inactive'}\n </span>\n </div>\n </div>\n\n <div style={styles.webhookDetails}>\n Method: <strong>{webhook.method}</strong>\n </div>\n <div style={styles.webhookUrl}>{webhook.webhookUrl}</div>\n\n {testResult && (\n <div\n style={{\n ...styles.testResult,\n ...(testResult.success ? styles.testSuccess : styles.testFailure),\n }}\n >\n {testResult.success ? (\n <>\n ✅ Test successful! Status: {testResult.statusCode}, Latency: {testResult.latencyMs}ms\n </>\n ) : (\n <>❌ Test failed: {testResult.errorMessage || 'Unknown error'}</>\n )}\n </div>\n )}\n\n <div style={styles.webhookActions}>\n <button onClick={onEdit} style={{ ...styles.actionButton, ...styles.editButton }}>\n Edit\n </button>\n <button onClick={onTest} disabled={testing} style={{ ...styles.actionButton, ...styles.testButton }}>\n {testing ? 'Testing...' : 'Test'}\n </button>\n <button onClick={onToggle} style={{ ...styles.actionButton, ...styles.toggleButton }}>\n {webhook.isActive ? 'Disable' : 'Enable'}\n </button>\n <button onClick={onDelete} style={{ ...styles.actionButton, ...styles.deleteButton }}>\n Delete\n </button>\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const WebhookConfigPanel: React.FC<WebhookConfigPanelProps> = memo(function WebhookConfigPanel({\n dashboardId,\n widgetId,\n onWebhookCreated,\n onWebhookDeleted,\n}) {\n const [showForm, setShowForm] = useState(false);\n const [editingWebhook, setEditingWebhook] = useState<EventWebhookMapping | null>(null);\n const [testResults, setTestResults] = useState<Record<string, WebhookTestResult | null>>({});\n const [testingId, setTestingId] = useState<string | null>(null);\n\n const { webhooks, loading, createWebhook, updateWebhook, deleteWebhook, toggleWebhook, testWebhook } =\n useEventWebhooks({ dashboardId, widgetId });\n\n const handleSave = useCallback(\n async (data: CreateEventWebhookMappingInput | UpdateEventWebhookMappingInput) => {\n if ('id' in data) {\n const result = await updateWebhook(data);\n if (result) {\n setEditingWebhook(null);\n setShowForm(false);\n }\n } else {\n const result = await createWebhook(data);\n if (result) {\n setShowForm(false);\n onWebhookCreated?.(result);\n }\n }\n },\n [createWebhook, updateWebhook, onWebhookCreated]\n );\n\n const handleDelete = useCallback(\n async (id: string) => {\n if (confirm('Are you sure you want to delete this webhook?')) {\n const success = await deleteWebhook(id);\n if (success) {\n onWebhookDeleted?.(id);\n }\n }\n },\n [deleteWebhook, onWebhookDeleted]\n );\n\n const handleToggle = useCallback(\n async (webhook: EventWebhookMapping) => {\n await toggleWebhook(webhook.id, !webhook.isActive);\n },\n [toggleWebhook]\n );\n\n const handleTest = useCallback(\n async (id: string) => {\n setTestingId(id);\n const result = await testWebhook(id);\n setTestResults((prev) => ({ ...prev, [id]: result }));\n setTestingId(null);\n },\n [testWebhook]\n );\n\n const handleEdit = useCallback((webhook: EventWebhookMapping) => {\n setEditingWebhook(webhook);\n setShowForm(true);\n }, []);\n\n const handleCancel = useCallback(() => {\n setShowForm(false);\n setEditingWebhook(null);\n }, []);\n\n return (\n <div style={styles.container}>\n <div style={styles.header}>\n <h3 style={styles.title}>Webhook Configuration</h3>\n {!showForm && (\n <button onClick={() => setShowForm(true)} style={styles.addButton}>\n + Add Webhook\n </button>\n )}\n </div>\n\n {showForm && (\n <WebhookForm\n webhook={editingWebhook || undefined}\n dashboardId={dashboardId}\n widgetId={widgetId}\n onSave={handleSave}\n onCancel={handleCancel}\n loading={loading}\n />\n )}\n\n {loading && webhooks.length === 0 ? (\n <div style={styles.emptyState}>Loading...</div>\n ) : webhooks.length === 0 ? (\n <div style={styles.emptyState}>\n <p>No webhooks configured</p>\n <p style={{ fontSize: '13px', marginTop: '8px' }}>\n Add a webhook to receive events when actions are triggered.\n </p>\n </div>\n ) : (\n <div style={styles.webhookList as React.CSSProperties}>\n {webhooks.map((webhook) => (\n <WebhookCard\n key={webhook.id}\n webhook={webhook}\n onEdit={() => handleEdit(webhook)}\n onDelete={() => handleDelete(webhook.id)}\n onToggle={() => handleToggle(webhook)}\n onTest={() => handleTest(webhook.id)}\n testResult={testResults[webhook.id]}\n testing={testingId === webhook.id}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\n\nexport default WebhookConfigPanel;\n"],"mappings":"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"}
1
+ {"version":3,"file":"WebhookConfigPanel.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.tsx"],"sourcesContent":["/**\n * WebhookConfigPanel Component (v2.0)\n *\n * Panel for managing event webhook mappings.\n * Allows creating, editing, testing, and deleting webhooks.\n */\n\nimport React, { memo, useState, useCallback } from 'react';\nimport {\n useEventWebhooks,\n type HttpMethod,\n type EventWebhookMapping,\n type CreateEventWebhookMappingInput,\n type UpdateEventWebhookMappingInput,\n type WebhookTestResult,\n} from '../../../hooks/useEventWebhooks';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WebhookConfigPanelProps {\n /** Dashboard ID for webhook scope */\n dashboardId?: string;\n /** Widget ID for webhook scope */\n widgetId?: string;\n /** Callback when webhook is created */\n onWebhookCreated?: (webhook: EventWebhookMapping) => void;\n /** Callback when webhook is deleted */\n onWebhookDeleted?: (id: string) => void;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n padding: '16px',\n backgroundColor: 'var(--color-bg-surface)',\n borderRadius: '8px',\n } as React.CSSProperties,\n header: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: '16px',\n } as React.CSSProperties,\n title: {\n fontSize: '16px',\n fontWeight: 600,\n color: 'var(--color-text-primary)',\n margin: 0,\n } as React.CSSProperties,\n addButton: {\n padding: '8px 16px',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-text-inverse)',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: 500,\n cursor: 'pointer',\n } as React.CSSProperties,\n webhookList: {\n display: 'flex',\n flexDirection: 'column',\n gap: '12px',\n } as React.CSSProperties,\n webhookCard: {\n padding: '16px',\n backgroundColor: 'var(--color-bg-subtle)',\n borderRadius: '8px',\n border: '1px solid var(--color-border-subtle)',\n } as React.CSSProperties,\n webhookHeader: {\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'flex-start',\n marginBottom: '8px',\n } as React.CSSProperties,\n webhookTitle: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n } as React.CSSProperties,\n webhookName: {\n fontSize: '14px',\n fontWeight: 600,\n color: 'var(--color-text-primary)',\n } as React.CSSProperties,\n statusBadge: {\n padding: '2px 8px',\n borderRadius: '12px',\n fontSize: '12px',\n fontWeight: 500,\n } as React.CSSProperties,\n activeBadge: {\n backgroundColor: 'var(--color-status-success-bgSubtle)',\n color: 'var(--color-status-success-text)',\n } as React.CSSProperties,\n inactiveBadge: {\n backgroundColor: 'var(--color-status-warning-bgSubtle)',\n color: 'var(--color-status-warning-text)',\n } as React.CSSProperties,\n webhookDetails: {\n fontSize: '13px',\n color: 'var(--color-text-muted)',\n marginBottom: '4px',\n } as React.CSSProperties,\n webhookUrl: {\n fontSize: '12px',\n color: 'var(--color-text-placeholder)',\n fontFamily: 'monospace',\n wordBreak: 'break-all',\n } as React.CSSProperties,\n webhookActions: {\n display: 'flex',\n gap: '8px',\n marginTop: '12px',\n } as React.CSSProperties,\n actionButton: {\n padding: '6px 12px',\n fontSize: '12px',\n fontWeight: 500,\n borderRadius: '4px',\n border: 'none',\n cursor: 'pointer',\n } as React.CSSProperties,\n editButton: {\n backgroundColor: 'var(--color-bg-sunken)',\n color: 'var(--color-text-primary)',\n } as React.CSSProperties,\n testButton: {\n backgroundColor: 'var(--color-status-info-bgSubtle)',\n color: 'var(--color-status-info-text)',\n } as React.CSSProperties,\n deleteButton: {\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n color: 'var(--color-status-error-text)',\n } as React.CSSProperties,\n toggleButton: {\n backgroundColor: 'var(--color-bg-sunken)',\n color: 'var(--color-text-muted)',\n } as React.CSSProperties,\n emptyState: {\n textAlign: 'center',\n padding: '32px',\n color: 'var(--color-text-placeholder)',\n } as React.CSSProperties,\n form: {\n padding: '16px',\n backgroundColor: 'var(--color-bg-subtle)',\n borderRadius: '8px',\n marginBottom: '16px',\n } as React.CSSProperties,\n formGroup: {\n marginBottom: '12px',\n } as React.CSSProperties,\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--color-text-primary)',\n marginBottom: '4px',\n } as React.CSSProperties,\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid var(--color-border-default)',\n borderRadius: '6px',\n boxSizing: 'border-box',\n } as React.CSSProperties,\n select: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid var(--color-border-default)',\n borderRadius: '6px',\n boxSizing: 'border-box',\n backgroundColor: 'var(--color-bg-surface)',\n } as React.CSSProperties,\n textarea: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid var(--color-border-default)',\n borderRadius: '6px',\n boxSizing: 'border-box',\n fontFamily: 'monospace',\n minHeight: '80px',\n resize: 'vertical',\n } as React.CSSProperties,\n formActions: {\n display: 'flex',\n gap: '8px',\n justifyContent: 'flex-end',\n marginTop: '16px',\n } as React.CSSProperties,\n cancelButton: {\n padding: '8px 16px',\n backgroundColor: 'var(--color-bg-sunken)',\n color: 'var(--color-text-primary)',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n cursor: 'pointer',\n } as React.CSSProperties,\n saveButton: {\n padding: '8px 16px',\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-text-inverse)',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: 500,\n cursor: 'pointer',\n } as React.CSSProperties,\n testResult: {\n marginTop: '12px',\n padding: '12px',\n borderRadius: '6px',\n fontSize: '13px',\n } as React.CSSProperties,\n testSuccess: {\n backgroundColor: 'var(--color-status-success-bgSubtle)',\n color: 'var(--color-status-success-text)',\n } as React.CSSProperties,\n testFailure: {\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n color: 'var(--color-status-error-text)',\n } as React.CSSProperties,\n helpText: {\n fontSize: '12px',\n color: 'var(--color-text-placeholder)',\n marginTop: '4px',\n } as React.CSSProperties,\n};\n\n// ============================================================================\n// Webhook Form Component\n// ============================================================================\n\ninterface WebhookFormProps {\n webhook?: EventWebhookMapping;\n dashboardId?: string;\n widgetId?: string;\n onSave: (data: CreateEventWebhookMappingInput | UpdateEventWebhookMappingInput) => Promise<void>;\n onCancel: () => void;\n loading?: boolean;\n}\n\nconst WebhookForm: React.FC<WebhookFormProps> = memo(function WebhookForm({\n webhook,\n dashboardId,\n widgetId,\n onSave,\n onCancel,\n loading,\n}) {\n const [eventPattern, setEventPattern] = useState(webhook?.eventPattern || 'widget:*:clicked');\n const [webhookUrl, setWebhookUrl] = useState(webhook?.webhookUrl || '');\n const [method, setMethod] = useState(webhook?.method || 'POST');\n const [headers, setHeaders] = useState(webhook?.headers ? JSON.stringify(webhook.headers, null, 2) : '');\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n let parsedHeaders: Record<string, string> | undefined;\n if (headers.trim()) {\n try {\n parsedHeaders = JSON.parse(headers);\n } catch {\n alert('Invalid JSON in headers field');\n return;\n }\n }\n\n if (webhook) {\n // Update\n await onSave({\n id: webhook.id,\n eventPattern,\n webhookUrl,\n method: method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n headers: parsedHeaders || null,\n });\n } else {\n // Create\n await onSave({\n dashboardId,\n widgetId,\n eventPattern,\n webhookUrl,\n method: method as 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',\n headers: parsedHeaders,\n });\n }\n };\n\n return (\n <form style={styles.form} onSubmit={handleSubmit}>\n <div style={styles.formGroup}>\n <label style={styles.label}>Event Pattern *</label>\n <input\n type=\"text\"\n value={eventPattern}\n onChange={(e) => setEventPattern(e.target.value)}\n placeholder=\"widget:*:clicked\"\n style={styles.input}\n required\n />\n <p style={styles.helpText}>Use * as wildcard. Examples: widget:*:clicked, *:submit, button:save:*</p>\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>Webhook URL *</label>\n <input\n type=\"url\"\n value={webhookUrl}\n onChange={(e) => setWebhookUrl(e.target.value)}\n placeholder=\"https://your-api.com/webhooks/bigconsole\"\n style={styles.input}\n required\n />\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>HTTP Method</label>\n <select value={method} onChange={(e) => setMethod(e.target.value as HttpMethod)} style={styles.select}>\n <option value=\"POST\">POST</option>\n <option value=\"PUT\">PUT</option>\n <option value=\"PATCH\">PATCH</option>\n <option value=\"GET\">GET</option>\n <option value=\"DELETE\">DELETE</option>\n </select>\n </div>\n\n <div style={styles.formGroup}>\n <label style={styles.label}>Custom Headers (JSON)</label>\n <textarea\n value={headers}\n onChange={(e) => setHeaders(e.target.value)}\n placeholder={'{\\n \"Authorization\": \"Bearer your-token\"\\n}'}\n style={styles.textarea as React.CSSProperties}\n />\n </div>\n\n <div style={styles.formActions}>\n <button type=\"button\" onClick={onCancel} style={styles.cancelButton}>\n Cancel\n </button>\n <button type=\"submit\" disabled={loading} style={styles.saveButton}>\n {loading ? 'Saving...' : webhook ? 'Update Webhook' : 'Create Webhook'}\n </button>\n </div>\n </form>\n );\n});\n\n// ============================================================================\n// Webhook Card Component\n// ============================================================================\n\ninterface WebhookCardProps {\n webhook: EventWebhookMapping;\n onEdit: () => void;\n onDelete: () => void;\n onToggle: () => void;\n onTest: () => void;\n testResult?: WebhookTestResult | null;\n testing?: boolean;\n}\n\nconst WebhookCard: React.FC<WebhookCardProps> = memo(function WebhookCard({\n webhook,\n onEdit,\n onDelete,\n onToggle,\n onTest,\n testResult,\n testing,\n}) {\n return (\n <div style={styles.webhookCard}>\n <div style={styles.webhookHeader}>\n <div style={styles.webhookTitle}>\n <span style={{ fontSize: '16px' }}>📡</span>\n <span style={styles.webhookName}>{webhook.eventPattern}</span>\n <span\n style={{\n ...styles.statusBadge,\n ...(webhook.isActive ? styles.activeBadge : styles.inactiveBadge),\n }}\n >\n {webhook.isActive ? 'Active' : 'Inactive'}\n </span>\n </div>\n </div>\n\n <div style={styles.webhookDetails}>\n Method: <strong>{webhook.method}</strong>\n </div>\n <div style={styles.webhookUrl}>{webhook.webhookUrl}</div>\n\n {testResult && (\n <div\n style={{\n ...styles.testResult,\n ...(testResult.success ? styles.testSuccess : styles.testFailure),\n }}\n >\n {testResult.success ? (\n <>\n ✅ Test successful! Status: {testResult.statusCode}, Latency: {testResult.latencyMs}ms\n </>\n ) : (\n <>❌ Test failed: {testResult.errorMessage || 'Unknown error'}</>\n )}\n </div>\n )}\n\n <div style={styles.webhookActions}>\n <button onClick={onEdit} style={{ ...styles.actionButton, ...styles.editButton }}>\n Edit\n </button>\n <button onClick={onTest} disabled={testing} style={{ ...styles.actionButton, ...styles.testButton }}>\n {testing ? 'Testing...' : 'Test'}\n </button>\n <button onClick={onToggle} style={{ ...styles.actionButton, ...styles.toggleButton }}>\n {webhook.isActive ? 'Disable' : 'Enable'}\n </button>\n <button onClick={onDelete} style={{ ...styles.actionButton, ...styles.deleteButton }}>\n Delete\n </button>\n </div>\n </div>\n );\n});\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\nexport const WebhookConfigPanel: React.FC<WebhookConfigPanelProps> = memo(function WebhookConfigPanel({\n dashboardId,\n widgetId,\n onWebhookCreated,\n onWebhookDeleted,\n}) {\n const [showForm, setShowForm] = useState(false);\n const [editingWebhook, setEditingWebhook] = useState<EventWebhookMapping | null>(null);\n const [testResults, setTestResults] = useState<Record<string, WebhookTestResult | null>>({});\n const [testingId, setTestingId] = useState<string | null>(null);\n\n const { webhooks, loading, createWebhook, updateWebhook, deleteWebhook, toggleWebhook, testWebhook } =\n useEventWebhooks({ dashboardId, widgetId });\n\n const handleSave = useCallback(\n async (data: CreateEventWebhookMappingInput | UpdateEventWebhookMappingInput) => {\n if ('id' in data) {\n const result = await updateWebhook(data);\n if (result) {\n setEditingWebhook(null);\n setShowForm(false);\n }\n } else {\n const result = await createWebhook(data);\n if (result) {\n setShowForm(false);\n onWebhookCreated?.(result);\n }\n }\n },\n [createWebhook, updateWebhook, onWebhookCreated]\n );\n\n const handleDelete = useCallback(\n async (id: string) => {\n if (confirm('Are you sure you want to delete this webhook?')) {\n const success = await deleteWebhook(id);\n if (success) {\n onWebhookDeleted?.(id);\n }\n }\n },\n [deleteWebhook, onWebhookDeleted]\n );\n\n const handleToggle = useCallback(\n async (webhook: EventWebhookMapping) => {\n await toggleWebhook(webhook.id, !webhook.isActive);\n },\n [toggleWebhook]\n );\n\n const handleTest = useCallback(\n async (id: string) => {\n setTestingId(id);\n const result = await testWebhook(id);\n setTestResults((prev) => ({ ...prev, [id]: result }));\n setTestingId(null);\n },\n [testWebhook]\n );\n\n const handleEdit = useCallback((webhook: EventWebhookMapping) => {\n setEditingWebhook(webhook);\n setShowForm(true);\n }, []);\n\n const handleCancel = useCallback(() => {\n setShowForm(false);\n setEditingWebhook(null);\n }, []);\n\n return (\n <div style={styles.container}>\n <div style={styles.header}>\n <h3 style={styles.title}>Webhook Configuration</h3>\n {!showForm && (\n <button onClick={() => setShowForm(true)} style={styles.addButton}>\n + Add Webhook\n </button>\n )}\n </div>\n\n {showForm && (\n <WebhookForm\n webhook={editingWebhook || undefined}\n dashboardId={dashboardId}\n widgetId={widgetId}\n onSave={handleSave}\n onCancel={handleCancel}\n loading={loading}\n />\n )}\n\n {loading && webhooks.length === 0 ? (\n <div style={styles.emptyState}>Loading...</div>\n ) : webhooks.length === 0 ? (\n <div style={styles.emptyState}>\n <p>No webhooks configured</p>\n <p style={{ fontSize: '13px', marginTop: '8px' }}>\n Add a webhook to receive events when actions are triggered.\n </p>\n </div>\n ) : (\n <div style={styles.webhookList as React.CSSProperties}>\n {webhooks.map((webhook) => (\n <WebhookCard\n key={webhook.id}\n webhook={webhook}\n onEdit={() => handleEdit(webhook)}\n onDelete={() => handleDelete(webhook.id)}\n onToggle={() => handleToggle(webhook)}\n onTest={() => handleTest(webhook.id)}\n testResult={testResults[webhook.id]}\n testing={testingId === webhook.id}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\n\nexport default WebhookConfigPanel;\n"],"mappings":"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"}