@finos/legend-data-cube
Version:
263 lines • 16.8 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { observer } from 'mobx-react-lite';
import { AllCommunityModule } from 'ag-grid-community';
import { AllEnterpriseModule } from 'ag-grid-enterprise';
import { AgGridReact } from 'ag-grid-react';
import { DataCubeIcon, Switch, cn, Global, css } from '@finos/legend-art';
import { generateBackgroundColorUtilityClassName, generateFontCaseUtilityClassName, generateFontFamilyUtilityClassName, generateFontSizeUtilityClassName, generateFontUnderlineUtilityClassName, generateTextAlignUtilityClassName, generateTextColorUtilityClassName, INTERNAL__GridClientUtilityCssClassName, } from '../../../stores/view/grid/DataCubeGridClientEngine.js';
import { DataCubeFont, DataCubeFontCase, DataCubeFontFormatUnderlineVariant, DataCubeFontTextAlignment, DataCubeGridMode, DEFAULT_ROW_BACKGROUND_COLOR, DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR, } from '../../../stores/core/DataCubeQueryEngine.js';
import { isNonNullable } from '@finos/legend-shared';
import { generateBaseGridOptions } from '../../../stores/view/grid/DataCubeGridConfigurationBuilder.js';
import { FormBadge_WIP } from '../../core/DataCubeFormUtils.js';
import { useDataCube } from '../../DataCubeProvider.js';
import { DataCubeMultidimensionalGrid } from './DataCubeMultidimensionalGrid.js';
// NOTE: This is a workaround to prevent ag-grid license key check from flooding the console screen
// with its stack trace in Chrome.
// We MUST NEVER completely surpress this warning in production, else it's a violation of the ag-grid license!
// See https://www.ag-grid.com/react-data-grid/licensing/
const __INTERNAL__original_console_error = console.error; // eslint-disable-line no-console
function textColorStyle(key, configuration) {
return `${Array.from(new Set([
configuration[`${key}ForegroundColor`],
...configuration.columns
.map((column) => column[`${key}ForegroundColor`])
.filter(isNonNullable),
]).values())
.map((color) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateTextColorUtilityClassName(color, key)}{color:${color};}`)
.join('\n')}`;
}
function backgroundColorStyle(key, configuration) {
return `${Array.from(new Set([
configuration[`${key}BackgroundColor`],
...configuration.columns
.map((column) => column[`${key}BackgroundColor`])
.filter(isNonNullable),
]).values())
.map((color) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateBackgroundColorUtilityClassName(color, key)}{background-color:${color};}`)
.join('\n')};`;
}
export const DataCubeGridStyleController = observer((props) => {
const { configuration } = props;
return (_jsx(Global, { styles: css `
.${INTERNAL__GridClientUtilityCssClassName.ROOT} {
--ag-odd-row-background-color: ${configuration.alternateRowsStandardMode &&
!configuration.alternateRows
? DEFAULT_ROW_HIGHLIGHT_BACKGROUND_COLOR
: DEFAULT_ROW_BACKGROUND_COLOR};
--ag-cell-horizontal-border: ${configuration.showVerticalGridLines
? `1px solid
${configuration.gridLineColor}`
: 'none'};
--ag-row-border-color: ${configuration.showHorizontalGridLines
? configuration.gridLineColor
: 'transparent'};
}
.${INTERNAL__GridClientUtilityCssClassName.ROOT}
.${INTERNAL__GridClientUtilityCssClassName.HIGHLIGHT_ROW} {
background-color: ${configuration.alternateRows
? configuration.alternateRowsColor
: DEFAULT_ROW_BACKGROUND_COLOR};
}
${[
DataCubeFont.ARIAL,
DataCubeFont.ROBOTO,
DataCubeFont.ROBOTO_CONDENSED,
]
.map((fontFamily) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontFamilyUtilityClassName(fontFamily)}{font-family:${fontFamily},sans-serif;}`)
.join('\n')}
${[
DataCubeFont.GEORGIA,
DataCubeFont.ROBOTO_SERIF,
DataCubeFont.TIMES_NEW_ROMAN,
]
.map((fontFamily) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontFamilyUtilityClassName(fontFamily)}{font-family:${fontFamily},serif;}`)
.join('\n')}
${[
DataCubeFont.JERBRAINS_MONO,
DataCubeFont.ROBOTO_MONO,
DataCubeFont.UBUNTU_MONO,
]
.map((fontFamily) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontFamilyUtilityClassName(fontFamily)}{font-family:${fontFamily},monospace;}`)
.join('\n')}
.${INTERNAL__GridClientUtilityCssClassName.FONT_BOLD} {
font-weight: 700;
}
${[
4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32,
36, 48, 72,
]
.map((fontSize) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontSizeUtilityClassName(fontSize)}{font-size:${fontSize}px;}`)
.join('\n')}
.${INTERNAL__GridClientUtilityCssClassName.ROOT}
.${INTERNAL__GridClientUtilityCssClassName.FONT_ITALIC} {
font-style: italic;
}
${[
DataCubeFontFormatUnderlineVariant.SOLID,
DataCubeFontFormatUnderlineVariant.DASHED,
DataCubeFontFormatUnderlineVariant.DOTTED,
DataCubeFontFormatUnderlineVariant.DOUBLE,
DataCubeFontFormatUnderlineVariant.WAVY,
]
.map((variant) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontUnderlineUtilityClassName(variant)}{text-decoration:underline ${variant};}`)
.join('\n')}
.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${INTERNAL__GridClientUtilityCssClassName.FONT_STRIKETHROUGH} {
text-decoration: line-through;
}
${[
DataCubeFontCase.LOWERCASE,
DataCubeFontCase.UPPERCASE,
DataCubeFontCase.CAPITALIZE,
]
.map((fontCase) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateFontCaseUtilityClassName(fontCase)}{text-transform:${fontCase};}`)
.join('\n')}
${[
DataCubeFontTextAlignment.LEFT,
DataCubeFontTextAlignment.CENTER,
DataCubeFontTextAlignment.RIGHT,
]
.map((alignment) => `.${INTERNAL__GridClientUtilityCssClassName.ROOT} .${generateTextAlignUtilityClassName(alignment)}{text-align:${alignment};}`)
.join('\n')};
${backgroundColorStyle('normal', configuration)}
${backgroundColorStyle('zero', configuration)}
${backgroundColorStyle('negative', configuration)}
${backgroundColorStyle('error', configuration)}
${textColorStyle('normal', configuration)}
${textColorStyle('zero', configuration)}
${textColorStyle('negative', configuration)}
${textColorStyle('error', configuration)}
.${INTERNAL__GridClientUtilityCssClassName.ROOT}
.${INTERNAL__GridClientUtilityCssClassName.BLUR} {
filter: blur(3px);
}
.${INTERNAL__GridClientUtilityCssClassName.ROOT}
.${INTERNAL__GridClientUtilityCssClassName.BLUR}:hover {
filter: none;
}
` }));
});
const DataCubeGridScroller = observer((props) => {
const { view } = props;
const grid = view.grid;
const scrollHintText = grid.scrollHintText;
const gridClientSideBarElement = document.querySelector('.data-cube-grid .ag-side-bar');
const gridVerticalScrollbar = document.querySelector('.data-cube-grid .ag-body-vertical-scroll');
return (_jsxs("div", { className: "absolute -top-10 flex items-center rounded-sm border border-neutral-300 bg-neutral-100 p-1 pr-2 text-neutral-500 shadow-sm", style: {
right: (gridClientSideBarElement !== null
? gridClientSideBarElement.getBoundingClientRect().width + 6
: 10) +
(gridVerticalScrollbar !== null
? gridVerticalScrollbar.getBoundingClientRect().width
: 0),
}, children: [_jsx(DataCubeIcon.TableScroll, { className: "text-lg" }), _jsx("div", { className: "ml-1 font-mono text-sm", children: scrollHintText ?? '' })] }));
});
const DataCubeGridStatusBar = observer((props) => {
const { view } = props;
const dataCube = useDataCube();
const grid = view.grid;
return (_jsxs("div", { className: "relative flex h-5 w-full select-none justify-between border-b border-neutral-200 bg-neutral-100", children: [Boolean(grid.scrollHintText) && _jsx(DataCubeGridScroller, { view: view }), _jsx("div", {}), _jsxs("div", { className: "flex h-full items-center", children: [_jsx("div", { className: "flex h-full items-center px-2 font-mono text-sm text-neutral-500", children: grid.clientDataSource.rowCount
? `Rows: ${grid.clientDataSource.rowCount}`
: '' }), grid.rowLimit !== undefined &&
grid.configuration.showWarningForTruncatedResult && (
// TODO: if we want to properly warn if the data has been truncated due to row limit,
// this would require us to fetch n+1 rows when limit=n
// This is feature is not difficult to implement, but it would be implemented most cleanly
// when we change the query execution engine to return the total number of rows,
// so for now, we simply just warn about truncation whenever a limit != -1 is specified
_jsxs(_Fragment, { children: [_jsx("div", { className: "h-3 w-[1px] bg-neutral-200" }), _jsxs("div", { className: "flex h-full items-center px-2 text-orange-500", children: [_jsx(DataCubeIcon.Warning, { className: "stroke-[3px]" }), _jsx("div", { className: "ml-1 text-sm font-semibold", children: `Results truncated to fit within row limit (${grid.rowLimit})` })] })] })), _jsx("div", { className: "h-3 w-[1px] bg-neutral-200" }), _jsxs("button", { className: "flex h-full items-center p-2", onClick: () => {
grid.setPaginationEnabled(!grid.isPaginationEnabled);
}, children: [_jsx(Switch, { checked: grid.isPaginationEnabled, classes: {
root: 'p-0 w-6 h-5 flex items-center',
input: 'w-2',
checked: '!translate-x-2 ease-in-out duration-100 transition',
thumb: cn('w-2 h-2', {
'bg-sky-600': grid.isPaginationEnabled,
'bg-neutral-500': !grid.isPaginationEnabled,
}),
switchBase: 'p-0.5 mt-1 translate-x-0 ease-in-out duration-100 transition',
track: cn('h-3 w-5 border', {
'!bg-sky-100 border-sky-600': grid.isPaginationEnabled,
'!bg-neutral-100 border-neutral-500': !grid.isPaginationEnabled,
}),
}, disableRipple: true, disableFocusRipple: true }), _jsx("div", { className: cn('text-sm', {
'text-sky-600': grid.isPaginationEnabled,
'text-neutral-500': !grid.isPaginationEnabled,
}), children: "Pagination" })] }), view.dataCube.options?.enableCache && (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-3 w-[1px] bg-neutral-200" }), _jsxs("button", { className: "flex h-full items-center p-2", onClick: () => {
grid
.setCachingEnabled(!grid.isCachingEnabled)
.catch((error) => dataCube.alertService.alertUnhandledError(error));
}, children: [_jsx(Switch, { checked: grid.isCachingEnabled, classes: {
root: 'p-0 w-6 h-5 flex items-center',
input: 'w-2',
checked: '!translate-x-2 ease-in-out duration-100 transition',
thumb: cn('w-2 h-2', {
'bg-sky-600': grid.isCachingEnabled,
'bg-neutral-500': !grid.isCachingEnabled,
}),
switchBase: 'p-0.5 mt-1 translate-x-0 ease-in-out duration-100 transition',
track: cn('h-3 w-5 border', {
'!bg-sky-100 border-sky-600': grid.isCachingEnabled,
'!bg-neutral-100 border-neutral-500': !grid.isCachingEnabled,
}),
}, disableRipple: true, disableFocusRipple: true, disabled: view.processCacheState.isInProgress, title: view.processCacheState.isInProgress
? 'Processing cache...'
: '' }), _jsxs("div", { className: cn('flex items-center text-sm', {
'text-sky-600': grid.isCachingEnabled,
'text-neutral-500': !grid.isCachingEnabled,
}), children: ["Cache ", _jsx(FormBadge_WIP, {})] })] })] }))] })] }));
});
const DataCubeStandardGridClient = observer((props) => {
const { view } = props;
const grid = view.grid;
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV !== 'production' && !grid.isClientConfigured) {
// eslint-disable-next-line no-console
console.error = (message, ...agrs) => {
console.debug(`%c ${message}`, 'color: silver'); // eslint-disable-line no-console
};
}
return (_jsx("div", { className: "relative h-[calc(100%_-_20px)] w-full", children: _jsx(AgGridReact, { theme: "legacy", className: "data-cube-grid ag-theme-quartz", rowModelType: "serverSide", serverSideDatasource: grid.clientDataSource, context: {
view,
}, onGridReady: (params) => {
grid
.configureClient(params.api)
.catch((error) => view.alertService.alertUnhandledError(error));
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV !== 'production') {
// restore original error logging
console.error = __INTERNAL__original_console_error; // eslint-disable-line no-console
}
}, modules: [AllCommunityModule, AllEnterpriseModule], ...generateBaseGridOptions(view) }) }));
});
const DataCubeStandardGrid = observer((props) => {
const { view } = props;
const configuration = view.grid.configuration;
return (_jsxs("div", { className: "h-[calc(100%_-_48px)] w-full", children: [_jsx(DataCubeGridStyleController, { configuration: configuration }), _jsx(DataCubeStandardGridClient, { view: view }), _jsx(DataCubeGridStatusBar, { view: view })] }));
});
export const DataCubeGrid = observer((props) => {
const { view } = props;
switch (view.info.configuration.gridMode) {
case DataCubeGridMode.MULTIDIMENSIONAL:
return _jsx(DataCubeMultidimensionalGrid, { view: view });
case DataCubeGridMode.STANDARD:
return _jsx(DataCubeStandardGrid, { view: view });
default:
return (_jsx("div", { className: "border-t-1 border-b-1 h-[calc(100%_-_48px)] w-full border border-neutral-200 bg-neutral-50" }));
}
});
//# sourceMappingURL=DataCubeGrid.js.map