@burdenoff/microfe-bigconsole 2026.929.1 → 2026.929.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.
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +410 -674
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +100 -97
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +1 -5
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/actionConfig.js +56 -0
- package/dist/bigconsole/components/widgets/actionConfig.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionConfigDialog.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/ActionConfigDialog.tsx"],"sourcesContent":["/**\n * ActionConfigDialog Component (v2.1)\n *\n * Modal dialog for creating/editing widget actions.\n *\n * v2.1 (BOFF-5659): reframed around the *outcome* — \"When clicked, do this\" —\n * instead of the abstract action Type. A button always emits\n * `widget:<name>:clicked`; the dialog now lets the user attach the behaviour\n * inline. Today the two shippable outcomes are:\n * - \"Call a webhook / my API\" → captures a URL + method; the parent pairs the\n * action with an EventWebhookMapping bound to that event (no backend change).\n * - \"Just emit an event\" → the raw emit, for callers wiring their own\n * consumers.\n * The action `name` (the event id) is auto-derived from the label and tucked\n * under Advanced so there is a single required field.\n *\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { Zap, Plus, Pencil, ChevronDown, ChevronRight } from 'lucide-react';\nimport { BIGCONSOLE_PERMISSIONS } from '../../../constants/permissions';\nimport type {\n WidgetAction,\n ActionStyle,\n ActionConfirmation,\n CreateWidgetActionInput,\n UpdateWidgetActionInput,\n} from '../../hooks/useWidgetActions';\nimport type { HttpMethod } from '../../hooks/useEventWebhooks';\nimport { Section } from '../common';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** What should happen when the button is clicked. */\nexport type ActionOutcome = 'WEBHOOK' | 'EMIT';\n\n/** Webhook binding drafted in the dialog and reconciled by the parent. */\nexport interface ActionWebhookDraft {\n url: string;\n method: HttpMethod;\n}\n\n/**\n * The action fields passed to the create/update mutation. The webhook binding\n * is passed as a SEPARATE onSave argument (never embedded here) so it can never\n * leak into the GraphQL input.\n */\nexport type ActionSaveData = Omit<CreateWidgetActionInput, 'widgetId'> | UpdateWidgetActionInput;\n\nexport interface ActionConfigDialogProps {\n isOpen: boolean;\n action?: WidgetAction;\n /** Existing webhook binding for the edited action (prefills the URL field). */\n initialWebhook?: ActionWebhookDraft | null;\n isLoading?: boolean;\n /** A save failure from the parent (action or webhook mutation) to surface inline. */\n saveError?: string | null;\n onClose: () => void;\n /** `webhook` is the paired binding, or `null` to remove any existing one. */\n onSave: (data: ActionSaveData, webhook: ActionWebhookDraft | null) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst HTTP_METHODS: HttpMethod[] = ['POST', 'GET', 'PUT', 'PATCH', 'DELETE'];\n\n/** Stable style values + preview colors; labels are resolved via i18n in-component. */\nconst ACTION_STYLE_META: { value: ActionStyle; color: string }[] = [\n { value: 'PRIMARY', color: 'var(--color-action-primary-bg)' },\n { value: 'SECONDARY', color: 'var(--color-action-secondary-bg)' },\n { value: 'SUCCESS', color: 'var(--color-status-success-bg)' },\n { value: 'WARNING', color: 'var(--color-status-warning-bg)' },\n { value: 'DANGER', color: 'var(--color-action-danger-bg)' },\n];\n\n/** Stable icon values; labels are resolved via i18n in-component. */\nconst ICON_VALUES = [\n '',\n 'refresh',\n 'download',\n 'upload',\n 'trash',\n 'edit',\n 'plus',\n 'check',\n 'eye',\n 'copy',\n 'share',\n 'settings',\n 'filter',\n 'search',\n] as const;\n\n// Derive the event-id (action name) from a human label: \"Refresh Data\" -> \"refresh_data\".\nfunction slugifyName(label: string): string {\n return label\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '');\n}\n\n// Field labels sit BELOW group headings in the type ladder: `medium` here,\n// `bold` + uppercase tracking for the group heading. Previously both were\n// semibold body-sm, so a label and a group heading were indistinguishable.\nconst labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n};\n\n/** Group heading inside the dialog body: \"Appearance\" / \"Behaviour\" / \"Advanced\". */\nconst groupHeadingStyle: React.CSSProperties = {\n margin: '0 0 var(--space-controlGap) 0',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-bold)',\n letterSpacing: '0.06em',\n textTransform: 'uppercase',\n color: 'var(--color-text-secondary)',\n};\n\nconst hintStyle: React.CSSProperties = {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n};\n\nconst selectContentStyle: React.CSSProperties = {\n zIndex: 9999,\n backgroundColor: 'var(--color-overlay-popoverBg, var(--color-bg-surface))',\n border: '1px solid var(--color-border-subtle)',\n boxShadow: 'var(--shadow-elevation-3)',\n borderRadius: 'var(--radius-button)',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ActionConfigDialog: FC<ActionConfigDialogProps> = memo(function ActionConfigDialog({\n isOpen,\n action,\n initialWebhook,\n isLoading = false,\n saveError,\n onClose,\n onSave,\n}) {\n const { t } = useI18n();\n const isEditMode = !!action;\n const labelInputRef = useRef<HTMLInputElement>(null);\n // True once the user touches the webhook fields, so a late-arriving\n // `initialWebhook` fetch can seed the form without clobbering in-progress edits.\n const webhookTouchedRef = useRef(false);\n\n // Form state\n const [label, setLabel] = useState('');\n const [name, setName] = useState('');\n const [nameEdited, setNameEdited] = useState(false);\n const [style, setStyle] = useState<ActionStyle>('PRIMARY');\n const [icon, setIcon] = useState('');\n const [outcome, setOutcome] = useState<ActionOutcome>('WEBHOOK');\n const [webhookUrl, setWebhookUrl] = useState('');\n const [webhookMethod, setWebhookMethod] = useState<HttpMethod>('POST');\n const [disabled, setDisabled] = useState(false);\n const [hidden, setHidden] = useState(false);\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [hasConfirmation, setHasConfirmation] = useState(false);\n const [confirmTitle, setConfirmTitle] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action')\n );\n const [confirmMessage, setConfirmMessage] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?')\n );\n const [confirmLabel, setConfirmLabel] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm')\n );\n const [cancelLabel, setCancelLabel] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel')\n );\n const [error, setError] = useState<string | null>(null);\n\n // Localized option lists — value/enum fields stay stable; only the display copy is translated.\n const OUTCOMES = useMemo<{ value: ActionOutcome; label: string; hint: string }[]>(\n () => [\n {\n value: 'WEBHOOK',\n label: t('bigconsole.widget.actions.outcome.webhook.label', 'Call a webhook / my API'),\n hint: t(\n 'bigconsole.widget.actions.outcome.webhook.hint',\n 'Sends an HTTP request to the URL below every time the button is clicked.'\n ),\n },\n {\n value: 'EMIT',\n label: t('bigconsole.widget.actions.outcome.emit.label', 'Just emit an event (advanced)'),\n hint: t(\n 'bigconsole.widget.actions.outcome.emit.hint',\n 'Emits widget:<name>:clicked. Wire it up yourself in the Webhooks/Events section.'\n ),\n },\n ],\n [t]\n );\n\n const ACTION_STYLES = useMemo<{ value: ActionStyle; label: string; color: string }[]>(() => {\n const labels: Record<ActionStyle, string> = {\n PRIMARY: t('bigconsole.widget.actions.style.primary', 'Primary'),\n SECONDARY: t('bigconsole.widget.actions.style.secondary', 'Secondary'),\n SUCCESS: t('bigconsole.widget.actions.style.success', 'Success'),\n WARNING: t('bigconsole.widget.actions.style.warning', 'Warning'),\n DANGER: t('bigconsole.widget.actions.style.danger', 'Danger'),\n GHOST: t('bigconsole.widget.actions.style.ghost', 'Ghost'),\n LINK: t('bigconsole.widget.actions.style.link', 'Link'),\n };\n return ACTION_STYLE_META.map((s) => ({ value: s.value, label: labels[s.value], color: s.color }));\n }, [t]);\n\n const ICON_OPTIONS = useMemo(() => {\n const labels: Record<(typeof ICON_VALUES)[number], string> = {\n '': t('bigconsole.widget.actions.icon.none', 'No icon'),\n refresh: t('bigconsole.widget.actions.icon.refresh', 'Refresh'),\n download: t('bigconsole.widget.actions.icon.download', 'Download'),\n upload: t('bigconsole.widget.actions.icon.upload', 'Upload'),\n trash: t('bigconsole.widget.actions.icon.trash', 'Trash'),\n edit: t('bigconsole.widget.actions.icon.edit', 'Edit'),\n plus: t('bigconsole.widget.actions.icon.plus', 'Plus'),\n check: t('bigconsole.widget.actions.icon.check', 'Check'),\n eye: t('bigconsole.widget.actions.icon.eye', 'View'),\n copy: t('bigconsole.widget.actions.icon.copy', 'Copy'),\n share: t('bigconsole.widget.actions.icon.share', 'Share'),\n settings: t('bigconsole.widget.actions.icon.settings', 'Settings'),\n filter: t('bigconsole.widget.actions.icon.filter', 'Filter'),\n search: t('bigconsole.widget.actions.icon.search', 'Search'),\n };\n return ICON_VALUES.map((value) => ({ value, label: labels[value] }));\n }, [t]);\n\n // Reset form when the dialog opens or the edited action changes. Deliberately\n // does NOT depend on `initialWebhook` — that fetch can settle after the dialog\n // is open, and re-running this would wipe the user's in-progress edits (#6).\n // The webhook fields are seeded by the separate effect below.\n useEffect(() => {\n if (!isOpen) return;\n\n webhookTouchedRef.current = false;\n setWebhookUrl('');\n setWebhookMethod('POST');\n\n if (action) {\n setLabel(action.label);\n setName(action.name);\n setNameEdited(false);\n setStyle(action.style);\n setIcon(action.icon || '');\n setDisabled(action.disabled);\n setHidden(action.hidden);\n // Default to \"emit\"; the seed effect flips to WEBHOOK if a mapping exists.\n setOutcome('EMIT');\n setHasConfirmation(!!action.confirmation);\n if (action.confirmation) {\n setConfirmTitle(action.confirmation.title);\n setConfirmMessage(action.confirmation.message);\n setConfirmLabel(\n action.confirmation.confirmLabel || t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm')\n );\n setCancelLabel(\n action.confirmation.cancelLabel || t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel')\n );\n } else {\n setConfirmTitle(t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'));\n setConfirmMessage(t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?'));\n setConfirmLabel(t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'));\n setCancelLabel(t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'));\n }\n } else {\n setLabel('');\n setName('');\n setNameEdited(false);\n setStyle('PRIMARY');\n setIcon('');\n setOutcome('WEBHOOK');\n setDisabled(false);\n setHidden(false);\n setHasConfirmation(false);\n setConfirmTitle(t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'));\n setConfirmMessage(t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?'));\n setConfirmLabel(t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'));\n setCancelLabel(t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'));\n }\n setShowAdvanced(false);\n setError(null);\n // Focus the label after the dialog paints — a double rAF is more reliable than\n // a magic setTimeout delay and doesn't race the open animation.\n const raf = requestAnimationFrame(() => requestAnimationFrame(() => labelInputRef.current?.focus()));\n return () => cancelAnimationFrame(raf);\n }, [isOpen, action, t]);\n\n // Seed the webhook fields from the (possibly late-arriving) mapping fetch,\n // unless the user has already started editing them.\n useEffect(() => {\n if (!isOpen || !initialWebhook || webhookTouchedRef.current) return;\n setOutcome('WEBHOOK');\n setWebhookUrl(initialWebhook.url);\n setWebhookMethod(initialWebhook.method);\n }, [isOpen, initialWebhook]);\n\n // Keep the auto-derived name in sync with the label until the user overrides it.\n const handleLabelChange = useCallback(\n (value: string) => {\n setLabel(value);\n if (!nameEdited) setName(slugifyName(value));\n if (error) setError(null);\n },\n [nameEdited, error]\n );\n\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedLabel = label.trim();\n if (!trimmedLabel) {\n setError(t('bigconsole.widget.actions.validation.labelRequired', 'Button label is required'));\n labelInputRef.current?.focus();\n return;\n }\n\n // The action name is the event id (webhook contract). It is set once at\n // creation and never rewritten on edit — re-slugifying a stored name like\n // `refresh-v2` would silently change `widget:refresh-v2:clicked` and break\n // existing bindings/consumers (#1).\n const finalName =\n isEditMode && action ? action.name : slugifyName(nameEdited ? name : label) || slugifyName(label);\n if (!finalName) {\n setError(\n t('bigconsole.widget.actions.validation.labelLettersOrNumbers', 'Enter a label using letters or numbers')\n );\n return;\n }\n\n if (outcome === 'WEBHOOK') {\n const url = webhookUrl.trim();\n if (!url) {\n setError(\n t('bigconsole.widget.actions.validation.urlRequired', 'Enter the URL to call when the button is clicked')\n );\n return;\n }\n if (!/^https?:\\/\\//i.test(url)) {\n setError(\n t('bigconsole.widget.actions.validation.urlScheme', 'Webhook URL must start with http:// or https://')\n );\n return;\n }\n }\n\n const confirmation: ActionConfirmation | undefined = hasConfirmation\n ? {\n title: confirmTitle.trim() || t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'),\n message: confirmMessage.trim() || t('bigconsole.widget.actions.confirm.fallbackMessage', 'Are you sure?'),\n confirmLabel: confirmLabel.trim() || t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'),\n cancelLabel: cancelLabel.trim() || t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'),\n }\n : undefined;\n\n const webhook: ActionWebhookDraft | null =\n outcome === 'WEBHOOK' ? { url: webhookUrl.trim(), method: webhookMethod } : null;\n\n if (isEditMode && action) {\n const updateData: ActionSaveData = {\n id: action.id,\n name: finalName,\n label: trimmedLabel,\n // Webhook/emit outcomes must be a BUTTON so the click runs onAction and\n // emits the event. Saving a stale LINK type would render an <a> that\n // bypasses onAction, so the webhook would never fire (#3).\n type: 'BUTTON',\n style,\n icon: icon || undefined,\n confirmation: hasConfirmation ? confirmation : null,\n disabled,\n hidden,\n };\n onSave(updateData, webhook);\n } else {\n const createData: ActionSaveData = {\n name: finalName,\n label: trimmedLabel,\n // Webhook/emit outcomes must be a BUTTON so the click runs onAction and\n // emits the event. Saving a stale LINK type would render an <a> that\n // bypasses onAction, so the webhook would never fire (#3).\n type: 'BUTTON',\n style,\n icon: icon || undefined,\n confirmation,\n disabled,\n hidden,\n };\n onSave(createData, webhook);\n }\n },\n [\n label,\n name,\n nameEdited,\n outcome,\n webhookUrl,\n webhookMethod,\n style,\n icon,\n disabled,\n hidden,\n hasConfirmation,\n confirmTitle,\n confirmMessage,\n confirmLabel,\n cancelLabel,\n isEditMode,\n action,\n onSave,\n t,\n ]\n );\n\n const getStyleColor = (s: ActionStyle) =>\n ACTION_STYLES.find((as) => as.value === s)?.color || 'var(--color-action-primary-bg)';\n\n const activeOutcome = OUTCOMES.find((o) => o.value === outcome);\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isLoading && onClose()}>\n {/*\n Section emphasis (BOFF-5636). The dialog now sizes to the viewport\n (`min(500px, 100vw - 2rem)`) and its title uses the same body-md scale as\n the inspector that spawns it — a modal opened FROM a panel should not\n outrank the panel. Its three groups (appearance / behaviour / advanced)\n carry real headings instead of three competing border tricks.\n */}\n <DialogContent style={{ width: 'min(500px, calc(100vw - 2rem))', maxWidth: 'calc(100vw - 2rem)', padding: 0 }}>\n {/* Header */}\n <DialogHeader style={{ padding: 'var(--space-cardPadding) var(--space-cardPadding) 0' }}>\n <div\n style={{\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n minWidth: 0,\n }}\n >\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n boxShadow: 'var(--shadow-elevation-2)',\n }}\n >\n {isEditMode ? (\n <Pencil\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n ) : (\n <Zap\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n )}\n </div>\n <div>\n <DialogTitle\n style={{\n fontSize: 'var(--font-size-body-md)',\n fontWeight: 'var(--font-weight-bold)',\n color: 'var(--color-text-primary)',\n margin: 0,\n }}\n >\n {isEditMode\n ? t('bigconsole.widget.actions.header.editTitle', 'Edit Button')\n : t('bigconsole.widget.actions.header.addTitle', 'Add Button')}\n </DialogTitle>\n <DialogDescription\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n margin: 'var(--space-controlGap) 0 0 0',\n }}\n >\n {isEditMode\n ? t('bigconsole.widget.actions.header.editDescription', 'Update the button and what it does')\n : t('bigconsole.widget.actions.header.addDescription', 'Add a button and choose what it does')}\n </DialogDescription>\n </div>\n </div>\n </DialogHeader>\n\n <form onSubmit={handleSubmit}>\n {/* Form Content */}\n <div style={{ padding: 'var(--space-cardPadding)', maxHeight: '65vh', minWidth: 0, overflowY: 'auto' }}>\n {/* Error Display — local validation error or a save failure from the parent. */}\n {(error || saveError) && (\n <Section\n tone=\"danger\"\n padding=\"compact\"\n headingLevel={3}\n title=\"This button could not be saved\"\n className=\"mb-form-gap\"\n data-testid=\"action-config-error\"\n >\n <p role=\"alert\" className=\"break-words text-sm text-[var(--color-status-error-text)]\">\n {error || saveError}\n </p>\n </Section>\n )}\n\n {/* ---- Group 1: how the button looks ---- */}\n <h3 style={groupHeadingStyle}>Appearance</h3>\n\n {/* Label Field */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label style={labelStyle}>\n {t('bigconsole.widget.actions.field.buttonLabel', 'Button label')}{' '}\n <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n ref={labelInputRef}\n value={label}\n onChange={(e) => handleLabelChange(e.target.value)}\n placeholder={t(\n 'bigconsole.widget.actions.field.buttonLabelPlaceholder',\n 'e.g., Refresh Data, Export CSV'\n )}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n <p style={hintStyle}>\n {t('bigconsole.widget.actions.field.buttonLabelHint', 'Text shown on the button')}\n </p>\n </div>\n\n {/* Style + Icon Row */}\n <div\n style={{\n display: 'grid',\n // Collapses to one column below ~440px so each control keeps a\n // usable width inside a phone-width dialog.\n gridTemplateColumns: 'repeat(auto-fit, minmax(11rem, 1fr))',\n gap: 'var(--space-formGap)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <div>\n <label style={labelStyle}>{t('bigconsole.widget.actions.field.style', 'Style')}</label>\n <Select value={style} onValueChange={(v) => setStyle(v as ActionStyle)} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {ACTION_STYLES.map((s) => (\n <SelectItem key={s.value} value={s.value}>\n {s.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div>\n <label style={labelStyle}>{t('bigconsole.widget.actions.field.icon', 'Icon')}</label>\n <Select value={icon} onValueChange={setIcon} disabled={isLoading}>\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue placeholder={t('bigconsole.widget.actions.icon.none', 'No icon')} />\n </SelectTrigger>\n <SelectContent style={{ ...selectContentStyle, maxHeight: '200px' }}>\n {ICON_OPTIONS.map((i) => (\n <SelectItem key={i.value || 'none'} value={i.value || 'none'}>\n {i.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {/* Style Preview */}\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n marginBottom: 'var(--space-formGap)',\n padding: 'var(--space-controlGap)',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-button)',\n }}\n >\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n {t('bigconsole.widget.actions.preview.label', 'Preview:')}\n </span>\n <button\n type=\"button\"\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n backgroundColor: getStyleColor(style),\n color: 'var(--color-action-primary-text)',\n border: 'none',\n cursor: 'default',\n }}\n >\n {label || t('bigconsole.widget.actions.preview.buttonFallback', 'Button')}\n </button>\n </div>\n\n {/* ---- Group 2: what the button does ---- */}\n <h3 style={{ ...groupHeadingStyle, marginTop: 'var(--space-formGap)' }}>Behaviour</h3>\n\n {/* When clicked (outcome) */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <label style={labelStyle}>{t('bigconsole.widget.actions.field.whenClicked', 'When clicked')}</label>\n <Select\n value={outcome}\n onValueChange={(v) => {\n webhookTouchedRef.current = true;\n setOutcome(v as ActionOutcome);\n }}\n disabled={isLoading}\n >\n <SelectTrigger style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {OUTCOMES.map((o) => (\n <SelectItem key={o.value} value={o.value}>\n {o.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {activeOutcome && <p style={hintStyle}>{activeOutcome.hint}</p>}\n </div>\n\n {/* Webhook config (only for the WEBHOOK outcome) */}\n {outcome === 'WEBHOOK' && (\n <div\n style={{\n marginBottom: 'var(--space-formGap)',\n paddingLeft: 'var(--space-formGap)',\n borderLeft: '2px solid var(--color-border-subtle)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label style={labelStyle}>\n {t('bigconsole.widget.actions.webhook.urlLabel', 'URL')}{' '}\n <span style={{ color: 'var(--color-status-error-text)' }}>*</span>\n </label>\n <Input\n value={webhookUrl}\n onChange={(e) => {\n webhookTouchedRef.current = true;\n setWebhookUrl(e.target.value);\n if (error) setError(null);\n }}\n placeholder={t('bigconsole.widget.actions.webhook.urlPlaceholder', 'https://your-service.com/hook')}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div style={{ maxWidth: '160px', minWidth: 0 }}>\n <label style={labelStyle}>{t('bigconsole.widget.actions.webhook.methodLabel', 'Method')}</label>\n <Select\n value={webhookMethod}\n onValueChange={(v) => {\n webhookTouchedRef.current = true;\n setWebhookMethod(v as HttpMethod);\n }}\n disabled={isLoading}\n >\n <SelectTrigger\n style={{ height: 'var(--size-controlHeight-md)', fontSize: 'var(--font-size-body-sm)' }}\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {HTTP_METHODS.map((m) => (\n <SelectItem key={m} value={m}>\n {m}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <p style={hintStyle}>\n {t(\n 'bigconsole.widget.actions.webhook.payloadHint',\n \"The widget's current data is sent as the request payload.\"\n )}\n </p>\n {/^http:\\/\\//i.test(webhookUrl.trim()) && (\n <p style={{ ...hintStyle, color: 'var(--color-status-warning-text)' }}>\n {t('bigconsole.widget.actions.webhook.insecureWarningPrefix', 'Warning:')} <code>http://</code>{' '}\n {t(\n 'bigconsole.widget.actions.webhook.insecureWarningMiddle',\n \"is unencrypted — the widget's data will be sent in plaintext. Use\"\n )}{' '}\n <code>https://</code>{' '}\n {t(\n 'bigconsole.widget.actions.webhook.insecureWarningSuffix',\n 'if it may contain anything sensitive.'\n )}\n </p>\n )}\n </div>\n )}\n\n {/* Confirmation Section */}\n <div style={{ paddingTop: 'var(--space-formGap)', borderTop: '1px solid var(--color-border-subtle)' }}>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <Checkbox\n checked={hasConfirmation}\n onCheckedChange={(c) => setHasConfirmation(c === true)}\n disabled={isLoading}\n />\n <span\n style={{\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-semibold)',\n color: 'var(--color-text-primary)',\n }}\n >\n {t('bigconsole.widget.actions.confirm.toggleLabel', 'Ask for confirmation first')}\n </span>\n </label>\n\n {hasConfirmation && (\n <div\n style={{\n paddingLeft: 'var(--space-formGap)',\n borderLeft: '2px solid var(--color-border-subtle)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.widget.actions.confirm.dialogTitleLabel', 'Dialog Title')}\n </label>\n <Input\n value={confirmTitle}\n onChange={(e) => setConfirmTitle(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.widget.actions.confirm.messageLabel', 'Message')}\n </label>\n <Textarea\n value={confirmMessage}\n onChange={(e) => setConfirmMessage(e.target.value)}\n rows={2}\n disabled={isLoading}\n style={{ fontSize: 'var(--font-size-body-sm)', resize: 'none' }}\n />\n </div>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(11rem, 1fr))',\n gap: 'var(--space-controlGap)',\n }}\n >\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.widget.actions.confirm.confirmButtonLabel', 'Confirm Button')}\n </label>\n <Input\n value={confirmLabel}\n onChange={(e) => setConfirmLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n <div>\n <label\n style={{\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n {t('bigconsole.widget.actions.confirm.cancelButtonLabel', 'Cancel Button')}\n </label>\n <Input\n value={cancelLabel}\n onChange={(e) => setCancelLabel(e.target.value)}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-sm)', fontSize: 'var(--font-size-body-sm)' }}\n />\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* ---- Group 3: advanced disclosure — event name + visibility ---- */}\n <div style={{ paddingTop: 'var(--space-formGap)', borderTop: '1px solid var(--color-border-subtle)' }}>\n {/* The disclosure button IS this group's heading, so the heading wraps it. */}\n <h3 style={{ ...groupHeadingStyle, margin: 0 }}>\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n aria-expanded={showAdvanced}\n aria-controls=\"action-config-advanced\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n minHeight: 'var(--size-controlHeight-md)',\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n font: 'inherit',\n letterSpacing: 'inherit',\n textTransform: 'inherit',\n color: 'inherit',\n }}\n >\n {showAdvanced ? (\n <ChevronDown style={{ height: '14px', width: '14px' }} />\n ) : (\n <ChevronRight style={{ height: '14px', width: '14px' }} />\n )}\n {t('bigconsole.widget.actions.advanced.toggle', 'Advanced')}\n </button>\n </h3>\n\n {showAdvanced && (\n <div\n id=\"action-config-advanced\"\n style={{\n marginTop: 'var(--space-formGap)',\n display: 'flex',\n flexDirection: 'column',\n gap: 'var(--space-formGap)',\n }}\n >\n <div>\n <label style={labelStyle}>\n {t('bigconsole.widget.actions.advanced.eventNameLabel', 'Event name (id)')}\n </label>\n <Input\n value={isEditMode && action ? action.name : name}\n onChange={(e) => {\n setName(e.target.value);\n setNameEdited(true);\n }}\n placeholder={t('bigconsole.widget.actions.advanced.eventNamePlaceholder', 'auto from label')}\n // The event id is the webhook/consumer contract; it is fixed\n // once the action exists and cannot be changed on edit (#1).\n disabled={isLoading || isEditMode}\n style={{\n height: 'var(--size-controlHeight-md)',\n fontSize: 'var(--font-size-body-sm)',\n fontFamily: 'var(--font-family-mono)',\n }}\n />\n <p style={hintStyle}>\n {t('bigconsole.widget.actions.advanced.emitsPrefix', 'Emits')}{' '}\n <code>\n widget:{isEditMode && action ? action.name : slugifyName(name || label) || '<name>'}:clicked\n </code>\n .{' '}\n {isEditMode\n ? t('bigconsole.widget.actions.advanced.emitsFixed', 'Fixed once created.')\n : t('bigconsole.widget.actions.advanced.emitsAutoDerived', 'Auto-derived from the label.')}\n </p>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-sectionGap)' }}>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n }}\n >\n <Checkbox\n checked={disabled}\n onCheckedChange={(c) => setDisabled(c === true)}\n disabled={isLoading}\n />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>\n {t('bigconsole.widget.actions.advanced.disabled', 'Disabled')}\n </span>\n </label>\n <label\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--space-controlGap)',\n cursor: 'pointer',\n }}\n >\n <Checkbox checked={hidden} onCheckedChange={(c) => setHidden(c === true)} disabled={isLoading} />\n <span style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-primary)' }}>\n {t('bigconsole.widget.actions.advanced.hidden', 'Hidden')}\n </span>\n </label>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer */}\n <DialogFooter\n style={{\n padding: 'var(--space-formGap) var(--space-pagePadding)',\n borderTop: '1px solid var(--color-border-subtle)',\n backgroundColor: 'var(--color-bg-sunken)',\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--space-controlGap)',\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={onClose}\n disabled={isLoading}\n style={{ height: 'var(--size-controlHeight-md)' }}\n >\n {t('bigconsole.widget.actions.footer.cancel', 'Cancel')}\n </Button>\n {/*\n Gate the save on the matching widget-action permission — create for\n a new button, update for an edit. `disable` keeps the button visible\n (so the reason is discoverable) but non-submittable when denied.\n */}\n <PermissionButton\n permission={\n isEditMode ? BIGCONSOLE_PERMISSIONS.WIDGET_ACTION_UPDATE : BIGCONSOLE_PERMISSIONS.WIDGET_ACTION_CREATE\n }\n deniedBehavior=\"disable\"\n >\n <Button\n type=\"submit\"\n disabled={isLoading || !label.trim()}\n style={{ height: 'var(--size-controlHeight-md)', backgroundColor: 'var(--color-action-primary-bg)' }}\n >\n {isLoading ? (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n <Spinner style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n {t('bigconsole.widget.actions.footer.saving', 'Saving...')}\n </span>\n ) : (\n <span style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-iconGap)' }}>\n {isEditMode ? (\n <Pencil style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n ) : (\n <Plus style={{ height: 'var(--size-icon-sm)', width: 'var(--size-icon-sm)' }} />\n )}\n {isEditMode\n ? t('bigconsole.widget.actions.footer.updateButton', 'Update Button')\n : t('bigconsole.widget.actions.footer.addButton', 'Add Button')}\n </span>\n )}\n </Button>\n </PermissionButton>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ActionConfigDialog;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ActionConfigDialog.js","names":[],"sources":["../../../../src/bigconsole/components/widgets/ActionConfigDialog.tsx"],"sourcesContent":["/**\n * ActionConfigDialog: compact API button setup (BOFF-7626).\n *\n * Modal dialog for creating/editing widget actions.\n *\n * v2.1 (BOFF-5659): reframed around the *outcome* — \"When clicked, do this\" —\n * instead of the abstract action Type. A button always emits\n * `widget:<name>:clicked`; the dialog now lets the user attach the behaviour\n * inline. Today the two shippable outcomes are:\n * - \"Call a webhook / my API\" → captures a URL + method; the parent pairs the\n * action with an EventWebhookMapping bound to that event (no backend change).\n * - \"Just emit an event\" → the raw emit, for callers wiring their own\n * consumers.\n * The action `name` (the event id) is auto-derived from the label and tucked\n * under More options. Label and destination are the two required inputs.\n *\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useMemo, useRef, useId } from 'react';\nimport {\n ResponsiveDialog as Dialog,\n ResponsiveDialogContent as DialogContent,\n ResponsiveDialogDescription as DialogDescription,\n ResponsiveDialogFooter as DialogFooter,\n ResponsiveDialogHeader as DialogHeader,\n ResponsiveDialogTitle as DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Textarea } from '@burdenoff/fe-libs/ui';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@burdenoff/fe-libs/ui';\nimport { Checkbox } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { ChevronDown, ChevronRight } from 'lucide-react';\nimport { BIGCONSOLE_PERMISSIONS } from '../../../constants/permissions';\nimport type { WidgetAction, ActionStyle, ActionConfirmation } from '../../hooks/useWidgetActions';\nimport type { HttpMethod } from '../../hooks/useEventWebhooks';\nimport { Section } from '../common';\nimport {\n slugifyActionName,\n validateActionConfig,\n serializeActionConfig,\n type ActionConfigError,\n type ActionConfigDraft,\n type ActionOutcome,\n type ActionSaveData,\n type ActionWebhookDraft,\n} from './actionConfig';\nexport type { ActionOutcome, ActionSaveData, ActionWebhookDraft } from './actionConfig';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ActionConfigDialogProps {\n isOpen: boolean;\n action?: WidgetAction;\n /** Existing webhook binding for the edited action (prefills the URL field). */\n initialWebhook?: ActionWebhookDraft | null;\n isLoading?: boolean;\n /** A save failure from the parent (action or webhook mutation) to surface inline. */\n saveError?: string | null;\n onClose: () => void;\n /** `webhook` is the paired binding, or `null` to remove any existing one. */\n onSave: (data: ActionSaveData, webhook: ActionWebhookDraft | null) => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst HTTP_METHODS: HttpMethod[] = ['POST', 'GET', 'PUT', 'PATCH', 'DELETE'];\n\n/** Stable style values + preview colors; labels are resolved via i18n in-component. */\nconst ACTION_STYLE_META: { value: ActionStyle; color: string }[] = [\n { value: 'PRIMARY', color: 'var(--color-action-primary-bg)' },\n { value: 'SECONDARY', color: 'var(--color-action-secondary-bg)' },\n { value: 'SUCCESS', color: 'var(--color-status-success-bg)' },\n { value: 'WARNING', color: 'var(--color-status-warning-bg)' },\n { value: 'DANGER', color: 'var(--color-action-danger-bg)' },\n { value: 'GHOST', color: 'transparent' },\n { value: 'LINK', color: 'transparent' },\n];\n\n/** Stable icon values; labels are resolved via i18n in-component. */\nconst ICON_VALUES = [\n '',\n 'refresh',\n 'download',\n 'upload',\n 'trash',\n 'edit',\n 'plus',\n 'check',\n 'eye',\n 'copy',\n 'share',\n 'settings',\n 'filter',\n 'search',\n] as const;\n\n// Field labels sit BELOW group headings in the type ladder: `medium` here,\n// `bold` + uppercase tracking for the group heading. Previously both were\n// semibold body-sm, so a label and a group heading were indistinguishable.\nconst labelStyle: React.CSSProperties = {\n display: 'block',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-text-primary)',\n marginBottom: 'var(--space-controlGap)',\n};\n\n/** Group heading inside the dialog body: \"Appearance\" / \"Behaviour\" / \"Advanced\". */\nconst groupHeadingStyle: React.CSSProperties = {\n margin: '0 0 var(--space-controlGap) 0',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-bold)',\n letterSpacing: '0.06em',\n textTransform: 'uppercase',\n color: 'var(--color-text-secondary)',\n};\n\nconst hintStyle: React.CSSProperties = {\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-muted)',\n marginTop: 'var(--space-controlGap)',\n};\n\nconst selectContentStyle: React.CSSProperties = {\n zIndex: 9999,\n backgroundColor: 'var(--color-overlay-popoverBg, var(--color-bg-surface))',\n border: '1px solid var(--color-border-subtle)',\n boxShadow: 'var(--shadow-elevation-3)',\n borderRadius: 'var(--radius-button)',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ActionConfigDialog: FC<ActionConfigDialogProps> = memo(function ActionConfigDialog({\n isOpen,\n action,\n initialWebhook,\n isLoading = false,\n saveError,\n onClose,\n onSave,\n}) {\n const { t } = useI18n();\n const isEditMode = !!action;\n const labelInputRef = useRef<HTMLInputElement>(null);\n const urlInputRef = useRef<HTMLInputElement>(null);\n const nameInputRef = useRef<HTMLInputElement>(null);\n const fieldId = useId();\n const fallbackNameRef = useRef('');\n // True once the user touches the webhook fields, so a late-arriving\n // `initialWebhook` fetch can seed the form without clobbering in-progress edits.\n const webhookTouchedRef = useRef(false);\n\n // Form state\n const [label, setLabel] = useState('');\n const [name, setName] = useState('');\n const [nameEdited, setNameEdited] = useState(false);\n const [style, setStyle] = useState<ActionStyle>('PRIMARY');\n const [icon, setIcon] = useState('');\n const [outcome, setOutcome] = useState<ActionOutcome>('WEBHOOK');\n const [webhookUrl, setWebhookUrl] = useState('');\n const [webhookMethod, setWebhookMethod] = useState<HttpMethod>('POST');\n const [disabled, setDisabled] = useState(false);\n const [hidden, setHidden] = useState(false);\n const [showAdvanced, setShowAdvanced] = useState(false);\n const [hasConfirmation, setHasConfirmation] = useState(false);\n const [confirmTitle, setConfirmTitle] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action')\n );\n const [confirmMessage, setConfirmMessage] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?')\n );\n const [confirmLabel, setConfirmLabel] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm')\n );\n const [cancelLabel, setCancelLabel] = useState(() =>\n t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel')\n );\n const [error, setError] = useState<ActionConfigError | null>(null);\n\n // Localized option lists — value/enum fields stay stable; only the display copy is translated.\n const ACTION_STYLES = useMemo<{ value: ActionStyle; label: string; color: string }[]>(() => {\n const labels: Record<ActionStyle, string> = {\n PRIMARY: t('bigconsole.widget.actions.style.primary', 'Primary'),\n SECONDARY: t('bigconsole.widget.actions.style.secondary', 'Secondary'),\n SUCCESS: t('bigconsole.widget.actions.style.success', 'Success'),\n WARNING: t('bigconsole.widget.actions.style.warning', 'Warning'),\n DANGER: t('bigconsole.widget.actions.style.danger', 'Danger'),\n GHOST: t('bigconsole.widget.actions.style.ghost', 'Ghost'),\n LINK: t('bigconsole.widget.actions.style.link', 'Link'),\n };\n return ACTION_STYLE_META.map((s) => ({ value: s.value, label: labels[s.value], color: s.color }));\n }, [t]);\n\n const ICON_OPTIONS = useMemo(() => {\n const labels: Record<(typeof ICON_VALUES)[number], string> = {\n '': t('bigconsole.widget.actions.icon.none', 'No icon'),\n refresh: t('bigconsole.widget.actions.icon.refresh', 'Refresh'),\n download: t('bigconsole.widget.actions.icon.download', 'Download'),\n upload: t('bigconsole.widget.actions.icon.upload', 'Upload'),\n trash: t('bigconsole.widget.actions.icon.trash', 'Trash'),\n edit: t('bigconsole.widget.actions.icon.edit', 'Edit'),\n plus: t('bigconsole.widget.actions.icon.plus', 'Plus'),\n check: t('bigconsole.widget.actions.icon.check', 'Check'),\n eye: t('bigconsole.widget.actions.icon.eye', 'View'),\n copy: t('bigconsole.widget.actions.icon.copy', 'Copy'),\n share: t('bigconsole.widget.actions.icon.share', 'Share'),\n settings: t('bigconsole.widget.actions.icon.settings', 'Settings'),\n filter: t('bigconsole.widget.actions.icon.filter', 'Filter'),\n search: t('bigconsole.widget.actions.icon.search', 'Search'),\n };\n return ICON_VALUES.map((value) => ({ value, label: labels[value] }));\n }, [t]);\n\n // Reset form when the dialog opens or the edited action changes. Deliberately\n // does NOT depend on `initialWebhook` — that fetch can settle after the dialog\n // is open, and re-running this would wipe the user's in-progress edits (#6).\n // The webhook fields are seeded by the separate effect below.\n useEffect(() => {\n if (!isOpen) return;\n\n webhookTouchedRef.current = false;\n // Non-Latin labels still get an internal ID without asking users to name an event.\n fallbackNameRef.current = `button_${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`;\n setWebhookUrl('');\n setWebhookMethod('POST');\n\n if (action) {\n setLabel(action.label);\n setName(action.name);\n setNameEdited(false);\n setStyle(action.style);\n setIcon(action.icon || '');\n setDisabled(action.disabled);\n setHidden(action.hidden);\n // Default to \"emit\"; the seed effect flips to WEBHOOK if a mapping exists.\n setOutcome('EMIT');\n setHasConfirmation(!!action.confirmation);\n if (action.confirmation) {\n setConfirmTitle(action.confirmation.title);\n setConfirmMessage(action.confirmation.message);\n setConfirmLabel(\n action.confirmation.confirmLabel || t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm')\n );\n setCancelLabel(\n action.confirmation.cancelLabel || t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel')\n );\n } else {\n setConfirmTitle(t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'));\n setConfirmMessage(t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?'));\n setConfirmLabel(t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'));\n setCancelLabel(t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'));\n }\n } else {\n setLabel('');\n setName('');\n setNameEdited(false);\n setStyle('PRIMARY');\n setIcon('');\n setOutcome('WEBHOOK');\n setDisabled(false);\n setHidden(false);\n setHasConfirmation(false);\n setConfirmTitle(t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'));\n setConfirmMessage(t('bigconsole.widget.actions.confirm.defaultMessage', 'Are you sure you want to proceed?'));\n setConfirmLabel(t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'));\n setCancelLabel(t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'));\n }\n setShowAdvanced(false);\n setError(null);\n // Focus the label after the dialog paints — a double rAF is more reliable than\n // a magic setTimeout delay and doesn't race the open animation.\n const raf = requestAnimationFrame(() => requestAnimationFrame(() => labelInputRef.current?.focus()));\n return () => cancelAnimationFrame(raf);\n }, [isOpen, action, t]);\n\n // Seed the webhook fields from the (possibly late-arriving) mapping fetch,\n // unless the user has already started editing them.\n useEffect(() => {\n if (!isOpen || !initialWebhook || webhookTouchedRef.current) return;\n setOutcome('WEBHOOK');\n setWebhookUrl(initialWebhook.url);\n setWebhookMethod(initialWebhook.method);\n }, [isOpen, initialWebhook]);\n\n // Keep the auto-derived name in sync with the label until the user overrides it.\n const handleLabelChange = useCallback(\n (value: string) => {\n setLabel(value);\n if (!nameEdited && !isEditMode) setName(slugifyActionName(value) || fallbackNameRef.current);\n if (error) setError(null);\n },\n [nameEdited, error, isEditMode]\n );\n\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n const finalName =\n isEditMode && action\n ? action.name\n : slugifyActionName(nameEdited ? name : label) || slugifyActionName(label) || fallbackNameRef.current;\n\n const confirmation: ActionConfirmation | undefined = hasConfirmation\n ? {\n title: confirmTitle.trim() || t('bigconsole.widget.actions.confirm.defaultTitle', 'Confirm Action'),\n message: confirmMessage.trim() || t('bigconsole.widget.actions.confirm.fallbackMessage', 'Are you sure?'),\n confirmLabel: confirmLabel.trim() || t('bigconsole.widget.actions.confirm.defaultConfirmLabel', 'Confirm'),\n cancelLabel: cancelLabel.trim() || t('bigconsole.widget.actions.confirm.defaultCancelLabel', 'Cancel'),\n }\n : undefined;\n\n const draft: ActionConfigDraft = {\n label,\n name: finalName,\n outcome,\n url: webhookUrl,\n method: webhookMethod,\n style,\n icon,\n confirmation: confirmation ?? null,\n disabled,\n hidden,\n };\n const invalid = validateActionConfig(draft);\n setError(invalid);\n if (invalid) {\n if (invalid.field === 'name') setShowAdvanced(true);\n const input = invalid.field === 'url' ? urlInputRef : invalid.field === 'label' ? labelInputRef : nameInputRef;\n // A hidden advanced field must mount before it can receive focus.\n requestAnimationFrame(() => input.current?.focus());\n return;\n }\n const payload = serializeActionConfig(draft, action);\n onSave(payload.data, payload.webhook);\n },\n [\n label,\n name,\n nameEdited,\n outcome,\n webhookUrl,\n webhookMethod,\n style,\n icon,\n disabled,\n hidden,\n hasConfirmation,\n confirmTitle,\n confirmMessage,\n confirmLabel,\n cancelLabel,\n isEditMode,\n action,\n onSave,\n t,\n ]\n );\n\n const getStyleColor = (s: ActionStyle) =>\n ACTION_STYLES.find((as) => as.value === s)?.color || 'var(--color-action-primary-bg)';\n\n const errorMessage =\n error?.field === 'url'\n ? error.reason === 'required'\n ? t('bigconsole.widget.actions.validation.urlRequired', 'Enter the URL to call when the button is clicked')\n : t('bigconsole.widget.actions.validation.urlScheme', 'Enter a complete URL starting with http:// or https://')\n : error?.field === 'label'\n ? t('bigconsole.widget.actions.validation.labelRequired', 'Button label is required')\n : error\n ? t(\n 'bigconsole.widget.actions.validation.labelLettersOrNumbers',\n 'Enter an event name using letters or numbers'\n )\n : null;\n const fieldError = (field: ActionConfigError['field']) =>\n error?.field === field ? (\n <p id={`${fieldId}-${field}-error`} role=\"alert\" className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">\n {errorMessage}\n </p>\n ) : null;\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isLoading && onClose()}>\n {/* Sheets sit at z-120. This nested dialog must remain above its inspector. */}\n <DialogContent\n data-testid=\"action-config-dialog\"\n showHandle={false}\n style={{\n width: 'min(500px, calc(100vw - 2rem))',\n maxWidth: 'calc(100vw - 2rem)',\n maxHeight: 'calc(100dvh - 2rem)',\n padding: 0,\n gap: 0,\n zIndex: 140,\n display: 'flex',\n flexDirection: 'column',\n }}\n onEscapeKeyDown={(event) => {\n if (isLoading) event.preventDefault();\n }}\n >\n <DialogHeader className=\"p-4 pr-12 text-left\">\n <DialogTitle>\n {isEditMode\n ? t('bigconsole.widget.actions.header.editTitle', 'Edit Button')\n : t('bigconsole.widget.actions.header.addTitle', 'Add Button')}\n </DialogTitle>\n <DialogDescription>\n {isEditMode\n ? t('bigconsole.widget.actions.header.editDescription', 'Update the button and what it does')\n : t(\n 'bigconsole.widget.actions.header.addDescription',\n 'Add a button that sends this widget’s data to an API.'\n )}\n </DialogDescription>\n </DialogHeader>\n <form\n onSubmit={handleSubmit}\n noValidate\n className=\"flex min-h-0 flex-col\"\n style={{ maxHeight: 'calc(100dvh - 8rem)' }}\n >\n <div className=\"min-h-0 overflow-y-auto px-4 pb-4\">\n {saveError && (\n <Section\n tone=\"danger\"\n padding=\"compact\"\n headingLevel={3}\n title={t('bigconsole.widget.actions.validation.saveFailed', 'This button could not be saved')}\n className=\"mb-4\"\n >\n <p role=\"alert\" className=\"break-words text-sm\">\n {saveError}\n </p>\n </Section>\n )}\n <div className=\"mb-4\">\n <label htmlFor={`${fieldId}-label`} style={labelStyle}>\n {t('bigconsole.widget.actions.field.buttonLabel', 'Button label')} *\n </label>\n <Input\n id={`${fieldId}-label`}\n ref={labelInputRef}\n value={label}\n onChange={(e) => handleLabelChange(e.target.value)}\n placeholder={t(\n 'bigconsole.widget.actions.field.buttonLabelPlaceholder',\n 'e.g., Refresh Data, Export CSV'\n )}\n disabled={isLoading}\n aria-required\n aria-invalid={error?.field === 'label'}\n aria-describedby={error?.field === 'label' ? `${fieldId}-label-error` : undefined}\n />\n {fieldError('label')}\n </div>\n <div className=\"mb-4\">\n <p style={labelStyle}>{t('bigconsole.widget.actions.field.whenClicked', 'When clicked')}</p>\n <p className=\"text-sm text-text-secondary\" data-testid=\"action-outcome-summary\">\n {outcome === 'WEBHOOK'\n ? t('bigconsole.widget.actions.outcome.webhook.label', 'Send data to an API')\n : t('bigconsole.widget.actions.outcome.emit.label', 'Emit a custom event')}\n </p>\n </div>\n {outcome === 'WEBHOOK' && (\n <div className=\"mb-4\">\n <label htmlFor={`${fieldId}-url`} style={labelStyle}>\n {t('bigconsole.widget.actions.webhook.urlLabel', 'Destination URL')} *\n </label>\n <Input\n id={`${fieldId}-url`}\n ref={urlInputRef}\n type=\"url\"\n value={webhookUrl}\n onChange={(e) => {\n webhookTouchedRef.current = true;\n setWebhookUrl(e.target.value);\n if (error?.field === 'url') setError(null);\n }}\n placeholder={t('bigconsole.widget.actions.webhook.urlPlaceholder', 'https://your-service.com/hook')}\n disabled={isLoading}\n aria-required\n aria-invalid={error?.field === 'url'}\n aria-describedby={error?.field === 'url' ? `${fieldId}-url-error` : `${fieldId}-url-hint`}\n />\n {fieldError('url')}\n <p id={`${fieldId}-url-hint`} style={hintStyle}>\n {t(\n 'bigconsole.widget.actions.webhook.payloadHint',\n \"The widget's current data is sent as the request payload.\"\n )}\n </p>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n aria-expanded={showAdvanced}\n aria-controls={`${fieldId}-options`}\n className=\"flex min-h-10 items-center gap-2 text-sm font-medium\"\n disabled={isLoading}\n >\n {showAdvanced ? <ChevronDown className=\"size-4\" /> : <ChevronRight className=\"size-4\" />}\n {t('bigconsole.widget.actions.advanced.toggle', 'More options')}\n </button>\n {/* Collapse display, never reset the values used when submitting. */}\n <div\n id={`${fieldId}-options`}\n hidden={!showAdvanced}\n className=\"space-y-4 border-t border-border-subtle pt-4\"\n >\n <div>\n <h3 style={groupHeadingStyle}>{t('bigconsole.widget.actions.options.appearance', 'Appearance')}</h3>\n <div className=\"grid grid-cols-2 gap-3\">\n <div>\n <label id={`${fieldId}-style-label`} htmlFor={`${fieldId}-style`} style={labelStyle}>\n {t('bigconsole.widget.actions.field.style', 'Style')}\n </label>\n <Select\n value={style}\n onValueChange={(v) => {\n const selected = ACTION_STYLES.find((s) => s.value === v);\n if (selected) setStyle(selected.value);\n }}\n disabled={isLoading}\n >\n <SelectTrigger id={`${fieldId}-style`} aria-labelledby={`${fieldId}-style-label`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {ACTION_STYLES.map((s) => (\n <SelectItem key={s.value} value={s.value}>\n {s.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div>\n <label id={`${fieldId}-icon-label`} htmlFor={`${fieldId}-icon`} style={labelStyle}>\n {t('bigconsole.widget.actions.field.icon', 'Icon')}\n </label>\n <Select\n value={icon || 'none'}\n onValueChange={(value) => setIcon(value === 'none' ? '' : value)}\n disabled={isLoading}\n >\n <SelectTrigger id={`${fieldId}-icon`} aria-labelledby={`${fieldId}-icon-label`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={{ ...selectContentStyle, maxHeight: '200px' }}>\n {ICON_OPTIONS.map((i) => (\n <SelectItem key={i.value || 'none'} value={i.value || 'none'}>\n {i.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"mt-3 flex items-center gap-2 rounded-button bg-bg-sunken p-2\">\n <span className=\"text-sm text-text-muted\">\n {t('bigconsole.widget.actions.preview.label', 'Preview:')}\n </span>\n <span\n className=\"rounded-button px-3 py-1 text-sm\"\n style={{ backgroundColor: getStyleColor(style), color: 'var(--color-action-primary-text)' }}\n >\n {label || t('bigconsole.widget.actions.preview.buttonFallback', 'Button')}\n </span>\n </div>\n </div>\n {outcome === 'WEBHOOK' && (\n <div>\n <label id={`${fieldId}-method-label`} htmlFor={`${fieldId}-method`} style={labelStyle}>\n {t('bigconsole.widget.actions.webhook.methodLabel', 'Request method')}\n </label>\n <Select\n value={webhookMethod}\n onValueChange={(v) => {\n const method = HTTP_METHODS.find((m) => m === v);\n if (method) {\n webhookTouchedRef.current = true;\n setWebhookMethod(method);\n }\n }}\n disabled={isLoading}\n >\n <SelectTrigger id={`${fieldId}-method`} aria-labelledby={`${fieldId}-method-label`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent style={selectContentStyle}>\n {HTTP_METHODS.map((m) => (\n <SelectItem key={m} value={m}>\n {m}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n )}\n <div>\n <label className=\"flex items-center gap-2 text-sm\">\n <Checkbox\n checked={hasConfirmation}\n onCheckedChange={(c) => setHasConfirmation(c === true)}\n disabled={isLoading}\n />\n {t('bigconsole.widget.actions.confirm.toggleLabel', 'Ask for confirmation first')}\n </label>\n {hasConfirmation && (\n <div className=\"mt-3 space-y-3\">\n <label htmlFor={`${fieldId}-message`} style={labelStyle}>\n {t('bigconsole.widget.actions.confirm.messageLabel', 'Message')}\n </label>\n <Textarea\n id={`${fieldId}-message`}\n value={confirmMessage}\n onChange={(e) => setConfirmMessage(e.target.value)}\n rows={2}\n disabled={isLoading}\n />\n <details>\n <summary className=\"cursor-pointer text-sm text-text-secondary\">\n {t('bigconsole.widget.actions.confirm.customize', 'Customize confirmation labels')}\n </summary>\n <div className=\"mt-3 space-y-3\">\n <div>\n <label htmlFor={`${fieldId}-confirm-title`} style={labelStyle}>\n {t('bigconsole.widget.actions.confirm.dialogTitleLabel', 'Dialog Title')}\n </label>\n <Input\n id={`${fieldId}-confirm-title`}\n value={confirmTitle}\n onChange={(e) => setConfirmTitle(e.target.value)}\n disabled={isLoading}\n />\n </div>\n <div>\n <label htmlFor={`${fieldId}-confirm-label`} style={labelStyle}>\n {t('bigconsole.widget.actions.confirm.confirmButtonLabel', 'Confirm Button')}\n </label>\n <Input\n id={`${fieldId}-confirm-label`}\n value={confirmLabel}\n onChange={(e) => setConfirmLabel(e.target.value)}\n disabled={isLoading}\n />\n </div>\n <div>\n <label htmlFor={`${fieldId}-cancel-label`} style={labelStyle}>\n {t('bigconsole.widget.actions.confirm.cancelButtonLabel', 'Cancel Button')}\n </label>\n <Input\n id={`${fieldId}-cancel-label`}\n value={cancelLabel}\n onChange={(e) => setCancelLabel(e.target.value)}\n disabled={isLoading}\n />\n </div>\n </div>\n </details>\n </div>\n )}\n </div>\n <div>\n <label className=\"flex items-center gap-2 text-sm\">\n <Checkbox\n checked={outcome === 'EMIT'}\n onCheckedChange={(checked) => {\n webhookTouchedRef.current = true;\n setOutcome(checked === true ? 'EMIT' : 'WEBHOOK');\n setError(null);\n }}\n disabled={isLoading}\n />\n {t('bigconsole.widget.actions.options.customEvent', 'Use a custom event instead of calling an API')}\n </label>\n <p style={hintStyle}>\n {t(\n 'bigconsole.widget.actions.outcome.emit.hint',\n 'For integrations configured in Webhooks / Events.'\n )}\n </p>\n <div className=\"mt-3\">\n <label htmlFor={`${fieldId}-name`} style={labelStyle}>\n {t('bigconsole.widget.actions.advanced.eventNameLabel', 'Event name (id)')}\n </label>\n <Input\n id={`${fieldId}-name`}\n ref={nameInputRef}\n value={isEditMode && action ? action.name : name}\n onChange={(e) => {\n setName(e.target.value);\n setNameEdited(true);\n if (error?.field === 'name') setError(null);\n }}\n disabled={isLoading || isEditMode}\n aria-invalid={error?.field === 'name'}\n aria-describedby={error?.field === 'name' ? `${fieldId}-name-error` : undefined}\n />\n {fieldError('name')}\n <p style={hintStyle}>\n <code>\n widget:{isEditMode && action ? action.name : slugifyActionName(name || label) || '<name>'}:clicked\n </code>\n </p>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-4 text-sm\">\n <label className=\"flex items-center gap-2\">\n <Checkbox checked={disabled} onCheckedChange={(c) => setDisabled(c === true)} disabled={isLoading} />\n {t('bigconsole.widget.actions.advanced.disabled', 'Disabled')}\n </label>\n <label className=\"flex items-center gap-2\">\n <Checkbox checked={hidden} onCheckedChange={(c) => setHidden(c === true)} disabled={isLoading} />\n {t('bigconsole.widget.actions.advanced.hidden', 'Hidden')}\n </label>\n </div>\n </div>\n </div>\n <DialogFooter className=\"shrink-0 border-t border-border-subtle bg-bg-sunken p-4\">\n <Button type=\"button\" variant=\"outline\" onClick={onClose} disabled={isLoading}>\n {t('bigconsole.widget.actions.footer.cancel', 'Cancel')}\n </Button>\n <PermissionButton\n permission={\n isEditMode ? BIGCONSOLE_PERMISSIONS.WIDGET_ACTION_UPDATE : BIGCONSOLE_PERMISSIONS.WIDGET_ACTION_CREATE\n }\n deniedBehavior=\"disable\"\n >\n <Button type=\"submit\" disabled={isLoading}>\n {isLoading ? (\n <>\n <Spinner className=\"size-4\" />\n {t('bigconsole.widget.actions.footer.saving', 'Saving...')}\n </>\n ) : isEditMode ? (\n t('bigconsole.widget.actions.footer.updateButton', 'Update Button')\n ) : (\n t('bigconsole.widget.actions.footer.addButton', 'Add Button')\n )}\n </Button>\n </PermissionButton>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ActionConfigDialog;\n"],"mappings":"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"}
|
|
@@ -812,18 +812,106 @@ var D = he(function({ isOpen: he, onClose: g }) {
|
|
|
812
812
|
/* @__PURE__ */ w(x, {
|
|
813
813
|
value: "general",
|
|
814
814
|
className: "mt-0",
|
|
815
|
-
children: A && /* @__PURE__ */ T(r, { children: [
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
815
|
+
children: A && /* @__PURE__ */ T(r, { children: [
|
|
816
|
+
/* @__PURE__ */ w(de, {
|
|
817
|
+
title: A.title,
|
|
818
|
+
description: A.description,
|
|
819
|
+
refreshInterval: A.refreshInterval,
|
|
820
|
+
onTitleChange: (e) => Q("title", e),
|
|
821
|
+
onDescriptionChange: (e) => Q("description", e),
|
|
822
|
+
onRefreshIntervalChange: (e) => Q("refreshInterval", e)
|
|
823
|
+
}),
|
|
824
|
+
/* @__PURE__ */ w(n, {
|
|
825
|
+
title: D("bigconsole.widget.properties.actions.heading", "Buttons"),
|
|
826
|
+
description: D("bigconsole.widget.properties.actions.subheading", "Configure buttons on this widget"),
|
|
827
|
+
headingLevel: 3,
|
|
828
|
+
meta: H.length > 0 ? /* @__PURE__ */ w("span", {
|
|
829
|
+
className: "rounded-pill bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
830
|
+
children: H.length
|
|
831
|
+
}) : void 0,
|
|
832
|
+
actions: /* @__PURE__ */ T(_, {
|
|
833
|
+
size: "sm",
|
|
834
|
+
onClick: Mt,
|
|
835
|
+
children: [/* @__PURE__ */ w(be, { className: "size-4" }), D("bigconsole.widget.properties.actions.add", "Add button")]
|
|
836
|
+
}),
|
|
837
|
+
"data-testid": "widget-inspector-actions",
|
|
838
|
+
children: mt ? /* @__PURE__ */ w("div", {
|
|
839
|
+
className: "flex justify-center py-8",
|
|
840
|
+
children: /* @__PURE__ */ w(Pe, { className: "size-6" })
|
|
841
|
+
}) : H.length === 0 ? /* @__PURE__ */ w("p", {
|
|
842
|
+
className: "text-sm text-text-secondary",
|
|
843
|
+
children: D("bigconsole.widget.properties.actions.empty", "No buttons yet — add one to let viewers take an action.")
|
|
844
|
+
}) : /* @__PURE__ */ w("div", {
|
|
845
|
+
className: "space-y-2",
|
|
846
|
+
children: [...H].sort((e, t) => e.order - t.order).map((e, t) => /* @__PURE__ */ w(Ce, {
|
|
847
|
+
className: e.disabled ? "opacity-60" : "",
|
|
848
|
+
children: /* @__PURE__ */ T(we, {
|
|
849
|
+
className: "p-3 flex items-center gap-2",
|
|
850
|
+
children: [
|
|
851
|
+
/* @__PURE__ */ T("div", {
|
|
852
|
+
className: "flex flex-col gap-0.5",
|
|
853
|
+
children: [/* @__PURE__ */ w(_, {
|
|
854
|
+
variant: "ghost",
|
|
855
|
+
size: "icon-sm",
|
|
856
|
+
onClick: () => It(t),
|
|
857
|
+
disabled: t === 0,
|
|
858
|
+
className: "h-5 w-5",
|
|
859
|
+
children: /* @__PURE__ */ w(_e, { className: "size-3" })
|
|
860
|
+
}), /* @__PURE__ */ w(_, {
|
|
861
|
+
variant: "ghost",
|
|
862
|
+
size: "icon-sm",
|
|
863
|
+
onClick: () => Lt(t),
|
|
864
|
+
disabled: t === H.length - 1,
|
|
865
|
+
className: "h-5 w-5",
|
|
866
|
+
children: /* @__PURE__ */ w(ge, { className: "size-3" })
|
|
867
|
+
})]
|
|
868
|
+
}),
|
|
869
|
+
/* @__PURE__ */ T("div", {
|
|
870
|
+
className: "flex-1 min-w-0",
|
|
871
|
+
children: [/* @__PURE__ */ T("div", {
|
|
872
|
+
className: "flex items-center gap-2",
|
|
873
|
+
children: [/* @__PURE__ */ w("span", {
|
|
874
|
+
"aria-hidden": "true",
|
|
875
|
+
className: `size-2 shrink-0 rounded-full ${Ve[e.style] || He}`
|
|
876
|
+
}), /* @__PURE__ */ w("span", {
|
|
877
|
+
className: "text-sm font-medium truncate",
|
|
878
|
+
children: e.label
|
|
879
|
+
})]
|
|
880
|
+
}), /* @__PURE__ */ w("p", {
|
|
881
|
+
className: "text-xs text-text-secondary truncate",
|
|
882
|
+
children: jt.has(e.name) ? D("bigconsole.widget.properties.actions.webhookSummary", "→ {{method}} {{url}}", {
|
|
883
|
+
method: jt.get(e.name)?.method ?? "",
|
|
884
|
+
url: jt.get(e.name)?.webhookUrl ?? ""
|
|
885
|
+
}) : D("bigconsole.widget.properties.actions.emitsEvent", "Emits an event")
|
|
886
|
+
})]
|
|
887
|
+
}),
|
|
888
|
+
/* @__PURE__ */ T("div", {
|
|
889
|
+
className: "flex shrink-0 gap-1",
|
|
890
|
+
children: [/* @__PURE__ */ w(_, {
|
|
891
|
+
variant: "ghost",
|
|
892
|
+
size: "icon-sm",
|
|
893
|
+
"aria-label": `Edit ${e.label}`,
|
|
894
|
+
onClick: () => Nt(e),
|
|
895
|
+
children: /* @__PURE__ */ w(ye, { className: "size-4" })
|
|
896
|
+
}), /* @__PURE__ */ w(_, {
|
|
897
|
+
variant: "ghost",
|
|
898
|
+
size: "icon-sm",
|
|
899
|
+
"aria-label": `Delete ${e.label}`,
|
|
900
|
+
onClick: () => Ft(e.id),
|
|
901
|
+
children: /* @__PURE__ */ w(xe, { className: "size-4" })
|
|
902
|
+
})]
|
|
903
|
+
})
|
|
904
|
+
]
|
|
905
|
+
})
|
|
906
|
+
}, e.id))
|
|
907
|
+
})
|
|
908
|
+
}),
|
|
909
|
+
Xe && Ze && /* @__PURE__ */ w(pe, {
|
|
910
|
+
position: Ze,
|
|
911
|
+
columns: me.cols,
|
|
912
|
+
onChange: Qe
|
|
913
|
+
})
|
|
914
|
+
] })
|
|
827
915
|
}),
|
|
828
916
|
/* @__PURE__ */ w(x, {
|
|
829
917
|
value: "data",
|
|
@@ -1155,91 +1243,6 @@ var D = he(function({ isOpen: he, onClose: g }) {
|
|
|
1155
1243
|
onSave: (e) => Q("template", e)
|
|
1156
1244
|
})
|
|
1157
1245
|
}),
|
|
1158
|
-
/* @__PURE__ */ w(n, {
|
|
1159
|
-
title: D("bigconsole.widget.properties.actions.heading", "Widget Actions"),
|
|
1160
|
-
description: D("bigconsole.widget.properties.actions.subheading", "Configure buttons on this widget"),
|
|
1161
|
-
headingLevel: 3,
|
|
1162
|
-
meta: H.length > 0 ? /* @__PURE__ */ w("span", {
|
|
1163
|
-
className: "rounded-pill bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
1164
|
-
children: H.length
|
|
1165
|
-
}) : void 0,
|
|
1166
|
-
actions: /* @__PURE__ */ T(_, {
|
|
1167
|
-
size: "sm",
|
|
1168
|
-
onClick: Mt,
|
|
1169
|
-
children: [/* @__PURE__ */ w(be, { className: "size-4" }), D("bigconsole.widget.properties.actions.add", "Add")]
|
|
1170
|
-
}),
|
|
1171
|
-
"data-testid": "widget-inspector-actions",
|
|
1172
|
-
children: mt ? /* @__PURE__ */ w("div", {
|
|
1173
|
-
className: "flex justify-center py-8",
|
|
1174
|
-
children: /* @__PURE__ */ w(Pe, { className: "size-6" })
|
|
1175
|
-
}) : H.length === 0 ? /* @__PURE__ */ w("p", {
|
|
1176
|
-
className: "text-sm text-text-secondary",
|
|
1177
|
-
children: D("bigconsole.widget.properties.actions.empty", "No actions configured")
|
|
1178
|
-
}) : /* @__PURE__ */ w("div", {
|
|
1179
|
-
className: "space-y-2",
|
|
1180
|
-
children: [...H].sort((e, t) => e.order - t.order).map((e, t) => /* @__PURE__ */ w(Ce, {
|
|
1181
|
-
className: e.disabled ? "opacity-60" : "",
|
|
1182
|
-
children: /* @__PURE__ */ T(we, {
|
|
1183
|
-
className: "p-3 flex items-center gap-2",
|
|
1184
|
-
children: [
|
|
1185
|
-
/* @__PURE__ */ T("div", {
|
|
1186
|
-
className: "flex flex-col gap-0.5",
|
|
1187
|
-
children: [/* @__PURE__ */ w(_, {
|
|
1188
|
-
variant: "ghost",
|
|
1189
|
-
size: "icon-sm",
|
|
1190
|
-
onClick: () => It(t),
|
|
1191
|
-
disabled: t === 0,
|
|
1192
|
-
className: "h-5 w-5",
|
|
1193
|
-
children: /* @__PURE__ */ w(_e, { className: "size-3" })
|
|
1194
|
-
}), /* @__PURE__ */ w(_, {
|
|
1195
|
-
variant: "ghost",
|
|
1196
|
-
size: "icon-sm",
|
|
1197
|
-
onClick: () => Lt(t),
|
|
1198
|
-
disabled: t === H.length - 1,
|
|
1199
|
-
className: "h-5 w-5",
|
|
1200
|
-
children: /* @__PURE__ */ w(ge, { className: "size-3" })
|
|
1201
|
-
})]
|
|
1202
|
-
}),
|
|
1203
|
-
/* @__PURE__ */ T("div", {
|
|
1204
|
-
className: "flex-1 min-w-0",
|
|
1205
|
-
children: [/* @__PURE__ */ T("div", {
|
|
1206
|
-
className: "flex items-center gap-2",
|
|
1207
|
-
children: [/* @__PURE__ */ w("span", {
|
|
1208
|
-
"aria-hidden": "true",
|
|
1209
|
-
className: `size-2 shrink-0 rounded-full ${Ve[e.style] || He}`
|
|
1210
|
-
}), /* @__PURE__ */ w("span", {
|
|
1211
|
-
className: "text-sm font-medium truncate",
|
|
1212
|
-
children: e.label
|
|
1213
|
-
})]
|
|
1214
|
-
}), /* @__PURE__ */ w("p", {
|
|
1215
|
-
className: "text-xs text-text-secondary truncate",
|
|
1216
|
-
children: jt.has(e.name) ? D("bigconsole.widget.properties.actions.webhookSummary", "→ {{method}} {{url}}", {
|
|
1217
|
-
method: jt.get(e.name)?.method ?? "",
|
|
1218
|
-
url: jt.get(e.name)?.webhookUrl ?? ""
|
|
1219
|
-
}) : D("bigconsole.widget.properties.actions.emitsEvent", "Emits an event")
|
|
1220
|
-
})]
|
|
1221
|
-
}),
|
|
1222
|
-
/* @__PURE__ */ T("div", {
|
|
1223
|
-
className: "flex shrink-0 gap-1",
|
|
1224
|
-
children: [/* @__PURE__ */ w(_, {
|
|
1225
|
-
variant: "ghost",
|
|
1226
|
-
size: "icon-sm",
|
|
1227
|
-
"aria-label": `Edit ${e.label}`,
|
|
1228
|
-
onClick: () => Nt(e),
|
|
1229
|
-
children: /* @__PURE__ */ w(ye, { className: "size-4" })
|
|
1230
|
-
}), /* @__PURE__ */ w(_, {
|
|
1231
|
-
variant: "ghost",
|
|
1232
|
-
size: "icon-sm",
|
|
1233
|
-
"aria-label": `Delete ${e.label}`,
|
|
1234
|
-
onClick: () => Ft(e.id),
|
|
1235
|
-
children: /* @__PURE__ */ w(xe, { className: "size-4" })
|
|
1236
|
-
})]
|
|
1237
|
-
})
|
|
1238
|
-
]
|
|
1239
|
-
})
|
|
1240
|
-
}, e.id))
|
|
1241
|
-
})
|
|
1242
|
-
}),
|
|
1243
1246
|
/* @__PURE__ */ w(n, {
|
|
1244
1247
|
title: D("bigconsole.widget.properties.section.drilldown", "Drilldown"),
|
|
1245
1248
|
description: "Where a click on this widget's data takes the viewer.",
|