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

Added drag functionality to update precendence for sort condition #3316

Merged
merged 8 commits into from
Dec 10, 2023
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
import type { Writable } from 'svelte/store';
import { flip } from 'svelte/animate';
import { Icon, Button } from '@mathesar-component-library';
import {
getTabularDataStoreFromContext,
type Sorting,
Sorting,
} from '@mathesar/stores/table-data';
import { iconAddNew } from '@mathesar/icons';
import SortEntry from '@mathesar/components/sort-entry/SortEntry.svelte';
Expand Down Expand Up @@ -47,29 +48,185 @@
return newSort.with(newColumnId, sortDirection);
});
}

// Functionality for making sort entries draggable.

let sortEntries: any[];

Check warning on line 54 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Unexpected any. Specify a different type
$: {
sortEntries = [...$sorting];
}
let sortContainer: HTMLDivElement;
let topPosition = 0;
let isDragging = false;
let dragSortEntry: HTMLElement;
let selectedSortEntry = -1;
let currentSlotIndex = -1;

function handleSortPointerDown(event: PointerEvent) {
if (selectedSortEntry != -1) {

Check failure on line 66 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Expected '!==' and instead saw '!='
isDragging = true;
const containerRect = sortContainer.getBoundingClientRect();
const sortEntryRect = dragSortEntry.getBoundingClientRect();

// Calculate the new top position of the box within the container
topPosition = Math.max(
0,
Math.min(
containerRect.height - sortEntryRect.height,
event.clientY - containerRect.top - sortEntryRect.height / 2,
),
);
if (selectedSortEntry >= 0) {
// Initally the selectedSortEntry would be at it's slot.
currentSlotIndex = selectedSortEntry;

dragSortEntry.style.top = `${topPosition}px`;
dragSortEntry.style.width = `${containerRect.width}px`;
}
}

// Attach events to the body for global pointer move and up events
document.body.addEventListener('pointermove', handleSortPointerMove);

Check failure on line 89 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'handleSortPointerMove' was used before it was defined
document.body.addEventListener('pointerup', handleSortPointerUp);

Check failure on line 90 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'handleSortPointerUp' was used before it was defined
}

function handleSortPointerMove(event: PointerEvent) {
if (isDragging) {
const containerRect = sortContainer.getBoundingClientRect();
const sortEntryRect = dragSortEntry.getBoundingClientRect();

// Calculate the new top position of the box within the container
topPosition = Math.max(
0,
Math.min(
containerRect.height - sortEntryRect.height,
event.clientY - containerRect.top - sortEntryRect.height / 2,
),
);

// Get the slot on which the selected entry is hovering.
let slotHeight = sortEntryRect.height;

Check failure on line 108 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'slotHeight' is never reassigned. Use 'const' instead
const nearestSlot = Math.round(topPosition / slotHeight) * slotHeight;
currentSlotIndex = Math.round(nearestSlot / slotHeight);

// Replace the Sort Entries
if (selectedSortEntry != currentSlotIndex) {

Check failure on line 113 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Expected '!==' and instead saw '!='
move(selectedSortEntry, currentSlotIndex);

Check failure on line 114 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'move' was used before it was defined
selectedSortEntry = currentSlotIndex;
}

// Update the styles directly within the function
if (selectedSortEntry >= 0) {
dragSortEntry.style.top = `${topPosition}px`;
dragSortEntry.style.width = `${containerRect.width}px`;
}
}
}
function handleSortPointerUp(event: PointerEvent) {

Check warning on line 125 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'event' is defined but never used
if (isDragging) {
isDragging = false;

// Do not update if sortentries are unchanged
if (!arraysEqual(sortEntries, [...$sorting])) {

Check failure on line 130 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'arraysEqual' was used before it was defined
// Update the new sort order in sorting store
sorting.update((s: Sorting) => {

Check warning on line 132 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

's' is defined but never used
let newSort = new Sorting(sortEntries);

Check failure on line 133 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

'newSort' is never reassigned. Use 'const' instead
return newSort;
});
}

// Detach the pointer move and up events
document.body.removeEventListener('pointermove', handleSortPointerMove);
document.body.removeEventListener('pointerup', handleSortPointerUp);
}

selectedSortEntry = -1;
currentSlotIndex = -1;
}

function move(i: number, j: number) {
let t = sortEntries[i];

Check failure on line 148 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

't' is never reassigned. Use 'const' instead
sortEntries[i] = sortEntries[j];
sortEntries[j] = t;
sortEntries = [...sortEntries];
}
function arraysEqual(a1: any[], a2: any[]) {

Check warning on line 153 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Unexpected any. Specify a different type

Check warning on line 153 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Unexpected any. Specify a different type
/* WARNING: arrays must not contain {objects} or behavior may be undefined */
return JSON.stringify(a1) == JSON.stringify(a2);

Check failure on line 155 in mathesar_ui/src/systems/table-view/actions-pane/record-operations/sort/Sort.svelte

View workflow job for this annotation

GitHub Actions / Run front end linter

Expected '===' and instead saw '=='
}
</script>

<div class="sorters">
<div class="header">Sort</div>
<div class="content">
{#each [...$sorting] as [columnId, sortDirection], index (columnId)}
<SortEntry
columns={$processedColumns}
columnsAllowedForSelection={availableColumnIds}
getColumnLabel={(processedColumn) => processedColumn?.column.name ?? ''}
getColumnConstraintType={(column) =>
getColumnConstraintTypeByColumnId(column.id, $processedColumns)}
columnIdentifier={columnId}
{sortDirection}
on:remove={() => removeSortColumn(columnId)}
disableColumnChange={index < $sorting.size - 1}
on:update={(e) =>
updateSortEntry(
columnId,
e.detail.columnIdentifier,
e.detail.sortDirection,
)}
/>

<div
class="content sort-container"
bind:this={sortContainer}
on:pointerdown={handleSortPointerDown}
on:pointermove={handleSortPointerMove}
on:pointerup={handleSortPointerUp}
>
{#if selectedSortEntry != -1}
<div bind:this={dragSortEntry} class="sort-entry selected-sort-entry">
<div class="grab grab-selected">
<svg
xmlns="http://www.w3.org/2000/svg"
height="1em"
viewBox="0 0 448 512"
><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
d="M128 136c0-22.1-17.9-40-40-40L40 96C17.9 96 0 113.9 0 136l0 48c0 22.1 17.9 40 40 40H88c22.1 0 40-17.9 40-40l0-48zm0 192c0-22.1-17.9-40-40-40H40c-22.1 0-40 17.9-40 40l0 48c0 22.1 17.9 40 40 40H88c22.1 0 40-17.9 40-40V328zm32-192v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V136c0-22.1-17.9-40-40-40l-48 0c-22.1 0-40 17.9-40 40zM288 328c0-22.1-17.9-40-40-40H200c-22.1 0-40 17.9-40 40l0 48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V328zm32-192v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V136c0-22.1-17.9-40-40-40l-48 0c-22.1 0-40 17.9-40 40zM448 328c0-22.1-17.9-40-40-40H360c-22.1 0-40 17.9-40 40v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V328z"
/></svg
>
</div>
<SortEntry
columns={$processedColumns}
columnsAllowedForSelection={availableColumnIds}
getColumnLabel={(processedColumn) =>
processedColumn?.column.name ?? ''}
getColumnConstraintType={(column) =>
getColumnConstraintTypeByColumnId(column.id, $processedColumns)}
columnIdentifier={sortEntries[selectedSortEntry][0]}
sortDirection={sortEntries[selectedSortEntry][1]}
on:remove={() => removeSortColumn(sortEntries[selectedSortEntry][0])}
disableColumnChange={false}
/>
</div>
{/if}
{#each sortEntries as [columnId, sortDirection], index (columnId)}
<div
class="sort-entry"
animate:flip={{ delay: 0, duration: 250 }}
class:ghost-entry={selectedSortEntry == index}
>
<div class="grab" on:pointerdown={() => (selectedSortEntry = index)}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="1em"
viewBox="0 0 448 512"
><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
d="M128 136c0-22.1-17.9-40-40-40L40 96C17.9 96 0 113.9 0 136l0 48c0 22.1 17.9 40 40 40H88c22.1 0 40-17.9 40-40l0-48zm0 192c0-22.1-17.9-40-40-40H40c-22.1 0-40 17.9-40 40l0 48c0 22.1 17.9 40 40 40H88c22.1 0 40-17.9 40-40V328zm32-192v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V136c0-22.1-17.9-40-40-40l-48 0c-22.1 0-40 17.9-40 40zM288 328c0-22.1-17.9-40-40-40H200c-22.1 0-40 17.9-40 40l0 48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V328zm32-192v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V136c0-22.1-17.9-40-40-40l-48 0c-22.1 0-40 17.9-40 40zM448 328c0-22.1-17.9-40-40-40H360c-22.1 0-40 17.9-40 40v48c0 22.1 17.9 40 40 40h48c22.1 0 40-17.9 40-40V328z"
/></svg
>
</div>
<SortEntry
columns={$processedColumns}
columnsAllowedForSelection={availableColumnIds}
getColumnLabel={(processedColumn) =>
processedColumn?.column.name ?? ''}
getColumnConstraintType={(column) =>
getColumnConstraintTypeByColumnId(column.id, $processedColumns)}
columnIdentifier={columnId}
{sortDirection}
on:remove={() => removeSortColumn(columnId)}
disableColumnChange={false}
on:update={(e) =>
updateSortEntry(
columnId,
e.detail.columnIdentifier,
e.detail.sortDirection,
)}
/>
</div>
{:else}
<span>No sorting condition has been added</span>
{/each}
Expand All @@ -85,6 +242,41 @@
</div>

<style lang="scss">
.grab {
margin-right: 5px;
cursor: grab;
}

.grab-selected {
background-color: white;
cursor: grabbing;
}

.sort-container {
position: relative;
user-select: none;
}

.sort-entry {
display: flex;
flex-direction: row;
align-items: center;
position: relative;
padding: 5px 0 5px 0;
}

.ghost-entry {
visibility: hidden;
}

.selected-sort-entry {
position: absolute;
background-color: transparent;
z-index: 2000;
width: 100%;
top: 30;
}

.sorters {
padding: 1rem;
display: flex;
Expand All @@ -106,10 +298,6 @@
:global(.select-sort-column) {
flex-grow: 1;
}

> :global(* + *) {
margin-top: 0.5rem;
}
}

.header {
Expand Down
Loading