mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
formview save
This commit is contained in:
parent
90c4b44fdb
commit
ec90a8b952
@ -2,6 +2,9 @@
|
||||
let lastFocusedDataGrid = null;
|
||||
const getCurrentDataGrid = () =>
|
||||
lastFocusedDataGrid?.getTabId && lastFocusedDataGrid?.getTabId() == getActiveTabId() ? lastFocusedDataGrid : null;
|
||||
export function clearLastFocusedDataGrid() {
|
||||
lastFocusedDataGrid = null;
|
||||
}
|
||||
|
||||
registerCommand({
|
||||
id: 'dataGrid.refresh',
|
||||
@ -205,6 +208,7 @@
|
||||
import { copyTextToClipboard } from '../utility/clipboard';
|
||||
import invalidateCommands from '../commands/invalidateCommands';
|
||||
import createRef from '../utility/createRef';
|
||||
import { clearLastFocusedFormView } from '../formview/FormView.svelte';
|
||||
|
||||
export let onLoadNextData = undefined;
|
||||
export let grider = undefined;
|
||||
@ -666,7 +670,6 @@
|
||||
}
|
||||
|
||||
function handleGridKeyDown(event) {
|
||||
|
||||
if ($inplaceEditorState.cell) return;
|
||||
|
||||
if (
|
||||
@ -903,6 +906,7 @@
|
||||
on:keydown={handleGridKeyDown}
|
||||
on:focus={() => {
|
||||
lastFocusedDataGrid = instance;
|
||||
clearLastFocusedFormView();
|
||||
invalidateCommands();
|
||||
}}
|
||||
on:paste={handlePaste}
|
||||
|
@ -2,6 +2,9 @@
|
||||
let lastFocusedFormView = null;
|
||||
const getCurrentDataForm = () =>
|
||||
lastFocusedFormView?.getTabId && lastFocusedFormView?.getTabId() == getActiveTabId() ? lastFocusedFormView : null;
|
||||
export function clearLastFocusedFormView() {
|
||||
lastFocusedFormView = null;
|
||||
}
|
||||
|
||||
registerCommand({
|
||||
id: 'dataForm.switchToTable',
|
||||
@ -12,6 +15,17 @@
|
||||
onClick: () => getCurrentDataForm().switchToTable(),
|
||||
});
|
||||
|
||||
registerCommand({
|
||||
id: 'dataForm.save',
|
||||
group: 'save',
|
||||
category: 'Data form',
|
||||
name: 'Save',
|
||||
toolbar: true,
|
||||
icon: 'icon save',
|
||||
testEnabled: () => getCurrentDataForm()?.getFormer()?.allowSave,
|
||||
onClick: () => getCurrentDataForm().save(),
|
||||
});
|
||||
|
||||
function isDataCell(cell) {
|
||||
return cell[1] % 2 == 1;
|
||||
}
|
||||
@ -27,15 +41,18 @@
|
||||
|
||||
import registerCommand from '../commands/registerCommand';
|
||||
import DataGridCell from '../datagrid/DataGridCell.svelte';
|
||||
import { clearLastFocusedDataGrid } from '../datagrid/DataGridCore.svelte';
|
||||
import InplaceEditor from '../datagrid/InplaceEditor.svelte';
|
||||
import { cellFromEvent } from '../datagrid/selection';
|
||||
import ColumnLabel from '../elements/ColumnLabel.svelte';
|
||||
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
||||
import { plusExpandIcon } from '../icons/expandIcons';
|
||||
import FontIcon from '../icons/FontIcon.svelte';
|
||||
|
||||
import { getActiveTabId } from '../stores';
|
||||
import contextMenu from '../utility/contextMenu';
|
||||
import createReducer from '../utility/createReducer';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import resizeObserver from '../utility/resizeObserver';
|
||||
|
||||
export let config;
|
||||
@ -46,6 +63,7 @@
|
||||
export let isLoading;
|
||||
export let former;
|
||||
export let formDisplay;
|
||||
export let onSave;
|
||||
|
||||
let wrapperHeight = 1;
|
||||
let rowHeight = 1;
|
||||
@ -73,6 +91,10 @@
|
||||
return tabid;
|
||||
}
|
||||
|
||||
export function getFormer() {
|
||||
return former;
|
||||
}
|
||||
|
||||
export function switchToTable() {
|
||||
setConfig(cfg => ({
|
||||
...cfg,
|
||||
@ -81,6 +103,15 @@
|
||||
}));
|
||||
}
|
||||
|
||||
export function save() {
|
||||
if ($inplaceEditorState.cell) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'shouldSave' });
|
||||
return;
|
||||
}
|
||||
if (onSave) onSave();
|
||||
}
|
||||
|
||||
const handleTableMouseDown = event => {
|
||||
if (event.target.closest('.buttonLike')) return;
|
||||
if (event.target.closest('.resizeHandleControl')) return;
|
||||
@ -93,12 +124,12 @@
|
||||
event.preventDefault();
|
||||
const cell = cellFromEvent(event);
|
||||
|
||||
if (isDataCell(cell) && !_.isEqual(cell, inplaceEditorState.cell) && _.isEqual(cell, currentCell)) {
|
||||
if (isDataCell(cell) && !_.isEqual(cell, $inplaceEditorState.cell) && _.isEqual(cell, currentCell)) {
|
||||
// @ts-ignore
|
||||
if (rowData) {
|
||||
dispatchInsplaceEditor({ type: 'show', cell, selectAll: true });
|
||||
}
|
||||
} else if (!_.isEqual(cell, inplaceEditorState.cell)) {
|
||||
} else if (!_.isEqual(cell, $inplaceEditorState.cell)) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'close' });
|
||||
}
|
||||
@ -161,83 +192,155 @@
|
||||
return [{ command: 'dataForm.switchToTable' }];
|
||||
}
|
||||
|
||||
$: console.log('rowHeight', rowHeight);
|
||||
function handleKeyDown(event) {
|
||||
if ($inplaceEditorState.cell) return;
|
||||
|
||||
if (
|
||||
!event.ctrlKey &&
|
||||
!event.altKey &&
|
||||
((event.keyCode >= keycodes.a && event.keyCode <= keycodes.z) ||
|
||||
(event.keyCode >= keycodes.n0 && event.keyCode <= keycodes.n9) ||
|
||||
event.keyCode == keycodes.dash)
|
||||
) {
|
||||
// @ts-ignore
|
||||
event.preventDefault();
|
||||
dispatchInsplaceEditor({ type: 'show', text: event.key, cell: currentCell });
|
||||
// console.log('event', event.nativeEvent);
|
||||
}
|
||||
|
||||
if (event.keyCode == keycodes.f2) {
|
||||
// @ts-ignore
|
||||
dispatchInsplaceEditor({ type: 'show', cell: currentCell, selectAll: true });
|
||||
}
|
||||
|
||||
handleCursorMove(event);
|
||||
}
|
||||
|
||||
const scrollIntoView = cell => {
|
||||
const element = domCells[`${cell[0]},${cell[1]}`];
|
||||
if (element) element.scrollIntoView();
|
||||
};
|
||||
|
||||
const moveCurrentCell = (row, col) => {
|
||||
if (row < 0) row = 0;
|
||||
if (col < 0) col = 0;
|
||||
if (col >= columnChunks.length * 2) col = columnChunks.length * 2 - 1;
|
||||
const chunk = columnChunks[Math.floor(col / 2)];
|
||||
if (chunk && row >= chunk.length) row = chunk.length - 1;
|
||||
currentCell = [row, col];
|
||||
scrollIntoView(currentCell);
|
||||
};
|
||||
|
||||
const handleCursorMove = event => {
|
||||
if (event.ctrlKey) {
|
||||
switch (event.keyCode) {
|
||||
case keycodes.leftArrow:
|
||||
return moveCurrentCell(currentCell[0], 0);
|
||||
case keycodes.rightArrow:
|
||||
return moveCurrentCell(currentCell[0], columnChunks.length * 2 - 1);
|
||||
}
|
||||
}
|
||||
switch (event.keyCode) {
|
||||
case keycodes.leftArrow:
|
||||
return moveCurrentCell(currentCell[0], currentCell[1] - 1);
|
||||
case keycodes.rightArrow:
|
||||
return moveCurrentCell(currentCell[0], currentCell[1] + 1);
|
||||
case keycodes.upArrow:
|
||||
return moveCurrentCell(currentCell[0] - 1, currentCell[1]);
|
||||
case keycodes.downArrow:
|
||||
return moveCurrentCell(currentCell[0] + 1, currentCell[1]);
|
||||
case keycodes.pageUp:
|
||||
return moveCurrentCell(0, currentCell[1]);
|
||||
case keycodes.pageDown:
|
||||
return moveCurrentCell(rowCount - 1, currentCell[1]);
|
||||
case keycodes.home:
|
||||
return moveCurrentCell(0, 0);
|
||||
case keycodes.end:
|
||||
return moveCurrentCell(rowCount - 1, columnChunks.length * 2 - 1);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="outer">
|
||||
<div class="wrapper" use:contextMenu={createMenu} bind:clientHeight={wrapperHeight}>
|
||||
{#each columnChunks as chunk, chunkIndex}
|
||||
<table on:mousedown={handleTableMouseDown}>
|
||||
{#each chunk as col, rowIndex}
|
||||
<tr>
|
||||
<td
|
||||
class="header-cell"
|
||||
data-row={rowIndex}
|
||||
data-col={chunkIndex * 2}
|
||||
style={`height: ${rowHeight}px`}
|
||||
class:isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2}
|
||||
bind:this={domCells[`${rowIndex},${chunkIndex * 2}`]}
|
||||
use:resizeObserver={chunkIndex == 0 && rowIndex == 0}
|
||||
on:resize={e => {
|
||||
// @ts-ignore
|
||||
if (rowHeight == 1) rowHeight = e.detail.height;
|
||||
}}
|
||||
>
|
||||
<div class="header-cell-inner">
|
||||
{#if col.foreignKey}
|
||||
<FontIcon
|
||||
icon={plusExpandIcon(formDisplay.isExpandedColumn(col.uniqueName))}
|
||||
on:click={e => {
|
||||
e.stopPropagation();
|
||||
formDisplay.toggleExpandedColumn(col.uniqueName);
|
||||
{#if isLoading}
|
||||
<LoadingInfo wrapper message="Loading data" />
|
||||
{:else}
|
||||
<div class="outer">
|
||||
<div class="wrapper" use:contextMenu={createMenu} bind:clientHeight={wrapperHeight}>
|
||||
{#each columnChunks as chunk, chunkIndex}
|
||||
<table on:mousedown={handleTableMouseDown}>
|
||||
{#each chunk as col, rowIndex}
|
||||
<tr>
|
||||
<td
|
||||
class="header-cell"
|
||||
data-row={rowIndex}
|
||||
data-col={chunkIndex * 2}
|
||||
style={`height: ${rowHeight}px`}
|
||||
class:isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2}
|
||||
bind:this={domCells[`${rowIndex},${chunkIndex * 2}`]}
|
||||
use:resizeObserver={chunkIndex == 0 && rowIndex == 0}
|
||||
on:resize={e => {
|
||||
// @ts-ignore
|
||||
if (rowHeight == 1) rowHeight = e.detail.height;
|
||||
}}
|
||||
>
|
||||
<div class="header-cell-inner">
|
||||
{#if col.foreignKey}
|
||||
<FontIcon
|
||||
icon={plusExpandIcon(formDisplay.isExpandedColumn(col.uniqueName))}
|
||||
on:click={e => {
|
||||
e.stopPropagation();
|
||||
formDisplay.toggleExpandedColumn(col.uniqueName);
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<FontIcon icon="icon invisible-box" />
|
||||
{/if}
|
||||
<span style={`margin-left: ${(col.uniquePath.length - 1) * 20}px`} />
|
||||
<ColumnLabel {...col} headerText={col.columnName} />
|
||||
</div>
|
||||
</td>
|
||||
<DataGridCell
|
||||
{rowIndex}
|
||||
{col}
|
||||
{rowData}
|
||||
colIndex={chunkIndex * 2 + 1}
|
||||
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
||||
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)}
|
||||
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]}
|
||||
hideContent={$inplaceEditorState.cell &&
|
||||
rowIndex == $inplaceEditorState.cell[0] &&
|
||||
chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
|
||||
>
|
||||
{#if $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
|
||||
<InplaceEditor
|
||||
width={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
|
||||
inplaceEditorState={$inplaceEditorState}
|
||||
{dispatchInsplaceEditor}
|
||||
cellValue={rowData[col.uniqueName]}
|
||||
onSetValue={value => {
|
||||
former.setCellValue(col.uniqueName, value);
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<FontIcon icon="icon invisible-box" />
|
||||
{/if}
|
||||
<span style={`margin-left: ${(col.uniquePath.length - 1) * 20}px`} />
|
||||
<ColumnLabel {...col} headerText={col.columnName} />
|
||||
</div>
|
||||
</td>
|
||||
<DataGridCell
|
||||
{rowIndex}
|
||||
{col}
|
||||
{rowData}
|
||||
colIndex={chunkIndex * 2 + 1}
|
||||
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
||||
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)}
|
||||
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]}
|
||||
hideContent={$inplaceEditorState.cell &&
|
||||
rowIndex == $inplaceEditorState.cell[0] &&
|
||||
chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
|
||||
>
|
||||
{#if $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]}
|
||||
<InplaceEditor
|
||||
width={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
|
||||
inplaceEditorState={$inplaceEditorState}
|
||||
{dispatchInsplaceEditor}
|
||||
cellValue={rowData[col.uniqueName]}
|
||||
onSetValue={value => {
|
||||
former.setCellValue(col.uniqueName, value);
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</DataGridCell>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
{/each}
|
||||
<input
|
||||
type="text"
|
||||
class="focus-field"
|
||||
bind:this={domFocusField}
|
||||
on:focus={() => {
|
||||
lastFocusedFormView = instance;
|
||||
invalidateCommands();
|
||||
}}
|
||||
/>
|
||||
</DataGridCell>
|
||||
</tr>
|
||||
{/each}
|
||||
</table>
|
||||
{/each}
|
||||
<input
|
||||
type="text"
|
||||
class="focus-field"
|
||||
bind:this={domFocusField}
|
||||
on:focus={() => {
|
||||
lastFocusedFormView = instance;
|
||||
clearLastFocusedDataGrid();
|
||||
invalidateCommands();
|
||||
}}
|
||||
on:keydown={handleKeyDown}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
table {
|
||||
|
@ -20,6 +20,14 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { changeSetToSql, createChangeSet } from 'dbgate-datalib';
|
||||
import { scriptToSql } from 'dbgate-sqltree';
|
||||
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
||||
|
||||
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
||||
|
||||
import { showModal } from '../modals/modalTools';
|
||||
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
import ChangeSetFormer from './ChangeSetFormer';
|
||||
import FormView from './FormView.svelte';
|
||||
@ -28,6 +36,8 @@
|
||||
export let changeSetState;
|
||||
export let dispatchChangeSet;
|
||||
export let masterLoadedTime;
|
||||
export let conid;
|
||||
export let database;
|
||||
|
||||
let isLoadingData = false;
|
||||
let isLoadedData = false;
|
||||
@ -117,6 +127,35 @@
|
||||
}
|
||||
|
||||
$: former = new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay);
|
||||
|
||||
async function handleConfirmSql(sql) {
|
||||
const resp = await axiosInstance.request({
|
||||
url: 'database-connections/query-data',
|
||||
method: 'post',
|
||||
params: {
|
||||
conid,
|
||||
database,
|
||||
},
|
||||
data: { sql },
|
||||
});
|
||||
const { errorMessage } = resp.data || {};
|
||||
if (errorMessage) {
|
||||
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
|
||||
} else {
|
||||
dispatchChangeSet({ type: 'reset', value: createChangeSet() });
|
||||
formDisplay.reload();
|
||||
}
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const script = changeSetToSql(changeSetState && changeSetState.value, formDisplay.dbinfo);
|
||||
const sql = scriptToSql(formDisplay.driver, script);
|
||||
showModal(ConfirmSqlModal, {
|
||||
sql,
|
||||
onConfirm: () => handleConfirmSql(sql),
|
||||
engine: formDisplay.engine,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} />
|
||||
<FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} onSave={handleSave} />
|
||||
|
Loading…
Reference in New Issue
Block a user