From 288702a9c5b3b5440b4216c24177de88422f35b2 Mon Sep 17 00:00:00 2001 From: Matthew Runyon Date: Tue, 16 Jul 2024 22:43:31 -0500 Subject: [PATCH 1/8] feat: Adjustable grid density --- .../src/components/ThemeBootstrap.tsx | 10 +++- packages/code-studio/src/AppRoot.tsx | 6 +-- packages/code-studio/src/index.tsx | 18 ++++--- .../code-studio/src/settings/SettingsMenu.tsx | 47 +++++++--------- .../src/settings/ThemeSectionContent.tsx | 54 +++++++++++++++++++ packages/code-studio/src/styleguide/Grids.tsx | 14 +++++ .../code-studio/src/styleguide/StyleGuide.tsx | 5 -- packages/grid/src/GridMetricCalculator.ts | 16 ++++++ packages/iris-grid/src/IrisGrid.tsx | 41 +++++++++++--- packages/iris-grid/src/IrisGridRenderer.ts | 5 +- packages/iris-grid/src/IrisGridTheme.ts | 52 +++++++++++++++++- .../iris-grid/src/IrisGridThemeProvider.tsx | 9 +++- packages/redux/src/store.ts | 1 + 13 files changed, 223 insertions(+), 55 deletions(-) create mode 100644 packages/code-studio/src/settings/ThemeSectionContent.tsx diff --git a/packages/app-utils/src/components/ThemeBootstrap.tsx b/packages/app-utils/src/components/ThemeBootstrap.tsx index 9d683ad984..c59533de47 100644 --- a/packages/app-utils/src/components/ThemeBootstrap.tsx +++ b/packages/app-utils/src/components/ThemeBootstrap.tsx @@ -4,6 +4,8 @@ import { MonacoThemeProvider } from '@deephaven/console'; import { ThemeProvider } from '@deephaven/components'; import { IrisGridThemeProvider } from '@deephaven/iris-grid'; import { getThemeDataFromPlugins, PluginsContext } from '@deephaven/plugin'; +import { useSelector } from 'react-redux'; +import { getSettings, type RootState } from '@deephaven/redux'; export interface ThemeBootstrapProps { children: React.ReactNode; @@ -21,11 +23,17 @@ export function ThemeBootstrap({ children }: ThemeBootstrapProps): JSX.Element { [pluginModules] ); + const settings = useSelector>( + getSettings + ); + return ( - {children} + + {children} + diff --git a/packages/code-studio/src/AppRoot.tsx b/packages/code-studio/src/AppRoot.tsx index 2da9605c64..6195e29513 100644 --- a/packages/code-studio/src/AppRoot.tsx +++ b/packages/code-studio/src/AppRoot.tsx @@ -25,11 +25,7 @@ export function AppRoot(): JSX.Element { // @ts-ignore window['__react-beautiful-dnd-disable-dev-warnings'] = true; - return ( - - - - ); + return ; } export default AppRoot; diff --git a/packages/code-studio/src/index.tsx b/packages/code-studio/src/index.tsx index 5daf81ceb7..8bc0334ed6 100644 --- a/packages/code-studio/src/index.tsx +++ b/packages/code-studio/src/index.tsx @@ -4,6 +4,8 @@ import '@deephaven/components/scss/BaseStyleSheet.scss'; import { LoadingOverlay, preloadTheme } from '@deephaven/components'; import { ApiBootstrap } from '@deephaven/jsapi-bootstrap'; import logInit from './log/LogInit'; +import { Provider } from 'react-redux'; +import { store } from '@deephaven/redux'; logInit(); @@ -59,13 +61,15 @@ async function getCorePlugins() { ReactDOM.render( }> - - - + + + + + , document.getElementById('root') diff --git a/packages/code-studio/src/settings/SettingsMenu.tsx b/packages/code-studio/src/settings/SettingsMenu.tsx index 93bf36a8ff..a1eab26a6b 100644 --- a/packages/code-studio/src/settings/SettingsMenu.tsx +++ b/packages/code-studio/src/settings/SettingsMenu.tsx @@ -15,7 +15,9 @@ import { Button, CopyButton, GLOBAL_SHORTCUTS, + Item, Logo, + Picker, ThemeContext, ThemePicker, Tooltip, @@ -40,6 +42,7 @@ import { getFormattedVersionInfo, } from './SettingsUtils'; import AdvancedSectionContent from './AdvancedSectionContent'; +import ThemeSectionContent from './ThemeSectionContent'; interface SettingsMenuProps { serverConfigValues: ServerConfigValues; @@ -258,33 +261,23 @@ export class SettingsMenu extends Component< - - {contextValue => { - assertNotNull(contextValue, 'ThemeContext value is null'); - - return contextValue.themes.length > 1 ? ( - - - Theme - - } - > - - - ) : null; - }} - + + + Theme + + } + > + + >( + getSettings + ); + const dispatch = useDispatch(); + + const updateDensity = useCallback( + (density: ItemKey | null) => { + if ( + density !== 'normal' && + density !== 'compact' && + density !== 'spacious' + ) { + throw new Error(`Invalid grid density value: ${density}`); + } + dispatch(updateSettings({ gridDensity: density })); + }, + [dispatch] + ); + + const density = settings.gridDensity ?? 'normal'; + + assertNotNull(theme, 'ThemeContext value is null'); + + return ( + <> + + + Normal + Compact + Spacious + + + ); +} + +export default ThemeSectionContent; diff --git a/packages/code-studio/src/styleguide/Grids.tsx b/packages/code-studio/src/styleguide/Grids.tsx index 42dc1f461f..71e7cb792c 100644 --- a/packages/code-studio/src/styleguide/Grids.tsx +++ b/packages/code-studio/src/styleguide/Grids.tsx @@ -22,6 +22,12 @@ function Grids(): ReactElement { const [irisGridModel] = useState( new MockIrisGridTreeModel(dh, new MockTreeGridModel()) ); + const [irisGridCompactModel] = useState( + new MockIrisGridTreeModel(dh, new MockTreeGridModel()) + ); + const [irisGridSpaciousModel] = useState( + new MockIrisGridTreeModel(dh, new MockTreeGridModel()) + ); const [model] = useState(new MockGridModel()); const [theme] = useState>({ autoSelectRow: true, @@ -70,6 +76,14 @@ function Grids(): ReactElement { +

Iris Grid Compact

+ + + +

Iris Grid Spacious

+ + + ); diff --git a/packages/code-studio/src/styleguide/StyleGuide.tsx b/packages/code-studio/src/styleguide/StyleGuide.tsx index 336b8ab9c4..c2a24bfb31 100644 --- a/packages/code-studio/src/styleguide/StyleGuide.tsx +++ b/packages/code-studio/src/styleguide/StyleGuide.tsx @@ -74,8 +74,6 @@ function StyleGuide(): React.ReactElement { >

Deephaven UI Components

- - {/* {isIsolatedSection ? null : ( */} : null} - {/* )} */} - {/* {isIsolatedSection ? null : ( */} - {/* )} */} diff --git a/packages/grid/src/GridMetricCalculator.ts b/packages/grid/src/GridMetricCalculator.ts index 59b5959beb..ec58635cb9 100644 --- a/packages/grid/src/GridMetricCalculator.ts +++ b/packages/grid/src/GridMetricCalculator.ts @@ -1844,6 +1844,14 @@ export class GridMetricCalculator { this.userColumnWidths = userColumnWidths; } + /** + * Resets all the calculated column widths + * Useful if the theme minimum column width changes + */ + resetCalculatedColumnWidths(): void { + this.calculatedColumnWidths = new Map(); + } + /** * Sets the width for the specified row * @param row The row model index to set @@ -1868,6 +1876,14 @@ export class GridMetricCalculator { this.userRowHeights = userRowHeights; this.calculatedRowHeights.delete(row); } + + /** + * Resets all the calculated row heights + * Useful if the theme row height changes + */ + resetCalculatedRowHeights(): void { + this.calculatedRowHeights = new Map(); + } } export default GridMetricCalculator; diff --git a/packages/iris-grid/src/IrisGrid.tsx b/packages/iris-grid/src/IrisGrid.tsx index e84f92cb5a..f93931a92e 100644 --- a/packages/iris-grid/src/IrisGrid.tsx +++ b/packages/iris-grid/src/IrisGrid.tsx @@ -126,7 +126,13 @@ import ToastBottomBar from './ToastBottomBar'; import IrisGridMetricCalculator from './IrisGridMetricCalculator'; import IrisGridModelUpdater from './IrisGridModelUpdater'; import IrisGridRenderer from './IrisGridRenderer'; -import { createDefaultIrisGridTheme, IrisGridThemeType } from './IrisGridTheme'; +import { + createDefaultIrisGridTheme, + IrisGridThemeType, + NORMAL_DENSITY_THEME, + COMPACT_DENSITY_THEME, + SPACIOUS_DENSITY_THEME, +} from './IrisGridTheme'; import ColumnStatistics from './ColumnStatistics'; import './IrisGrid.scss'; import AdvancedFilterCreator from './AdvancedFilterCreator'; @@ -352,6 +358,8 @@ export interface IrisGridProps { // Pass in a custom renderer to the grid for advanced use cases renderer?: IrisGridRenderer; + + density?: 'compact' | 'normal' | 'spacious'; } export interface IrisGridState { @@ -1396,17 +1404,31 @@ class IrisGrid extends Component { floatingRowCount: number ): IrisGridThemeType => { // If a theme is available via context, use that as the base theme. - // If iris-grid is standalone without a context, initialize a default theme. - const defaultTheme = contextTheme ?? createDefaultIrisGridTheme(); + // If iris-grid is standalone without a context, use the default theme. + const defaultTheme = createDefaultIrisGridTheme(); + const baseTheme = contextTheme ?? defaultTheme; // We only show the row footers when we have floating rows for aggregations const rowFooterWidth = floatingRowCount > 0 - ? theme?.rowFooterWidth ?? defaultTheme.rowFooterWidth + ? theme?.rowFooterWidth ?? baseTheme.rowFooterWidth : 0; + const { metricCalculator } = this.state; + if (metricCalculator != null) { + metricCalculator.resetCalculatedColumnWidths(); + metricCalculator.resetCalculatedRowHeights(); + } + + const { density } = this.props; + return { - ...defaultTheme, + // Base theme includes global density settings + ...baseTheme, + // Explicitly set density overrides base theme + ...(density === 'normal' ? NORMAL_DENSITY_THEME : {}), + ...(density === 'compact' ? COMPACT_DENSITY_THEME : {}), + ...(density === 'spacious' ? SPACIOUS_DENSITY_THEME : {}), ...theme, autoSelectRow: !isEditable, rowFooterWidth, @@ -4231,6 +4253,7 @@ class IrisGrid extends Component { } const theme = this.getTheme(); + const { columnHeaderHeight: singleColumnHeaderHeight } = theme; const filter = this.getCachedFilter( customFilters, @@ -4812,7 +4835,13 @@ class IrisGrid extends Component { /> )} {!isMenuShown && ( -
+