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,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>
</>
);
}

View File

@@ -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>
);
}

View File

@@ -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}
/>
);
}

View File

@@ -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;
}
}

View File

@@ -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>
);
}

View File

@@ -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>
</>
);
}

View File

@@ -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>
);
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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,
});
}