@burdenoff/microfe-bigconsole 2026.610.1 → 2026.612.2

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 (31) hide show
  1. package/dist/bigconsole/components/dashboard/DashboardCanvas.js +3 -3
  2. package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
  3. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +6 -5
  4. package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
  5. package/dist/bigconsole/components/widgets/WidgetRegistry.js +2 -1
  6. package/dist/bigconsole/components/widgets/WidgetRegistry.js.map +1 -1
  7. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +4 -4
  8. package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
  9. package/dist/bigconsole/components/widgets/form/FormWidget.js +20 -20
  10. package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
  11. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +1 -1
  12. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  13. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js +2 -2
  14. package/dist/bigconsole/components/widgets/map-widget/MapWidget.js.map +1 -1
  15. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +2 -2
  16. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  17. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +37 -37
  18. package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
  19. package/dist/bigconsole/hooks/useDashboardOperations.js +92 -70
  20. package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
  21. package/dist/bigconsole/pages/DashboardBuilderPage.js +220 -200
  22. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  23. package/dist/bigconsole/pages/DashboardViewPage.js +11 -9
  24. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  25. package/dist/bigconsole/pages/DashboardsPage.js +501 -164
  26. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  27. package/dist/bigconsole/pages/InsightsPage.js +783 -395
  28. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  29. package/dist/generated/wspace-operations.js +105 -107
  30. package/dist/generated/wspace-operations.js.map +1 -1
  31. package/package.json +1 -1
@@ -67,27 +67,27 @@ var m = {
67
67
  display: "block",
68
68
  fontSize: "13px",
69
69
  fontWeight: 500,
70
- color: "#374151",
70
+ color: "var(--color-text-primary)",
71
71
  marginBottom: "6px"
72
72
  },
73
73
  required: {
74
- color: "#dc2626",
74
+ color: "var(--color-status-error-text)",
75
75
  marginLeft: "2px"
76
76
  },
77
77
  input: {
78
78
  width: "100%",
79
79
  padding: "8px 12px",
80
80
  fontSize: "14px",
81
- border: "1px solid #d1d5db",
81
+ border: "1px solid var(--color-border-default)",
82
82
  borderRadius: "6px",
83
- backgroundColor: "#ffffff",
83
+ backgroundColor: "var(--color-bg-surface)",
84
84
  transition: "border-color 0.15s, box-shadow 0.15s",
85
85
  outline: "none"
86
86
  },
87
- inputError: { borderColor: "#dc2626" },
87
+ inputError: { borderColor: "var(--color-status-error-border)" },
88
88
  inputFocus: {
89
- borderColor: "#6366f1",
90
- boxShadow: "0 0 0 3px rgba(99, 102, 241, 0.1)"
89
+ borderColor: "var(--color-border-focus)",
90
+ boxShadow: "var(--shadow-focus)"
91
91
  },
92
92
  textarea: {
93
93
  resize: "vertical",
@@ -113,12 +113,12 @@ var m = {
113
113
  },
114
114
  helpText: {
115
115
  fontSize: "12px",
116
- color: "#6b7280",
116
+ color: "var(--color-text-muted)",
117
117
  marginTop: "4px"
118
118
  },
119
119
  errorText: {
120
120
  fontSize: "12px",
121
- color: "#dc2626",
121
+ color: "var(--color-status-error-text)",
122
122
  marginTop: "4px",
123
123
  display: "flex",
124
124
  alignItems: "center",
@@ -129,8 +129,8 @@ var m = {
129
129
  justifyContent: "flex-end",
130
130
  gap: "12px",
131
131
  padding: "12px 16px",
132
- borderTop: "1px solid #e5e7eb",
133
- backgroundColor: "#f9fafb"
132
+ borderTop: "1px solid var(--color-border-subtle)",
133
+ backgroundColor: "var(--color-bg-subtle)"
134
134
  },
135
135
  button: {
136
136
  display: "inline-flex",
@@ -145,24 +145,24 @@ var m = {
145
145
  border: "none"
146
146
  },
147
147
  submitButton: {
148
- backgroundColor: "#6366f1",
149
- color: "#ffffff"
148
+ backgroundColor: "var(--color-action-primary-bg)",
149
+ color: "var(--color-text-inverse)"
150
150
  },
151
151
  resetButton: {
152
- backgroundColor: "#ffffff",
153
- color: "#374151",
154
- border: "1px solid #d1d5db"
152
+ backgroundColor: "var(--color-bg-surface)",
153
+ color: "var(--color-text-primary)",
154
+ border: "1px solid var(--color-border-default)"
155
155
  },
156
156
  successMessage: {
157
157
  display: "flex",
158
158
  alignItems: "center",
159
159
  gap: "8px",
160
160
  padding: "12px 16px",
161
- backgroundColor: "#ecfdf5",
162
- border: "1px solid #a7f3d0",
161
+ backgroundColor: "var(--color-status-success-bgSubtle)",
162
+ border: "1px solid var(--color-status-success-border)",
163
163
  borderRadius: "6px",
164
164
  marginBottom: "16px",
165
- color: "#065f46",
165
+ color: "var(--color-status-success-text)",
166
166
  fontSize: "14px"
167
167
  },
168
168
  emptyState: {
@@ -172,7 +172,7 @@ var m = {
172
172
  justifyContent: "center",
173
173
  height: "100%",
174
174
  padding: "32px",
175
- color: "#6b7280",
175
+ color: "var(--color-text-muted)",
176
176
  textAlign: "center"
177
177
  }
178
178
  }, h = e(function({ widget: e, data: h = {}, onDrilldown: g, onSubmit: _ }) {
@@ -1 +1 @@
1
- {"version":3,"file":"FormWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/form/FormWidget.tsx"],"sourcesContent":["/**\n * FormWidget Component\n *\n * Interactive form widget for data input with validation and submit actions.\n * v2.0 spec compliant widget type.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport type {\n Widget,\n FormConfig as FormConfigType,\n FormFieldConfig,\n FormFieldType as FormFieldTypeAlias,\n FormFieldOption,\n FormValidationRule,\n} from '../../../types';\nimport { AlertCircle, CheckCircle, Send, RotateCcw, Settings, Loader2 } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Re-export types from main types file\nexport type FieldType = FormFieldTypeAlias;\nexport type FormField = FormFieldConfig;\nexport type SelectOption = FormFieldOption;\nexport type ValidationRule = FormValidationRule;\nexport type FormConfig = FormConfigType;\n\nexport interface FormWidgetProps {\n widget: Widget;\n data?: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n onSubmit?: (formData: Record<string, unknown>) => void;\n}\n\ninterface FieldErrors {\n [fieldName: string]: string | null;\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nfunction validateField(value: unknown, field: FormField): string | null {\n const strValue = String(value ?? '');\n const isEmpty = value === null || value === undefined || strValue.trim() === '';\n\n // Check required\n if (field.required && isEmpty) {\n return `${field.label} is required`;\n }\n\n // Skip other validations if empty and not required\n if (isEmpty) return null;\n\n // Apply validation rules\n if (field.validation) {\n for (const rule of field.validation) {\n switch (rule.type) {\n case 'required':\n if (isEmpty) return rule.message;\n break;\n case 'minLength':\n if (strValue.length < Number(rule.value)) return rule.message;\n break;\n case 'maxLength':\n if (strValue.length > Number(rule.value)) return rule.message;\n break;\n case 'min':\n if (Number(value) < Number(rule.value)) return rule.message;\n break;\n case 'max':\n if (Number(value) > Number(rule.value)) return rule.message;\n break;\n case 'pattern':\n if (rule.value && !new RegExp(String(rule.value)).test(strValue)) {\n return rule.message;\n }\n break;\n case 'email':\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return rule.message;\n }\n break;\n }\n }\n }\n\n // Type-specific validation\n if (field.type === 'email' && !field.validation?.some((r) => r.type === 'email')) {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return 'Please enter a valid email address';\n }\n }\n\n if (field.type === 'url') {\n try {\n new URL(strValue);\n } catch {\n return 'Please enter a valid URL';\n }\n }\n\n if (field.type === 'number') {\n if (isNaN(Number(value))) {\n return 'Please enter a valid number';\n }\n if (field.min !== undefined && Number(value) < Number(field.min)) {\n return `Value must be at least ${field.min}`;\n }\n if (field.max !== undefined && Number(value) > Number(field.max)) {\n return `Value must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\nfunction validateForm(values: Record<string, unknown>, fields: FormField[]): FieldErrors {\n const errors: FieldErrors = {};\n for (const field of fields) {\n const error = validateField(values[field.name], field);\n if (error) {\n errors[field.name] = error;\n }\n }\n return errors;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n height: '100%',\n overflow: 'hidden',\n },\n form: {\n flex: 1,\n overflow: 'auto',\n padding: '16px',\n },\n fieldWrapper: {\n marginBottom: '16px',\n },\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: '#374151',\n marginBottom: '6px',\n },\n required: {\n color: '#dc2626',\n marginLeft: '2px',\n },\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n backgroundColor: '#ffffff',\n transition: 'border-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n },\n inputError: {\n borderColor: '#dc2626',\n },\n inputFocus: {\n borderColor: '#6366f1',\n boxShadow: '0 0 0 3px rgba(99, 102, 241, 0.1)',\n },\n textarea: {\n resize: 'vertical' as const,\n minHeight: '80px',\n },\n select: {\n appearance: 'none' as const,\n backgroundImage: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\")`,\n backgroundPosition: 'right 8px center',\n backgroundRepeat: 'no-repeat',\n backgroundSize: '20px',\n paddingRight: '36px',\n },\n checkbox: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n },\n checkboxInput: {\n width: '16px',\n height: '16px',\n cursor: 'pointer',\n },\n helpText: {\n fontSize: '12px',\n color: '#6b7280',\n marginTop: '4px',\n },\n errorText: {\n fontSize: '12px',\n color: '#dc2626',\n marginTop: '4px',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n },\n footer: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n backgroundColor: '#f9fafb',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'all 0.15s',\n border: 'none',\n },\n submitButton: {\n backgroundColor: '#6366f1',\n color: '#ffffff',\n },\n resetButton: {\n backgroundColor: '#ffffff',\n color: '#374151',\n border: '1px solid #d1d5db',\n },\n successMessage: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 16px',\n backgroundColor: '#ecfdf5',\n border: '1px solid #a7f3d0',\n borderRadius: '6px',\n marginBottom: '16px',\n color: '#065f46',\n fontSize: '14px',\n },\n emptyState: {\n display: 'flex',\n flexDirection: 'column' as const,\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n padding: '32px',\n color: '#6b7280',\n textAlign: 'center' as const,\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const FormWidget: FC<FormWidgetProps> = memo(function FormWidget({ widget, data = {}, onDrilldown, onSubmit }) {\n const defaultConfig: FormConfig = {\n fields: [],\n layout: 'vertical',\n submitLabel: 'Submit',\n showReset: true,\n validateOnBlur: true,\n validateOnChange: false,\n };\n const config: FormConfig = widget.config\n ? { ...defaultConfig, ...(widget.config as Partial<FormConfig>) }\n : defaultConfig;\n\n // Initialize form values from default values or data\n const initialValues = useMemo(() => {\n const values: Record<string, unknown> = {};\n for (const field of config.fields) {\n values[field.name] = data[field.name] ?? field.defaultValue ?? (field.type === 'checkbox' ? false : '');\n }\n return values;\n }, [config.fields, data]);\n\n const [values, setValues] = useState<Record<string, unknown>>(initialValues);\n const [errors, setErrors] = useState<FieldErrors>({});\n const [touched, setTouched] = useState<Set<string>>(new Set());\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n\n // Handle field change\n const handleChange = useCallback(\n (fieldName: string, value: unknown) => {\n setValues((prev) => ({ ...prev, [fieldName]: value }));\n setSubmitSuccess(false);\n\n if (config.validateOnChange) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(value, field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnChange]\n );\n\n // Handle field blur\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => new Set(prev).add(fieldName));\n\n if (config.validateOnBlur) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(values[fieldName], field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnBlur, values]\n );\n\n // Handle form submit\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // Validate all fields\n const allErrors = validateForm(values, config.fields);\n setErrors(allErrors);\n setTouched(new Set(config.fields.map((f) => f.name)));\n\n // Check if there are errors\n const hasErrors = Object.values(allErrors).some((e) => e !== null);\n if (hasErrors) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n // Emit form submit event via onDrilldown or onSubmit\n const formData = {\n ...values,\n _action: config.submitAction || 'form_submit',\n _widgetId: widget.id,\n _timestamp: new Date().toISOString(),\n };\n\n if (onSubmit) {\n await onSubmit(formData);\n }\n\n if (onDrilldown) {\n onDrilldown({\n type: 'form_submit',\n action: config.submitAction || 'form_submit',\n data: formData,\n });\n }\n\n setSubmitSuccess(true);\n } catch (error) {\n } finally {\n setIsSubmitting(false);\n }\n },\n [values, config.fields, config.submitAction, widget.id, onSubmit, onDrilldown]\n );\n\n // Handle form reset\n const handleReset = useCallback(() => {\n setValues(initialValues);\n setErrors({});\n setTouched(new Set());\n setSubmitSuccess(false);\n }, [initialValues]);\n\n // Render a field\n const renderField = useCallback(\n (field: FormField) => {\n const value = values[field.name];\n const error = touched.has(field.name) ? errors[field.name] : null;\n const hasError = Boolean(error);\n\n const inputStyle = {\n ...styles.input,\n ...(hasError ? styles.inputError : {}),\n };\n\n switch (field.type) {\n case 'textarea':\n return (\n <textarea\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n rows={field.rows || 4}\n style={{ ...inputStyle, ...styles.textarea }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n );\n\n case 'select':\n return (\n <select\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n style={{ ...inputStyle, ...styles.select }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n >\n <option value=\"\">{field.placeholder || `Select ${field.label}...`}</option>\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n\n case 'checkbox':\n return (\n <div style={styles.checkbox}>\n <input\n type=\"checkbox\"\n id={field.name}\n name={field.name}\n checked={Boolean(value)}\n disabled={field.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.checked)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={field.name} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {field.label}\n </label>\n </div>\n );\n\n case 'radio':\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {field.options?.map((opt) => (\n <div key={opt.value} style={styles.checkbox}>\n <input\n type=\"radio\"\n id={`${field.name}-${opt.value}`}\n name={field.name}\n value={opt.value}\n checked={value === opt.value}\n disabled={field.disabled || opt.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={`${field.name}-${opt.value}`} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {opt.label}\n </label>\n </div>\n ))}\n </div>\n );\n\n case 'hidden':\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\n\n default:\n return (\n <input\n type={field.type}\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n min={field.min}\n max={field.max}\n step={field.step}\n pattern={field.pattern}\n style={inputStyle}\n onChange={(e) =>\n handleChange(field.name, field.type === 'number' ? e.target.valueAsNumber : e.target.value)\n }\n onBlur={() => handleBlur(field.name)}\n />\n );\n }\n },\n [values, errors, touched, isSubmitting, handleChange, handleBlur]\n );\n\n // Empty state\n if (config.fields.length === 0) {\n return (\n <div style={styles.emptyState}>\n <Settings style={{ width: '48px', height: '48px', marginBottom: '16px', opacity: 0.5 }} />\n <p style={{ fontSize: '14px' }}>Configure Form Fields</p>\n <p style={{ fontSize: '12px', marginTop: '4px' }}>Add fields in widget settings to create your form</p>\n </div>\n );\n }\n\n // Grid layout styles\n const gridStyle =\n config.layout === 'grid'\n ? {\n display: 'grid',\n gridTemplateColumns: `repeat(${config.columns || 2}, 1fr)`,\n gap: '16px',\n }\n : {};\n\n return (\n <div style={styles.container}>\n <form onSubmit={handleSubmit} style={{ ...styles.form, ...gridStyle }}>\n {/* Success message */}\n {submitSuccess && config.successMessage && (\n <div style={{ ...styles.successMessage, gridColumn: '1 / -1' }}>\n <CheckCircle style={{ width: '18px', height: '18px' }} />\n {config.successMessage}\n </div>\n )}\n\n {/* Form fields */}\n {config.fields.map((field) => {\n if (field.type === 'hidden') {\n return renderField(field);\n }\n\n const error = touched.has(field.name) ? errors[field.name] : null;\n\n return (\n <div key={field.name} style={styles.fieldWrapper}>\n {field.type !== 'checkbox' && (\n <label htmlFor={field.name} style={styles.label}>\n {field.label}\n {field.required && <span style={styles.required}>*</span>}\n </label>\n )}\n\n {renderField(field)}\n\n {field.helpText && !error && <p style={styles.helpText}>{field.helpText}</p>}\n\n {error && (\n <p style={styles.errorText}>\n <AlertCircle style={{ width: '14px', height: '14px' }} />\n {error}\n </p>\n )}\n </div>\n );\n })}\n </form>\n\n {/* Footer with buttons */}\n <div style={styles.footer}>\n {config.showReset !== false && (\n <button\n type=\"button\"\n onClick={handleReset}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.resetButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n <RotateCcw style={{ width: '16px', height: '16px' }} />\n {config.resetLabel || 'Reset'}\n </button>\n )}\n\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.submitButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n {isSubmitting ? (\n <Loader2 style={{ width: '16px', height: '16px', animation: 'spin 1s linear infinite' }} />\n ) : (\n <Send style={{ width: '16px', height: '16px' }} />\n )}\n {config.submitLabel || 'Submit'}\n </button>\n </div>\n </div>\n );\n});\n\nexport default FormWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"FormWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/form/FormWidget.tsx"],"sourcesContent":["/**\n * FormWidget Component\n *\n * Interactive form widget for data input with validation and submit actions.\n * v2.0 spec compliant widget type.\n */\n\nimport { type FC, memo, useState, useCallback, useMemo } from 'react';\nimport type {\n Widget,\n FormConfig as FormConfigType,\n FormFieldConfig,\n FormFieldType as FormFieldTypeAlias,\n FormFieldOption,\n FormValidationRule,\n} from '../../../types';\nimport { AlertCircle, CheckCircle, Send, RotateCcw, Settings, Loader2 } from 'lucide-react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// Re-export types from main types file\nexport type FieldType = FormFieldTypeAlias;\nexport type FormField = FormFieldConfig;\nexport type SelectOption = FormFieldOption;\nexport type ValidationRule = FormValidationRule;\nexport type FormConfig = FormConfigType;\n\nexport interface FormWidgetProps {\n widget: Widget;\n data?: Record<string, unknown>;\n /** Whether the widget is in edit mode */\n isEditMode?: boolean;\n /** Whether the widget is selected */\n isSelected?: boolean;\n /** Whether data is loading */\n isLoading?: boolean;\n /** Error message if any */\n error?: string | null;\n /** Callback when widget is clicked */\n onClick?: () => void;\n onDrilldown?: (selectedData: Record<string, unknown>) => void;\n onSubmit?: (formData: Record<string, unknown>) => void;\n}\n\ninterface FieldErrors {\n [fieldName: string]: string | null;\n}\n\n// ============================================================================\n// Validation\n// ============================================================================\n\nfunction validateField(value: unknown, field: FormField): string | null {\n const strValue = String(value ?? '');\n const isEmpty = value === null || value === undefined || strValue.trim() === '';\n\n // Check required\n if (field.required && isEmpty) {\n return `${field.label} is required`;\n }\n\n // Skip other validations if empty and not required\n if (isEmpty) return null;\n\n // Apply validation rules\n if (field.validation) {\n for (const rule of field.validation) {\n switch (rule.type) {\n case 'required':\n if (isEmpty) return rule.message;\n break;\n case 'minLength':\n if (strValue.length < Number(rule.value)) return rule.message;\n break;\n case 'maxLength':\n if (strValue.length > Number(rule.value)) return rule.message;\n break;\n case 'min':\n if (Number(value) < Number(rule.value)) return rule.message;\n break;\n case 'max':\n if (Number(value) > Number(rule.value)) return rule.message;\n break;\n case 'pattern':\n if (rule.value && !new RegExp(String(rule.value)).test(strValue)) {\n return rule.message;\n }\n break;\n case 'email':\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return rule.message;\n }\n break;\n }\n }\n }\n\n // Type-specific validation\n if (field.type === 'email' && !field.validation?.some((r) => r.type === 'email')) {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(strValue)) {\n return 'Please enter a valid email address';\n }\n }\n\n if (field.type === 'url') {\n try {\n new URL(strValue);\n } catch {\n return 'Please enter a valid URL';\n }\n }\n\n if (field.type === 'number') {\n if (isNaN(Number(value))) {\n return 'Please enter a valid number';\n }\n if (field.min !== undefined && Number(value) < Number(field.min)) {\n return `Value must be at least ${field.min}`;\n }\n if (field.max !== undefined && Number(value) > Number(field.max)) {\n return `Value must be at most ${field.max}`;\n }\n }\n\n return null;\n}\n\nfunction validateForm(values: Record<string, unknown>, fields: FormField[]): FieldErrors {\n const errors: FieldErrors = {};\n for (const field of fields) {\n const error = validateField(values[field.name], field);\n if (error) {\n errors[field.name] = error;\n }\n }\n return errors;\n}\n\n// ============================================================================\n// Styles\n// ============================================================================\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column' as const,\n height: '100%',\n overflow: 'hidden',\n },\n form: {\n flex: 1,\n overflow: 'auto',\n padding: '16px',\n },\n fieldWrapper: {\n marginBottom: '16px',\n },\n label: {\n display: 'block',\n fontSize: '13px',\n fontWeight: 500,\n color: 'var(--color-text-primary)',\n marginBottom: '6px',\n },\n required: {\n color: 'var(--color-status-error-text)',\n marginLeft: '2px',\n },\n input: {\n width: '100%',\n padding: '8px 12px',\n fontSize: '14px',\n border: '1px solid var(--color-border-default)',\n borderRadius: '6px',\n backgroundColor: 'var(--color-bg-surface)',\n transition: 'border-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n },\n inputError: {\n borderColor: 'var(--color-status-error-border)',\n },\n inputFocus: {\n borderColor: 'var(--color-border-focus)',\n boxShadow: 'var(--shadow-focus)',\n },\n textarea: {\n resize: 'vertical' as const,\n minHeight: '80px',\n },\n select: {\n appearance: 'none' as const,\n backgroundImage: `url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\")`,\n backgroundPosition: 'right 8px center',\n backgroundRepeat: 'no-repeat',\n backgroundSize: '20px',\n paddingRight: '36px',\n },\n checkbox: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n },\n checkboxInput: {\n width: '16px',\n height: '16px',\n cursor: 'pointer',\n },\n helpText: {\n fontSize: '12px',\n color: 'var(--color-text-muted)',\n marginTop: '4px',\n },\n errorText: {\n fontSize: '12px',\n color: 'var(--color-status-error-text)',\n marginTop: '4px',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n },\n footer: {\n display: 'flex',\n justifyContent: 'flex-end',\n gap: '12px',\n padding: '12px 16px',\n borderTop: '1px solid var(--color-border-subtle)',\n backgroundColor: 'var(--color-bg-subtle)',\n },\n button: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 16px',\n fontSize: '14px',\n fontWeight: 500,\n borderRadius: '6px',\n cursor: 'pointer',\n transition: 'all 0.15s',\n border: 'none',\n },\n submitButton: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-text-inverse)',\n },\n resetButton: {\n backgroundColor: 'var(--color-bg-surface)',\n color: 'var(--color-text-primary)',\n border: '1px solid var(--color-border-default)',\n },\n successMessage: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 16px',\n backgroundColor: 'var(--color-status-success-bgSubtle)',\n border: '1px solid var(--color-status-success-border)',\n borderRadius: '6px',\n marginBottom: '16px',\n color: 'var(--color-status-success-text)',\n fontSize: '14px',\n },\n emptyState: {\n display: 'flex',\n flexDirection: 'column' as const,\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n padding: '32px',\n color: 'var(--color-text-muted)',\n textAlign: 'center' as const,\n },\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const FormWidget: FC<FormWidgetProps> = memo(function FormWidget({ widget, data = {}, onDrilldown, onSubmit }) {\n const defaultConfig: FormConfig = {\n fields: [],\n layout: 'vertical',\n submitLabel: 'Submit',\n showReset: true,\n validateOnBlur: true,\n validateOnChange: false,\n };\n const config: FormConfig = widget.config\n ? { ...defaultConfig, ...(widget.config as Partial<FormConfig>) }\n : defaultConfig;\n\n // Initialize form values from default values or data\n const initialValues = useMemo(() => {\n const values: Record<string, unknown> = {};\n for (const field of config.fields) {\n values[field.name] = data[field.name] ?? field.defaultValue ?? (field.type === 'checkbox' ? false : '');\n }\n return values;\n }, [config.fields, data]);\n\n const [values, setValues] = useState<Record<string, unknown>>(initialValues);\n const [errors, setErrors] = useState<FieldErrors>({});\n const [touched, setTouched] = useState<Set<string>>(new Set());\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitSuccess, setSubmitSuccess] = useState(false);\n\n // Handle field change\n const handleChange = useCallback(\n (fieldName: string, value: unknown) => {\n setValues((prev) => ({ ...prev, [fieldName]: value }));\n setSubmitSuccess(false);\n\n if (config.validateOnChange) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(value, field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnChange]\n );\n\n // Handle field blur\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => new Set(prev).add(fieldName));\n\n if (config.validateOnBlur) {\n const field = config.fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(values[fieldName], field);\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n }\n }\n },\n [config.fields, config.validateOnBlur, values]\n );\n\n // Handle form submit\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n\n // Validate all fields\n const allErrors = validateForm(values, config.fields);\n setErrors(allErrors);\n setTouched(new Set(config.fields.map((f) => f.name)));\n\n // Check if there are errors\n const hasErrors = Object.values(allErrors).some((e) => e !== null);\n if (hasErrors) {\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n // Emit form submit event via onDrilldown or onSubmit\n const formData = {\n ...values,\n _action: config.submitAction || 'form_submit',\n _widgetId: widget.id,\n _timestamp: new Date().toISOString(),\n };\n\n if (onSubmit) {\n await onSubmit(formData);\n }\n\n if (onDrilldown) {\n onDrilldown({\n type: 'form_submit',\n action: config.submitAction || 'form_submit',\n data: formData,\n });\n }\n\n setSubmitSuccess(true);\n } catch (error) {\n } finally {\n setIsSubmitting(false);\n }\n },\n [values, config.fields, config.submitAction, widget.id, onSubmit, onDrilldown]\n );\n\n // Handle form reset\n const handleReset = useCallback(() => {\n setValues(initialValues);\n setErrors({});\n setTouched(new Set());\n setSubmitSuccess(false);\n }, [initialValues]);\n\n // Render a field\n const renderField = useCallback(\n (field: FormField) => {\n const value = values[field.name];\n const error = touched.has(field.name) ? errors[field.name] : null;\n const hasError = Boolean(error);\n\n const inputStyle = {\n ...styles.input,\n ...(hasError ? styles.inputError : {}),\n };\n\n switch (field.type) {\n case 'textarea':\n return (\n <textarea\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n rows={field.rows || 4}\n style={{ ...inputStyle, ...styles.textarea }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n );\n\n case 'select':\n return (\n <select\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n style={{ ...inputStyle, ...styles.select }}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n >\n <option value=\"\">{field.placeholder || `Select ${field.label}...`}</option>\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value} disabled={opt.disabled}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n\n case 'checkbox':\n return (\n <div style={styles.checkbox}>\n <input\n type=\"checkbox\"\n id={field.name}\n name={field.name}\n checked={Boolean(value)}\n disabled={field.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.checked)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={field.name} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {field.label}\n </label>\n </div>\n );\n\n case 'radio':\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>\n {field.options?.map((opt) => (\n <div key={opt.value} style={styles.checkbox}>\n <input\n type=\"radio\"\n id={`${field.name}-${opt.value}`}\n name={field.name}\n value={opt.value}\n checked={value === opt.value}\n disabled={field.disabled || opt.disabled || isSubmitting}\n style={styles.checkboxInput}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n />\n <label htmlFor={`${field.name}-${opt.value}`} style={{ fontSize: '14px', cursor: 'pointer' }}>\n {opt.label}\n </label>\n </div>\n ))}\n </div>\n );\n\n case 'hidden':\n return <input type=\"hidden\" name={field.name} value={String(value ?? '')} />;\n\n default:\n return (\n <input\n type={field.type}\n id={field.name}\n name={field.name}\n value={String(value ?? '')}\n placeholder={field.placeholder}\n required={field.required}\n disabled={field.disabled || isSubmitting}\n readOnly={field.readonly}\n min={field.min}\n max={field.max}\n step={field.step}\n pattern={field.pattern}\n style={inputStyle}\n onChange={(e) =>\n handleChange(field.name, field.type === 'number' ? e.target.valueAsNumber : e.target.value)\n }\n onBlur={() => handleBlur(field.name)}\n />\n );\n }\n },\n [values, errors, touched, isSubmitting, handleChange, handleBlur]\n );\n\n // Empty state\n if (config.fields.length === 0) {\n return (\n <div style={styles.emptyState}>\n <Settings style={{ width: '48px', height: '48px', marginBottom: '16px', opacity: 0.5 }} />\n <p style={{ fontSize: '14px' }}>Configure Form Fields</p>\n <p style={{ fontSize: '12px', marginTop: '4px' }}>Add fields in widget settings to create your form</p>\n </div>\n );\n }\n\n // Grid layout styles\n const gridStyle =\n config.layout === 'grid'\n ? {\n display: 'grid',\n gridTemplateColumns: `repeat(${config.columns || 2}, 1fr)`,\n gap: '16px',\n }\n : {};\n\n return (\n <div style={styles.container}>\n <form onSubmit={handleSubmit} style={{ ...styles.form, ...gridStyle }}>\n {/* Success message */}\n {submitSuccess && config.successMessage && (\n <div style={{ ...styles.successMessage, gridColumn: '1 / -1' }}>\n <CheckCircle style={{ width: '18px', height: '18px' }} />\n {config.successMessage}\n </div>\n )}\n\n {/* Form fields */}\n {config.fields.map((field) => {\n if (field.type === 'hidden') {\n return renderField(field);\n }\n\n const error = touched.has(field.name) ? errors[field.name] : null;\n\n return (\n <div key={field.name} style={styles.fieldWrapper}>\n {field.type !== 'checkbox' && (\n <label htmlFor={field.name} style={styles.label}>\n {field.label}\n {field.required && <span style={styles.required}>*</span>}\n </label>\n )}\n\n {renderField(field)}\n\n {field.helpText && !error && <p style={styles.helpText}>{field.helpText}</p>}\n\n {error && (\n <p style={styles.errorText}>\n <AlertCircle style={{ width: '14px', height: '14px' }} />\n {error}\n </p>\n )}\n </div>\n );\n })}\n </form>\n\n {/* Footer with buttons */}\n <div style={styles.footer}>\n {config.showReset !== false && (\n <button\n type=\"button\"\n onClick={handleReset}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.resetButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n <RotateCcw style={{ width: '16px', height: '16px' }} />\n {config.resetLabel || 'Reset'}\n </button>\n )}\n\n <button\n type=\"submit\"\n onClick={handleSubmit}\n disabled={isSubmitting}\n style={{\n ...styles.button,\n ...styles.submitButton,\n opacity: isSubmitting ? 0.6 : 1,\n }}\n >\n {isSubmitting ? (\n <Loader2 style={{ width: '16px', height: '16px', animation: 'spin 1s linear infinite' }} />\n ) : (\n <Send style={{ width: '16px', height: '16px' }} />\n )}\n {config.submitLabel || 'Submit'}\n </button>\n </div>\n </div>\n );\n});\n\nexport default FormWidget;\n"],"mappings":"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"}
@@ -27,7 +27,7 @@ var a = e(function({ widget: e, data: a, onClick: o }) {
27
27
  children: [
28
28
  /* @__PURE__ */ n("div", {
29
29
  className: "w-2 h-2 rounded-full",
30
- style: { backgroundColor: e.color || "#6b7280" }
30
+ style: { backgroundColor: e.color || "var(--color-text-muted)" }
31
31
  }),
32
32
  /* @__PURE__ */ n("span", {
33
33
  className: "text-xs font-medium text-text-primary truncate",
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/kanban/KanbanWidget.tsx"],"sourcesContent":["/**\n * KanbanWidget Component\n *\n * Simple kanban board view with columns and tasks.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KanbanWidgetProps {\n widget: Widget;\n data?: KanbanData;\n onClick?: (task: KanbanTask) => void;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n color?: string;\n}\n\nexport interface KanbanTask {\n id: string;\n title: string;\n column: string;\n priority?: 'high' | 'medium' | 'low';\n assignee?: string;\n labels?: string[];\n dueDate?: string;\n}\n\nexport interface KanbanData {\n columns?: KanbanColumn[];\n tasks?: KanbanTask[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getPriorityColor(priority?: string): string {\n switch (priority) {\n case 'high':\n return 'bg-state-error/20 text-state-error';\n case 'medium':\n return 'bg-state-warning/20 text-state-warning';\n case 'low':\n return 'bg-state-success/20 text-state-success';\n default:\n return 'bg-bg-muted text-text-secondary';\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const KanbanWidget: FC<KanbanWidgetProps> = memo(function KanbanWidget({ widget: _widget, data, onClick }) {\n const columns = useMemo(() => data?.columns || [], [data?.columns]);\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n\n // Group tasks by column\n const tasksByColumn = useMemo(() => {\n const grouped: Record<string, KanbanTask[]> = {};\n columns.forEach((col) => {\n grouped[col.id] = tasks.filter((t) => t.column === col.id);\n });\n return grouped;\n }, [columns, tasks]);\n\n if (!columns.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 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2\"\n />\n </svg>\n <p>No board data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full p-2 gap-2 overflow-x-auto\">\n {columns.map((column) => {\n const columnTasks = tasksByColumn[column.id] || [];\n\n return (\n <div key={column.id} className=\"flex-shrink-0 w-48 flex flex-col bg-bg-muted/50 rounded-lg\">\n {/* Column Header */}\n <div className=\"flex items-center gap-2 p-2 border-b border-border-default\">\n <div className=\"w-2 h-2 rounded-full\" style={{ backgroundColor: column.color || '#6b7280' }} />\n <span className=\"text-xs font-medium text-text-primary truncate\">{column.title}</span>\n <span className=\"ml-auto text-xs text-text-tertiary\">{columnTasks.length}</span>\n </div>\n\n {/* Tasks */}\n <div className=\"flex-1 p-2 space-y-2 overflow-y-auto\">\n {columnTasks.map((task) => (\n <div\n key={task.id}\n className={`\n p-2 bg-bg-surface rounded border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(task)}\n >\n <p className=\"text-xs font-medium text-text-primary line-clamp-2\">{task.title}</p>\n\n <div className=\"flex items-center gap-1 mt-2 flex-wrap\">\n {task.priority && (\n <span className={`px-1.5 py-0.5 text-[10px] rounded ${getPriorityColor(task.priority)}`}>\n {task.priority}\n </span>\n )}\n {task.assignee && (\n <span className=\"px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text\">\n {task.assignee}\n </span>\n )}\n </div>\n </div>\n ))}\n\n {columnTasks.length === 0 && <p className=\"text-[10px] text-text-tertiary text-center py-4\">No tasks</p>}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n\nexport default KanbanWidget;\n"],"mappings":";;;AA4CA,SAAS,EAAiB,GAA2B;AACnD,SAAQ,GAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;;;AAQb,IAAa,IAAsC,EAAK,SAAsB,EAAE,QAAQ,GAAS,SAAM,cAAW;CAChH,IAAM,IAAU,QAAc,GAAM,WAAW,EAAE,EAAE,CAAC,GAAM,QAAQ,CAAC,EAC7D,IAAQ,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,GAAM,MAAM,CAAC,EAGvD,IAAgB,QAAc;EAClC,IAAM,IAAwC,EAAE;AAIhD,SAHA,EAAQ,SAAS,MAAQ;AACvB,KAAQ,EAAI,MAAM,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;IAC1D,EACK;IACN,CAAC,GAAS,EAAM,CAAC;AAyBpB,QAvBK,EAAQ,SAwBX,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAc,EAAc,EAAO,OAAO,EAAE;AAElD,UACE,kBAAC,OAAD;IAAqB,WAAU;cAA/B,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;OAAuB,OAAO,EAAE,iBAAiB,EAAO,SAAS,WAAW;OAAI,CAAA;MAC/F,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAO;OAAa,CAAA;MACtF,kBAAC,QAAD;OAAM,WAAU;iBAAsC,EAAY;OAAc,CAAA;MAC5E;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAY,KAAK,MAChB,kBAAC,OAAD;MAEE,WAAW;;wBAEL,IAAU,kDAAkD,GAAG;;;MAGrE,eAAe,IAAU,EAAK;gBAPhC,CASE,kBAAC,KAAD;OAAG,WAAU;iBAAsD,EAAK;OAAU,CAAA,EAElF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAW,qCAAqC,EAAiB,EAAK,SAAS;kBAClF,EAAK;QACD,CAAA,EAER,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CAEL;SACF;QAtBC,EAAK,GAsBN,CACN,EAED,EAAY,WAAW,KAAK,kBAAC,KAAD;MAAG,WAAU;gBAAkD;MAAY,CAAA,CACpG;OACF;MAvCI,EAAO,GAuCX;IAER;EACE,CAAA,GArEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAER,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,iBAAiB,CAAA,CAChB;;EACF,CAAA;EAsDV"}
1
+ {"version":3,"file":"KanbanWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/kanban/KanbanWidget.tsx"],"sourcesContent":["/**\n * KanbanWidget Component\n *\n * Simple kanban board view with columns and tasks.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KanbanWidgetProps {\n widget: Widget;\n data?: KanbanData;\n onClick?: (task: KanbanTask) => void;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n color?: string;\n}\n\nexport interface KanbanTask {\n id: string;\n title: string;\n column: string;\n priority?: 'high' | 'medium' | 'low';\n assignee?: string;\n labels?: string[];\n dueDate?: string;\n}\n\nexport interface KanbanData {\n columns?: KanbanColumn[];\n tasks?: KanbanTask[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getPriorityColor(priority?: string): string {\n switch (priority) {\n case 'high':\n return 'bg-state-error/20 text-state-error';\n case 'medium':\n return 'bg-state-warning/20 text-state-warning';\n case 'low':\n return 'bg-state-success/20 text-state-success';\n default:\n return 'bg-bg-muted text-text-secondary';\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const KanbanWidget: FC<KanbanWidgetProps> = memo(function KanbanWidget({ widget: _widget, data, onClick }) {\n const columns = useMemo(() => data?.columns || [], [data?.columns]);\n const tasks = useMemo(() => data?.tasks || [], [data?.tasks]);\n\n // Group tasks by column\n const tasksByColumn = useMemo(() => {\n const grouped: Record<string, KanbanTask[]> = {};\n columns.forEach((col) => {\n grouped[col.id] = tasks.filter((t) => t.column === col.id);\n });\n return grouped;\n }, [columns, tasks]);\n\n if (!columns.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 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2\"\n />\n </svg>\n <p>No board data</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full p-2 gap-2 overflow-x-auto\">\n {columns.map((column) => {\n const columnTasks = tasksByColumn[column.id] || [];\n\n return (\n <div key={column.id} className=\"flex-shrink-0 w-48 flex flex-col bg-bg-muted/50 rounded-lg\">\n {/* Column Header */}\n <div className=\"flex items-center gap-2 p-2 border-b border-border-default\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: column.color || 'var(--color-text-muted)' }}\n />\n <span className=\"text-xs font-medium text-text-primary truncate\">{column.title}</span>\n <span className=\"ml-auto text-xs text-text-tertiary\">{columnTasks.length}</span>\n </div>\n\n {/* Tasks */}\n <div className=\"flex-1 p-2 space-y-2 overflow-y-auto\">\n {columnTasks.map((task) => (\n <div\n key={task.id}\n className={`\n p-2 bg-bg-surface rounded border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(task)}\n >\n <p className=\"text-xs font-medium text-text-primary line-clamp-2\">{task.title}</p>\n\n <div className=\"flex items-center gap-1 mt-2 flex-wrap\">\n {task.priority && (\n <span className={`px-1.5 py-0.5 text-[10px] rounded ${getPriorityColor(task.priority)}`}>\n {task.priority}\n </span>\n )}\n {task.assignee && (\n <span className=\"px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text\">\n {task.assignee}\n </span>\n )}\n </div>\n </div>\n ))}\n\n {columnTasks.length === 0 && <p className=\"text-[10px] text-text-tertiary text-center py-4\">No tasks</p>}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n\nexport default KanbanWidget;\n"],"mappings":";;;AA4CA,SAAS,EAAiB,GAA2B;AACnD,SAAQ,GAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;;;AAQb,IAAa,IAAsC,EAAK,SAAsB,EAAE,QAAQ,GAAS,SAAM,cAAW;CAChH,IAAM,IAAU,QAAc,GAAM,WAAW,EAAE,EAAE,CAAC,GAAM,QAAQ,CAAC,EAC7D,IAAQ,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,GAAM,MAAM,CAAC,EAGvD,IAAgB,QAAc;EAClC,IAAM,IAAwC,EAAE;AAIhD,SAHA,EAAQ,SAAS,MAAQ;AACvB,KAAQ,EAAI,MAAM,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;IAC1D,EACK;IACN,CAAC,GAAS,EAAM,CAAC;AAyBpB,QAvBK,EAAQ,SAwBX,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAc,EAAc,EAAO,OAAO,EAAE;AAElD,UACE,kBAAC,OAAD;IAAqB,WAAU;cAA/B,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,2BAA2B;OACrE,CAAA;MACF,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAO;OAAa,CAAA;MACtF,kBAAC,QAAD;OAAM,WAAU;iBAAsC,EAAY;OAAc,CAAA;MAC5E;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAY,KAAK,MAChB,kBAAC,OAAD;MAEE,WAAW;;wBAEL,IAAU,kDAAkD,GAAG;;;MAGrE,eAAe,IAAU,EAAK;gBAPhC,CASE,kBAAC,KAAD;OAAG,WAAU;iBAAsD,EAAK;OAAU,CAAA,EAElF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAW,qCAAqC,EAAiB,EAAK,SAAS;kBAClF,EAAK;QACD,CAAA,EAER,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CAEL;SACF;QAtBC,EAAK,GAsBN,CACN,EAED,EAAY,WAAW,KAAK,kBAAC,KAAD;MAAG,WAAU;gBAAkD;MAAY,CAAA,CACpG;OACF;MA1CI,EAAO,GA0CX;IAER;EACE,CAAA,GAxEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,QAAO;IACP,SAAQ;cAER,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAG,iBAAiB,CAAA,CAChB;;EACF,CAAA;EAyDV"}
@@ -43,7 +43,7 @@ var i = e(function({ widget: e, data: i, onClick: a, onDrilldown: o }) {
43
43
  children: [
44
44
  /* @__PURE__ */ n("div", {
45
45
  className: "w-2 h-2 rounded-full",
46
- style: { backgroundColor: e.color || "#3b82f6" }
46
+ style: { backgroundColor: e.color || "var(--color-chart-1)" }
47
47
  }),
48
48
  /* @__PURE__ */ n("span", {
49
49
  className: "text-xs text-text-primary truncate max-w-[80px]",
@@ -71,7 +71,7 @@ var i = e(function({ widget: e, data: i, onClick: a, onDrilldown: o }) {
71
71
  className: "flex items-center gap-2",
72
72
  children: [/* @__PURE__ */ n("div", {
73
73
  className: "w-2 h-2 rounded-full flex-shrink-0",
74
- style: { backgroundColor: e.color || "#3b82f6" }
74
+ style: { backgroundColor: e.color || "var(--color-chart-1)" }
75
75
  }), /* @__PURE__ */ n("span", {
76
76
  className: "text-xs text-text-primary",
77
77
  children: e.name
@@ -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 }) {