mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-20 08:56:00 +00:00
remove web
This commit is contained in:
@@ -1,183 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { ManagerInnerContainer } from '../datagrid/ManagerStyles';
|
||||
import { FontIcon } from '../icons';
|
||||
import useTheme from '../theme/useTheme';
|
||||
import keycodes from '../utility/keycodes';
|
||||
|
||||
const Row = styled.div`
|
||||
// margin-left: 5px;
|
||||
// margin-right: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// padding: 5px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: ${props => props.theme.manager_background_blue[1]};
|
||||
}
|
||||
`;
|
||||
const Name = styled.div`
|
||||
white-space: nowrap;
|
||||
margin: 5px;
|
||||
`;
|
||||
const Buttons = styled.div`
|
||||
white-space: nowrap;
|
||||
`;
|
||||
const Icon = styled(FontIcon)`
|
||||
// margin-left: 5px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
&:hover {
|
||||
background-color: ${props => props.theme.manager_background3};
|
||||
}
|
||||
padding: 5px;
|
||||
`;
|
||||
const EditorInput = styled.input`
|
||||
width: calc(100% - 10px);
|
||||
background-color: ${props =>
|
||||
// @ts-ignore
|
||||
props.isError ? props.theme.manager_background_red[1] : props.theme.manager_background};
|
||||
`;
|
||||
|
||||
function ColumnNameEditor({
|
||||
onEnter,
|
||||
onBlur = undefined,
|
||||
focusOnCreate = false,
|
||||
blurOnEnter = false,
|
||||
existingNames,
|
||||
defaultValue = '',
|
||||
...other
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const [value, setValue] = React.useState(defaultValue || '');
|
||||
const editorRef = React.useRef(null);
|
||||
const isError = value && existingNames && existingNames.includes(value);
|
||||
const handleKeyDown = event => {
|
||||
if (value && event.keyCode == keycodes.enter && !isError) {
|
||||
onEnter(value);
|
||||
setValue('');
|
||||
if (blurOnEnter) editorRef.current.blur();
|
||||
}
|
||||
if (event.keyCode == keycodes.escape) {
|
||||
setValue('');
|
||||
editorRef.current.blur();
|
||||
}
|
||||
};
|
||||
const handleBlur = () => {
|
||||
if (value && !isError) {
|
||||
onEnter(value);
|
||||
setValue('');
|
||||
}
|
||||
if (onBlur) onBlur();
|
||||
};
|
||||
React.useEffect(() => {
|
||||
if (focusOnCreate) editorRef.current.focus();
|
||||
}, [focusOnCreate]);
|
||||
return (
|
||||
<EditorInput
|
||||
theme={theme}
|
||||
ref={editorRef}
|
||||
type="text"
|
||||
onKeyDown={handleKeyDown}
|
||||
onBlur={handleBlur}
|
||||
value={value}
|
||||
onChange={ev => setValue(ev.target.value)}
|
||||
// @ts-ignore
|
||||
isError={isError}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function exchange(array, i1, i2) {
|
||||
const i1r = (i1 + array.length) % array.length;
|
||||
const i2r = (i2 + array.length) % array.length;
|
||||
const res = [...array];
|
||||
[res[i1r], res[i2r]] = [res[i2r], res[i1r]];
|
||||
return res;
|
||||
}
|
||||
|
||||
function ColumnManagerRow({ column, onEdit, onRemove, onUp, onDown }) {
|
||||
const [isHover, setIsHover] = React.useState(false);
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Row onMouseEnter={() => setIsHover(true)} onMouseLeave={() => setIsHover(false)} theme={theme}>
|
||||
<Name>{column.columnName}</Name>
|
||||
<Buttons>
|
||||
<Icon icon="icon edit" onClick={onEdit} theme={theme} />
|
||||
<Icon icon="icon delete" onClick={onRemove} theme={theme} />
|
||||
<Icon icon="icon arrow-up" onClick={onUp} theme={theme} />
|
||||
<Icon icon="icon arrow-down" onClick={onDown} theme={theme} />
|
||||
</Buttons>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
function dispatchChangeColumns(props, func, rowFunc = null) {
|
||||
const { modelState, dispatchModel } = props;
|
||||
const model = modelState.value;
|
||||
|
||||
dispatchModel({
|
||||
type: 'set',
|
||||
value: {
|
||||
rows: rowFunc ? model.rows.map(rowFunc) : model.rows,
|
||||
structure: {
|
||||
...model.structure,
|
||||
columns: func(model.structure.columns),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export default function FreeTableColumnEditor(props) {
|
||||
const { modelState, dispatchModel } = props;
|
||||
const [editingColumn, setEditingColumn] = React.useState(null);
|
||||
const model = modelState.value;
|
||||
return (
|
||||
<>
|
||||
<ManagerInnerContainer style={{ maxWidth: props.managerSize }}>
|
||||
{model.structure.columns.map((column, index) =>
|
||||
index == editingColumn ? (
|
||||
<ColumnNameEditor
|
||||
defaultValue={column.columnName}
|
||||
onEnter={columnName => {
|
||||
dispatchChangeColumns(
|
||||
props,
|
||||
cols => cols.map((col, i) => (index == i ? { columnName } : col)),
|
||||
row => _.mapKeys(row, (v, k) => (k == column.columnName ? columnName : k))
|
||||
);
|
||||
}}
|
||||
onBlur={() => setEditingColumn(null)}
|
||||
focusOnCreate
|
||||
blurOnEnter
|
||||
existingNames={model.structure.columns.map(x => x.columnName)}
|
||||
/>
|
||||
) : (
|
||||
<ColumnManagerRow
|
||||
key={column.uniqueName}
|
||||
column={column}
|
||||
onEdit={() => setEditingColumn(index)}
|
||||
onRemove={() => {
|
||||
dispatchChangeColumns(props, cols => cols.filter((c, i) => i != index));
|
||||
}}
|
||||
onUp={() => {
|
||||
dispatchChangeColumns(props, cols => exchange(cols, index, index - 1));
|
||||
}}
|
||||
onDown={() => {
|
||||
dispatchChangeColumns(props, cols => exchange(cols, index, index + 1));
|
||||
}}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<ColumnNameEditor
|
||||
onEnter={columnName => {
|
||||
dispatchChangeColumns(props, cols => [...cols, { columnName }]);
|
||||
}}
|
||||
placeholder="New column"
|
||||
existingNames={model.structure.columns.map(x => x.columnName)}
|
||||
/>
|
||||
</ManagerInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import { runMacro } from 'dbgate-datalib';
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { HorizontalSplitter, VerticalSplitter } from '../widgets/Splitter';
|
||||
import FreeTableColumnEditor from './FreeTableColumnEditor';
|
||||
import FreeTableGridCore from './FreeTableGridCore';
|
||||
import MacroDetail from './MacroDetail';
|
||||
import MacroManager from './MacroManager';
|
||||
import WidgetColumnBar, { WidgetColumnBarItem } from '../widgets/WidgetColumnBar';
|
||||
import useTheme from '../theme/useTheme';
|
||||
|
||||
const LeftContainer = styled.div`
|
||||
background-color: ${props => props.theme.manager_background};
|
||||
display: flex;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const DataGridContainer = styled.div`
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
function extractMacroValuesForMacro(macroValues, macro) {
|
||||
if (!macro) return {};
|
||||
return {
|
||||
..._.fromPairs((macro.args || []).filter(x => x.default != null).map(x => [x.name, x.default])),
|
||||
..._.mapKeys(macroValues, (v, k) => k.replace(/^.*#/, '')),
|
||||
};
|
||||
}
|
||||
|
||||
export default function FreeTableGrid(props) {
|
||||
const { modelState, dispatchModel } = props;
|
||||
const theme = useTheme();
|
||||
const [managerSize, setManagerSize] = React.useState(0);
|
||||
const [selectedMacro, setSelectedMacro] = React.useState(null);
|
||||
const [macroValues, setMacroValues] = React.useState({});
|
||||
const [selectedCells, setSelectedCells] = React.useState([]);
|
||||
const handleExecuteMacro = () => {
|
||||
const newModel = runMacro(
|
||||
selectedMacro,
|
||||
extractMacroValuesForMacro(macroValues, selectedMacro),
|
||||
modelState.value,
|
||||
false,
|
||||
selectedCells
|
||||
);
|
||||
dispatchModel({ type: 'set', value: newModel });
|
||||
setSelectedMacro(null);
|
||||
};
|
||||
// console.log('macroValues', macroValues);
|
||||
return (
|
||||
<HorizontalSplitter initialValue="300px" size={managerSize} setSize={setManagerSize}>
|
||||
<LeftContainer theme={theme}>
|
||||
<WidgetColumnBar>
|
||||
<WidgetColumnBarItem title="Columns" name="columns" height="40%">
|
||||
<FreeTableColumnEditor {...props} />
|
||||
</WidgetColumnBarItem>
|
||||
<WidgetColumnBarItem title="Macros" name="macros">
|
||||
<MacroManager
|
||||
{...props}
|
||||
managerSize={managerSize}
|
||||
selectedMacro={selectedMacro}
|
||||
setSelectedMacro={setSelectedMacro}
|
||||
/>
|
||||
</WidgetColumnBarItem>
|
||||
</WidgetColumnBar>
|
||||
</LeftContainer>
|
||||
|
||||
<DataGridContainer>
|
||||
<VerticalSplitter initialValue="70%">
|
||||
<FreeTableGridCore
|
||||
{...props}
|
||||
macroPreview={selectedMacro}
|
||||
macroValues={extractMacroValuesForMacro(macroValues, selectedMacro)}
|
||||
onSelectionChanged={setSelectedCells}
|
||||
setSelectedMacro={setSelectedMacro}
|
||||
/>
|
||||
{!!selectedMacro && (
|
||||
<MacroDetail
|
||||
selectedMacro={selectedMacro}
|
||||
setSelectedMacro={setSelectedMacro}
|
||||
onChangeValues={setMacroValues}
|
||||
macroValues={macroValues}
|
||||
onExecute={handleExecuteMacro}
|
||||
/>
|
||||
)}
|
||||
</VerticalSplitter>
|
||||
</DataGridContainer>
|
||||
</HorizontalSplitter>
|
||||
);
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import { createGridCache, FreeTableGridDisplay } from 'dbgate-datalib';
|
||||
import React from 'react';
|
||||
import DataGridCore from '../datagrid/DataGridCore';
|
||||
import useShowModal from '../modals/showModal';
|
||||
import axios from '../utility/axios';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import FreeTableGrider from './FreeTableGrider';
|
||||
import MacroPreviewGrider from './MacroPreviewGrider';
|
||||
import uuidv1 from 'uuid/v1';
|
||||
import ImportExportModal from '../modals/ImportExportModal';
|
||||
|
||||
export default function FreeTableGridCore(props) {
|
||||
const {
|
||||
modelState,
|
||||
dispatchModel,
|
||||
config,
|
||||
setConfig,
|
||||
macroPreview,
|
||||
macroValues,
|
||||
onSelectionChanged,
|
||||
setSelectedMacro,
|
||||
} = props;
|
||||
const [cache, setCache] = React.useState(createGridCache());
|
||||
const [selectedCells, setSelectedCells] = React.useState([]);
|
||||
const showModal = useShowModal();
|
||||
const grider = React.useMemo(
|
||||
() =>
|
||||
macroPreview
|
||||
? new MacroPreviewGrider(modelState.value, macroPreview, macroValues, selectedCells)
|
||||
: FreeTableGrider.factory(props),
|
||||
[
|
||||
...FreeTableGrider.factoryDeps(props),
|
||||
macroPreview,
|
||||
macroPreview ? macroValues : null,
|
||||
macroPreview ? selectedCells : null,
|
||||
]
|
||||
);
|
||||
const display = React.useMemo(
|
||||
() => new FreeTableGridDisplay(grider.model || modelState.value, config, setConfig, cache, setCache),
|
||||
[modelState.value, config, cache, grider]
|
||||
);
|
||||
|
||||
async function exportGrid() {
|
||||
const jslid = uuidv1();
|
||||
await axios.post('jsldata/save-free-table', { jslid, data: modelState.value });
|
||||
const initialValues = {};
|
||||
initialValues.sourceStorageType = 'jsldata';
|
||||
initialValues.sourceJslId = jslid;
|
||||
initialValues.sourceList = ['editor-data'];
|
||||
showModal(modalState => <ImportExportModal modalState={modalState} initialValues={initialValues} />);
|
||||
}
|
||||
|
||||
const handleSelectionChanged = React.useCallback(
|
||||
cells => {
|
||||
if (onSelectionChanged) onSelectionChanged(cells);
|
||||
setSelectedCells(cells);
|
||||
},
|
||||
[setSelectedCells]
|
||||
);
|
||||
|
||||
const handleKeyDown = React.useCallback(event => {
|
||||
if (event.keyCode == keycodes.escape) {
|
||||
setSelectedMacro(null);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<DataGridCore
|
||||
{...props}
|
||||
grider={grider}
|
||||
display={display}
|
||||
onSelectionChanged={macroPreview ? handleSelectionChanged : null}
|
||||
frameSelection={!!macroPreview}
|
||||
exportGrid={exportGrid}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import { FreeTableModel } from 'dbgate-datalib';
|
||||
import Grider, { GriderRowStatus } from '../datagrid/Grider';
|
||||
|
||||
export default class FreeTableGrider extends Grider {
|
||||
public model: FreeTableModel;
|
||||
private batchModel: FreeTableModel;
|
||||
|
||||
constructor(public modelState, public dispatchModel) {
|
||||
super();
|
||||
this.model = modelState && modelState.value;
|
||||
}
|
||||
getRowData(index: any) {
|
||||
return this.model.rows[index];
|
||||
}
|
||||
get rowCount() {
|
||||
return this.model.rows.length;
|
||||
}
|
||||
get currentModel(): FreeTableModel {
|
||||
return this.batchModel || this.model;
|
||||
}
|
||||
set currentModel(value) {
|
||||
if (this.batchModel) this.batchModel = value;
|
||||
else this.dispatchModel({ type: 'set', value });
|
||||
}
|
||||
setCellValue(index: number, uniqueName: string, value: any) {
|
||||
const model = this.currentModel;
|
||||
if (model.rows[index])
|
||||
this.currentModel = {
|
||||
...model,
|
||||
rows: model.rows.map((row, i) => (index == i ? { ...row, [uniqueName]: value } : row)),
|
||||
};
|
||||
}
|
||||
get editable() {
|
||||
return true;
|
||||
}
|
||||
get canInsert() {
|
||||
return true;
|
||||
}
|
||||
get allowSave() {
|
||||
return true;
|
||||
}
|
||||
insertRow(): number {
|
||||
const model = this.currentModel;
|
||||
this.currentModel = {
|
||||
...model,
|
||||
rows: [...model.rows, {}],
|
||||
};
|
||||
return this.currentModel.rows.length - 1;
|
||||
}
|
||||
deleteRow(index: number) {
|
||||
const model = this.currentModel;
|
||||
this.currentModel = {
|
||||
...model,
|
||||
rows: model.rows.filter((row, i) => index != i),
|
||||
};
|
||||
}
|
||||
beginUpdate() {
|
||||
this.batchModel = this.model;
|
||||
}
|
||||
endUpdate() {
|
||||
if (this.model != this.batchModel) {
|
||||
this.dispatchModel({ type: 'set', value: this.batchModel });
|
||||
this.batchModel = null;
|
||||
}
|
||||
}
|
||||
|
||||
static factory({ modelState, dispatchModel }): FreeTableGrider {
|
||||
return new FreeTableGrider(modelState, dispatchModel);
|
||||
}
|
||||
static factoryDeps({ modelState, dispatchModel }) {
|
||||
return [modelState, dispatchModel];
|
||||
}
|
||||
undo() {
|
||||
this.dispatchModel({ type: 'undo' });
|
||||
}
|
||||
redo() {
|
||||
this.dispatchModel({ type: 'redo' });
|
||||
}
|
||||
get canUndo() {
|
||||
return this.modelState.canUndo;
|
||||
}
|
||||
get canRedo() {
|
||||
return this.modelState.canRedo;
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
import React from 'react';
|
||||
import ToolbarButton from '../widgets/ToolbarButton';
|
||||
import styled from 'styled-components';
|
||||
import { TabPage, TabControl } from '../widgets/TabControl';
|
||||
import dimensions from '../theme/dimensions';
|
||||
import GenericEditor from '../sqleditor/GenericEditor';
|
||||
import MacroParameters from './MacroParameters';
|
||||
import { WidgetTitle } from '../widgets/WidgetStyles';
|
||||
import { FormButton } from '../utility/forms';
|
||||
import FormStyledButton from '../widgets/FormStyledButton';
|
||||
import { FontIcon } from '../icons';
|
||||
import useTheme from '../theme/useTheme';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: ${props => props.theme.gridheader_background_cyan[0]};
|
||||
height: ${dimensions.toolBar.height}px;
|
||||
min-height: ${dimensions.toolBar.height}px;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid ${props => props.theme.border};
|
||||
border-bottom: 1px solid ${props => props.theme.border};
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
font-weight: bold;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const HeaderText = styled.div`
|
||||
margin-left: 10px;
|
||||
`;
|
||||
|
||||
const MacroDetailContainer = styled.div`
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
`;
|
||||
|
||||
const MacroDetailTabWrapper = styled.div`
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
|
||||
const MacroSection = styled.div`
|
||||
margin: 5px;
|
||||
`;
|
||||
|
||||
const TextWrapper = styled.div`
|
||||
margin: 5px;
|
||||
`;
|
||||
|
||||
const Buttons = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
function MacroHeader({ selectedMacro, setSelectedMacro, onExecute }) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Container theme={theme}>
|
||||
<Header>
|
||||
<FontIcon icon="img macro" />
|
||||
<HeaderText>{selectedMacro.title}</HeaderText>
|
||||
</Header>
|
||||
<Buttons>
|
||||
<ToolbarButton icon="icon run" onClick={onExecute} patchY={6}>
|
||||
Execute
|
||||
</ToolbarButton>
|
||||
<ToolbarButton icon="icon close" onClick={() => setSelectedMacro(null)} patchY={6}>
|
||||
Close
|
||||
</ToolbarButton>
|
||||
</Buttons>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default function MacroDetail({ selectedMacro, setSelectedMacro, onChangeValues, macroValues, onExecute }) {
|
||||
return (
|
||||
<MacroDetailContainer>
|
||||
<MacroHeader selectedMacro={selectedMacro} setSelectedMacro={setSelectedMacro} onExecute={onExecute} />
|
||||
<TabControl>
|
||||
<TabPage label="Macro detail" key="detail">
|
||||
<MacroDetailTabWrapper>
|
||||
<MacroSection>
|
||||
<WidgetTitle>Execute</WidgetTitle>
|
||||
<FormStyledButton value="Execute" onClick={onExecute} />
|
||||
</MacroSection>
|
||||
|
||||
<MacroSection>
|
||||
<WidgetTitle>Parameters</WidgetTitle>
|
||||
{selectedMacro.args && selectedMacro.args.length > 0 ? (
|
||||
<MacroParameters
|
||||
key={selectedMacro.name}
|
||||
args={selectedMacro.args}
|
||||
onChangeValues={onChangeValues}
|
||||
macroValues={macroValues}
|
||||
namePrefix={`${selectedMacro.name}#`}
|
||||
/>
|
||||
) : (
|
||||
<TextWrapper>This macro has no parameters</TextWrapper>
|
||||
)}
|
||||
</MacroSection>
|
||||
<MacroSection>
|
||||
<WidgetTitle>Description</WidgetTitle>
|
||||
<TextWrapper>{selectedMacro.description}</TextWrapper>
|
||||
</MacroSection>
|
||||
</MacroDetailTabWrapper>
|
||||
</TabPage>
|
||||
<TabPage label="JavaScript" key="javascript">
|
||||
<GenericEditor readOnly value={selectedMacro.code} mode="javascript" />
|
||||
</TabPage>
|
||||
</TabControl>
|
||||
</MacroDetailContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import styled from 'styled-components';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import { ManagerInnerContainer } from '../datagrid/ManagerStyles';
|
||||
import SearchInput from '../widgets/SearchInput';
|
||||
import { WidgetTitle } from '../widgets/WidgetStyles';
|
||||
import macros from './macros';
|
||||
import { AppObjectList } from '../appobj/AppObjectList';
|
||||
import MacroAppObject from '../appobj/MacroAppObject';
|
||||
|
||||
const SearchBoxWrapper = styled.div`
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
export default function MacroManager({ managerSize, selectedMacro, setSelectedMacro }) {
|
||||
const [filter, setFilter] = React.useState('');
|
||||
|
||||
return (
|
||||
<>
|
||||
<ManagerInnerContainer style={{ maxWidth: managerSize }}>
|
||||
<SearchBoxWrapper>
|
||||
<SearchInput placeholder="Search macros" filter={filter} setFilter={setFilter} />
|
||||
</SearchBoxWrapper>
|
||||
<AppObjectList
|
||||
list={_.sortBy(macros, 'title')}
|
||||
AppObjectComponent={MacroAppObject}
|
||||
onObjectClick={macro => setSelectedMacro(macro)}
|
||||
getCommonProps={data => ({
|
||||
isBold: selectedMacro && selectedMacro.name == data.name,
|
||||
})}
|
||||
filter={filter}
|
||||
groupFunc={data => data.group}
|
||||
/>
|
||||
{/* {macros.map((macro) => (
|
||||
<MacroListItem key={`${macro.group}/${macro.name}`} macro={macro} />
|
||||
))} */}
|
||||
</ManagerInnerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import FormArgumentList from '../utility/FormArgumentList';
|
||||
import { FormProvider } from '../utility/FormProvider';
|
||||
|
||||
export default function MacroParameters({ args, onChangeValues, macroValues, namePrefix }) {
|
||||
if (!args || args.length == 0) return null;
|
||||
const initialValues = {
|
||||
..._.fromPairs(args.filter(x => x.default != null).map(x => [`${namePrefix}${x.name}`, x.default])),
|
||||
...macroValues,
|
||||
};
|
||||
return (
|
||||
<FormProvider initialValues={initialValues}>
|
||||
<FormArgumentList args={args} onChangeValues={onChangeValues} namePrefix={namePrefix} />
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { FreeTableModel, MacroDefinition, MacroSelectedCell, runMacro } from 'dbgate-datalib';
|
||||
import Grider, { GriderRowStatus } from '../datagrid/Grider';
|
||||
import _ from 'lodash';
|
||||
|
||||
function convertToSet(row, field) {
|
||||
if (!row) return null;
|
||||
if (!row[field]) return null;
|
||||
if (_.isSet(row[field])) return row[field];
|
||||
return new Set(row[field]);
|
||||
}
|
||||
|
||||
export default class MacroPreviewGrider extends Grider {
|
||||
model: FreeTableModel;
|
||||
_errors: string[] = [];
|
||||
constructor(model: FreeTableModel, macro: MacroDefinition, macroArgs: {}, selectedCells: MacroSelectedCell[]) {
|
||||
super();
|
||||
this.model = runMacro(macro, macroArgs, model, true, selectedCells, this._errors);
|
||||
}
|
||||
|
||||
get errors() {
|
||||
return this._errors;
|
||||
}
|
||||
|
||||
getRowStatus(index): GriderRowStatus {
|
||||
const row = this.model.rows[index];
|
||||
return {
|
||||
status: (row && row.__rowStatus) || 'regular',
|
||||
modifiedFields: convertToSet(row, '__modifiedFields'),
|
||||
insertedFields: convertToSet(row, '__insertedFields'),
|
||||
deletedFields: convertToSet(row, '__deletedFields'),
|
||||
};
|
||||
}
|
||||
|
||||
getRowData(index: any) {
|
||||
return this.model.rows[index];
|
||||
}
|
||||
get rowCount() {
|
||||
return this.model.rows.length;
|
||||
}
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
const macros = [
|
||||
{
|
||||
title: 'Remove diacritics',
|
||||
name: 'removeDiacritics',
|
||||
group: 'Text',
|
||||
description: 'Removes diacritics from selected cells',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.deburr(value)`,
|
||||
},
|
||||
{
|
||||
title: 'Search & replace text',
|
||||
name: 'stringReplace',
|
||||
group: 'Text',
|
||||
description: 'Search & replace text or regular expression',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Find',
|
||||
name: 'find',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Replace with',
|
||||
name: 'replace',
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Case sensitive',
|
||||
name: 'caseSensitive',
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Regular expression',
|
||||
name: 'isRegex',
|
||||
},
|
||||
],
|
||||
code: `
|
||||
const rtext = args.isRegex ? args.find : modules.lodash.escapeRegExp(args.find);
|
||||
const rflags = args.caseSensitive ? 'g' : 'ig';
|
||||
return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace || '') : value
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Change text case',
|
||||
name: 'changeTextCase',
|
||||
group: 'Text',
|
||||
description: 'Uppercase, lowercase and other case functions',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'select',
|
||||
options: ['toUpper', 'toLower', 'lowerCase', 'upperCase', 'kebabCase', 'snakeCase', 'camelCase', 'startCase'],
|
||||
label: 'Type',
|
||||
name: 'type',
|
||||
default: 'toUpper',
|
||||
},
|
||||
],
|
||||
code: `return modules.lodash[args.type](value)`,
|
||||
},
|
||||
{
|
||||
title: 'Row index',
|
||||
name: 'rowIndex',
|
||||
group: 'Tools',
|
||||
description: 'Index of row from 1 (autoincrement)',
|
||||
type: 'transformValue',
|
||||
code: `return rowIndex + 1`,
|
||||
},
|
||||
{
|
||||
title: 'Generate UUID',
|
||||
name: 'uuidv1',
|
||||
group: 'Tools',
|
||||
description: 'Generate unique identifier',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: 'uuidv1', name: 'V1 - from timestamp' },
|
||||
{ value: 'uuidv4', name: 'V4 - random generated' },
|
||||
],
|
||||
label: 'Version',
|
||||
name: 'version',
|
||||
default: 'uuidv1',
|
||||
},
|
||||
],
|
||||
code: `return modules[args.version]()`,
|
||||
},
|
||||
{
|
||||
title: 'Current date',
|
||||
name: 'currentDate',
|
||||
group: 'Tools',
|
||||
description: 'Gets current date',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Format',
|
||||
name: 'format',
|
||||
default: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
],
|
||||
code: `return modules.moment().format(args.format)`,
|
||||
},
|
||||
{
|
||||
title: 'Duplicate rows',
|
||||
name: 'duplicateRows',
|
||||
group: 'Tools',
|
||||
description: 'Duplicate selected rows',
|
||||
type: 'transformRows',
|
||||
code: `
|
||||
const selectedRowIndexes = modules.lodash.uniq(selectedCells.map(x => x.row));
|
||||
const selectedRows = modules.lodash.groupBy(selectedCells, 'row');
|
||||
const maxIndex = modules.lodash.max(selectedRowIndexes);
|
||||
return [
|
||||
...rows.slice(0, maxIndex + 1),
|
||||
...selectedRowIndexes.map(index => ({
|
||||
...modules.lodash.pick(rows[index], selectedRows[index].map(x => x.column)),
|
||||
__rowStatus: 'inserted',
|
||||
})),
|
||||
...rows.slice(maxIndex + 1),
|
||||
]
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Delete empty rows',
|
||||
name: 'deleteEmptyRows',
|
||||
group: 'Tools',
|
||||
description: 'Delete empty rows - rows with all values null or empty string',
|
||||
type: 'transformRows',
|
||||
code: `
|
||||
return rows.map(row => {
|
||||
if (cols.find(col => row[col])) return row;
|
||||
return {
|
||||
...row,
|
||||
__rowStatus: 'deleted',
|
||||
};
|
||||
})
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Duplicate columns',
|
||||
name: 'duplicateColumns',
|
||||
group: 'Tools',
|
||||
description: 'Duplicate selected columns',
|
||||
type: 'transformData',
|
||||
code: `
|
||||
const selectedColumnNames = modules.lodash.uniq(selectedCells.map(x => x.column));
|
||||
const selectedRowIndexes = modules.lodash.uniq(selectedCells.map(x => x.row));
|
||||
const addedColumnNames = selectedColumnNames.map(col => (args.prefix || '') + col + (args.postfix || ''));
|
||||
const resultRows = rows.map((row, rowIndex) => ({
|
||||
...row,
|
||||
...(selectedRowIndexes.includes(rowIndex) ? modules.lodash.fromPairs(selectedColumnNames.map(col => [(args.prefix || '') + col + (args.postfix || ''), row[col]])) : {}),
|
||||
__insertedFields: addedColumnNames,
|
||||
}));
|
||||
const resultCols = [
|
||||
...cols,
|
||||
...addedColumnNames,
|
||||
];
|
||||
return {
|
||||
rows: resultRows,
|
||||
cols: resultCols,
|
||||
}
|
||||
`,
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Prefix',
|
||||
name: 'prefix',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Postfix',
|
||||
name: 'postfix',
|
||||
default: '_copy',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Extract date fields',
|
||||
name: 'extractDateFields',
|
||||
group: 'Tools',
|
||||
description: 'Extract yaear, month, day and other date/time fields from selection and adds it as new columns',
|
||||
type: 'transformData',
|
||||
code: `
|
||||
const selectedColumnNames = modules.lodash.uniq(selectedCells.map(x => x.column));
|
||||
const selectedRowIndexes = modules.lodash.uniq(selectedCells.map(x => x.row));
|
||||
const addedColumnNames = modules.lodash.compact([args.year, args.month, args.day, args.hour, args.minute, args.second]);
|
||||
const selectedRows = modules.lodash.groupBy(selectedCells, 'row');
|
||||
const resultRows = rows.map((row, rowIndex) => {
|
||||
if (!selectedRowIndexes.includes(rowIndex)) return {
|
||||
...row,
|
||||
__insertedFields: addedColumnNames,
|
||||
};
|
||||
let mom = null;
|
||||
for(const cell of selectedRows[rowIndex]) {
|
||||
const m = modules.moment(row[cell.column]);
|
||||
if (m.isValid()) {
|
||||
mom = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mom) return {
|
||||
...row,
|
||||
__insertedFields: addedColumnNames,
|
||||
};
|
||||
|
||||
const fields = {
|
||||
[args.year]: mom.year(),
|
||||
[args.month]: mom.month() + 1,
|
||||
[args.day]: mom.day(),
|
||||
[args.hour]: mom.hour(),
|
||||
[args.minute]: mom.minute(),
|
||||
[args.second]: mom.second(),
|
||||
};
|
||||
|
||||
return {
|
||||
...row,
|
||||
...modules.lodash.pick(fields, addedColumnNames),
|
||||
__insertedFields: addedColumnNames,
|
||||
}
|
||||
});
|
||||
const resultCols = [
|
||||
...cols,
|
||||
...addedColumnNames,
|
||||
];
|
||||
return {
|
||||
rows: resultRows,
|
||||
cols: resultCols,
|
||||
}
|
||||
`,
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Year name',
|
||||
name: 'year',
|
||||
default: 'year',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Month name',
|
||||
name: 'month',
|
||||
default: 'month',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Day name',
|
||||
name: 'day',
|
||||
default: 'day',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Hour name',
|
||||
name: 'hour',
|
||||
default: 'hour',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Minute name',
|
||||
name: 'minute',
|
||||
default: 'minute',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Second name',
|
||||
name: 'second',
|
||||
default: 'second',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default macros;
|
||||
@@ -1,14 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import useOpenNewTab from '../utility/useOpenNewTab';
|
||||
|
||||
export default function useNewFreeTable() {
|
||||
const openNewTab = useOpenNewTab();
|
||||
|
||||
return ({ title = undefined, ...props } = {}) =>
|
||||
openNewTab({
|
||||
title: title || 'Data #',
|
||||
icon: 'img free-table',
|
||||
tabComponent: 'FreeTableTab',
|
||||
props,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user