Skip to content

Commit db219ca

Browse files
georgecwanmofojed
andauthored
feat: Create UI to Display Partitioned Tables (#1663)
- `PartitionedTable` objects can now be opened and displayed with a new UI - Supports switching between partitions and viewing the merged or key table - Partition aware parquet tables will also share this new UI - The new UI will no longer allow users to enter invalid partitions - Closes #1143 - Depends on the following changes to core: - deephaven/deephaven-core#4789 - deephaven/deephaven-core#4931 - deephaven/deephaven-core#4940 ### Testing Instructions #### PartitionedTable 1. Run the code and open the table `pt` ```py from deephaven import empty_table _t = empty_table(100).update(["verylongcolumn=(int)Math.floor(i/5)", "veryveryverylongcolumn=i"]) pt = _t.partition_by(["verylongcolumn", "veryveryverylongcolumn"]) ``` 2. Check that the features specified in the [spec](https://user-images.githubusercontent.com/1576283/268390627-d427b993-1d09-43a5-960f-4e6cd0848f36.png) are present: - Resizing the panel horizontally wraps the dropdown without wrapping the '>' - Hovering over the 'Key' and 'Merge' buttons displays the correct labels - The initial partition should be the first valid partition available when all columns are sorted in descending order - Options in the dropdown are displayed in descending order 3. Clicking the 'Key' and 'Merge' tables should correctly display the respective table and the button should visually indicate if one of them is being displayed. All the dropdowns should show empty values while one of the buttons is active. - While one of the toggle buttons is active, only the leftmost dropdown should be enabled 4. After clearing the dropdowns by clicking either the 'Key' or 'Merge' button, selecting any value on any dropdown should automatically set the remaining dropdowns and display a valid partition. 5. Dropdowns should only contain values that are valid with respect to the selected values of all the dropdowns left of it 6. Changing the value of a dropdown should try to preserve dropdowns to the right of it. If this is not possible, the values of the dropdowns right of it should be changed so that a valid partition can be displayed. #### Parquet Tables 1. Run the following code and verify that all tables display and function correctly for every data type ```py from deephaven import empty_table part = empty_table(4).update("II=ii") from deephaven.parquet import write, read write(part, "/tmp/pt-test/intCol=0/part.parquet") write(part, "/tmp/pt-test/intCol=1/part.parquet") int_partition = read("/tmp/pt-test") write(part, "/tmp/string-test/stringCol=hello/part.parquet") write(part, "/tmp/string-test/stringCol=world/part.parquet") string_partition = read("/tmp/string-test") write(part, "/tmp/double-test/doubleCol=1.5/part.parquet") write(part, "/tmp/double-test/doubleCol=2.5/part.parquet") double_partition = read("/tmp/double-test") write(part, "/tmp/char-test/charCol=a/part.parquet") write(part, "/tmp/char-test/charCol=b/part.parquet") char_partition = read("/tmp/char-test") write(part, "/tmp/long-test/longCol=2147483648/part.parquet") write(part, "/tmp/long-test/longCol=2147483650/part.parquet") long_partition = read("/tmp/long-test") write(part, "/tmp/bool-test/boolCol=true/part.parquet") write(part, "/tmp/bool-test/boolCol=false/part.parquet") bool_partition = read("/tmp/bool-test") write(part, "/tmp/multi_test/x=0/y=0/part.parquet") write(part, "/tmp/multi_test/x=0/y=1/part.parquet") write(part, "/tmp/multi_test/x=1/y=0/part.parquet") write(part, "/tmp/multi_test/x=1/y=1/part.parquet") write(part, "/tmp/multi_test/x=1/y=2/part.parquet") multi_partition = read("/tmp/multi_test") ``` --------- Co-authored-by: georgecwan <georgecwan@users.noreply.github.com> Co-authored-by: mikebender <mikebender@deephaven.io>
1 parent c6a099d commit db219ca

36 files changed

Lines changed: 1441 additions & 1116 deletions

package-lock.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/code-studio/src/styleguide/MockIrisGridTreeModel.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,22 @@ class MockIrisGridTreeModel
222222
// Ignore for mock
223223
}
224224

225+
get partition(): never[] {
226+
return [];
227+
}
228+
229+
set partition(partition: never[]) {
230+
// Ignore for mock
231+
}
232+
233+
get partitionColumns(): never[] {
234+
return [];
235+
}
236+
237+
set partitionColumns(partitionColumns: never[]) {
238+
// Ignore for mock
239+
}
240+
225241
set formatter(formatter: Formatter) {
226242
// Ignore for mock
227243
}

packages/components/src/Option.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
1-
import React from 'react';
1+
import React, { OptionHTMLAttributes } from 'react';
22

3-
export type OptionProps = {
3+
export type OptionProps = OptionHTMLAttributes<HTMLOptionElement> & {
44
children: React.ReactNode;
5-
disabled?: boolean;
6-
value: string;
75
'data-testid'?: string;
86
};
97

10-
function Option({
11-
children,
12-
disabled,
13-
value,
14-
'data-testid': dataTestId,
15-
}: OptionProps): JSX.Element {
16-
return (
17-
<option value={value} disabled={disabled} data-testid={dataTestId}>
18-
{children}
19-
</option>
20-
);
8+
function Option({ children, ...props }: OptionProps): JSX.Element {
9+
// eslint-disable-next-line react/jsx-props-no-spreading
10+
return <option {...props}>{children}</option>;
2111
}
2212

2313
export default Option;

packages/console/src/common/ConsoleUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class ConsoleUtils {
5656
return (
5757
type === dh.VariableType.TABLE ||
5858
type === dh.VariableType.TREETABLE ||
59-
type === dh.VariableType.HIERARCHICALTABLE
59+
type === dh.VariableType.HIERARCHICALTABLE ||
60+
type === dh.VariableType.PARTITIONEDTABLE
6061
);
6162
}
6263

packages/console/src/common/ObjectIcon.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ function ObjectIcon({ type }: ObjectIconProps): JSX.Element {
1414
case dh.VariableType.TABLEMAP:
1515
case dh.VariableType.TREETABLE:
1616
case dh.VariableType.HIERARCHICALTABLE:
17+
case dh.VariableType.PARTITIONEDTABLE:
1718
return <FontAwesomeIcon icon={dhTable} />;
1819
case dh.VariableType.FIGURE:
1920
return <FontAwesomeIcon icon={vsGraph} />;

packages/dashboard-core-plugins/src/GridPluginConfig.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ const GridPluginConfig: WidgetPlugin = {
99
type: PluginType.WIDGET_PLUGIN,
1010
component: GridWidgetPlugin,
1111
panelComponent: GridPanelPlugin,
12-
supportedTypes: ['Table', 'TreeTable', 'HierarchicalTable'],
12+
supportedTypes: [
13+
'Table',
14+
'TreeTable',
15+
'HierarchicalTable',
16+
'PartitionedTable',
17+
],
1318
icon: dhTable,
1419
};
1520

packages/dashboard-core-plugins/src/panels/IrisGridPanel.tsx

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
ColumnHeaderGroup,
4444
IrisGridContextMenuData,
4545
IrisGridTableModel,
46+
PartitionConfig,
4647
} from '@deephaven/iris-grid';
4748
import {
4849
AdvancedFilterOptions,
@@ -126,9 +127,7 @@ export interface PanelState {
126127
type LoadedPanelState = PanelState & {
127128
irisGridPanelState: PanelState['irisGridPanelState'] & {
128129
partitions?: (string | null)[];
129-
partitionColumns?: ColumnName[];
130130
partition?: string | null;
131-
partitionColumn?: ColumnName | null;
132131
};
133132
};
134133

@@ -190,7 +189,7 @@ interface IrisGridPanelState {
190189
movedRows: readonly MoveOperation[];
191190
isSelectingPartition: boolean;
192191
partitions: (string | null)[];
193-
partitionColumns: Column[];
192+
partitionConfig?: PartitionConfig;
194193
rollupConfig?: UIRollupConfig;
195194
showSearchBar: boolean;
196195
searchValue: string;
@@ -296,7 +295,6 @@ export class IrisGridPanel extends PureComponent<
296295
movedRows: [],
297296
isSelectingPartition: false,
298297
partitions: [],
299-
partitionColumns: [],
300298
rollupConfig: undefined,
301299
showSearchBar: false,
302300
searchValue: '',
@@ -466,13 +464,11 @@ export class IrisGridPanel extends PureComponent<
466464
model: IrisGridModel,
467465
isSelectingPartition: boolean,
468466
partitions: (string | null)[],
469-
partitionColumns: Column[],
470467
advancedSettings: Map<AdvancedSettingsType, boolean>
471468
) =>
472469
IrisGridUtils.dehydrateIrisGridPanelState(model, {
473470
isSelectingPartition,
474471
partitions,
475-
partitionColumns,
476472
advancedSettings,
477473
})
478474
);
@@ -499,7 +495,8 @@ export class IrisGridPanel extends PureComponent<
499495
pendingDataMap: PendingDataMap<UIRow>,
500496
frozenColumns: readonly ColumnName[],
501497
conditionalFormats: readonly SidebarFormattingRule[],
502-
columnHeaderGroups: readonly ColumnHeaderGroup[]
498+
columnHeaderGroups: readonly ColumnHeaderGroup[],
499+
partitionConfig: PartitionConfig | undefined
503500
) => {
504501
assertNotNull(this.irisGridUtils);
505502
return this.irisGridUtils.dehydrateIrisGridState(model, {
@@ -525,6 +522,7 @@ export class IrisGridPanel extends PureComponent<
525522
frozenColumns,
526523
conditionalFormats,
527524
columnHeaderGroups,
525+
partitionConfig,
528526
});
529527
}
530528
);
@@ -1035,12 +1033,8 @@ export class IrisGridPanel extends PureComponent<
10351033
}[]
10361034
);
10371035
}
1038-
const {
1039-
isSelectingPartition,
1040-
partitions,
1041-
partitionColumns,
1042-
advancedSettings,
1043-
} = IrisGridUtils.hydrateIrisGridPanelState(model, irisGridPanelState);
1036+
const { isSelectingPartition, partitions, advancedSettings } =
1037+
IrisGridUtils.hydrateIrisGridPanelState(model, irisGridPanelState);
10441038
assertNotNull(this.irisGridUtils);
10451039
const {
10461040
advancedFilters,
@@ -1063,6 +1057,7 @@ export class IrisGridPanel extends PureComponent<
10631057
frozenColumns,
10641058
conditionalFormats,
10651059
columnHeaderGroups,
1060+
partitionConfig,
10661061
} = this.irisGridUtils.hydrateIrisGridState(model, {
10671062
...irisGridState,
10681063
...irisGridStateOverrides,
@@ -1084,7 +1079,6 @@ export class IrisGridPanel extends PureComponent<
10841079
movedColumns,
10851080
movedRows,
10861081
partitions,
1087-
partitionColumns,
10881082
quickFilters,
10891083
reverseType,
10901084
rollupConfig,
@@ -1102,6 +1096,7 @@ export class IrisGridPanel extends PureComponent<
11021096
isStuckToBottom,
11031097
isStuckToRight,
11041098
columnHeaderGroups,
1099+
partitionConfig,
11051100
});
11061101
} catch (error) {
11071102
log.error('loadPanelState failed to load panelState', panelState, error);
@@ -1117,7 +1112,6 @@ export class IrisGridPanel extends PureComponent<
11171112
panelState: oldPanelState,
11181113
isSelectingPartition,
11191114
partitions,
1120-
partitionColumns,
11211115
advancedSettings,
11221116
} = this.state;
11231117
const {
@@ -1140,6 +1134,7 @@ export class IrisGridPanel extends PureComponent<
11401134
frozenColumns,
11411135
conditionalFormats,
11421136
columnHeaderGroups,
1137+
partitionConfig,
11431138
} = irisGridState;
11441139
assertNotNull(model);
11451140
assertNotNull(metrics);
@@ -1153,7 +1148,6 @@ export class IrisGridPanel extends PureComponent<
11531148
model,
11541149
isSelectingPartition,
11551150
partitions,
1156-
partitionColumns,
11571151
advancedSettings
11581152
),
11591153
this.getDehydratedIrisGridState(
@@ -1177,7 +1171,8 @@ export class IrisGridPanel extends PureComponent<
11771171
pendingDataMap,
11781172
frozenColumns,
11791173
conditionalFormats,
1180-
columnHeaderGroups
1174+
columnHeaderGroups,
1175+
partitionConfig
11811176
),
11821177
this.getDehydratedGridState(
11831178
model,
@@ -1241,7 +1236,7 @@ export class IrisGridPanel extends PureComponent<
12411236
movedColumns,
12421237
movedRows,
12431238
partitions,
1244-
partitionColumns,
1239+
partitionConfig,
12451240
quickFilters,
12461241
reverseType,
12471242
rollupConfig,
@@ -1323,7 +1318,7 @@ export class IrisGridPanel extends PureComponent<
13231318
movedColumns={movedColumns}
13241319
movedRows={movedRows}
13251320
partitions={partitions}
1326-
partitionColumns={partitionColumns}
1321+
partitionConfig={partitionConfig}
13271322
quickFilters={quickFilters}
13281323
reverseType={reverseType}
13291324
rollupConfig={rollupConfig}

packages/embed-grid/src/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const SUPPORTED_TYPES: string[] = [
2323
dh.VariableType.TREETABLE,
2424
dh.VariableType.HIERARCHICALTABLE,
2525
dh.VariableType.PANDAS,
26+
dh.VariableType.PARTITIONEDTABLE,
2627
];
2728

2829
export type Command = 'filter' | 'sort';

packages/grid/src/DataBarGridModel.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { GridThemeType } from '.';
21
import { ModelIndex } from './GridMetrics';
32
import GridModel from './GridModel';
4-
import { GridColor } from './GridTheme';
3+
import { GridColor, type GridTheme as GridThemeType } from './GridTheme';
54

65
export type Marker = { value: number; color: string };
76
export type AxisOption = 'proportional' | 'middle' | 'directional';

packages/iris-grid/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@deephaven/filters": "file:../filters",
3737
"@deephaven/grid": "file:../grid",
3838
"@deephaven/icons": "file:../icons",
39+
"@deephaven/jsapi-components": "file:../jsapi-components",
3940
"@deephaven/jsapi-types": "file:../jsapi-types",
4041
"@deephaven/jsapi-utils": "file:../jsapi-utils",
4142
"@deephaven/log": "file:../log",

0 commit comments

Comments
 (0)