UNPKG

@adaptabletools/adaptable

Version:

Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

375 lines (374 loc) 22 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import * as React from 'react'; import { CheckBox } from '../../../components/CheckBox'; import ErrorBox from '../../../components/ErrorBox'; import FormLayout, { FormRow } from '../../../components/FormLayout'; import { Tag } from '../../../components/Tag'; import { ColorPicker } from '../../../components/ColorPicker'; import { RangesComponent } from '../../Components/RangesComponent'; import { ColumnSelector } from '../../Components/Selectors/ColumnSelector'; import { getGraySwatchColor } from '../../UIHelper'; import { useOnePageAdaptableWizardContext } from '../../Wizard/OnePageAdaptableWizard'; import AdaptableInput from '../../Components/AdaptableInput'; import { Box, Flex } from '../../../components/Flex'; import { BulletRangesSummaryPreview } from './StyledColumnWizardStyleSection/Components/BulletRangesSummaryPreview'; import { SingleSelect } from '../../../components/NewSelect'; import { getCellFontStyleSummaryItems, StyledColumnFontStyleEditor, } from './StyledColumnSliceStyleEditors'; import { Card } from '../../../components/Card'; import { renderSummaryStringTags } from '../../Wizard/SummaryColorTag'; import { formatBarStyleCellTextLayoutSummary, getActiveBarStyleCellTextTokens, hasBarStyleCellTextConfigured, patchBarStyleCellTextPlacement, resolveBarStyleCellTextLayout, toggleBarStyleCellTextToken, } from '../../../Utilities/Helpers/StyledColumns/BarStylesHelper'; import { BarStyleCellTextLayoutEditor } from './StyledColumnWizardStyleSection/Components/BarStyleCellTextLayoutEditor'; const BULLET_STYLE_FORM_SIZES = ['200px', '1fr']; const getTargetSummary = (target) => { if (target == undefined) { return null; } if (Array.isArray(target)) { return target .map((entry) => formatSingleBulletTargetSummary(entry)) .filter(Boolean) .join(', '); } return formatSingleBulletTargetSummary(target); }; const formatSingleBulletTargetSummary = (target) => { if (typeof target === 'number') { return String(target); } if (typeof target === 'string') { return target; } const t = target; return t.Label ?? String(t.Value); }; const formatBulletOriginLabel = (origin) => { if (origin == undefined) { return 'Auto'; } if (typeof origin === 'number') { return `Custom (${origin})`; } return origin; }; const formatBulletCellTextSummary = (cellText) => cellText?.map((t) => (t === 'CellValue' ? 'Cell Value' : 'Percent Value')).join(' + ') ?? ''; const formatBulletToolTipSummary = (toolTipText) => toolTipText?.map((t) => (t === 'CellValue' ? 'Cell Value' : 'Percent Value')).join(' + ') ?? ''; export const getStyledColumnBulletRangesViewValues = (data) => { const bullet = data.BulletChartStyle; if (!bullet) { return []; } const bandCount = bullet.CellRanges?.length ?? 0; const items = [`Bands: ${bandCount}`]; if (bullet.RangeValueType != null) { items.push(`Range Value Type: ${bullet.RangeValueType}`); } return items; }; const buildStyledColumnBulletStyleSummaryStrings = (bullet, options) => { const items = []; const targetProperties = bullet.TargetProperties; const targetSummary = getTargetSummary(targetProperties?.Target); if (targetSummary) { items.push(`Target: ${targetSummary}`); } const marker = targetProperties?.Marker; if (marker?.Shape && marker.Shape !== 'Line') { items.push(`Target Marker Shape: ${marker.Shape}`); } if (marker?.Color) { items.push(`Target Marker Colour: ${marker.Color}`); } if (marker?.Size != null) { items.push(`Target Marker Size: ${marker.Size}px`); } if (bullet.Orientation === 'Vertical') { items.push('Orientation: Vertical'); } const barProperties = bullet.Bar; if (barProperties?.Color) { items.push(`Bar Colour: ${barProperties.Color}`); } if (barProperties?.Height != null) { items.push(`${bullet.Orientation === 'Vertical' ? 'Bar Width' : 'Bar Height'}: ${barProperties.Height}px`); } items.push(`Origin: ${formatBulletOriginLabel(bullet.Origin)}`); if (bullet.BackColor) { items.push(`Back Colour: ${bullet.BackColor}`); } if (hasBarStyleCellTextConfigured(bullet.CellTextProperties)) { const tokens = getActiveBarStyleCellTextTokens(bullet.CellTextProperties); items.push(`Cell Text: ${formatBulletCellTextSummary(tokens)}`); const layoutSummary = formatBarStyleCellTextLayoutSummary(resolveBarStyleCellTextLayout(bullet.CellTextProperties)); if (layoutSummary) { items.push(`Placement: ${layoutSummary}`); } } else if (options.includeEmptyCellText) { items.push('Cell Text: None'); } getCellFontStyleSummaryItems(bullet.Font).forEach(({ label, value }) => { items.push(`${label}: ${value}`); }); if (bullet.ToolTipText?.length) { items.push(`Tooltip: ${formatBulletToolTipSummary(bullet.ToolTipText)}`); } else if (options.includeEmptyTooltip) { items.push('Tooltip: No Tooltip'); } return items; }; export const getStyledColumnBulletStyleViewValues = (data) => { const bullet = data.BulletChartStyle; if (!bullet) { return []; } return buildStyledColumnBulletStyleSummaryStrings(bullet, { includeEmptyCellText: false, includeEmptyTooltip: false, }); }; export const renderStyledColumnBulletRangesSummary = (data) => { const bullet = data.BulletChartStyle; if (!bullet) { return _jsx(Tag, { children: "No bands defined" }); } const tagItems = getStyledColumnBulletRangesViewValues(data); return (_jsxs(Flex, { flexDirection: "column", className: "twa:gap-2 twa:items-start", children: [renderSummaryStringTags(tagItems), _jsx(BulletRangesSummaryPreview, { bulletStyle: bullet })] })); }; export const StyledColumnBulletRangesView = ({ data }) => renderStyledColumnBulletRangesSummary(data); export const renderStyledColumnBulletStyleSummary = (data) => { const bullet = data.BulletChartStyle; if (!bullet) { return _jsx(Tag, { children: "No Styling Defined" }); } const items = buildStyledColumnBulletStyleSummaryStrings(bullet, { includeEmptyCellText: true, includeEmptyTooltip: true, }); if (!items.length) { return _jsx(Tag, { children: "No Style Defined" }); } return renderSummaryStringTags(items); }; export const renderStyledColumnBulletSummary = (data) => { const bullet = data.BulletChartStyle; if (!bullet) { return _jsx(Tag, { children: "No Styling Defined" }); } return (_jsxs(Flex, { flexDirection: "column", className: "twa:gap-3 twa:items-start", children: [renderStyledColumnBulletRangesSummary(data), renderStyledColumnBulletStyleSummary(data)] })); }; const getSimpleTargetMode = (target) => { if (target == undefined) { return 'None'; } const value = Array.isArray(target) ? extractTargetValue(target[0]) : extractTargetValue(target); if (value === 'Col-Avg') return 'Col-Avg'; if (value === 'Col-Median') return 'Col-Median'; if (typeof value === 'number') return 'Number'; if (typeof value === 'string') return 'Column'; return 'None'; }; const extractTargetValue = (t) => { if (t == undefined) return undefined; if (typeof t === 'object') { return t.Value; } return t; }; const MARKER_SHAPES = [ { value: 'Line', label: 'Line' }, { value: 'Triangle', label: 'Triangle' }, { value: 'Dot', label: 'Dot' }, { value: 'Diamond', label: 'Diamond' }, ]; export const StyledColumnWizardBulletSection = (props) => { const variant = props.variant ?? 'style'; const { data, api } = useOnePageAdaptableWizardContext(); const column = React.useMemo(() => { const columnId = data.ColumnId; if (!columnId) { return undefined; } return api.columnApi.getColumnWithColumnId(columnId); }, [data.ColumnId, api]); const minMaxRangeValues = React.useMemo(() => { if (!column) { return null; } return { min: api.styledColumnApi.internalApi.getMinValueForNumericColumn(column), max: api.styledColumnApi.internalApi.getMaxValueForNumericColumn(column), }; }, [column, api]); const scope = { ColumnIds: [data.ColumnId] }; const bullet = data.BulletChartStyle ?? {}; const disabled = !data.ColumnId || !column; const update = (patch) => { props.onChange({ ...data, BulletChartStyle: { ...bullet, ...patch, }, }); }; const onUpdateRanges = (ranges) => { update({ CellRanges: ranges }); }; const onUpdateColumnComparison = (columnComparison) => { update({ ColumnComparison: columnComparison }); }; const onRangeValueTypeChange = React.useCallback((rangeValueType) => { const ranges = rangeValueType === 'Number' ? api.columnScopeApi.createCellColorRangesForScope(scope) : [ { Min: 0, Max: 100, Color: getGraySwatchColor(), }, ]; props.onChange({ ...data, BulletChartStyle: { ...bullet, CellRanges: ranges, RangeValueType: rangeValueType, }, }); }, [data, bullet]); const currentMode = getSimpleTargetMode(bullet.TargetProperties?.Target); const updateTargetProperties = (patch) => { const merged = { ...bullet.TargetProperties, ...patch, }; const isEmpty = merged.Target == undefined && merged.Marker == undefined; update({ TargetProperties: isEmpty ? undefined : merged }); }; const setTarget = (target) => updateTargetProperties({ Target: target }); const handleTargetModeChange = (mode) => { if (mode === 'None') { setTarget(undefined); return; } if (mode === 'Col-Avg' || mode === 'Col-Median') { setTarget(mode); return; } if (mode === 'Number') { setTarget(minMaxRangeValues?.max ?? 0); return; } if (mode === 'Column') { const candidate = api.columnApi.getNumericColumns().find((c) => c.columnId !== data.ColumnId); setTarget(candidate?.columnId ?? ''); return; } }; const handleNumericTargetChange = (value) => { setTarget(value == undefined || isNaN(value) ? 0 : value); }; const handleColumnTargetChange = (columnId) => { setTarget(columnId); }; const updateBar = (patch) => { const merged = { ...bullet.Bar, ...patch, }; const isEmpty = merged.Color == undefined && merged.Height == undefined; update({ Bar: isEmpty ? undefined : merged }); }; const updateMarker = (patch) => { updateTargetProperties({ Marker: { Shape: 'Line', ...bullet.TargetProperties?.Marker, ...patch, }, }); }; const toggleCellText = (token, show) => { update(toggleBarStyleCellTextToken(bullet.CellTextProperties, token, show)); }; const onCellTextPlacementChange = (token, patch) => { update({ CellTextProperties: patchBarStyleCellTextPlacement(bullet.CellTextProperties, token, patch), }); }; const toggleToolTipText = (token, checked) => { const current = bullet.ToolTipText ?? []; const next = checked ? Array.from(new Set([...current, token])) : current.filter((t) => t !== token); update({ ToolTipText: next }); }; if (!data.ColumnId || !column) { return (_jsx(Box, { children: _jsx(ErrorBox, { className: "twa:mt-2", children: !data.ColumnId ? 'You need to select a column before styling.' : `Column "${data.ColumnId}" was not found in the grid.` }) })); } if (variant === 'ranges') { return (_jsx(Box, { children: _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Ranges" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Define qualitative bands for the bullet scale" })] }), _jsx(Card.Body, { children: _jsx(RangesComponent, { disabled: disabled, minMaxRangeValues: minMaxRangeValues, api: api, scope: scope, ranges: bullet.CellRanges, rangeValueType: bullet.RangeValueType, onRangeValueTypeChange: onRangeValueTypeChange, columnComparison: bullet.ColumnComparison, updateRanges: onUpdateRanges, updateColumnComparison: onUpdateColumnComparison, hideColumnComparison: true }) })] }) })); } const primaryTarget = Array.isArray(bullet.TargetProperties?.Target) ? bullet.TargetProperties?.Target?.[0] : bullet.TargetProperties?.Target; const numericTargetValue = typeof primaryTarget === 'number' ? primaryTarget : typeof primaryTarget?.Value === 'number' ? primaryTarget.Value : undefined; const columnTargetValue = typeof primaryTarget === 'string' && primaryTarget !== 'Col-Avg' && primaryTarget !== 'Col-Median' ? primaryTarget : typeof primaryTarget?.Value === 'string' ? primaryTarget.Value : undefined; const markerCfg = bullet.TargetProperties?.Marker; const marker = { Shape: markerCfg?.Shape ?? 'Line', Color: markerCfg?.Color ?? '', Size: markerCfg?.Size ?? (markerCfg?.Shape === 'Line' ? 2 : 8), }; const cellTextProperties = bullet.CellTextProperties; const cellTextDisabled = !hasBarStyleCellTextConfigured(cellTextProperties) || disabled; return (_jsxs(Box, { children: [_jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Target" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Select a target value for the bullet scale" })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Target:", children: _jsx(Box, { className: "twa:max-w-[180px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: currentMode, onValueChange: (v) => handleTargetModeChange(v), items: [ { value: 'None', label: 'None' }, { value: 'Number', label: 'Fixed Number' }, { value: 'Column', label: 'Column' }, { value: 'Col-Avg', label: 'Column Average' }, { value: 'Col-Median', label: 'Column Median' }, ] }) }) }), currentMode === 'Number' && (_jsx(FormRow, { label: "Target Value:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(AdaptableInput, { type: "number", value: numericTargetValue ?? '', onChange: (e) => handleNumericTargetChange(e.target.value === '' ? undefined : Number(e.target.value)) }) }) })), currentMode === 'Column' && (_jsx(FormRow, { label: "Target Column:", children: _jsx(Box, { className: "twa:max-w-[220px]", children: _jsx(ColumnSelector, { type: "number", value: columnTargetValue ?? '', onChange: handleColumnTargetChange, filterColumn: (c) => c.columnId !== data.ColumnId, placeholder: "Select numeric column" }) }) })), currentMode !== 'None' && (_jsxs(_Fragment, { children: [_jsx(FormRow, { label: "Marker Shape:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: marker.Shape, onValueChange: (s) => updateMarker({ Shape: s }), items: MARKER_SHAPES.map((s) => ({ value: s.value, label: s.label })) }) }) }), _jsx(FormRow, { label: "Marker Colour:", children: _jsx(ColorPicker, { disabled: disabled, api: api, value: marker.Color || undefined, onChange: (c) => updateMarker({ Color: c }) }) }), _jsx(FormRow, { label: "Marker Size:", children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: marker.Size, onChange: (e) => updateMarker({ Size: Number(e.target.value) }) }) }) })] }))] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Bar" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Set the bar orientation and height" })] }), _jsx(Card.Body, { children: _jsxs(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: [_jsx(FormRow, { label: "Orientation:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: bullet.Orientation ?? 'Horizontal', onValueChange: (v) => update({ Orientation: v }), items: [ { value: 'Horizontal', label: 'Horizontal' }, { value: 'Vertical', label: 'Vertical' }, ] }) }) }), bullet.Orientation === 'Vertical' && (_jsx(FormRow, { label: "", children: _jsxs(Box, { className: "twa:text-xs twa:text-neutral-500", children: ["Tip: vertical bullet charts need a tall row height to be readable (we recommend at least 60px). Set ", _jsx("code", { children: "rowHeight" }), " on ", _jsx("code", { children: " gridOptions " }), " or use", ' ', _jsx("code", { children: "getRowHeight" }), "."] }) })), _jsx(FormRow, { label: "Bar Colour:", children: _jsx(ColorPicker, { disabled: disabled, api: api, value: bullet.Bar?.Color, onChange: (c) => updateBar({ Color: c }) }) }), _jsx(FormRow, { label: bullet.Orientation === 'Vertical' ? 'Bar Width (px):' : 'Bar Height (px):', children: _jsx(Box, { className: "twa:max-w-[100px]", children: _jsx(AdaptableInput, { type: "number", min: 1, value: bullet.Bar?.Height ?? '', onChange: (e) => updateBar({ Height: e.target.value === '' ? undefined : Number(e.target.value), }), placeholder: "8" }) }) }), _jsx(FormRow, { label: "Origin:", children: _jsx(Box, { className: "twa:max-w-[160px]", children: _jsx(SingleSelect, { className: "twa:w-full", value: typeof bullet.Origin === 'number' ? 'Number' : bullet.Origin ?? 'Auto', onValueChange: (v) => { if (v === 'Auto' || v === 'Zero') { update({ Origin: v }); } else { update({ Origin: 0 }); } }, items: [ { value: 'Auto', label: 'Auto' }, { value: 'Zero', label: 'Zero' }, ] }) }) })] }) })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Cell Text" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Pick which values to display and where each one sits around the bar" })] }), _jsxs(Card.Body, { children: [_jsx(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: _jsx(BarStyleCellTextLayoutEditor, { disabled: disabled, cellTextProperties: cellTextProperties, onToggle: toggleCellText, onPlacementChange: onCellTextPlacementChange }) }), _jsx(Box, { className: `twa:mt-3 twa:pt-3 twa:border-t twa:border-foreground/15 ${cellTextDisabled ? 'twa:opacity-50' : ''}`, children: _jsx(StyledColumnFontStyleEditor, { api: api, disabled: cellTextDisabled, value: bullet.Font, onChange: (next) => { if (next) { update({ Font: next }); } else { const cleaned = { ...bullet }; delete cleaned.Font; props.onChange({ ...data, BulletChartStyle: cleaned }); } } }) })] })] }), _jsxs(Card, { shadow: false, className: "twa:mb-3", children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Tooltip" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Choose whether to display a tooltip" })] }), _jsx(Card.Body, { children: _jsx(FormLayout, { sizes: [...BULLET_STYLE_FORM_SIZES], children: _jsxs(FormRow, { label: "Tooltip Display:", children: [_jsx(CheckBox, { disabled: disabled, checked: bullet.ToolTipText?.includes('CellValue'), onChange: (checked) => toggleToolTipText('CellValue', checked), children: "Cell Value" }), ' ', _jsx(CheckBox, { disabled: disabled, className: "twa:ml-3", checked: bullet.ToolTipText?.includes('PercentageValue'), onChange: (checked) => toggleToolTipText('PercentageValue', checked), children: "Percent Value" })] }) }) })] })] })); };