grid commands + ctx menu

This commit is contained in:
Jan Prochazka
2021-03-06 20:32:02 +01:00
parent 49f22e1a3b
commit e49c0169da
5 changed files with 168 additions and 19 deletions

View File

@@ -48,6 +48,7 @@ registerCommand({
icon: 'icon connection', icon: 'icon connection',
toolbarName: 'Add connection', toolbarName: 'Add connection',
category: 'New', category: 'New',
toolbarOrder: 1,
name: 'Connection', name: 'Connection',
onClick: () => showModal(ConnectionModal), onClick: () => showModal(ConnectionModal),
}); });

View File

@@ -42,6 +42,61 @@
onClick: () => get(currentDataGrid).revertAllChanges(), onClick: () => get(currentDataGrid).revertAllChanges(),
}); });
registerCommand({
id: 'dataGrid.deleteSelectedRows',
category: 'Data grid',
name: 'Delete selected rows',
keyText: 'Ctrl+Delete',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).deleteSelectedRows(),
});
registerCommand({
id: 'dataGrid.insertNewRow',
category: 'Data grid',
name: 'Insert new row',
keyText: 'Insert',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).insertNewRow(),
});
registerCommand({
id: 'dataGrid.setNull',
category: 'Data grid',
name: 'Set NULL',
keyText: 'Ctrl+0',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).setNull(),
});
registerCommand({
id: 'dataGrid.undo',
category: 'Data grid',
name: 'Undo',
keyText: 'Ctrl+Z',
icon: 'icon undo',
toolbar: true,
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSet?.canUndo),
onClick: () => get(currentDataGrid).undo(),
});
registerCommand({
id: 'dataGrid.redo',
category: 'Data grid',
name: 'Redo',
keyText: 'Ctrl+Y',
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSet?.canRedo),
onClick: () => get(currentDataGrid).redo(),
});
registerCommand({
id: 'dataGrid.reconnect',
category: 'Data grid',
name: 'Reconnect',
enabledStore: derived(currentDataGrid, grid => grid != null),
onClick: () => get(currentDataGrid).reconnect(),
});
function getRowCountInfo(selectedCells, grider, realColumnUniqueNames, selectedRowData, allRowCount) { function getRowCountInfo(selectedCells, grider, realColumnUniqueNames, selectedRowData, allRowCount) {
if (selectedCells.length > 1 && selectedCells.every(x => _.isNumber(x[0]) && _.isNumber(x[1]))) { if (selectedCells.length > 1 && selectedCells.every(x => _.isNumber(x[0]) && _.isNumber(x[1]))) {
let sum = _.sumBy(selectedCells, cell => { let sum = _.sumBy(selectedCells, cell => {
@@ -77,6 +132,7 @@
import DataGridRow from './DataGridRow.svelte'; import DataGridRow from './DataGridRow.svelte';
import { getFilterType, getFilterValueExpression } from 'dbgate-filterparser'; import { getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
import stableStringify from 'json-stable-stringify'; import stableStringify from 'json-stable-stringify';
import contextMenu from '../utility/contextMenu';
import { tick } from 'svelte'; import { tick } from 'svelte';
import { import {
cellIsSelected, cellIsSelected,
@@ -96,6 +152,7 @@
import keycodes from '../utility/keycodes'; import keycodes from '../utility/keycodes';
import { nullStore } from '../stores'; import { nullStore } from '../stores';
import memberStore from '../utility/memberStore'; import memberStore from '../utility/memberStore';
import axios from '../utility/axios';
export let loadNextData = undefined; export let loadNextData = undefined;
export let grider = undefined; export let grider = undefined;
@@ -161,6 +218,47 @@
grider.revertAllChanges(); grider.revertAllChanges();
} }
export function deleteSelectedRows() {
grider.beginUpdate();
for (const index of getSelectedRowIndexes()) {
if (_.isNumber(index)) grider.deleteRow(index);
}
grider.endUpdate();
}
export function insertNewRow() {
if (grider.canInsert) {
const rowIndex = grider.insertRow();
const cell = [rowIndex, (currentCell && currentCell[1]) || 0];
// @ts-ignore
currentCell = cell;
// @ts-ignore
selectedCells = [cell];
scrollIntoView(cell);
}
}
export function setNull() {
grider.beginUpdate();
selectedCells.filter(isRegularCell).forEach(cell => {
setCellValue(cell, null);
});
grider.endUpdate();
}
export function undo() {
grider.undo();
}
export function redo() {
grider.redo();
}
export async function reconnect() {
await axios.post('database-connections/refresh', { conid, database });
display.reload();
}
$: autofillMarkerCell = $: autofillMarkerCell =
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1 selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))] ? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
@@ -416,10 +514,10 @@
// // this.saveAndFocus(); // // this.saveAndFocus();
// } // }
if (event.keyCode == keycodes.n0 && event.ctrlKey) { // if (event.keyCode == keycodes.n0 && event.ctrlKey) {
event.preventDefault(); // event.preventDefault();
setNull(); // setNull();
} // }
// if (event.keyCode == keycodes.r && event.ctrlKey) { // if (event.keyCode == keycodes.r && event.ctrlKey) {
// event.preventDefault(); // event.preventDefault();
@@ -542,14 +640,6 @@
return null; return null;
} }
function setNull() {
grider.beginUpdate();
selectedCells.filter(isRegularCell).forEach(cell => {
setCellValue(cell, null);
});
grider.endUpdate();
}
function setCellValue(cell, value) { function setCellValue(cell, value) {
grider.setCellValue(cell[0], realColumnUniqueNames[cell[1]], value); grider.setCellValue(cell[0], realColumnUniqueNames[cell[1]], value);
} }
@@ -598,9 +688,30 @@
} }
return {}; return {};
}, {}); }, {});
function createMenu() {
return [
{ command: 'dataGrid.refresh' },
{ divider: true },
{ command: 'dataGrid.save' },
{ command: 'dataGrid.revertRowChanges' },
{ command: 'dataGrid.revertAllChanges' },
{ command: 'dataGrid.deleteSelectedRows' },
{ command: 'dataGrid.insertNewRow' },
{ command: 'dataGrid.setNull' },
{ divider: true },
{ command: 'dataGrid.undo' },
{ command: 'dataGrid.redo' },
];
}
</script> </script>
<div class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight}> <div
class="container"
bind:clientWidth={containerWidth}
bind:clientHeight={containerHeight}
use:contextMenu={createMenu}
>
<input <input
type="text" type="text"
class="focus-field" class="focus-field"

View File

@@ -24,12 +24,30 @@
if (newLeft != null) element.style.left = `${newLeft}px`; if (newLeft != null) element.style.left = `${newLeft}px`;
if (newTop != null) element.style.top = `${newTop}px`; if (newTop != null) element.style.top = `${newTop}px`;
} }
function mapItem(item, commands) {
if (item.command) {
const command = commands[item.command];
if (command) {
return {
text: command.name,
keyText: command.keyText,
onClick: command.onClick,
disabled: !command.enabled,
};
}
return null;
}
return item;
}
</script> </script>
<script> <script>
import _ from 'lodash';
import clickOutside from '../utility/clickOutside'; import clickOutside from '../utility/clickOutside';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { commands } from '../stores';
export let items; export let items;
export let top; export let top;
@@ -55,12 +73,12 @@
on:clickOutside={() => dispatch('close')} on:clickOutside={() => dispatch('close')}
bind:this={element} bind:this={element}
> >
{#each items as item} {#each _.compact(items.map(x => mapItem(x, $commands))) as item}
{#if item.divider} {#if item.divider}
<li class="divider" /> <li class="divider" />
{:else} {:else}
<li> <li>
<a on:click={() => handleClick(item)}> <a on:click={() => handleClick(item)} class:disabled={item.disabled}>
{item.text} {item.text}
{#if item.keyText} {#if item.keyText}
<span class="keyText">{item.keyText}</span> <span class="keyText">{item.keyText}</span>
@@ -86,6 +104,7 @@
min-width: 160px; min-width: 160px;
z-index: 1050; z-index: 1050;
cursor: default; cursor: default;
white-space: nowrap;
} }
.keyText { .keyText {
@@ -103,7 +122,11 @@
color: #262626; color: #262626;
} }
a:hover { a.disabled {
color: gray;
}
a:hover:not(.disabled) {
background-color: #f5f5f5; background-color: #f5f5f5;
text-decoration: none; text-decoration: none;
color: #262626; color: #262626;

View File

@@ -1,3 +1,11 @@
<script context="module">
function getCommandTitle(command) {
let res = command.text;
if (command.keyText) res += ` (${command.keyText})`;
return res;
}
</script>
<script> <script>
import _ from 'lodash'; import _ from 'lodash';
import App from '../App.svelte'; import App from '../App.svelte';
@@ -12,9 +20,14 @@
<div class="container"> <div class="container">
{#each list as command} {#each list as command}
<ToolbarButton icon={command.icon} on:click={command.onClick} disabled={!command.enabled} <ToolbarButton
>{command.toolbarName || command.name}</ToolbarButton icon={command.icon}
on:click={command.onClick}
disabled={!command.enabled}
title={getCommandTitle(command)}
> >
{command.toolbarName || command.name}
</ToolbarButton>
{/each} {/each}
</div> </div>

View File

@@ -4,6 +4,7 @@
export let disabled; export let disabled;
export let icon; export let icon;
export let title;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
@@ -13,7 +14,7 @@
} }
</script> </script>
<div class="button" on:click={handleClick} class:disabled> <div class="button" on:click={handleClick} class:disabled {title}>
<div class="inner"> <div class="inner">
<span class="icon" class:disabled><FontIcon {icon} /></span> <span class="icon" class:disabled><FontIcon {icon} /></span>
<slot /> <slot />