Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor CellSelection data structure and store #3037

Merged
merged 104 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
6c67004
Begin scaffolding new Selection data structure
seancolsen Jul 13, 2023
be561de
Upgrade iter-tools package
seancolsen Jul 18, 2023
29aedab
Fill in more logic within Selection scaffolding
seancolsen Jul 18, 2023
8b5ccdc
Improve some naming
seancolsen Jul 18, 2023
66f4e63
Rename classes to mark old code as deprecated
seancolsen Jul 18, 2023
8157a8b
Begin integrating SheetSelection into TabularData
seancolsen Jul 19, 2023
a2eda36
Merge branch 'develop' into selection
seancolsen Jul 19, 2023
b3dd122
Merge branch 'develop' into selection
seancolsen Jul 27, 2023
1f0fe62
Merge branch 'develop' into selection
seancolsen Aug 22, 2023
16eaf92
Merge branch 'develop' into selection
seancolsen Aug 24, 2023
640eb9b
Some readability improvements
seancolsen Aug 25, 2023
de875e4
Add `intersect` method to ImmutableSet
seancolsen Aug 25, 2023
c64e12b
Refactor Series tests to use cases
seancolsen Aug 26, 2023
be749ba
Tiny readability improvement
seancolsen Aug 26, 2023
0476730
Implement SheetSelection.forNewPlane
seancolsen Aug 26, 2023
09cd219
Begin incorporating new Selection into table sheet
seancolsen Aug 28, 2023
63ef9cb
Show selection status in column header
seancolsen Aug 29, 2023
a69d20a
Merge branch 'develop' into selection
seancolsen Aug 29, 2023
bc8b8fe
Fix clipboard code to work with new selection code
seancolsen Sep 1, 2023
59e25fa
Merge branch 'develop' into selection
seancolsen Sep 1, 2023
cc61dc3
Remove legacySelection from table inspector
seancolsen Sep 11, 2023
dd7f242
Modify util fn to handle non-rectangular selection
seancolsen Sep 11, 2023
70927ff
Refactor ExtractColumnsModal to use new selection
seancolsen Sep 11, 2023
9bc1e5e
Deprecate selection within Data Explorer
seancolsen Sep 11, 2023
aeae784
Use new Selection code in data explorer cell tab
seancolsen Sep 12, 2023
efa0dcb
Use new Selection code in DE col tab and results
seancolsen Sep 12, 2023
faabf47
Remove lots of dead code
seancolsen Sep 12, 2023
9a9dbd8
Rename `isSelectedInRange` to `isSelected`
seancolsen Sep 12, 2023
24b4521
Merge branch 'develop' into selection
seancolsen Sep 19, 2023
5117eb2
Merge branch 'develop' into selection
seancolsen Nov 6, 2023
f4cda69
Merge branch 'develop' into selection
seancolsen Feb 5, 2024
ab60ce1
Handle movement keys
seancolsen Feb 6, 2024
5e72917
Begin moving mouse handling logic
seancolsen Feb 6, 2024
c205410
Refactor sheet element attributes
seancolsen Feb 6, 2024
44dd519
Use dedicated components for sheet cell types
seancolsen Feb 7, 2024
f544866
Add match utility function for TS pattern matching
seancolsen Feb 8, 2024
e8e5e34
Begin scaffolding to handle drag selection
seancolsen Feb 8, 2024
4f2a253
Document match function
seancolsen Feb 9, 2024
ab4aca0
Finish implementation of ofSheetCellRange method
seancolsen Feb 9, 2024
4e83d8d
Lift isSelected prop way up
seancolsen Feb 12, 2024
457513a
Clean up CellMode component
seancolsen Feb 12, 2024
2608b22
Remove table-view deps from CellInspector code
seancolsen Feb 18, 2024
ad9dd5e
Pass columnIdentifierKey via prop not import
seancolsen Feb 18, 2024
602e972
Use common CellInspector component within DE
seancolsen Feb 18, 2024
63b6dd9
Pass selection into data explorer sheet
seancolsen Feb 18, 2024
af35b89
Re-enable copying data explorer cells
seancolsen Feb 18, 2024
748134d
Reinstate row header selection in table page
seancolsen Feb 18, 2024
7fded1c
Reinstate row header selection in data explorer
seancolsen Feb 18, 2024
a2ee62d
Reinstate deleting records
seancolsen Mar 4, 2024
1fb4616
Merge branch 'develop' into selection
seancolsen Mar 4, 2024
53b8317
Fix checkbox toggle on click
seancolsen Mar 4, 2024
c1fee48
Fix LinkedRecordCell launch on click
seancolsen Mar 4, 2024
7bee2ed
Fix SingleSelectCell opening
seancolsen Mar 4, 2024
16fdd63
Implement shift+click to select range
seancolsen Mar 4, 2024
610c138
Order a table's processed columns sooner
seancolsen Mar 4, 2024
c123fda
Merge branch 'develop' into selection
seancolsen Mar 18, 2024
a8be26d
Clean up some dead code
seancolsen Mar 21, 2024
6c18123
Remove TODO code comment
seancolsen Mar 21, 2024
0f8cf9d
Improve code comments
seancolsen Mar 21, 2024
5e02d7e
Merge branch 'develop' into selection
seancolsen Apr 4, 2024
141d27c
Fix positioning of new record message
seancolsen Apr 4, 2024
e4f1ec5
Only render row control cell for rows with records
seancolsen Apr 4, 2024
218c59b
Add new record row when clicking placeholder
seancolsen Apr 4, 2024
89adabb
Implement SheetSelectionStore
seancolsen Apr 10, 2024
26a8c51
Fix some linting errors
seancolsen Apr 10, 2024
10f0aa2
Handle CellWrapper focus in pure CSS
seancolsen Apr 10, 2024
bbd1e64
Improve cell focus behavior
seancolsen Apr 10, 2024
894065a
Fix mousedown event on cell input element
seancolsen Apr 10, 2024
8ccb0a6
Prevent column resize from altering selection
seancolsen Apr 10, 2024
2dff73f
Improve parsing/serialization of cellId values
seancolsen Apr 10, 2024
0938b65
Add placeholder row to Plane
seancolsen Apr 10, 2024
2f9cc96
Allow typing into placeholder cells
seancolsen Apr 10, 2024
659c9e2
Remove some dead code
seancolsen Apr 11, 2024
2f0843c
Hide column resize handles during cell selection
seancolsen Apr 11, 2024
d7f91d8
Use default cursor everywhere in sheet during selection
seancolsen Apr 11, 2024
1557b55
Fix drag to re-order columns
seancolsen Apr 11, 2024
b6374d1
Auto-activate inspector tabs based on selection
seancolsen Apr 11, 2024
75eb454
Merge branch 'develop' into selection
seancolsen Apr 11, 2024
30b5e78
Merge branch 'develop' into selection
seancolsen Apr 17, 2024
a188a56
Set active cell to first-clicked when drag-selecting
seancolsen Apr 18, 2024
f003fae
Don't show text selection cursor on row header cells
seancolsen Apr 18, 2024
832e175
Show row header selection bg in Data Explorer
seancolsen Apr 18, 2024
95a1702
Fix reactivity regression with data explorer rows
seancolsen Apr 25, 2024
97c51bc
Don't set dummy rows in records store during fetch
seancolsen Apr 25, 2024
e0b5439
Improve code readability of fetch options
seancolsen Apr 25, 2024
0fe1df9
Loosen coupling between cause/effect of selection and inspector-tab-s…
seancolsen Apr 26, 2024
a2825a3
Fix activation of column tab when adding columns to exploration
seancolsen Apr 26, 2024
1fcb946
Merge branch 'develop' into selection
seancolsen Apr 26, 2024
6797efa
Activate and focus first data cell on table load
seancolsen Apr 26, 2024
0317a26
Fix linting problems
seancolsen Apr 26, 2024
6325be5
Improve logic within `forNewPlane`
seancolsen Apr 27, 2024
f4f4eeb
Small comment cleanup
seancolsen Apr 27, 2024
adf17b1
Reorganize some code
seancolsen Apr 28, 2024
aa211ac
Show loading indicator cell skeletons in record selector
seancolsen Apr 28, 2024
dfe5bfc
Ensure active cell falls within selected cells
seancolsen Apr 28, 2024
8d33995
Improve retention of active cell
seancolsen Apr 28, 2024
6ee7724
Remove dead code comments
seancolsen Apr 28, 2024
274b505
Fix failing tests
seancolsen Apr 29, 2024
28ae92e
Merge branch 'develop' into selection
seancolsen May 7, 2024
c371a20
Auto-sort imports in some files
seancolsen May 7, 2024
1798dd2
Merge branch 'develop' into selection
seancolsen May 7, 2024
69b771e
Merge branch 'develop' into selection
pavish May 27, 2024
fc3ba8f
Merge branch 'develop' into selection
pavish Jun 6, 2024
5489684
Fix regression: Table inspector tabs do not get highlighted based on …
pavish Jun 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions mathesar_ui/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
rules: {
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
'no-console': ['warn', { allow: ['error'] }],
'generator-star-spacing': 'off',
'no-continue': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/ban-ts-comment': [
Expand Down
8 changes: 4 additions & 4 deletions mathesar_ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mathesar_ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"dayjs": "^1.11.5",
"fast-diff": "^1.2.0",
"flatpickr": "^4.6.13",
"iter-tools": "^7.4.0",
"iter-tools": "^7.5.3",
"js-cookie": "^3.0.1",
"papaparse": "^5.4.1",
"perfect-scrollbar": "^1.5.5",
Expand Down
2 changes: 2 additions & 0 deletions mathesar_ui/src/component-library/common/actions/slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ export default function slider(
}

function start(e: MouseEvent | TouchEvent) {
e.stopPropagation();
e.preventDefault();
opts.onStart();
startingValue = opts.getStartingValue();
startingPosition = getPosition(e, opts.axis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ export default class ImmutableSet<T> {
return this.getNewInstance(set);
}

/**
* @returns a new ImmutableSet that contains only the items that are present
* in both this set and the other set. The order of the items in the returned
* set is taken from this set (not the supplied set).
*/
intersect(other: { has: (v: T) => boolean }): this {
return this.getNewInstance([...this].filter((v) => other.has(v)));
}

without(itemOrItems: T | T[]): this {
const items = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
const set = new Set(this.set);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ test('union', () => {
expect(a.union(empty).valuesArray()).toEqual([2, 7, 13, 19, 5]);
expect(empty.union(a).valuesArray()).toEqual([2, 7, 13, 19, 5]);
});

test('intersect', () => {
const a = new ImmutableSet([2, 7, 13, 19, 5]);
const b = new ImmutableSet([23, 13, 3, 2]);
const empty = new ImmutableSet<number>();
expect(a.intersect(a).valuesArray()).toEqual([2, 7, 13, 19, 5]);
expect(a.intersect(b).valuesArray()).toEqual([2, 13]);
expect(b.intersect(a).valuesArray()).toEqual([13, 2]);
expect(a.intersect(empty).valuesArray()).toEqual([]);
expect(empty.intersect(a).valuesArray()).toEqual([]);
expect(empty.intersect(empty).valuesArray()).toEqual([]);
});
27 changes: 5 additions & 22 deletions mathesar_ui/src/components/cell-fabric/CellFabric.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,16 @@
This component is meant to be common for tables, queries, and for import preview
-->
<script lang="ts">
import { createEventDispatcher } from 'svelte';

import type { HorizontalAlignment } from './data-types/components/typeDefinitions';
import type { CellColumnFabric } from './types';

type CustomEvents = {
onSelectionStart: { e: MouseEvent };
onMouseEnterCellWhileSelection: { e: MouseEvent };
};
const dispatch = createEventDispatcher<CustomEvents>();

export let columnFabric: CellColumnFabric;
export let value: unknown;
export let recordSummary: string | undefined = undefined;
export let setRecordSummary:
| ((recordId: string, recordSummary: string) => void)
| undefined = undefined;
export let isActive = false;
export let isSelectedInRange = false;
export let disabled = false;
export let showAsSkeleton = false;
export let horizontalAlignment: HorizontalAlignment | undefined = undefined;
Expand All @@ -31,34 +22,25 @@
export let isIndependentOfSheet = false;
export let showTruncationPopover = false;
export let canViewLinkedEntities = true;
export let lightText = false;

$: ({ cellComponentAndProps } = columnFabric);
$: ({ component } = cellComponentAndProps);
$: props = cellComponentAndProps.props as Record<string, unknown>;

function handleMouseDown(e: MouseEvent) {
dispatch('onSelectionStart', { e });
}

function handleMouseEnter(e: MouseEvent) {
dispatch('onMouseEnterCellWhileSelection', { e });
}
</script>

<div
class="cell-fabric"
data-column-identifier={columnFabric.id}
class:show-as-skeleton={showAsSkeleton}
class:is-independent={isIndependentOfSheet}
on:mousedown={handleMouseDown}
on:mouseenter={handleMouseEnter}
class:light-text={lightText}
>
<svelte:component
this={component}
{...props}
{columnFabric}
{isActive}
{isSelectedInRange}
{disabled}
{isIndependentOfSheet}
{horizontalAlignment}
Expand All @@ -70,9 +52,7 @@
{canViewLinkedEntities}
bind:value
on:movementKeyDown
on:activate
on:update
on:mouseenter
/>

<div class="loader">
Expand Down Expand Up @@ -118,4 +98,7 @@
.cell-fabric:not(.show-as-skeleton) .loader {
display: none;
}
.light-text {
color: var(--cell-text-color-processing);
}
</style>
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<script lang="ts">
import { tick } from 'svelte';
import { createEventDispatcher } from 'svelte';

import CellBackground from '@mathesar/components/CellBackground.svelte';
import type { ValueComparisonOutcome } from '@mathesar-component-library/types';

import type { HorizontalAlignment } from './typeDefinitions';

const dispatch = createEventDispatcher();

export let element: HTMLElement | undefined = undefined;
export let isActive = false;
export let isSelectedInRange = false;
export let disabled = false;
export let mode: 'edit' | 'default' = 'default';
export let multiLineTruncate = false;
Expand All @@ -26,58 +27,28 @@
*/
export let horizontalAlignment: HorizontalAlignment = 'left';

let isFocused = false;

function shouldAutoFocus(
_isActive: boolean,
_mode: 'edit' | 'default',
): boolean {
if (!_isActive) {
// Don't auto-focus inactive cells
return false;
}
if (_mode === 'edit') {
// Don't auto-focus cells in edit mode
return false;
}
/**
* This function exists to ensure that the cell is focused after the user
* moves from edit mode to default mode via pressing Enter.
*/
function autoFocus() {
if (!element) {
// Can't focus if we haven't mounted an element yet
return false;
}
if (element.contains(document.activeElement)) {
// Don't auto-focus if the cell contains another element that is already
// focused (e.g. an input).
return false;
return;
}
return true;
}

async function handleStateChange(
_isActive: boolean,
_mode: 'edit' | 'default',
) {
await tick();
if (shouldAutoFocus(_isActive, _mode)) {
element?.focus();
if (!element.contains(document.activeElement)) {
// Only auto-focus when the cell contains another element that is already
// focused (e.g. an input). If the user moves from edit mode to default
// mode via clicking on some UI element outside sheet, then we _don't_
// want to focus the cell. We want to keep the focus on the other UI
// element that they clicked.
return;
}
}
$: void handleStateChange(isActive, mode);

function handleFocus() {
isFocused = true;
// Note: you might think we ought to automatically activate the cell at this
// point to ensure that we don't have any cells which are focused but not
// active. I tried this and it caused bugs with selecting columns and rows
// via header cells. I didn't want to spend time tracking them down because
// we are planning to refactor the cell selection logic soon anyway. It
// doesn't _seem_ like we have any code which focuses the cell without
// activating it, but it would be nice to eventually build a better
// guarantee into the codebase which prevents cells from being focused
// without being activated.
element.focus();
}

function handleBlur() {
isFocused = false;
$: if (mode === 'default') {
autoFocus();
}

function handleCopy(e: ClipboardEvent) {
Expand All @@ -91,12 +62,21 @@
e.stopPropagation();
}
}

function handleMouseDown(e: MouseEvent) {
if (mode === 'edit') {
// In edit mode we want to capture mousedown events and prevent them from
// propagating to the sheet where mousedown events are used to select
// cells. Without this call, clicking inside a cell input would cause the
// cell to exit edit mode.
e.stopPropagation();
}
dispatch('mousedown', e);
}
</script>

<div
class="cell-wrapper"
class:is-active={isActive}
class:is-focused={isFocused}
class:disabled
class:is-edit-mode={mode === 'edit'}
class:truncate={multiLineTruncate && !isIndependentOfSheet}
Expand All @@ -105,20 +85,20 @@
class:exact-match={valueComparisonOutcome === 'exactMatch'}
class:substring-match={valueComparisonOutcome === 'substringMatch'}
class:no-match={valueComparisonOutcome === 'noMatch'}
data-active-cell={isActive ? '' : undefined}
bind:this={element}
on:click
on:dblclick
on:mousedown
on:mousedown={handleMouseDown}
on:mouseup
on:mouseenter
on:mouseleave
on:keydown
on:copy={handleCopy}
on:focus={handleFocus}
on:blur={handleBlur}
tabindex={-1}
{...$$restProps}
>
{#if mode !== 'edit'}
<CellBackground color="rgba(14, 101, 235, 0.1)" when={isSelectedInRange} />
<CellBackground
color="var(--cell-background-color)"
when={valueComparisonOutcome !== 'noMatch'}
Expand All @@ -144,11 +124,11 @@
text-align: right;
}

&.is-active {
&[data-active-cell] {
box-shadow: 0 0 0 2px var(--slate-300);
border-radius: 2px;

&.is-focused {
&:focus {
box-shadow: 0 0 0 2px var(--sky-700);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
type Props = CellTypeProps<Value>;

export let isActive: Props['isActive'];
export let isSelectedInRange: Props['isSelectedInRange'];
export let value: Props['value'];
export let disabled: Props['disabled'];
export let multiLineTruncate = false;
Expand Down Expand Up @@ -144,23 +143,15 @@
resetEditMode();
}

function handleMouseDown() {
if (!isActive) {
dispatch('activate');
}
}

onMount(initLastSavedValue);
</script>

<CellWrapper
{isActive}
{isSelectedInRange}
{disabled}
bind:element={cellRef}
on:dblclick={setModeToEdit}
on:keydown={handleKeyDown}
on:mousedown={handleMouseDown}
on:mouseenter
mode={isEditMode ? 'edit' : 'default'}
{multiLineTruncate}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import SteppedInputCell from '../SteppedInputCell.svelte';

const requiredProps = {
isActive: false,
isSelectedInRange: false,
isSelected: false,
disabled: false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
const dispatch = createEventDispatcher();

export let isActive: $$Props['isActive'];
export let isSelectedInRange: $$Props['isSelectedInRange'];
export let value: $$Props['value'] = undefined;
export let disabled: $$Props['disabled'];
export let isIndependentOfSheet: $$Props['isIndependentOfSheet'];
Expand All @@ -36,22 +35,14 @@
break;
}
}

function handleMouseDown() {
if (!isActive) {
dispatch('activate');
}
}
</script>

<CellWrapper
{isActive}
{isSelectedInRange}
{disabled}
{isIndependentOfSheet}
on:mouseenter
on:keydown={handleWrapperKeyDown}
on:mousedown={handleMouseDown}
>
<CellValue {value}>
{#if isDefinedNonNullable(value)}
Expand Down