mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-19 21:16:00 +00:00
grid commands + ctx menu
This commit is contained in:
@@ -48,6 +48,7 @@ registerCommand({
|
||||
icon: 'icon connection',
|
||||
toolbarName: 'Add connection',
|
||||
category: 'New',
|
||||
toolbarOrder: 1,
|
||||
name: 'Connection',
|
||||
onClick: () => showModal(ConnectionModal),
|
||||
});
|
||||
|
||||
@@ -42,6 +42,61 @@
|
||||
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) {
|
||||
if (selectedCells.length > 1 && selectedCells.every(x => _.isNumber(x[0]) && _.isNumber(x[1]))) {
|
||||
let sum = _.sumBy(selectedCells, cell => {
|
||||
@@ -77,6 +132,7 @@
|
||||
import DataGridRow from './DataGridRow.svelte';
|
||||
import { getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import contextMenu from '../utility/contextMenu';
|
||||
import { tick } from 'svelte';
|
||||
import {
|
||||
cellIsSelected,
|
||||
@@ -96,6 +152,7 @@
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { nullStore } from '../stores';
|
||||
import memberStore from '../utility/memberStore';
|
||||
import axios from '../utility/axios';
|
||||
|
||||
export let loadNextData = undefined;
|
||||
export let grider = undefined;
|
||||
@@ -161,6 +218,47 @@
|
||||
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 =
|
||||
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||
@@ -416,10 +514,10 @@
|
||||
// // this.saveAndFocus();
|
||||
// }
|
||||
|
||||
if (event.keyCode == keycodes.n0 && event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
setNull();
|
||||
}
|
||||
// if (event.keyCode == keycodes.n0 && event.ctrlKey) {
|
||||
// event.preventDefault();
|
||||
// setNull();
|
||||
// }
|
||||
|
||||
// if (event.keyCode == keycodes.r && event.ctrlKey) {
|
||||
// event.preventDefault();
|
||||
@@ -542,14 +640,6 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
function setNull() {
|
||||
grider.beginUpdate();
|
||||
selectedCells.filter(isRegularCell).forEach(cell => {
|
||||
setCellValue(cell, null);
|
||||
});
|
||||
grider.endUpdate();
|
||||
}
|
||||
|
||||
function setCellValue(cell, value) {
|
||||
grider.setCellValue(cell[0], realColumnUniqueNames[cell[1]], value);
|
||||
}
|
||||
@@ -598,9 +688,30 @@
|
||||
}
|
||||
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>
|
||||
|
||||
<div class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight}>
|
||||
<div
|
||||
class="container"
|
||||
bind:clientWidth={containerWidth}
|
||||
bind:clientHeight={containerHeight}
|
||||
use:contextMenu={createMenu}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="focus-field"
|
||||
|
||||
@@ -24,12 +24,30 @@
|
||||
if (newLeft != null) element.style.left = `${newLeft}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>
|
||||
import _ from 'lodash';
|
||||
import clickOutside from '../utility/clickOutside';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { commands } from '../stores';
|
||||
|
||||
export let items;
|
||||
export let top;
|
||||
@@ -55,12 +73,12 @@
|
||||
on:clickOutside={() => dispatch('close')}
|
||||
bind:this={element}
|
||||
>
|
||||
{#each items as item}
|
||||
{#each _.compact(items.map(x => mapItem(x, $commands))) as item}
|
||||
{#if item.divider}
|
||||
<li class="divider" />
|
||||
{:else}
|
||||
<li>
|
||||
<a on:click={() => handleClick(item)}>
|
||||
<a on:click={() => handleClick(item)} class:disabled={item.disabled}>
|
||||
{item.text}
|
||||
{#if item.keyText}
|
||||
<span class="keyText">{item.keyText}</span>
|
||||
@@ -86,6 +104,7 @@
|
||||
min-width: 160px;
|
||||
z-index: 1050;
|
||||
cursor: default;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.keyText {
|
||||
@@ -103,7 +122,11 @@
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
a.disabled {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
a:hover:not(.disabled) {
|
||||
background-color: #f5f5f5;
|
||||
text-decoration: none;
|
||||
color: #262626;
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
<script context="module">
|
||||
function getCommandTitle(command) {
|
||||
let res = command.text;
|
||||
if (command.keyText) res += ` (${command.keyText})`;
|
||||
return res;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import _ from 'lodash';
|
||||
import App from '../App.svelte';
|
||||
@@ -12,9 +20,14 @@
|
||||
|
||||
<div class="container">
|
||||
{#each list as command}
|
||||
<ToolbarButton icon={command.icon} on:click={command.onClick} disabled={!command.enabled}
|
||||
>{command.toolbarName || command.name}</ToolbarButton
|
||||
<ToolbarButton
|
||||
icon={command.icon}
|
||||
on:click={command.onClick}
|
||||
disabled={!command.enabled}
|
||||
title={getCommandTitle(command)}
|
||||
>
|
||||
{command.toolbarName || command.name}
|
||||
</ToolbarButton>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
export let disabled;
|
||||
export let icon;
|
||||
export let title;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@@ -13,7 +14,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="button" on:click={handleClick} class:disabled>
|
||||
<div class="button" on:click={handleClick} class:disabled {title}>
|
||||
<div class="inner">
|
||||
<span class="icon" class:disabled><FontIcon {icon} /></span>
|
||||
<slot />
|
||||
|
||||
Reference in New Issue
Block a user