formview save

This commit is contained in:
Jan Prochazka 2021-03-21 10:20:57 +01:00
parent 90c4b44fdb
commit ec90a8b952
3 changed files with 221 additions and 75 deletions

View File

@ -2,6 +2,9 @@
let lastFocusedDataGrid = null; let lastFocusedDataGrid = null;
const getCurrentDataGrid = () => const getCurrentDataGrid = () =>
lastFocusedDataGrid?.getTabId && lastFocusedDataGrid?.getTabId() == getActiveTabId() ? lastFocusedDataGrid : null; lastFocusedDataGrid?.getTabId && lastFocusedDataGrid?.getTabId() == getActiveTabId() ? lastFocusedDataGrid : null;
export function clearLastFocusedDataGrid() {
lastFocusedDataGrid = null;
}
registerCommand({ registerCommand({
id: 'dataGrid.refresh', id: 'dataGrid.refresh',
@ -205,6 +208,7 @@
import { copyTextToClipboard } from '../utility/clipboard'; import { copyTextToClipboard } from '../utility/clipboard';
import invalidateCommands from '../commands/invalidateCommands'; import invalidateCommands from '../commands/invalidateCommands';
import createRef from '../utility/createRef'; import createRef from '../utility/createRef';
import { clearLastFocusedFormView } from '../formview/FormView.svelte';
export let onLoadNextData = undefined; export let onLoadNextData = undefined;
export let grider = undefined; export let grider = undefined;
@ -666,7 +670,6 @@
} }
function handleGridKeyDown(event) { function handleGridKeyDown(event) {
if ($inplaceEditorState.cell) return; if ($inplaceEditorState.cell) return;
if ( if (
@ -903,6 +906,7 @@
on:keydown={handleGridKeyDown} on:keydown={handleGridKeyDown}
on:focus={() => { on:focus={() => {
lastFocusedDataGrid = instance; lastFocusedDataGrid = instance;
clearLastFocusedFormView();
invalidateCommands(); invalidateCommands();
}} }}
on:paste={handlePaste} on:paste={handlePaste}

View File

@ -2,6 +2,9 @@
let lastFocusedFormView = null; let lastFocusedFormView = null;
const getCurrentDataForm = () => const getCurrentDataForm = () =>
lastFocusedFormView?.getTabId && lastFocusedFormView?.getTabId() == getActiveTabId() ? lastFocusedFormView : null; lastFocusedFormView?.getTabId && lastFocusedFormView?.getTabId() == getActiveTabId() ? lastFocusedFormView : null;
export function clearLastFocusedFormView() {
lastFocusedFormView = null;
}
registerCommand({ registerCommand({
id: 'dataForm.switchToTable', id: 'dataForm.switchToTable',
@ -12,6 +15,17 @@
onClick: () => getCurrentDataForm().switchToTable(), 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) { function isDataCell(cell) {
return cell[1] % 2 == 1; return cell[1] % 2 == 1;
} }
@ -27,15 +41,18 @@
import registerCommand from '../commands/registerCommand'; import registerCommand from '../commands/registerCommand';
import DataGridCell from '../datagrid/DataGridCell.svelte'; import DataGridCell from '../datagrid/DataGridCell.svelte';
import { clearLastFocusedDataGrid } from '../datagrid/DataGridCore.svelte';
import InplaceEditor from '../datagrid/InplaceEditor.svelte'; import InplaceEditor from '../datagrid/InplaceEditor.svelte';
import { cellFromEvent } from '../datagrid/selection'; import { cellFromEvent } from '../datagrid/selection';
import ColumnLabel from '../elements/ColumnLabel.svelte'; import ColumnLabel from '../elements/ColumnLabel.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import { plusExpandIcon } from '../icons/expandIcons'; import { plusExpandIcon } from '../icons/expandIcons';
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import { getActiveTabId } from '../stores'; import { getActiveTabId } from '../stores';
import contextMenu from '../utility/contextMenu'; import contextMenu from '../utility/contextMenu';
import createReducer from '../utility/createReducer'; import createReducer from '../utility/createReducer';
import keycodes from '../utility/keycodes';
import resizeObserver from '../utility/resizeObserver'; import resizeObserver from '../utility/resizeObserver';
export let config; export let config;
@ -46,6 +63,7 @@
export let isLoading; export let isLoading;
export let former; export let former;
export let formDisplay; export let formDisplay;
export let onSave;
let wrapperHeight = 1; let wrapperHeight = 1;
let rowHeight = 1; let rowHeight = 1;
@ -73,6 +91,10 @@
return tabid; return tabid;
} }
export function getFormer() {
return former;
}
export function switchToTable() { export function switchToTable() {
setConfig(cfg => ({ setConfig(cfg => ({
...cfg, ...cfg,
@ -81,6 +103,15 @@
})); }));
} }
export function save() {
if ($inplaceEditorState.cell) {
// @ts-ignore
dispatchInsplaceEditor({ type: 'shouldSave' });
return;
}
if (onSave) onSave();
}
const handleTableMouseDown = event => { const handleTableMouseDown = event => {
if (event.target.closest('.buttonLike')) return; if (event.target.closest('.buttonLike')) return;
if (event.target.closest('.resizeHandleControl')) return; if (event.target.closest('.resizeHandleControl')) return;
@ -93,12 +124,12 @@
event.preventDefault(); event.preventDefault();
const cell = cellFromEvent(event); 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 // @ts-ignore
if (rowData) { if (rowData) {
dispatchInsplaceEditor({ type: 'show', cell, selectAll: true }); dispatchInsplaceEditor({ type: 'show', cell, selectAll: true });
} }
} else if (!_.isEqual(cell, inplaceEditorState.cell)) { } else if (!_.isEqual(cell, $inplaceEditorState.cell)) {
// @ts-ignore // @ts-ignore
dispatchInsplaceEditor({ type: 'close' }); dispatchInsplaceEditor({ type: 'close' });
} }
@ -161,83 +192,155 @@
return [{ command: 'dataForm.switchToTable' }]; 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> </script>
<div class="outer"> {#if isLoading}
<div class="wrapper" use:contextMenu={createMenu} bind:clientHeight={wrapperHeight}> <LoadingInfo wrapper message="Loading data" />
{#each columnChunks as chunk, chunkIndex} {:else}
<table on:mousedown={handleTableMouseDown}> <div class="outer">
{#each chunk as col, rowIndex} <div class="wrapper" use:contextMenu={createMenu} bind:clientHeight={wrapperHeight}>
<tr> {#each columnChunks as chunk, chunkIndex}
<td <table on:mousedown={handleTableMouseDown}>
class="header-cell" {#each chunk as col, rowIndex}
data-row={rowIndex} <tr>
data-col={chunkIndex * 2} <td
style={`height: ${rowHeight}px`} class="header-cell"
class:isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2} data-row={rowIndex}
bind:this={domCells[`${rowIndex},${chunkIndex * 2}`]} data-col={chunkIndex * 2}
use:resizeObserver={chunkIndex == 0 && rowIndex == 0} style={`height: ${rowHeight}px`}
on:resize={e => { class:isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2}
// @ts-ignore bind:this={domCells[`${rowIndex},${chunkIndex * 2}`]}
if (rowHeight == 1) rowHeight = e.detail.height; use:resizeObserver={chunkIndex == 0 && rowIndex == 0}
}} on:resize={e => {
> // @ts-ignore
<div class="header-cell-inner"> if (rowHeight == 1) rowHeight = e.detail.height;
{#if col.foreignKey} }}
<FontIcon >
icon={plusExpandIcon(formDisplay.isExpandedColumn(col.uniqueName))} <div class="header-cell-inner">
on:click={e => { {#if col.foreignKey}
e.stopPropagation(); <FontIcon
formDisplay.toggleExpandedColumn(col.uniqueName); 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} {/if}
<span style={`margin-left: ${(col.uniquePath.length - 1) * 20}px`} /> </DataGridCell>
<ColumnLabel {...col} headerText={col.columnName} /> </tr>
</div> {/each}
</td> </table>
<DataGridCell {/each}
{rowIndex} <input
{col} type="text"
{rowData} class="focus-field"
colIndex={chunkIndex * 2 + 1} bind:this={domFocusField}
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1} on:focus={() => {
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)} lastFocusedFormView = instance;
bind:domCell={domCells[`${rowIndex},${chunkIndex * 2 + 1}`]} clearLastFocusedDataGrid();
hideContent={$inplaceEditorState.cell && invalidateCommands();
rowIndex == $inplaceEditorState.cell[0] && }}
chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]} on:keydown={handleKeyDown}
> />
{#if $inplaceEditorState.cell && rowIndex == $inplaceEditorState.cell[0] && chunkIndex * 2 + 1 == $inplaceEditorState.cell[1]} </div>
<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();
}}
/>
</div> </div>
</div> {/if}
<style> <style>
table { table {

View File

@ -20,6 +20,14 @@
</script> </script>
<script lang="ts"> <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 axiosInstance from '../utility/axiosInstance';
import ChangeSetFormer from './ChangeSetFormer'; import ChangeSetFormer from './ChangeSetFormer';
import FormView from './FormView.svelte'; import FormView from './FormView.svelte';
@ -28,6 +36,8 @@
export let changeSetState; export let changeSetState;
export let dispatchChangeSet; export let dispatchChangeSet;
export let masterLoadedTime; export let masterLoadedTime;
export let conid;
export let database;
let isLoadingData = false; let isLoadingData = false;
let isLoadedData = false; let isLoadedData = false;
@ -117,6 +127,35 @@
} }
$: former = new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay); $: 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> </script>
<FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} /> <FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} onSave={handleSave} />