mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 18:03:58 +00:00
editing in form view
This commit is contained in:
@@ -11,6 +11,7 @@ import { ChangeCacheFunc, ChangeConfigFunc, DisplayColumn } from './GridDisplay'
|
||||
export class FormViewDisplay {
|
||||
isLoadedCorrectly = true;
|
||||
columns: DisplayColumn[];
|
||||
public baseTable: TableInfo;
|
||||
|
||||
constructor(
|
||||
public config: GridConfig,
|
||||
@@ -20,4 +21,5 @@ export class FormViewDisplay {
|
||||
public driver?: EngineDriver,
|
||||
public dbinfo: DatabaseInfo = null
|
||||
) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
import { filterName } from './filterName';
|
||||
import { TableGridDisplay } from './TableGridDisplay';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||
|
||||
export class TableFormViewDisplay extends FormViewDisplay {
|
||||
public table: TableInfo;
|
||||
// use utility functions from GridDisplay and publish result in FromViewDisplat interface
|
||||
private gridDisplay: TableGridDisplay;
|
||||
|
||||
@@ -35,13 +35,17 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
||||
|
||||
this.isLoadedCorrectly = this.gridDisplay.isLoadedCorrectly;
|
||||
this.columns = this.gridDisplay.columns;
|
||||
this.baseTable = this.gridDisplay.baseTable;
|
||||
}
|
||||
|
||||
getPrimaryKeyEqualCondition(): Condition {
|
||||
if (!this.config.formViewKey) return null;
|
||||
getPrimaryKeyEqualCondition(row = null): Condition {
|
||||
if (!row) row = this.config.formViewKey;
|
||||
if (!row) return null;
|
||||
const { primaryKey } = this.gridDisplay.baseTable;
|
||||
if (primaryKey) return null;
|
||||
return {
|
||||
conditionType: 'and',
|
||||
conditions: _.keys(this.config.formViewKey).map((columnName) => ({
|
||||
conditions: primaryKey.columns.map(({ columnName }) => ({
|
||||
conditionType: 'binary',
|
||||
operator: '=',
|
||||
left: {
|
||||
@@ -186,4 +190,25 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
||||
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
||||
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,
|
||||
}) {
|
||||
const editorRef = React.useRef();
|
||||
const widthRef = React.useRef(widthPx);
|
||||
const isChangedRef = React.useRef(!!inplaceEditorState.text);
|
||||
React.useEffect(() => {
|
||||
const editor = editorRef.current;
|
||||
@@ -88,9 +89,9 @@ export default function InplaceEditor({
|
||||
onChange={() => (isChangedRef.current = true)}
|
||||
onKeyDown={handleKeyDown}
|
||||
style={{
|
||||
width: widthPx,
|
||||
minWidth: widthPx,
|
||||
maxWidth: widthPx,
|
||||
width: widthRef.current,
|
||||
minWidth: widthRef.current,
|
||||
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 React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
@@ -48,7 +50,6 @@ const TableHeaderCell = styled.td`
|
||||
position: relative;
|
||||
|
||||
${(props) =>
|
||||
// @ts-ignore
|
||||
props.isSelected &&
|
||||
`
|
||||
background: initial;
|
||||
@@ -66,12 +67,17 @@ const TableBodyCell = styled.td`
|
||||
overflow: hidden;
|
||||
|
||||
${(props) =>
|
||||
// @ts-ignore
|
||||
props.isSelected &&
|
||||
`
|
||||
background: initial;
|
||||
background-color: ${props.theme.gridbody_selection[4]};
|
||||
color: ${props.theme.gridbody_invfont1};`}
|
||||
|
||||
${(props) =>
|
||||
!props.isSelected &&
|
||||
props.isModifiedCell &&
|
||||
`
|
||||
background-color: ${props.theme.gridbody_background_orange[1]};`}
|
||||
`;
|
||||
|
||||
const FocusField = styled.input`
|
||||
@@ -86,7 +92,7 @@ function isDataCell(cell) {
|
||||
}
|
||||
|
||||
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} */
|
||||
const formDisplay = props.formDisplay;
|
||||
const theme = useTheme();
|
||||
@@ -100,6 +106,8 @@ export default function FormView(props) {
|
||||
const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
|
||||
const columnChunks = _.chunk(formDisplay.columns, rowCount);
|
||||
|
||||
const { rowData, rowStatus } = former;
|
||||
|
||||
const handleSwitchToTable = () => {
|
||||
setConfig((cfg) => ({
|
||||
...cfg,
|
||||
@@ -318,6 +326,7 @@ export default function FormView(props) {
|
||||
data-col={chunkIndex * 2 + 1}
|
||||
// @ts-ignore
|
||||
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)}
|
||||
>
|
||||
{inplaceEditorState.cell &&
|
||||
@@ -328,7 +337,9 @@ export default function FormView(props) {
|
||||
inplaceEditorState={inplaceEditorState}
|
||||
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
||||
cellValue={rowData[col.uniqueName]}
|
||||
onSetValue={(value) => {}}
|
||||
onSetValue={(value) => {
|
||||
former.setCellValue(col.uniqueName, value);
|
||||
}}
|
||||
// grider={grider}
|
||||
// rowIndex={rowIndex}
|
||||
// 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 FormView from './FormView';
|
||||
import axios from '../utility/axios';
|
||||
import ChangeSetFormer from './ChangeSetFormer';
|
||||
|
||||
async function loadRow(props, sql) {
|
||||
const { conid, database } = props;
|
||||
@@ -26,7 +27,7 @@ async function loadRow(props, sql) {
|
||||
}
|
||||
|
||||
export default function SqlFormView(props) {
|
||||
const { formDisplay } = props;
|
||||
const { formDisplay, changeSetState, dispatchChangeSet } = props;
|
||||
const [rowData, setRowData] = React.useState(null);
|
||||
|
||||
const handleLoadCurrentRow = async () => {
|
||||
@@ -46,7 +47,14 @@ export default function SqlFormView(props) {
|
||||
if (formDisplay && !formDisplay.isLoadedCurrentRow(rowData)) {
|
||||
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 { formViewKey } = config;
|
||||
@@ -76,5 +84,5 @@ export default function SqlFormView(props) {
|
||||
// setDisplay(newDisplay);
|
||||
// }, [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