form view

This commit is contained in:
Jan Prochazka
2021-03-21 17:55:25 +01:00
parent 965a967450
commit 34f2fb2a0a
13 changed files with 329 additions and 10 deletions

View File

@@ -100,6 +100,50 @@
onClick: () => getCurrentDataForm().addToFilter(),
});
registerCommand({
id: 'dataForm.goToFirst',
category: 'Data form',
name: 'First',
keyText: 'Ctrl+Home',
toolbar: true,
icon: 'icon arrow-begin',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().navigate('begin'),
});
registerCommand({
id: 'dataForm.goToPrevious',
category: 'Data form',
name: 'Previous',
keyText: 'Ctrl+ArrowUp',
toolbar: true,
icon: 'icon arrow-left',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().navigate('previous'),
});
registerCommand({
id: 'dataForm.goToNext',
category: 'Data form',
name: 'Next',
keyText: 'Ctrl+ArrowDown',
toolbar: true,
icon: 'icon arrow-right',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().navigate('next'),
});
registerCommand({
id: 'dataForm.goToLast',
category: 'Data form',
name: 'Last',
keyText: 'Ctrl+End',
toolbar: true,
icon: 'icon arrow-end',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().navigate('end'),
});
function isDataCell(cell) {
return cell[1] % 2 == 1;
}
@@ -130,6 +174,7 @@
import createReducer from '../utility/createReducer';
import keycodes from '../utility/keycodes';
import resizeObserver from '../utility/resizeObserver';
import openReferenceForm from './openReferenceForm';
export let conid;
export let database;
@@ -142,6 +187,7 @@
export let former;
export let formDisplay;
export let onSave;
export let onNavigate;
let wrapperHeight = 1;
let rowHeight = 1;
@@ -161,10 +207,18 @@
$: rowData = former?.rowData;
$: rowStatus = former?.rowStatus;
$: rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
$: rowCount = Math.floor((wrapperHeight - 22) / (rowHeight + 2));
$: columnChunks = _.chunk(formDisplay.columns, rowCount) as any[][];
$: rowCountInfo = getRowCountInfo(rowCountBefore, allRowCount);
function getRowCountInfo(rowCountBefore, allRowCount) {
if (rowData == null) return 'No data';
if (allRowCount == null || rowCountBefore == null) return 'Loading row count...';
return `Row: ${(rowCountBefore + 1).toLocaleString()} / ${allRowCount.toLocaleString()}`;
}
export function getTabId() {
return tabid;
}
@@ -173,6 +227,10 @@
return former;
}
export function navigate(command) {
if (onNavigate) onNavigate(command);
}
export function switchToTable() {
setConfig(cfg => ({
...cfg,
@@ -293,7 +351,24 @@
return {};
}, {});
function createMenu() {
return [{ command: 'dataForm.switchToTable' }];
return [
{ command: 'dataForm.switchToTable' },
{ divider: true },
{ command: 'dataForm.filterSelected' },
{ command: 'dataForm.addToFilter' },
{ divider: true },
{ command: 'dataForm.save' },
{ command: 'dataForm.revertRowChanges' },
{ command: 'dataForm.setNull' },
{ divider: true },
{ command: 'dataForm.undo' },
{ command: 'dataForm.redo' },
{ divider: true },
{ command: 'dataForm.goToFirst' },
{ command: 'dataForm.goToPrevious' },
{ command: 'dataForm.goToNext' },
{ command: 'dataForm.goToLast' },
];
}
function handleKeyDown(event) {
@@ -363,6 +438,10 @@
return moveCurrentCell(rowCount - 1, columnChunks.length * 2 - 1);
}
};
function handleSetFormView(rowData, column) {
openReferenceForm(rowData, column, conid, database);
}
</script>
{#if isLoading}
@@ -400,7 +479,11 @@
<FontIcon icon="icon invisible-box" />
{/if}
<span style={`margin-left: ${(col.uniquePath.length - 1) * 20}px`} />
<ColumnLabel {...col} headerText={col.columnName} />
<ColumnLabel
{...col}
headerText={col.columnName}
extInfo={col.foreignKey ? ` -> ${col.foreignKey.refTableName}` : null}
/>
</div>
</td>
<DataGridCell
@@ -411,9 +494,11 @@
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]}
onSetFormView={handleSetFormView}
hideContent={!rowData ||
($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
@@ -443,6 +528,11 @@
on:keydown={handleKeyDown}
/>
</div>
{#if rowCountInfo}
<div class="row-count-label">
{rowCountInfo}
</div>
{/if}
</div>
{/if}
@@ -501,4 +591,11 @@
left: -1000px;
top: -1000px;
}
.row-count-label {
position: absolute;
background-color: var(--theme-bg-2);
right: 40px;
bottom: 20px;
}
</style>

View File

@@ -0,0 +1,34 @@
<script lang="ts">
import { getFilterType } from 'dbgate-filterparser';
import DataFilterControl from '../datagrid/DataFilterControl.svelte';
import ColumnLabel from '../elements/ColumnLabel.svelte';
import InlineButton from '../elements/InlineButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
export let column;
export let formDisplay;
export let filters;
</script>
{#if column}
<div class="m-1">
<div class="space-between">
<ColumnLabel {...column} />
<InlineButton
square
on:click={() => {
formDisplay.removeFilter(column.uniqueName);
}}
>
<FontIcon icon="icon delete" />
</InlineButton>
</div>
<DataFilterControl
filterType={getFilterType(column.dataType)}
filter={filters[column.uniqueName]}
setFilter={value => formDisplay.setFilter(column.uniqueName, value)}
/>
</div>
{/if}

View File

@@ -0,0 +1,32 @@
<script lang="ts">
import _ from 'lodash';
import ManagerInnerContainer from '../elements/ManagerInnerContainer.svelte';
import FormViewFilterColumn from './FormViewFilterColumn.svelte';
import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte';
export let managerSize;
export let formDisplay;
$: baseTable = formDisplay?.baseTable;
$: formFilterColumns = formDisplay?.config?.formFilterColumns;
$: filters = formDisplay?.config?.filters;
$: allFilterNames = _.union(_.keys(filters || {}), formFilterColumns || []);
</script>
{#if baseTable?.primaryKey}
<ManagerInnerContainer width={managerSize}>
{#each baseTable.primaryKey.columns as col}
<PrimaryKeyFilterEditor {baseTable} column={col} {formDisplay} />
{/each}
{#each allFilterNames as uniqueName}
<FormViewFilterColumn
column={formDisplay.columns.find(x => x.uniqueName == uniqueName)}
{formDisplay}
{filters}
/>
{/each}
</ManagerInnerContainer>
{/if}

View File

@@ -0,0 +1,51 @@
<script lang="ts">
import ColumnLabel from '../elements/ColumnLabel.svelte';
import InlineButton from '../elements/InlineButton.svelte';
import FontIcon from '../icons/FontIcon.svelte';
import keycodes from '../utility/keycodes';
export let column;
export let baseTable;
export let formDisplay;
let domEditor;
$: value = formDisplay.getKeyValue(column.columnName);
const applyFilter = () => {
formDisplay.requestKeyValue(column.columnName, domEditor.value);
};
const cancelFilter = () => {
formDisplay.cancelRequestKey();
formDisplay.reload();
};
const handleKeyDown = ev => {
if (ev.keyCode == keycodes.enter) {
applyFilter();
}
if (ev.keyCode == keycodes.escape) {
cancelFilter();
}
};
$: if (domEditor) domEditor.value = value;
</script>
<div class="m-1">
<div class="space-between">
<div>
<FontIcon icon="img primary-key" />
<ColumnLabel {...baseTable.columns.find(x => x.columnName == column.columnName)} />
</div>
{#if formDisplay.config.formViewKeyRequested}
<InlineButton square on:click={cancelFilter}>
<FontIcon icon="icon delete" />
</InlineButton>
{/if}
</div>
<div class="flex">
<input bind:this={domEditor} type="text" on:blur={applyFilter} on:keydown={handleKeyDown} />
</div>
</div>

View File

@@ -0,0 +1,25 @@
<script lang="ts">
import FontIcon from '../icons/FontIcon.svelte';
</script>
<div on:click|stopPropagation>
<FontIcon icon="icon form" />
</div>
<style>
div {
position: absolute;
right: 0px;
top: 1px;
color: var(--theme-font-3);
background-color: var(--theme-bg-1);
border: 1px solid var(--theme-bg-1);
}
div:hover {
color: var(--theme-font-hover);
border: var(--theme-border);
top: 1px;
right: 0px;
}
</style>

View File

@@ -38,6 +38,7 @@
export let masterLoadedTime;
export let conid;
export let database;
export let onReferenceSourceChanged;
let isLoadingData = false;
let isLoadedData = false;
@@ -128,6 +129,8 @@
$: former = new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay);
$: if (onReferenceSourceChanged && rowData) onReferenceSourceChanged([rowData], loadedTime);
async function handleConfirmSql(sql) {
const resp = await axiosInstance.request({
url: 'database-connections/query-data',
@@ -158,4 +161,12 @@
}
</script>
<FormView {...$$props} {former} isLoading={isLoadingData} {allRowCount} {rowCountBefore} onSave={handleSave} />
<FormView
{...$$props}
{former}
isLoading={isLoadingData}
{allRowCount}
{rowCountBefore}
onSave={handleSave}
onNavigate={handleNavigate}
/>

View File

@@ -29,3 +29,32 @@ export default function openReferenceForm(rowData, column, conid, database) {
}
);
}
export function openPrimaryKeyForm(rowData, baseTable, conid, database) {
const formViewKey = _.fromPairs(
baseTable.primaryKey.columns.map(({ columnName }) => [columnName, rowData[columnName]])
);
openNewTab(
{
title: baseTable.pureName,
icon: 'img table',
tabComponent: 'TableDataTab',
props: {
schemaName: baseTable.schemaName,
pureName: baseTable.pureName,
conid,
database,
objectTypeField: 'tables',
},
},
{
grid: {
isFormView: true,
formViewKey,
},
},
{
forceNewTab: true,
}
);
}