UNPKG

@adaptabletools/adaptable

Version:

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

232 lines (231 loc) 14.7 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import * as React from 'react'; import { ColumnTag, Tag } from '../../../../components/Tag'; import { getDisplayAggFuncNames, } from '../../../../AdaptableState/Common/AggregationColumns'; import { useAdaptable } from '../../../AdaptableContext'; import { ValueSelector } from '../../../Components/ValueSelector'; import { useOnePageAdaptableWizardContext } from '../../../Wizard/OnePageAdaptableWizard'; import { CollapsibleWizardCard, CollapsibleWizardValueSummary, getWizardAccordionSectionClassName, renderCompactColumnTags, useWizardCardAccordion, } from '../../../Wizard/CollapsibleWizardCard'; import { getLayoutWizardInitialExpandedCardId, isTableAggregationsSectionConfigured, } from './layoutWizardAccordionHelpers'; import { columnFilter } from './Utilities'; import { ColumnGroupTag } from '../../../Components/ColumnGroupTag'; import ArrayExtensions from '../../../../Utilities/Extensions/ArrayExtensions'; import { Card } from '../../../../components/Card'; import { Box, Flex } from '../../../../components/Flex'; import { SingleSelect } from '../../../../components/NewSelect'; import { LAYOUT_WIZARD_COLUMN_LIST_HEADER_CLASS, LAYOUT_WIZARD_COLUMN_LIST_OPTION_CLASS, LAYOUT_WIZARD_COLUMN_LIST_SEARCH_CLASS, } from './layoutWizardColumns'; import Radio, { RadioGroup } from '../../../../components/Radio'; import { TypeRadio } from '../../../Wizard/TypeRadio'; import { getTableAggregationSummaryValues } from '../../../../Strategy/Utilities/Layout/aggregationSummaryHelpers'; import { renderSummaryStringTags } from '../../../Wizard/SummaryColorTag'; const WEIGHTED_AVERAGE_AGG_FN_NAME = 'weightedAvg'; export const GRAND_TOTAL_ROW_LABELS = { off: 'None', top: 'Top', bottom: 'Bottom', pinnedTop: 'Pinned Top', pinnedBottom: 'Pinned Bottom', }; export const GRAND_TOTAL_ROW_DESCRIPTIONS = { off: 'Grand Total Row is not displayed in the grid', top: 'Grand Total Row is displayed at the top of the grid', bottom: 'Grand Total Row is displayed at the bottom of the grid', pinnedTop: 'Grand Total Row is pinned to the top of the grid', pinnedBottom: 'Grand Total Row is pinned to the bottom of the grid', }; export const GRAND_TOTAL_ROW_OPTIONS = [ 'off', 'top', 'bottom', 'pinnedTop', 'pinnedBottom', ]; export function getGrandTotalRowKey(layout) { const value = layout.GrandTotalRow; if (value == null || value === false) { return 'off'; } return value; } export function getGrandTotalRowLabel(layout) { return GRAND_TOTAL_ROW_LABELS[getGrandTotalRowKey(layout)]; } export function getGrandTotalRowDescription(layout) { return GRAND_TOTAL_ROW_DESCRIPTIONS[getGrandTotalRowKey(layout)]; } export function getAggFuncSummaryLabel(columnId, aggFunc, aggregationColumnsMap) { if (aggregationColumnsMap[columnId]) { return aggregationColumnsMap[columnId]; } if (typeof aggFunc === 'object' && aggFunc.type === 'weightedAverage') { return WEIGHTED_AVERAGE_AGG_FN_NAME; } if (typeof aggFunc === 'string') { return aggFunc; } return 'agg'; } export const isAggregationsSectionValid = (data) => { const weightedAvg = data.TableAggregationColumns ? (data.TableAggregationColumns || []).find(({ AggFunc }) => typeof AggFunc === 'object' && AggFunc.type === 'weightedAverage')?.AggFunc : null; if (weightedAvg && !weightedAvg.weightedColumnId) { return 'Weighted Average requires a weight column to be selected.'; } return true; }; export const AggregationsSectionSummary = (props) => { const adaptable = useAdaptable(); const { data: contextLayout } = useOnePageAdaptableWizardContext(); const layout = props.layout ?? contextLayout; const values = getTableAggregationSummaryValues(layout, adaptable.api); if (!values.length) { return _jsx(Tag, { children: "No Aggregations" }); } return renderSummaryStringTags(values); }; const ColumnRow = (props) => { const aggValue = props.layout?.TableAggregationColumns?.find((agg) => agg.ColumnId === props.column.columnId)?.AggFunc; const aggFunctionNames = getDisplayAggFuncNames(props.column); const currentAggFnName = props.aggregationColumnsMap[props.column.columnId]; const updateAggFunc = (fnName) => { let aggCols = [...(props.layout.TableAggregationColumns || [])]; const AggFuncValue = fnName === WEIGHTED_AVERAGE_AGG_FN_NAME ? { type: 'weightedAverage', weightedColumnId: null, } : fnName; let found = false; aggCols = aggCols.map(({ ColumnId, AggFunc }) => { if (ColumnId === props.column.columnId) { found = true; return { ColumnId, AggFunc: AggFuncValue, }; } return { ColumnId, AggFunc }; }); if (!found) { aggCols.push({ ColumnId: props.column.columnId, AggFunc: AggFuncValue, }); } props.onChangeAggFunction(aggCols); }; const updateWeightedColumn = (weightedColumnId) => { let aggCols = [...(props.layout.TableAggregationColumns || [])]; const AggFuncValue = { type: 'weightedAverage', weightedColumnId: weightedColumnId, }; let found = false; aggCols = aggCols.map(({ ColumnId, AggFunc }) => { if (ColumnId === props.column.columnId) { found = true; return { ColumnId, AggFunc: AggFuncValue, }; } return { ColumnId, AggFunc }; }); if (!found) { aggCols.push({ ColumnId: props.column.columnId, AggFunc: AggFuncValue, }); } props.onChangeAggFunction(aggCols); }; const weightColumnId = typeof aggValue === 'object' && aggValue.type === 'weightedAverage' ? aggValue.weightedColumnId : null; const weightColumnOptions = props.numberColumns .filter((col) => col.columnId !== props.column.columnId) .map((col) => ({ label: col.friendlyName, value: col.columnId, })); return (_jsxs(Flex, { alignItems: "center", className: "twa:min-w-0 twa:flex-wrap twa:gap-x-1.5 twa:gap-y-0.5", children: [_jsx(Box, { className: "twa:truncate", children: props.column.friendlyName }), _jsx(ColumnGroupTag, { column: props.column }), aggValue && (_jsx(SingleSelect, { size: "small", stopMouseDownPropagation: true, className: "twa:min-w-[6.5rem] twa:shrink-0", value: currentAggFnName, items: aggFunctionNames.map((fnName) => ({ label: fnName, value: fnName, })), onValueChange: updateAggFunc })), currentAggFnName === WEIGHTED_AVERAGE_AGG_FN_NAME && (_jsxs(Flex, { alignItems: "center", className: "twa:gap-1 twa:shrink-0", children: [_jsx(Box, { className: "twa:text-3", children: "Weight" }), _jsx(SingleSelect, { size: "small", stopMouseDownPropagation: true, className: "twa:min-w-[6.5rem]", placeholder: "Select Weight", value: weightColumnId, items: weightColumnOptions, onValueChange: updateWeightedColumn })] }))] })); }; export const AggregationsSection = (props) => { const adaptable = useAdaptable(); const { data: layout } = useOnePageAdaptableWizardContext(); const allAggregableColumns = adaptable.api.columnApi.getAggregatableColumns(); const allColumns = adaptable.api.columnApi.getUIAvailableColumns(); const numberColumns = adaptable.api.columnApi.getNumericColumns(); const allAggregatableColumnIds = allAggregableColumns.map((col) => col.columnId); (layout.TableAggregationColumns || []).forEach((agg) => { if (!allAggregatableColumnIds.includes(agg.ColumnId)) { allAggregatableColumnIds.push(agg.ColumnId); } }); const sortedAggregableColumns = ArrayExtensions.sortArrayWithOrder(allAggregatableColumnIds, (layout.TableAggregationColumns ?? []).map((agg) => agg.ColumnId), { sortUnorderedItems: false }) .map((colId) => adaptable.api.columnApi.getColumnWithColumnId(colId)) .filter(Boolean); const handleColumnsSelectionChange = React.useCallback((columnIds) => { const currentAggsMap = (layout.TableAggregationColumns || []).reduce((acc, { ColumnId, AggFunc }) => { acc[ColumnId] = AggFunc; return acc; }, {}); props.onChange({ ...layout, TableAggregationColumns: columnIds.map((colId) => { const AggFunc = currentAggsMap[colId] ?? adaptable.api.columnApi.getDefaultAggFunc(colId); return { ColumnId: colId, AggFunc, }; }), }); }, [layout]); const handleAggregationChange = React.useCallback((aggFunctions) => { props.onChange({ ...layout, TableAggregationColumns: aggFunctions, }); }, [layout]); const aggregationColumnsMap = React.useMemo(() => { const allColumnsMap = allColumns.reduce((acc, col) => { acc[col.columnId] = col; return acc; }, {}); return (layout.TableAggregationColumns || []).reduce((acc, { ColumnId: colId, AggFunc }) => { let fn = AggFunc; let fnName = ''; if (typeof fn === 'boolean') { fnName = allColumnsMap[colId].aggregationFunction; } if (typeof fn === 'object' && fn.type === 'weightedAverage') { fnName = WEIGHTED_AVERAGE_AGG_FN_NAME; } else if (typeof fn === 'string') { fnName = fn; } acc[colId] = fnName; return acc; }, {}); }, [layout]); const handleSuppressAggFuncInHeader = (checked) => { props.onChange({ ...layout, SuppressAggFuncInHeader: checked, }); }; const aggregationEntries = layout.TableAggregationColumns || []; const initialExpandedCardId = getLayoutWizardInitialExpandedCardId(props.layoutWizardMode, 'columns', isTableAggregationsSectionConfigured(layout)); const { bindCard, hasExpandedCard, expandedFillsSpace } = useWizardCardAccordion(initialExpandedCardId); return (_jsxs(Box, { className: getWizardAccordionSectionClassName(hasExpandedCard, expandedFillsSpace), children: [_jsx(CollapsibleWizardCard, { ...bindCard('columns', { fillAvailable: true }), surface: "panel", "data-name": "aggregation-columns", title: "Aggregation Columns", help: "Select a column and an aggregation function", collapsedHelp: "", compactSummary: renderCompactColumnTags(aggregationEntries.map(({ ColumnId }) => ColumnId), (columnId) => adaptable.api.columnApi.getFriendlyNameForColumnId(columnId), { emptyLabel: 'No columns' }), summary: aggregationEntries.length ? (_jsx(Flex, { flexWrap: "wrap", className: "twa:gap-1", children: aggregationEntries.map(({ ColumnId, AggFunc }) => (_jsxs(ColumnTag, { children: [adaptable.api.columnApi.getFriendlyNameForColumnId(ColumnId), " (", getAggFuncSummaryLabel(ColumnId, AggFunc, aggregationColumnsMap), ")"] }, ColumnId))) })) : (_jsx(Tag, { children: "No columns" })), className: "twa:overflow-hidden twa:flex twa:flex-col", bodyClassName: "twa:min-h-[200px] twa:max-h-[420px] twa:overflow-hidden twa:flex twa:flex-col twa:!pt-0 twa:!pb-0 twa:px-1", children: _jsx(Card, { shadow: false, className: "twa:h-full twa:overflow-hidden twa:flex twa:flex-col", children: _jsx(Card.Body, { className: "twa:flex-1 twa:min-h-0 twa:overflow-hidden twa:px-1 twa:pt-0 twa:pb-0", children: _jsx(Box, { className: "twa:flex twa:flex-col twa:gap-1.5 twa:h-full twa:overflow-hidden twa:flex-1 twa:min-h-0", "data-name": "aggregation-columns-container", children: _jsx(ValueSelector, { compact: true, showFilterInput: true, filter: columnFilter, filterPlaceholder: "Search Columns...", compactHeaderClassName: LAYOUT_WIZARD_COLUMN_LIST_HEADER_CLASS, compactFilterClassName: LAYOUT_WIZARD_COLUMN_LIST_SEARCH_CLASS, optionLayout: "label-beside-checkbox", toggleSelectionOnRowClick: true, optionClassName: LAYOUT_WIZARD_COLUMN_LIST_OPTION_CLASS, toIdentifier: (option) => `${option.columnId}`, toLabel: (option) => option.friendlyName ?? option.columnId, toListLabel: (column) => (_jsx(ColumnRow, { onChangeAggFunction: handleAggregationChange, layout: layout, column: column, aggregationColumnsMap: aggregationColumnsMap, numberColumns: numberColumns })), options: sortedAggregableColumns, value: aggregationEntries.map((agg) => agg.ColumnId), allowReorder: () => true, onChange: handleColumnsSelectionChange }) }) }) }) }), _jsx(CollapsibleWizardCard, { ...bindCard('suppress-header'), surface: "panel", "data-name": "omit-aggregation-from-header", title: "Aggregation Column Header", help: "Set behaviour for aggregation function names", collapsedHelp: "Behaviour for aggregation function names", compactSummary: _jsx(Tag, { children: layout.SuppressAggFuncInHeader ? 'Hide Function Name in Header' : 'Show Function Name in Header' }), summary: _jsx(CollapsibleWizardValueSummary, { value: _jsx(Tag, { children: layout.SuppressAggFuncInHeader ? 'Hide Function Name in Header' : 'Show Function Name in Header' }) }), children: _jsxs(RadioGroup, { orientation: "vertical", value: layout.SuppressAggFuncInHeader ?? false, onRadioChange: handleSuppressAggFuncInHeader, children: [_jsx(Radio, { value: false, children: "Show Aggregation function names" }), _jsx(Radio, { value: true, children: "Hide Aggregation function names" })] }) }), _jsx(CollapsibleWizardCard, { ...bindCard('grand-total'), surface: "panel", "data-name": "grand-total-row", title: "Grand Total Row", help: "Set position of the Grand Total Row in the grid", collapsedHelp: "Position of the Grand Total Row in the grid", compactSummary: _jsx(Tag, { children: getGrandTotalRowLabel(layout) }), summary: _jsx(CollapsibleWizardValueSummary, { value: _jsx(Tag, { children: getGrandTotalRowLabel(layout) }) }), children: _jsx(RadioGroup, { orientation: "vertical", value: getGrandTotalRowKey(layout), onRadioChange: (key) => { props.onChange({ ...layout, GrandTotalRow: key === 'off' ? null : key, }); }, children: GRAND_TOTAL_ROW_OPTIONS.map((key) => (_jsx(TypeRadio, { value: key, text: GRAND_TOTAL_ROW_LABELS[key], description: GRAND_TOTAL_ROW_DESCRIPTIONS[key] }, key))) }) })] })); };