mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 03:53:57 +00:00
editing in form view
This commit is contained in:
@@ -11,6 +11,7 @@ import { ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay'
|
|||||||
export class FormViewDisplay {
|
export class FormViewDisplay {
|
||||||
isLoadedCorrectly = true;
|
isLoadedCorrectly = true;
|
||||||
columns: DisplayColumn[];
|
columns: DisplayColumn[];
|
||||||
|
public baseTable: TableInfo;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public config: GridConfig,
|
public config: GridConfig,
|
||||||
@@ -20,4 +21,5 @@ export class FormViewDisplay {
|
|||||||
public driver?: EngineDriver,
|
public driver?: EngineDriver,
|
||||||
public dbinfo: DatabaseInfo = null
|
public dbinfo: DatabaseInfo = null
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import {
|
|||||||
import { filterName } from './filterName';
|
import { filterName } from './filterName';
|
||||||
import { TableGridDisplay } from './TableGridDisplay';
|
import { TableGridDisplay } from './TableGridDisplay';
|
||||||
import stableStringify from 'json-stable-stringify';
|
import stableStringify from 'json-stable-stringify';
|
||||||
|
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||||
|
|
||||||
export class TableFormViewDisplay extends FormViewDisplay {
|
export class TableFormViewDisplay extends FormViewDisplay {
|
||||||
public table: TableInfo;
|
|
||||||
// use utility functions from GridDisplay and publish result in FromViewDisplat interface
|
// use utility functions from GridDisplay and publish result in FromViewDisplat interface
|
||||||
private gridDisplay: TableGridDisplay;
|
private gridDisplay: TableGridDisplay;
|
||||||
|
|
||||||
@@ -35,13 +35,17 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
|||||||
|
|
||||||
this.isLoadedCorrectly = this.gridDisplay.isLoadedCorrectly;
|
this.isLoadedCorrectly = this.gridDisplay.isLoadedCorrectly;
|
||||||
this.columns = this.gridDisplay.columns;
|
this.columns = this.gridDisplay.columns;
|
||||||
|
this.baseTable = this.gridDisplay.baseTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrimaryKeyEqualCondition(): Condition {
|
getPrimaryKeyEqualCondition(row = null): Condition {
|
||||||
if (!this.config.formViewKey) return null;
|
if (!row) row = this.config.formViewKey;
|
||||||
|
if (!row) return null;
|
||||||
|
const { primaryKey } = this.gridDisplay.baseTable;
|
||||||
|
if (primaryKey) return null;
|
||||||
return {
|
return {
|
||||||
conditionType: 'and',
|
conditionType: 'and',
|
||||||
conditions: _.keys(this.config.formViewKey).map((columnName) => ({
|
conditions: primaryKey.columns.map(({ columnName }) => ({
|
||||||
conditionType: 'binary',
|
conditionType: 'binary',
|
||||||
operator: '=',
|
operator: '=',
|
||||||
left: {
|
left: {
|
||||||
@@ -186,4 +190,25 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
|||||||
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getChangeSetRow(row): ChangeSetRowDefinition {
|
||||||
|
if (!this.baseTable) return null;
|
||||||
|
return {
|
||||||
|
pureName: this.baseTable.pureName,
|
||||||
|
schemaName: this.baseTable.schemaName,
|
||||||
|
condition: this.extractKey(row),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getChangeSetField(row, uniqueName): ChangeSetFieldDefinition {
|
||||||
|
const col = this.columns.find((x) => x.uniqueName == uniqueName);
|
||||||
|
if (!col) return null;
|
||||||
|
if (!this.baseTable) return null;
|
||||||
|
if (this.baseTable.pureName != col.pureName || this.baseTable.schemaName != col.schemaName) return null;
|
||||||
|
return {
|
||||||
|
...this.getChangeSetRow(row),
|
||||||
|
uniqueName: uniqueName,
|
||||||
|
columnName: col.columnName,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default function InplaceEditor({
|
|||||||
onSetValue,
|
onSetValue,
|
||||||
}) {
|
}) {
|
||||||
const editorRef = React.useRef();
|
const editorRef = React.useRef();
|
||||||
|
const widthRef = React.useRef(widthPx);
|
||||||
const isChangedRef = React.useRef(!!inplaceEditorState.text);
|
const isChangedRef = React.useRef(!!inplaceEditorState.text);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
@@ -88,9 +89,9 @@ export default function InplaceEditor({
|
|||||||
onChange={() => (isChangedRef.current = true)}
|
onChange={() => (isChangedRef.current = true)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
style={{
|
style={{
|
||||||
width: widthPx,
|
width: widthRef.current,
|
||||||
minWidth: widthPx,
|
minWidth: widthRef.current,
|
||||||
maxWidth: widthPx,
|
maxWidth: widthRef.current,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
93
packages/web/src/formview/ChangeSetFormer.ts
Normal file
93
packages/web/src/formview/ChangeSetFormer.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import {
|
||||||
|
ChangeSet,
|
||||||
|
changeSetContainsChanges,
|
||||||
|
changeSetInsertNewRow,
|
||||||
|
createChangeSet,
|
||||||
|
deleteChangeSetRows,
|
||||||
|
findExistingChangeSetItem,
|
||||||
|
getChangeSetInsertedRows,
|
||||||
|
TableFormViewDisplay,
|
||||||
|
revertChangeSetRowChanges,
|
||||||
|
setChangeSetValue,
|
||||||
|
ChangeSetRowDefinition,
|
||||||
|
} from 'dbgate-datalib';
|
||||||
|
import Former from './Former';
|
||||||
|
|
||||||
|
export default class ChangeSetFormer extends Former {
|
||||||
|
public changeSet: ChangeSet;
|
||||||
|
public setChangeSet: Function;
|
||||||
|
private batchChangeSet: ChangeSet;
|
||||||
|
public rowDefinition: ChangeSetRowDefinition;
|
||||||
|
public rowStatus;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public sourceRow: any,
|
||||||
|
public changeSetState,
|
||||||
|
public dispatchChangeSet,
|
||||||
|
public display: TableFormViewDisplay
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.changeSet = changeSetState && changeSetState.value;
|
||||||
|
this.setChangeSet = (value) => dispatchChangeSet({ type: 'set', value });
|
||||||
|
this.batchChangeSet = null;
|
||||||
|
this.rowDefinition = display.getChangeSetRow(sourceRow);
|
||||||
|
const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(this.changeSet, this.rowDefinition);
|
||||||
|
this.rowData = matchedChangeSetItem ? { ...sourceRow, ...matchedChangeSetItem.fields } : sourceRow;
|
||||||
|
let status = 'regular';
|
||||||
|
if (matchedChangeSetItem && matchedField == 'updates') status = 'updated';
|
||||||
|
if (matchedField == 'deletes') status = 'deleted';
|
||||||
|
this.rowStatus = {
|
||||||
|
status,
|
||||||
|
modifiedFields:
|
||||||
|
matchedChangeSetItem && matchedChangeSetItem.fields ? new Set(Object.keys(matchedChangeSetItem.fields)) : null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
applyModification(changeSetReducer) {
|
||||||
|
if (this.batchChangeSet) {
|
||||||
|
this.batchChangeSet = changeSetReducer(this.batchChangeSet);
|
||||||
|
} else {
|
||||||
|
this.setChangeSet(changeSetReducer(this.changeSet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCellValue( uniqueName: string, value: any) {
|
||||||
|
const row = this.sourceRow;
|
||||||
|
const definition = this.display.getChangeSetField(row, uniqueName);
|
||||||
|
this.applyModification((chs) => setChangeSetValue(chs, definition, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRow(index: number) {
|
||||||
|
this.applyModification((chs) => deleteChangeSetRows(chs, this.rowDefinition));
|
||||||
|
}
|
||||||
|
|
||||||
|
beginUpdate() {
|
||||||
|
this.batchChangeSet = this.changeSet;
|
||||||
|
}
|
||||||
|
endUpdate() {
|
||||||
|
this.setChangeSet(this.batchChangeSet);
|
||||||
|
this.batchChangeSet = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
revertRowChanges() {
|
||||||
|
this.applyModification((chs) => revertChangeSetRowChanges(chs, this.rowDefinition));
|
||||||
|
}
|
||||||
|
revertAllChanges() {
|
||||||
|
this.applyModification((chs) => createChangeSet());
|
||||||
|
}
|
||||||
|
undo() {
|
||||||
|
this.dispatchChangeSet({ type: 'undo' });
|
||||||
|
}
|
||||||
|
redo() {
|
||||||
|
this.dispatchChangeSet({ type: 'redo' });
|
||||||
|
}
|
||||||
|
get canUndo() {
|
||||||
|
return this.changeSetState.canUndo;
|
||||||
|
}
|
||||||
|
get canRedo() {
|
||||||
|
return this.changeSetState.canRedo;
|
||||||
|
}
|
||||||
|
get containsChanges() {
|
||||||
|
return changeSetContainsChanges(this.changeSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
@@ -48,7 +50,6 @@ const TableHeaderCell = styled.td`
|
|||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
${(props) =>
|
${(props) =>
|
||||||
// @ts-ignore
|
|
||||||
props.isSelected &&
|
props.isSelected &&
|
||||||
`
|
`
|
||||||
background: initial;
|
background: initial;
|
||||||
@@ -66,12 +67,17 @@ const TableBodyCell = styled.td`
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
${(props) =>
|
${(props) =>
|
||||||
// @ts-ignore
|
|
||||||
props.isSelected &&
|
props.isSelected &&
|
||||||
`
|
`
|
||||||
background: initial;
|
background: initial;
|
||||||
background-color: ${props.theme.gridbody_selection[4]};
|
background-color: ${props.theme.gridbody_selection[4]};
|
||||||
color: ${props.theme.gridbody_invfont1};`}
|
color: ${props.theme.gridbody_invfont1};`}
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
!props.isSelected &&
|
||||||
|
props.isModifiedCell &&
|
||||||
|
`
|
||||||
|
background-color: ${props.theme.gridbody_background_orange[1]};`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FocusField = styled.input`
|
const FocusField = styled.input`
|
||||||
@@ -86,7 +92,7 @@ function isDataCell(cell) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function FormView(props) {
|
export default function FormView(props) {
|
||||||
const { rowData, toolbarPortalRef, tabVisible, config, setConfig, onNavigate } = props;
|
const { toolbarPortalRef, tabVisible, config, setConfig, onNavigate, former } = props;
|
||||||
/** @type {import('dbgate-datalib').FormViewDisplay} */
|
/** @type {import('dbgate-datalib').FormViewDisplay} */
|
||||||
const formDisplay = props.formDisplay;
|
const formDisplay = props.formDisplay;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@@ -100,6 +106,8 @@ export default function FormView(props) {
|
|||||||
const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
|
const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
|
||||||
const columnChunks = _.chunk(formDisplay.columns, rowCount);
|
const columnChunks = _.chunk(formDisplay.columns, rowCount);
|
||||||
|
|
||||||
|
const { rowData, rowStatus } = former;
|
||||||
|
|
||||||
const handleSwitchToTable = () => {
|
const handleSwitchToTable = () => {
|
||||||
setConfig((cfg) => ({
|
setConfig((cfg) => ({
|
||||||
...cfg,
|
...cfg,
|
||||||
@@ -318,6 +326,7 @@ export default function FormView(props) {
|
|||||||
data-col={chunkIndex * 2 + 1}
|
data-col={chunkIndex * 2 + 1}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
||||||
|
isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)}
|
||||||
ref={(element) => setCellRef(rowIndex, chunkIndex * 2 + 1, element)}
|
ref={(element) => setCellRef(rowIndex, chunkIndex * 2 + 1, element)}
|
||||||
>
|
>
|
||||||
{inplaceEditorState.cell &&
|
{inplaceEditorState.cell &&
|
||||||
@@ -328,7 +337,9 @@ export default function FormView(props) {
|
|||||||
inplaceEditorState={inplaceEditorState}
|
inplaceEditorState={inplaceEditorState}
|
||||||
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
||||||
cellValue={rowData[col.uniqueName]}
|
cellValue={rowData[col.uniqueName]}
|
||||||
onSetValue={(value) => {}}
|
onSetValue={(value) => {
|
||||||
|
former.setCellValue(col.uniqueName, value);
|
||||||
|
}}
|
||||||
// grider={grider}
|
// grider={grider}
|
||||||
// rowIndex={rowIndex}
|
// rowIndex={rowIndex}
|
||||||
// uniqueName={col.uniqueName}
|
// uniqueName={col.uniqueName}
|
||||||
|
|||||||
53
packages/web/src/formview/Former.ts
Normal file
53
packages/web/src/formview/Former.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// export interface GriderRowStatus {
|
||||||
|
// status: 'regular' | 'updated' | 'deleted' | 'inserted';
|
||||||
|
// modifiedFields?: Set<string>;
|
||||||
|
// insertedFields?: Set<string>;
|
||||||
|
// deletedFields?: Set<string>;
|
||||||
|
// }
|
||||||
|
|
||||||
|
export default abstract class Former {
|
||||||
|
public rowData: any;
|
||||||
|
|
||||||
|
// getRowStatus(index): GriderRowStatus {
|
||||||
|
// const res: GriderRowStatus = {
|
||||||
|
// status: 'regular',
|
||||||
|
// };
|
||||||
|
// return res;
|
||||||
|
// }
|
||||||
|
beginUpdate() {}
|
||||||
|
endUpdate() {}
|
||||||
|
setCellValue(uniqueName: string, value: any) {}
|
||||||
|
revertRowChanges() {}
|
||||||
|
revertAllChanges() {}
|
||||||
|
undo() {}
|
||||||
|
redo() {}
|
||||||
|
get editable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get canInsert() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get allowSave() {
|
||||||
|
return this.containsChanges;
|
||||||
|
}
|
||||||
|
get canUndo() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get canRedo() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get containsChanges() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get disableLoadNextPage() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
get errors() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
updateRow(changeObject) {
|
||||||
|
for (const key of Object.keys(changeObject)) {
|
||||||
|
this.setCellValue(key, changeObject[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
|||||||
import useExtensions from '../utility/useExtensions';
|
import useExtensions from '../utility/useExtensions';
|
||||||
import FormView from './FormView';
|
import FormView from './FormView';
|
||||||
import axios from '../utility/axios';
|
import axios from '../utility/axios';
|
||||||
|
import ChangeSetFormer from './ChangeSetFormer';
|
||||||
|
|
||||||
async function loadRow(props, sql) {
|
async function loadRow(props, sql) {
|
||||||
const { conid, database } = props;
|
const { conid, database } = props;
|
||||||
@@ -26,7 +27,7 @@ async function loadRow(props, sql) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function SqlFormView(props) {
|
export default function SqlFormView(props) {
|
||||||
const { formDisplay } = props;
|
const { formDisplay, changeSetState, dispatchChangeSet } = props;
|
||||||
const [rowData, setRowData] = React.useState(null);
|
const [rowData, setRowData] = React.useState(null);
|
||||||
|
|
||||||
const handleLoadCurrentRow = async () => {
|
const handleLoadCurrentRow = async () => {
|
||||||
@@ -46,7 +47,14 @@ export default function SqlFormView(props) {
|
|||||||
if (formDisplay && !formDisplay.isLoadedCurrentRow(rowData)) {
|
if (formDisplay && !formDisplay.isLoadedCurrentRow(rowData)) {
|
||||||
handleLoadCurrentRow();
|
handleLoadCurrentRow();
|
||||||
}
|
}
|
||||||
}, [formDisplay]);
|
}, [formDisplay, rowData]);
|
||||||
|
|
||||||
|
const former = React.useMemo(() => new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay), [
|
||||||
|
rowData,
|
||||||
|
changeSetState,
|
||||||
|
dispatchChangeSet,
|
||||||
|
formDisplay,
|
||||||
|
]);
|
||||||
|
|
||||||
// const { config, setConfig, cache, setCache, schemaName, pureName, conid, database } = props;
|
// const { config, setConfig, cache, setCache, schemaName, pureName, conid, database } = props;
|
||||||
// const { formViewKey } = config;
|
// const { formViewKey } = config;
|
||||||
@@ -76,5 +84,5 @@ export default function SqlFormView(props) {
|
|||||||
// setDisplay(newDisplay);
|
// setDisplay(newDisplay);
|
||||||
// }, [config, cache, conid, database, schemaName, pureName, dbinfo, extensions]);
|
// }, [config, cache, conid, database, schemaName, pureName, dbinfo, extensions]);
|
||||||
|
|
||||||
return <FormView {...props} rowData={rowData} onNavigate={handleNavigate} />;
|
return <FormView {...props} rowData={rowData} onNavigate={handleNavigate} former={former} />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user