Skip to content

Commit 5ef19c2

Browse files
authored
feat: Column organization overflow and undo/redo (#2546)
Adds column order and visibilty overflow menu with show hidden columns (for the visibility menu only) and undo/redo. Moves in the menu or on the grid add to the undo/redo stack. Hiding/unhiding adds to the undo/redo stack. Creating a new group will add to the stack as a whole action when it is named (moving columns + naming the group) Unchecking the "Show hidden columns" option will hide the hidden column/group entries in the menu. The setting is reset on menu open.
1 parent 5216008 commit 5ef19c2

24 files changed

Lines changed: 1130 additions & 132 deletions

packages/code-studio/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ export default defineConfig(({ mode }) => {
146146
css: {
147147
devSourcemap: true,
148148
},
149+
define: {
150+
'process.env': {},
151+
},
149152
plugins: [react()],
150153
esbuild: {
151154
/**

packages/components/src/shortcuts/GlobalShortcuts.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ const GLOBAL_SHORTCUTS = {
8686
macShortcut: [MODIFIER.SHIFT, KEY.ENTER],
8787
isEditable: false,
8888
}),
89+
UNDO: ShortcutRegistry.createAndAdd({
90+
id: 'GLOBAL.UNDO',
91+
name: 'Undo',
92+
shortcut: [MODIFIER.CTRL, KEY.Z],
93+
macShortcut: [MODIFIER.CMD, KEY.Z],
94+
isEditable: false,
95+
}),
96+
REDO: ShortcutRegistry.createAndAdd({
97+
id: 'GLOBAL.REDO',
98+
name: 'Redo',
99+
shortcut: [MODIFIER.CTRL, MODIFIER.SHIFT, KEY.Z],
100+
macShortcut: [MODIFIER.CMD, MODIFIER.SHIFT, KEY.Z],
101+
isEditable: false,
102+
}),
89103
};
90104

91105
export default GLOBAL_SHORTCUTS;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Override Bootstrap for Spectrum Menu items with keyboard shortcuts which we just re-export
2+
// Override for spectrum menu with keyboard shortcuts displayed
3+
[class*='spectrum-Menu'] {
4+
kbd {
5+
// Unsetting bootstrap overrides
6+
padding: unset;
7+
font-size: unset;
8+
color: unset;
9+
background-color: unset;
10+
border-radius: unset;
11+
12+
// From Spectrum styles to match the label
13+
padding-inline-start: var(--spectrum-global-dimension-size-125);
14+
line-height: var(--spectrum-global-font-line-height-small, 1.3);
15+
}
16+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import './SpectrumMenu.scss';
2+
3+
// eslint-disable-next-line import/prefer-default-export
4+
export { Menu as SpectrumMenu } from '@adobe/react-spectrum';

packages/components/src/spectrum/collections.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export {
55
// the Spectrum props type for upstream consumers that need to compose prop types.
66
type SpectrumComboBoxProps,
77
// ListBox - we aren't planning to support this component
8-
Menu as SpectrumMenu,
98
type SpectrumMenuProps,
109
MenuTrigger,
1110
type SpectrumMenuTriggerProps as MenuTriggerProps,
@@ -20,3 +19,4 @@ export {
2019
TagGroup,
2120
type SpectrumTagGroupProps as TagGroupProps,
2221
} from '@adobe/react-spectrum';
22+
export { SpectrumMenu } from './SpectrumMenu';

packages/embed-widget/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ export default defineConfig(({ mode }) => {
109109
},
110110
},
111111
},
112+
define: {
113+
'process.env': {},
114+
},
112115
optimizeDeps: {
113116
esbuildOptions: {
114117
// Some packages need this to start properly if they reference global

packages/grid/src/GridUtils.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ describe('move items', () => {
8888
});
8989

9090
it('skips moving an item to its original position', () => {
91-
const movedItems = GridUtils.moveItem(2, 2, []);
91+
const originalMoved: MoveOperation[] = [];
92+
const movedItems = GridUtils.moveItem(2, 2, originalMoved);
9293

93-
expect(movedItems.length).toBe(0);
94+
expect(movedItems).toBe(originalMoved);
9495
expectModelIndexes(movedItems, [0, 1, 2, 3]);
9596
expectVisibleIndexes(movedItems, [0, 1, 2, 3]);
9697
});
@@ -143,9 +144,10 @@ describe('move ranges', () => {
143144
});
144145

145146
it('skips moving an item to its original position', () => {
146-
const movedItems = GridUtils.moveRange([0, 2], 0, []);
147+
const originalMoved: MoveOperation[] = [];
148+
const movedItems = GridUtils.moveRange([0, 2], 0, originalMoved);
147149

148-
expect(movedItems.length).toBe(0);
150+
expect(movedItems).toBe(originalMoved);
149151
expectModelIndexes(movedItems, [0, 1, 2, 3]);
150152
expectVisibleIndexes(movedItems, [0, 1, 2, 3]);
151153
});

packages/grid/src/GridUtils.ts

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -753,18 +753,31 @@ export class GridUtils {
753753
* @param from The visible index to move from
754754
* @param to The visible index to move the item to
755755
* @param oldMovedItems The old reordered items
756-
* @returns The new reordered items
756+
* @returns The new reordered items. The original array if the operation is a no-op.
757757
*/
758+
static moveItem(
759+
from: VisibleIndex,
760+
to: VisibleIndex,
761+
oldMovedItems: MoveOperation[]
762+
): MoveOperation[];
763+
758764
static moveItem(
759765
from: VisibleIndex,
760766
to: VisibleIndex,
761767
oldMovedItems: readonly MoveOperation[]
762-
): MoveOperation[] {
768+
): readonly MoveOperation[];
769+
770+
// The overloads are so we can return the original array if the operation is a no-op
771+
static moveItem(
772+
from: VisibleIndex,
773+
to: VisibleIndex,
774+
oldMovedItems: MoveOperation[] | readonly MoveOperation[]
775+
): MoveOperation[] | readonly MoveOperation[] {
763776
if (from === to) {
764-
return [...oldMovedItems];
777+
return oldMovedItems;
765778
}
766779

767-
const movedItems: MoveOperation[] = [...oldMovedItems];
780+
const movedItems = [...oldMovedItems];
768781
const lastMovedItem = movedItems[movedItems.length - 1];
769782

770783
// Check if we should combine with the previous move
@@ -806,14 +819,29 @@ export class GridUtils {
806819
* E.g. Move range [0, 2] 1 item down (after element 3)
807820
* The move is [0, 2] -> 1 if this is false. [0, 2] -> 3 if this is true
808821
* Both will result in [0, 2] -> 1
809-
* @returns The new reordered items
822+
* @returns The new reordered items. The original array if the operation is a no-op.
810823
*/
824+
static moveRange(
825+
from: BoundedAxisRange,
826+
to: VisibleIndex,
827+
oldMovedItems: MoveOperation[],
828+
isPreMoveTo?: boolean
829+
): MoveOperation[];
830+
811831
static moveRange(
812832
from: BoundedAxisRange,
813833
toParam: VisibleIndex,
814834
oldMovedItems: readonly MoveOperation[],
835+
isPreMoveTo?: boolean
836+
): readonly MoveOperation[];
837+
838+
// The overloads are so we can return the original array if the operation is a no-op
839+
static moveRange(
840+
from: BoundedAxisRange,
841+
toParam: VisibleIndex,
842+
oldMovedItems: MoveOperation[] | readonly MoveOperation[],
815843
isPreMoveTo = false
816-
): MoveOperation[] {
844+
): MoveOperation[] | readonly MoveOperation[] {
817845
if (from[0] === from[1]) {
818846
return GridUtils.moveItem(from[0], toParam, oldMovedItems);
819847
}
@@ -825,7 +853,7 @@ export class GridUtils {
825853
}
826854

827855
if (from[0] === to) {
828-
return [...oldMovedItems];
856+
return oldMovedItems;
829857
}
830858

831859
const movedItems: MoveOperation[] = [...oldMovedItems];
@@ -863,8 +891,23 @@ export class GridUtils {
863891
from: VisibleIndex | BoundedAxisRange,
864892
to: VisibleIndex,
865893
oldMovedItems: MoveOperation[],
894+
isPreMoveTo?: boolean
895+
): MoveOperation[];
896+
897+
static moveItemOrRange(
898+
from: VisibleIndex | BoundedAxisRange,
899+
to: VisibleIndex,
900+
oldMovedItems: readonly MoveOperation[],
901+
isPreMoveTo?: boolean
902+
): readonly MoveOperation[];
903+
904+
// The overloads are so we can return the original array if the operation is a no-op
905+
static moveItemOrRange(
906+
from: VisibleIndex | BoundedAxisRange,
907+
to: VisibleIndex,
908+
oldMovedItems: MoveOperation[] | readonly MoveOperation[],
866909
isPreMoveTo = false
867-
): MoveOperation[] {
910+
): MoveOperation[] | readonly MoveOperation[] {
868911
return Array.isArray(from)
869912
? GridUtils.moveRange(from, to, oldMovedItems, isPreMoveTo)
870913
: GridUtils.moveItem(from, to, oldMovedItems);

packages/grid/src/mouse-handlers/GridColumnMoveMouseHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ class GridColumnMoveMouseHandler extends GridMouseHandler {
680680
draggingColumn: ColumnInfo,
681681
to: number,
682682
movedColumns: readonly MoveOperation[]
683-
): MoveOperation[] {
683+
): readonly MoveOperation[] {
684684
const newMovedColumns = draggingColumn.isColumnGroup
685685
? GridUtils.moveRange(draggingColumn.range, to, movedColumns)
686686
: GridUtils.moveItem(draggingColumn.visibleIndex, to, movedColumns);

packages/iris-grid/src/ColumnHeaderGroup.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,13 @@ export default class ColumnHeaderGroup implements IColumnHeaderGroup {
9191
get isNew(): boolean {
9292
return this.name.startsWith(ColumnHeaderGroup.NEW_GROUP_PREFIX);
9393
}
94+
95+
/**
96+
* Checks if a group is valid.
97+
* An invalid group needs to be re-parsed with the corresponding model.
98+
* @returns true if the group is valid (all children have indexes)
99+
*/
100+
isValid(): boolean {
101+
return this.children.length === this.childIndexes.length;
102+
}
94103
}

0 commit comments

Comments
 (0)