remove web

This commit is contained in:
Jan Prochazka
2021-02-20 19:15:11 +01:00
parent dd7db5904c
commit daf9e9d18b
240 changed files with 0 additions and 22572 deletions

View File

@@ -1,93 +0,0 @@
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);
}
}

View File

@@ -1,583 +0,0 @@
// @ts-nocheck
import _ from 'lodash';
import React from 'react';
import ReactDOM from 'react-dom';
import ColumnLabel from '../datagrid/ColumnLabel';
import { findForeignKeyForColumn } from 'dbgate-tools';
import styled from 'styled-components';
import useTheme from '../theme/useTheme';
import useDimensions from '../utility/useDimensions';
import FormViewToolbar from './FormViewToolbar';
import { useShowMenu } from '../modals/showMenu';
import FormViewContextMenu from './FormViewContextMenu';
import keycodes from '../utility/keycodes';
import { CellFormattedValue, ShowFormButton } from '../datagrid/DataGridRow';
import { cellFromEvent } from '../datagrid/selection';
import InplaceEditor from '../datagrid/InplaceEditor';
import { copyTextToClipboard } from '../utility/clipboard';
import { ExpandIcon, FontIcon } from '../icons';
import openReferenceForm from './openReferenceForm';
import useOpenNewTab from '../utility/useOpenNewTab';
import LoadingInfo from '../widgets/LoadingInfo';
const Table = styled.table`
border-collapse: collapse;
outline: none;
`;
const OuterWrapper = styled.div`
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
`;
const Wrapper = styled.div`
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
display: flex;
overflow-x: scroll;
`;
const TableRow = styled.tr`
background-color: ${props => props.theme.gridbody_background};
&:nth-child(6n + 3) {
background-color: ${props => props.theme.gridbody_background_alt2};
}
&:nth-child(6n + 6) {
background-color: ${props => props.theme.gridbody_background_alt3};
}
`;
const TableHeaderCell = styled.td`
border: 1px solid ${props => props.theme.border};
text-align: left;
padding: 2px;
background-color: ${props => props.theme.gridheader_background};
overflow: hidden;
position: relative;
${props =>
props.isSelected &&
`
background: initial;
background-color: ${props.theme.gridbody_selection[4]};
color: ${props.theme.gridbody_invfont1};`}
`;
const TableBodyCell = styled.td`
font-weight: normal;
border: 1px solid ${props => props.theme.border};
// border-collapse: collapse;
padding: 2px;
white-space: nowrap;
position: relative;
max-width: 500px;
overflow: hidden;
text-overflow: ellipsis;
${props =>
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`
// visibility: hidden
position: absolute;
left: -1000px;
top: -1000px;
`;
const RowCountLabel = styled.div`
position: absolute;
background-color: ${props => props.theme.gridbody_background_yellow[1]};
right: 40px;
bottom: 20px;
`;
const HintSpan = styled.span`
color: gray;
margin-left: 5px;
margin-right: 16px;
`;
const ColumnLabelMargin = styled(ColumnLabel)`
margin-right: 16px;
`;
function isDataCell(cell) {
return cell[1] % 2 == 1;
}
export default function FormView(props) {
const {
toolbarPortalRef,
tabVisible,
config,
setConfig,
onNavigate,
former,
onSave,
conid,
database,
onReload,
onReconnect,
allRowCount,
rowCountBefore,
onSelectionChanged,
isLoading,
} = props;
/** @type {import('dbgate-datalib').FormViewDisplay} */
const formDisplay = props.formDisplay;
const theme = useTheme();
const [headerRowRef, { height: rowHeight }] = useDimensions();
const [wrapperRef, { height: wrapperHeight }] = useDimensions();
const showMenu = useShowMenu();
const focusFieldRef = React.useRef(null);
const [currentCell, setCurrentCell] = React.useState([0, 0]);
const cellRefs = React.useRef({});
const openNewTab = useOpenNewTab();
const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
const columnChunks = _.chunk(formDisplay.columns, rowCount);
const { rowData, rowStatus } = former;
const handleSwitchToTable = () => {
setConfig(cfg => ({
...cfg,
isFormView: false,
formViewKey: null,
}));
};
const handleFilterThisValue = isDataCell(currentCell)
? () => formDisplay.filterCellValue(getCellColumn(currentCell), rowData)
: null;
const handleContextMenu = event => {
event.preventDefault();
showMenu(
event.pageX,
event.pageY,
<FormViewContextMenu
switchToTable={handleSwitchToTable}
onNavigate={onNavigate}
addToFilter={() => formDisplay.addFilterColumn(getCellColumn(currentCell))}
filterThisValue={handleFilterThisValue}
/>
);
};
const setCellRef = (row, col, element) => {
cellRefs.current[`${row},${col}`] = element;
};
React.useEffect(() => {
if (tabVisible) {
if (focusFieldRef.current) focusFieldRef.current.focus();
}
}, [tabVisible, focusFieldRef.current]);
React.useEffect(() => {
if (!onSelectionChanged || !rowData) return;
const col = getCellColumn(currentCell);
if (!col) return;
onSelectionChanged(rowData[col.uniqueName]);
}, [onSelectionChanged, currentCell, rowData]);
const checkMoveCursorBounds = (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;
return [row, col];
};
const handleCursorMove = event => {
if (event.ctrlKey) {
switch (event.keyCode) {
case keycodes.leftArrow:
return checkMoveCursorBounds(currentCell[0], 0);
case keycodes.rightArrow:
return checkMoveCursorBounds(currentCell[0], columnChunks.length * 2 - 1);
}
}
switch (event.keyCode) {
case keycodes.leftArrow:
return checkMoveCursorBounds(currentCell[0], currentCell[1] - 1);
case keycodes.rightArrow:
return checkMoveCursorBounds(currentCell[0], currentCell[1] + 1);
case keycodes.upArrow:
return checkMoveCursorBounds(currentCell[0] - 1, currentCell[1]);
case keycodes.downArrow:
return checkMoveCursorBounds(currentCell[0] + 1, currentCell[1]);
case keycodes.pageUp:
return checkMoveCursorBounds(0, currentCell[1]);
case keycodes.pageDown:
return checkMoveCursorBounds(rowCount - 1, currentCell[1]);
case keycodes.home:
return checkMoveCursorBounds(0, 0);
case keycodes.end:
return checkMoveCursorBounds(rowCount - 1, columnChunks.length * 2 - 1);
}
};
const handleKeyNavigation = event => {
if (event.ctrlKey) {
switch (event.keyCode) {
case keycodes.upArrow:
return 'previous';
case keycodes.downArrow:
return 'next';
case keycodes.home:
return 'begin';
case keycodes.end:
return 'end';
}
}
};
function handleSave() {
if (inplaceEditorState.cell) {
// @ts-ignore
dispatchInsplaceEditor({ type: 'shouldSave' });
return;
}
if (onSave) onSave();
}
function getCellColumn(cell) {
const chunk = columnChunks[Math.floor(cell[1] / 2)];
if (!chunk) return;
const column = chunk[cell[0]];
return column;
}
function setCellValue(cell, value) {
const column = getCellColumn(cell);
if (!column) return;
former.setCellValue(column.uniqueName, value);
}
function setNull() {
if (isDataCell(currentCell)) {
setCellValue(currentCell, null);
}
}
const scrollIntoView = cell => {
const element = cellRefs.current[`${cell[0]},${cell[1]}`];
if (element) element.scrollIntoView();
};
React.useEffect(() => {
scrollIntoView(currentCell);
}, [rowData]);
const moveCurrentCell = (row, col) => {
const moved = checkMoveCursorBounds(row, col);
setCurrentCell(moved);
scrollIntoView(moved);
};
function copyToClipboard() {
const column = getCellColumn(currentCell);
if (!column) return;
const text = currentCell[1] % 2 == 1 ? rowData[column.uniqueName] : column.columnName;
copyTextToClipboard(text);
}
const handleKeyDown = event => {
const navigation = handleKeyNavigation(event);
if (navigation) {
event.preventDefault();
onNavigate(navigation);
return;
}
const moved = handleCursorMove(event);
if (moved) {
setCurrentCell(moved);
scrollIntoView(moved);
event.preventDefault();
return;
}
if (event.keyCode == keycodes.s && event.ctrlKey) {
event.preventDefault();
handleSave();
// this.saveAndFocus();
}
if (event.keyCode == keycodes.n0 && event.ctrlKey) {
event.preventDefault();
setNull();
}
if (event.keyCode == keycodes.r && event.ctrlKey) {
event.preventDefault();
former.revertRowChanges();
}
// if (event.keyCode == keycodes.f && event.ctrlKey) {
// event.preventDefault();
// filterSelectedValue();
// }
if (event.keyCode == keycodes.z && event.ctrlKey) {
event.preventDefault();
former.undo();
}
if (event.keyCode == keycodes.y && event.ctrlKey) {
event.preventDefault();
former.redo();
}
if (event.keyCode == keycodes.c && event.ctrlKey) {
event.preventDefault();
copyToClipboard();
}
if (event.keyCode == keycodes.f && event.ctrlKey) {
event.preventDefault();
if (handleFilterThisValue) handleFilterThisValue();
}
if (event.keyCode == keycodes.f5) {
event.preventDefault();
onReload();
}
if (event.keyCode == keycodes.f4) {
event.preventDefault();
handleSwitchToTable();
}
if (
rowData &&
!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
dispatchInsplaceEditor({ type: 'show', text: event.nativeEvent.key, cell: currentCell });
return;
}
if (rowData && event.keyCode == keycodes.f2) {
// @ts-ignore
dispatchInsplaceEditor({ type: 'show', cell: currentCell, selectAll: true });
return;
}
};
const handleTableMouseDown = event => {
event.preventDefault();
if (focusFieldRef.current) focusFieldRef.current.focus();
if (event.target.closest('.buttonLike')) return;
if (event.target.closest('.resizeHandleControl')) return;
if (event.target.closest('input')) return;
// event.target.closest('table').focus();
event.preventDefault();
if (focusFieldRef.current) focusFieldRef.current.focus();
const cell = cellFromEvent(event);
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)) {
// @ts-ignore
dispatchInsplaceEditor({ type: 'close' });
}
// @ts-ignore
setCurrentCell(cell);
};
const getCellWidth = (row, col) => {
const element = cellRefs.current[`${row},${col}`];
if (element) return element.getBoundingClientRect().width;
return 100;
};
const rowCountInfo = React.useMemo(() => {
if (rowData == null) return 'No data';
if (allRowCount == null || rowCountBefore == null) return 'Loading row count...';
return `Row: ${(rowCountBefore + 1).toLocaleString()} / ${allRowCount.toLocaleString()}`;
}, [rowCountBefore, allRowCount]);
const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => {
switch (action.type) {
case 'show': {
const column = getCellColumn(action.cell);
if (!column) return state;
if (column.uniquePath.length > 1) return state;
// if (!grider.editable) return {};
return {
cell: action.cell,
text: action.text,
selectAll: action.selectAll,
};
}
case 'close': {
const [row, col] = currentCell || [];
if (focusFieldRef.current) focusFieldRef.current.focus();
// @ts-ignore
if (action.mode == 'enter' && row) setTimeout(() => moveCurrentCell(row + 1, col), 0);
// if (action.mode == 'save') setTimeout(handleSave, 0);
return {};
}
case 'shouldSave': {
return {
...state,
shouldSave: true,
};
}
}
return {};
}, {});
const toolbar =
toolbarPortalRef &&
toolbarPortalRef.current &&
tabVisible &&
ReactDOM.createPortal(
<FormViewToolbar
switchToTable={handleSwitchToTable}
onNavigate={onNavigate}
reload={onReload}
reconnect={onReconnect}
save={handleSave}
former={former}
/>,
toolbarPortalRef.current
);
if (isLoading) {
return (
<>
<LoadingInfo wrapper message="Loading data" />
{toolbar}
</>
);
}
if (!formDisplay || !formDisplay.isLoadedCorrectly) return toolbar;
return (
<OuterWrapper>
<Wrapper ref={wrapperRef} onContextMenu={handleContextMenu}>
{columnChunks.map((chunk, chunkIndex) => (
<Table key={chunkIndex} onMouseDown={handleTableMouseDown}>
{chunk.map((col, rowIndex) => (
<TableRow key={col.uniqueName} theme={theme} ref={headerRowRef} style={{ height: `${rowHeight}px` }}>
<TableHeaderCell
theme={theme}
data-row={rowIndex}
data-col={chunkIndex * 2}
// @ts-ignore
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2}
ref={element => setCellRef(rowIndex, chunkIndex * 2, element)}
>
<ColumnLabelMargin
{...col}
headerText={col.columnName}
style={{ marginLeft: (col.uniquePath.length - 1) * 20 }}
extInfo={col.foreignKey ? ` -> ${col.foreignKey.refTableName}` : null}
/>
{col.foreignKey && (
<ShowFormButton
theme={theme}
className="buttonLike"
onClick={e => {
e.stopPropagation();
formDisplay.toggleExpandedColumn(col.uniqueName);
}}
>
<ExpandIcon isExpanded={formDisplay.isExpandedColumn(col.uniqueName)} />
</ShowFormButton>
)}
</TableHeaderCell>
<TableBodyCell
theme={theme}
data-row={rowIndex}
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 &&
rowIndex == inplaceEditorState.cell[0] &&
chunkIndex * 2 + 1 == inplaceEditorState.cell[1] ? (
<InplaceEditor
widthPx={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
inplaceEditorState={inplaceEditorState}
dispatchInsplaceEditor={dispatchInsplaceEditor}
cellValue={rowData[col.uniqueName]}
onSetValue={value => {
former.setCellValue(col.uniqueName, value);
}}
// grider={grider}
// rowIndex={rowIndex}
// uniqueName={col.uniqueName}
/>
) : (
<>
{rowData && (
<CellFormattedValue value={rowData[col.uniqueName]} dataType={col.dataType} theme={theme} />
)}
{!!col.hintColumnName &&
rowData &&
!(rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)) && (
<HintSpan>{rowData[col.hintColumnName]}</HintSpan>
)}
{col.foreignKey && rowData && rowData[col.uniqueName] && (
<ShowFormButton
theme={theme}
className="buttonLike"
onClick={e => {
e.stopPropagation();
openReferenceForm(rowData, col, openNewTab, conid, database);
}}
>
<FontIcon icon="icon form" />
</ShowFormButton>
)}
</>
)}
</TableBodyCell>
</TableRow>
))}
</Table>
))}
<FocusField type="text" ref={focusFieldRef} onKeyDown={handleKeyDown} />
{toolbar}
</Wrapper>
{rowCountInfo && <RowCountLabel theme={theme}>{rowCountInfo}</RowCountLabel>}
</OuterWrapper>
);
}

View File

@@ -1,31 +0,0 @@
import React from 'react';
import { DropDownMenuItem, DropDownMenuDivider } from '../modals/DropDownMenu';
export default function FormViewContextMenu({ switchToTable, onNavigate, addToFilter, filterThisValue }) {
return (
<>
<DropDownMenuItem onClick={switchToTable} keyText="F4">
Table view
</DropDownMenuItem>
{addToFilter && <DropDownMenuItem onClick={addToFilter}>Add to filter</DropDownMenuItem>}
{filterThisValue && (
<DropDownMenuItem onClick={filterThisValue} keyText="Ctrl+F">
Filter this value
</DropDownMenuItem>
)}
<DropDownMenuDivider />
<DropDownMenuItem onClick={() => onNavigate('begin')} keyText="Ctrl+Home">
Navigate to begin
</DropDownMenuItem>
<DropDownMenuItem onClick={() => onNavigate('previous')} keyText="Ctrl+Up">
Navigate to previous
</DropDownMenuItem>
<DropDownMenuItem onClick={() => onNavigate('next')} keyText="Ctrl+Down">
Navigate to next
</DropDownMenuItem>
<DropDownMenuItem onClick={() => onNavigate('end')} keyText="Ctrl+End">
Navigate to end
</DropDownMenuItem>
</>
);
}

View File

@@ -1,116 +0,0 @@
import React from 'react';
import _ from 'lodash';
import { ManagerInnerContainer } from '../datagrid/ManagerStyles';
import styled from 'styled-components';
import ColumnLabel from '../datagrid/ColumnLabel';
import { TextField } from '../utility/inputs';
import { getFilterType } from 'dbgate-filterparser';
import DataFilterControl from '../datagrid/DataFilterControl';
import InlineButton from '../widgets/InlineButton';
import { FontIcon } from '../icons';
import keycodes from '../utility/keycodes';
const ColumnWrapper = styled.div`
margin: 5px;
`;
const ColumnNameWrapper = styled.div`
display: flex;
justify-content: space-between;
`;
const TextFieldWrapper = styled.div`
display: flex;
`;
const StyledTextField = styled(TextField)`
flex: 1;
`;
function PrimaryKeyFilterEditor({ column, baseTable, formDisplay }) {
const value = formDisplay.getKeyValue(column.columnName);
const editorRef = React.useRef(null);
React.useEffect(() => {
if (editorRef.current) {
editorRef.current.value = value;
}
}, [value, editorRef.current]);
const applyFilter = () => {
formDisplay.requestKeyValue(column.columnName, editorRef.current.value);
};
const cancelFilter = () => {
formDisplay.cancelRequestKey();
formDisplay.reload();
};
const handleKeyDown = ev => {
if (ev.keyCode == keycodes.enter) {
applyFilter();
}
if (ev.keyCode == keycodes.escape) {
cancelFilter();
}
};
return (
<ColumnWrapper>
<ColumnNameWrapper>
<div>
<FontIcon icon="img primary-key" />
<ColumnLabel {...baseTable.columns.find(x => x.columnName == column.columnName)} />
</div>
{formDisplay.config.formViewKeyRequested && (
<InlineButton square onClick={cancelFilter}>
<FontIcon icon="icon delete" />
</InlineButton>
)}
</ColumnNameWrapper>
<TextFieldWrapper>
<StyledTextField editorRef={editorRef} onBlur={applyFilter} onKeyDown={handleKeyDown} />
</TextFieldWrapper>
</ColumnWrapper>
);
}
export default function FormViewFilters(props) {
const { formDisplay } = props;
if (!formDisplay || !formDisplay.baseTable || !formDisplay.baseTable.primaryKey) return null;
const { baseTable } = formDisplay;
const { formFilterColumns, filters } = formDisplay.config || {};
const allFilterNames = _.union(_.keys(filters || {}), formFilterColumns || []);
return (
<ManagerInnerContainer style={{ maxWidth: props.managerSize }}>
{baseTable.primaryKey.columns.map(col => (
<PrimaryKeyFilterEditor key={col.columnName} baseTable={baseTable} column={col} formDisplay={formDisplay} />
))}
{allFilterNames.map(uniqueName => {
const column = formDisplay.columns.find(x => x.uniqueName == uniqueName)
// const column = baseTable.columns.find(x => x.columnName == columnName);
if (!column) return null;
return (
<ColumnWrapper key={uniqueName}>
<ColumnNameWrapper>
<ColumnLabel {...column} />
<InlineButton
square
onClick={() => {
formDisplay.removeFilter(column.uniqueName);
}}
>
<FontIcon icon="icon delete" />
</InlineButton>
</ColumnNameWrapper>
<DataFilterControl
filterType={getFilterType(column.dataType)}
filter={filters[column.uniqueName]}
setFilter={value => formDisplay.setFilter(column.uniqueName, value)}
/>
</ColumnWrapper>
);
})}
</ManagerInnerContainer>
);
}

View File

@@ -1,42 +0,0 @@
import React from 'react';
import ToolbarButton from '../widgets/ToolbarButton';
export default function FormViewToolbar({ switchToTable, onNavigate, reload, reconnect, former, save }) {
return (
<>
<ToolbarButton onClick={switchToTable} icon="icon table">
Table view
</ToolbarButton>
<ToolbarButton onClick={() => onNavigate('begin')} icon="icon arrow-begin">
First
</ToolbarButton>
<ToolbarButton onClick={() => onNavigate('previous')} icon="icon arrow-left">
Previous
</ToolbarButton>
<ToolbarButton onClick={() => onNavigate('next')} icon="icon arrow-right">
Next
</ToolbarButton>
<ToolbarButton onClick={() => onNavigate('end')} icon="icon arrow-end">
Last
</ToolbarButton>
<ToolbarButton onClick={reload} icon="icon reload">
Refresh
</ToolbarButton>
<ToolbarButton onClick={reconnect} icon="icon connection">
Reconnect
</ToolbarButton>
<ToolbarButton disabled={!former.canUndo} onClick={() => former.undo()} icon="icon undo">
Undo
</ToolbarButton>
<ToolbarButton disabled={!former.canRedo} onClick={() => former.redo()} icon="icon redo">
Redo
</ToolbarButton>
<ToolbarButton disabled={!former.allowSave} onClick={save} icon="icon save">
Save
</ToolbarButton>
<ToolbarButton disabled={!former.containsChanges} onClick={() => former.revertAllChanges()} icon="icon close">
Revert
</ToolbarButton>
</>
);
}

View File

@@ -1,53 +0,0 @@
// 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]);
}
}
}

View File

@@ -1,294 +0,0 @@
import { changeSetToSql, createChangeSet, TableFormViewDisplay } from 'dbgate-datalib';
import { findEngineDriver } from 'dbgate-tools';
import React from 'react';
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
import useExtensions from '../utility/useExtensions';
import FormView from './FormView';
import axios from '../utility/axios';
import ChangeSetFormer from './ChangeSetFormer';
import ConfirmSqlModal from '../modals/ConfirmSqlModal';
import ErrorMessageModal from '../modals/ErrorMessageModal';
import { scriptToSql } from 'dbgate-sqltree';
import useModalState from '../modals/useModalState';
import useShowModal from '../modals/showModal';
import stableStringify from 'json-stable-stringify';
async function loadRow(props, sql) {
const { conid, database } = props;
if (!sql) return null;
const response = await axios.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql },
});
if (response.data.errorMessage) return response.data;
return response.data.rows[0];
}
export default function SqlFormView(props) {
// console.log('SqlFormView', props);
const {
formDisplay,
changeSetState,
dispatchChangeSet,
conid,
database,
onReferenceSourceChanged,
refReloadToken,
} = props;
// const [rowData, setRowData] = React.useState(null);
// const [reloadToken, setReloadToken] = React.useState(0);
// const [rowCountInfo, setRowCountInfo] = React.useState(null);
// const [isLoading, setIsLoading] = React.useState(false);
// const loadedFiltersRef = React.useRef('');
const confirmSqlModalState = useModalState();
const [confirmSql, setConfirmSql] = React.useState('');
const showModal = useShowModal();
const changeSet = changeSetState && changeSetState.value;
const changeSetRef = React.useRef(changeSet);
changeSetRef.current = changeSet;
const [loadProps, setLoadProps] = React.useState({
isLoadingData: false,
isLoadedData: false,
rowData: null,
isLoadingCount: false,
isLoadedCount: false,
loadedTime: new Date().getTime(),
allRowCount: null,
rowCountBefore: null,
errorMessage: null,
});
const {
isLoadingData,
rowData,
isLoadedData,
isLoadingCount,
isLoadedCount,
loadedTime,
allRowCount,
rowCountBefore,
errorMessage,
} = loadProps;
const handleLoadCurrentRow = async () => {
if (isLoadingData) return;
let newLoadedRow = false;
if (formDisplay.config.formViewKeyRequested || formDisplay.config.formViewKey) {
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadingData: true,
}));
const row = await loadRow(props, formDisplay.getCurrentRowQuery());
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadingData: false,
isLoadedData: true,
rowData: row,
loadedTime: new Date().getTime(),
}));
newLoadedRow = row;
}
if (formDisplay.config.formViewKeyRequested && newLoadedRow) {
formDisplay.cancelRequestKey(newLoadedRow);
}
if (!newLoadedRow && !formDisplay.config.formViewKeyRequested) {
await handleNavigate('first');
}
};
const handleLoadRowCount = async () => {
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadingCount: true,
}));
const countRow = await loadRow(props, formDisplay.getCountQuery());
const countBeforeRow = await loadRow(props, formDisplay.getBeforeCountQuery());
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadedCount: true,
isLoadingCount: false,
allRowCount: countRow ? parseInt(countRow.count) : null,
rowCountBefore: countBeforeRow ? parseInt(countBeforeRow.count) : null,
}));
};
const handleNavigate = async command => {
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadingData: true,
}));
const row = await loadRow(props, formDisplay.navigateRowQuery(command));
if (row) {
formDisplay.navigate(row);
}
setLoadProps(oldLoadProps => ({
...oldLoadProps,
isLoadingData: false,
isLoadedData: true,
isLoadedCount: false,
allRowCount: null,
rowCountBefore: null,
rowData: row,
loadedTime: new Date().getTime(),
}));
};
React.useEffect(() => {
if (onReferenceSourceChanged && rowData) onReferenceSourceChanged([rowData], loadedTime);
}, [onReferenceSourceChanged, rowData, refReloadToken]);
React.useEffect(() => {
if (!formDisplay.isLoadedCorrectly) return;
if (!isLoadedData && !isLoadingData) handleLoadCurrentRow();
if (isLoadedData && !isLoadingCount && !isLoadedCount) handleLoadRowCount();
});
// React.useEffect(() => {
// loadedFiltersRef.current = formDisplay ? stableStringify(formDisplay.config) : null;
// }, [rowData]);
// React.useEffect(() => {
// if (formDisplay) handleLoadCurrentRow();
// setRowCountInfo(null);
// handleLoadRowCount();
// }, [reloadToken]);
// React.useEffect(() => {
// if (!formDisplay.isLoadedCorrectly) return;
// if (
// formDisplay &&
// (!formDisplay.isLoadedCurrentRow(rowData) ||
// loadedFiltersRef.current != stableStringify(formDisplay.config.filters))
// ) {
// handleLoadCurrentRow();
// }
// setRowCountInfo(null);
// handleLoadRowCount();
// }, [formDisplay]);
const reload = () => {
setLoadProps({
isLoadingData: false,
isLoadedData: false,
isLoadingCount: false,
isLoadedCount: false,
rowData: null,
loadedTime: new Date().getTime(),
allRowCount: null,
rowCountBefore: null,
errorMessage: null,
});
};
React.useEffect(() => {
if (props.masterLoadedTime && props.masterLoadedTime > loadedTime) {
formDisplay.reload();
}
if (formDisplay.cache.refreshTime > loadedTime) {
reload();
}
});
const former = React.useMemo(() => new ChangeSetFormer(rowData, changeSetState, dispatchChangeSet, formDisplay), [
rowData,
changeSetState,
dispatchChangeSet,
formDisplay,
]);
function handleSave() {
const script = changeSetToSql(changeSetRef.current, formDisplay.dbinfo);
const sql = scriptToSql(formDisplay.driver, script);
setConfirmSql(sql);
confirmSqlModalState.open();
}
async function handleConfirmSql() {
const resp = await axios.request({
url: 'database-connections/query-data',
method: 'post',
params: {
conid,
database,
},
data: { sql: confirmSql },
});
const { errorMessage } = resp.data || {};
if (errorMessage) {
showModal(modalState => (
<ErrorMessageModal modalState={modalState} message={errorMessage} title="Error when saving" />
));
} else {
dispatchChangeSet({ type: 'reset', value: createChangeSet() });
setConfirmSql(null);
formDisplay.reload();
// setReloadToken((x) => x + 1);
}
}
// const { config, setConfig, cache, setCache, schemaName, pureName, conid, database } = props;
// const { formViewKey } = config;
// const [display, setDisplay] = React.useState(null);
// const connection = useConnectionInfo({ conid });
// const dbinfo = useDatabaseInfo({ conid, database });
// const extensions = useExtensions();
// console.log('SqlFormView.props', props);
// React.useEffect(() => {
// const newDisplay = connection
// ? new TableFormViewDisplay(
// { schemaName, pureName },
// findEngineDriver(connection, extensions),
// config,
// setConfig,
// cache,
// setCache,
// dbinfo
// )
// : null;
// if (!newDisplay) return;
// if (display && display.isLoadedCorrectly && !newDisplay.isLoadedCorrectly) return;
// setDisplay(newDisplay);
// }, [config, cache, conid, database, schemaName, pureName, dbinfo, extensions]);
return (
<>
<FormView
{...props}
rowData={rowData}
onNavigate={handleNavigate}
former={former}
onSave={handleSave}
isLoading={isLoadingData}
onReload={() => formDisplay.reload()}
onReconnect={async () => {
await axios.post('database-connections/refresh', { conid, database });
formDisplay.reload();
}}
allRowCount={allRowCount}
rowCountBefore={rowCountBefore}
/>
<ConfirmSqlModal
modalState={confirmSqlModalState}
sql={confirmSql}
engine={formDisplay.engine}
onConfirm={handleConfirmSql}
/>
</>
);
}

View File

@@ -1,30 +0,0 @@
import _ from 'lodash';
export default function openReferenceForm(rowData, column, openNewTab, conid, database) {
const formViewKey = _.fromPairs(
column.foreignKey.columns.map(({ refColumnName, columnName }) => [refColumnName, rowData[columnName]])
);
openNewTab(
{
title: column.foreignKey.refTableName,
icon: 'img table',
tabComponent: 'TableDataTab',
props: {
schemaName: column.foreignKey.refSchemaName,
pureName: column.foreignKey.refTableName,
conid,
database,
objectTypeField: 'tables',
},
},
{
grid: {
isFormView: true,
formViewKey,
},
},
{
forceNewTab: true,
}
);
}