removed free table (data sheet) concept

This commit is contained in:
Jan Prochazka 2023-02-25 09:51:08 +01:00
parent 7c4a47c4c6
commit a77492440e
20 changed files with 65 additions and 857 deletions

View File

@ -3,7 +3,6 @@ const readline = require('readline');
const path = require('path');
const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
const socket = require('../utility/socket');
const { saveFreeTableData } = require('../utility/freeTableStorage');
const loadFilesRecursive = require('../utility/loadFilesRecursive');
const getJslFileName = require('../utility/getJslFileName');
const { getLogger } = require('dbgate-tools');
@ -162,34 +161,6 @@ module.exports = {
return true;
},
saveFreeTable_meta: true,
async saveFreeTable({ folder, file, data }) {
await saveFreeTableData(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), data);
socket.emitChanged(`archive-files-changed`, { folder });
return true;
},
loadFreeTable_meta: true,
async loadFreeTable({ folder, file }) {
return new Promise((resolve, reject) => {
const fileStream = fs.createReadStream(path.join(resolveArchiveFolder(folder), `${file}.jsonl`));
const liner = readline.createInterface({
input: fileStream,
});
let structure = null;
const rows = [];
liner.on('line', line => {
const data = JSON.parse(line);
if (structure) rows.push(data);
else structure = data;
});
liner.on('close', () => {
resolve({ structure, rows });
fileStream.close();
});
});
},
saveText_meta: true,
async saveText({ folder, file, text }) {
await fs.writeFile(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), text);
@ -206,6 +177,17 @@ module.exports = {
return true;
},
saveRows_meta: true,
async saveRows({ folder, file, rows }) {
const fileStream = fs.createWriteStream(path.join(resolveArchiveFolder(folder), `${file}.jsonl`));
for (const row of rows) {
await fileStream.write(JSON.stringify(row) + '\n');
}
await fileStream.close();
socket.emitChanged(`archive-files-changed`, { folder });
return true;
},
async getNewArchiveFolder({ database }) {
const isLink = database.endsWith(database);
const name = isLink ? database.slice(0, -5) : database;

View File

@ -4,7 +4,6 @@ const lineReader = require('line-reader');
const _ = require('lodash');
const { __ } = require('lodash/fp');
const DatastoreProxy = require('../utility/DatastoreProxy');
const { saveFreeTableData } = require('../utility/freeTableStorage');
const getJslFileName = require('../utility/getJslFileName');
const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
const requirePluginFunction = require('../utility/requirePluginFunction');
@ -189,18 +188,22 @@ module.exports = {
// }
},
saveFreeTable_meta: true,
async saveFreeTable({ jslid, data }) {
saveFreeTableData(getJslFileName(jslid), data);
return true;
},
saveText_meta: true,
async saveText({ jslid, text }) {
await fs.promises.writeFile(getJslFileName(jslid), text);
return true;
},
saveRows_meta: true,
async saveRows({ jslid, rows }) {
const fileStream = fs.createWriteStream(getJslFileName(jslid));
for (const row of rows) {
await fileStream.write(JSON.stringify(row) + '\n');
}
await fileStream.close();
return true;
},
extractTimelineChart_meta: true,
async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
const timestamp = requirePluginFunction(timestampFunction);

View File

@ -1,15 +0,0 @@
const fs = require('fs-extra');
async function saveFreeTableData(file, data) {
const { structure, rows } = data;
const fileStream = fs.createWriteStream(file);
await fileStream.write(JSON.stringify({ __isStreamHeader: true, ...structure }) + '\n');
for (const row of rows) {
await fileStream.write(JSON.stringify(row) + '\n');
}
await fileStream.close();
}
module.exports = {
saveFreeTableData,
};

View File

@ -1,48 +0,0 @@
import _ from 'lodash';
import type { EngineDriver, ViewInfo, ColumnInfo } from 'dbgate-types';
import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
import { GridConfig, GridCache } from './GridConfig';
import { FreeTableModel } from './FreeTableModel';
import { analyseCollectionDisplayColumns } from '.';
export class FreeTableGridDisplay extends GridDisplay {
constructor(
public model: FreeTableModel,
config: GridConfig,
setConfig: ChangeConfigFunc,
cache: GridCache,
setCache: ChangeCacheFunc
) {
super(config, setConfig, cache, setCache);
this.columns = model?.structure?.__isDynamicStructure
? analyseCollectionDisplayColumns(model?.rows, this)
: this.getDisplayColumns(model);
this.filterable = false;
this.sortable = false;
}
getDisplayColumns(model: FreeTableModel) {
return _.uniqBy(
model?.structure?.columns
?.map(col => this.getDisplayColumn(col))
?.map(col => ({
...col,
isChecked: this.isColumnChecked(col),
})) || [],
col => col.uniqueName
);
}
getDisplayColumn(col: ColumnInfo) {
const uniquePath = [col.columnName];
const uniqueName = uniquePath.join('.');
return {
...col,
pureName: 'data',
schemaName: '',
headerText: col.columnName,
uniqueName,
uniquePath,
};
}
}

View File

@ -1,27 +0,0 @@
import type { TableInfo } from 'dbgate-types';
export interface FreeTableModel {
structure: TableInfo;
rows: any[];
}
export function createFreeTableModel() {
return {
structure: {
columns: [
{
columnName: 'col1',
},
],
foreignKeys: [],
},
rows: [
{
col1: 'val1',
},
{
col1: 'val2',
},
],
};
}

View File

@ -1,4 +1,3 @@
import { FreeTableModel } from './FreeTableModel';
import _ from 'lodash';
import uuidv1 from 'uuid/v1';
import uuidv4 from 'uuid/v4';
@ -27,160 +26,6 @@ const modules = {
moment,
};
// function runTramsformValue(
// func,
// macroArgs: {},
// data: FreeTableModel,
// preview: boolean,
// selectedCells: MacroSelectedCell[],
// errors: string[] = []
// ) {
// const selectedRows = _.groupBy(selectedCells, 'row');
// const rows = data.rows.map((row, rowIndex) => {
// const selectedRow = selectedRows[rowIndex];
// if (selectedRow) {
// const modifiedFields = [];
// let res = null;
// for (const cell of selectedRow) {
// const { column } = cell;
// const oldValue = row[column];
// let newValue = oldValue;
// try {
// newValue = func(oldValue, macroArgs, modules, rowIndex, row, column);
// } catch (err) {
// errors.push(`Error processing column ${column} on row ${rowIndex}: ${err.message}`);
// }
// if (newValue != oldValue) {
// if (res == null) {
// res = { ...row };
// }
// res[column] = newValue;
// if (preview) modifiedFields.push(column);
// }
// }
// if (res) {
// if (modifiedFields.length > 0) {
// return {
// ...res,
// __modifiedFields: new Set(modifiedFields),
// };
// }
// return res;
// }
// return row;
// } else {
// return row;
// }
// });
// return {
// structure: data.structure,
// rows,
// };
// }
// function removePreviewRowFlags(rows) {
// rows = rows.filter(row => row.__rowStatus != 'deleted');
// rows = rows.map(row => {
// if (row.__rowStatus || row.__modifiedFields || row.__insertedFields || row.__deletedFields)
// return _.omit(row, ['__rowStatus', '__modifiedFields', '__insertedFields', '__deletedFields']);
// return row;
// });
// return rows;
// }
// function runTramsformRows(
// func,
// macroArgs: {},
// data: FreeTableModel,
// preview: boolean,
// selectedCells: MacroSelectedCell[],
// errors: string[] = []
// ) {
// let rows = data.rows;
// try {
// rows = func(
// data.rows,
// macroArgs,
// modules,
// selectedCells,
// data.structure.columns.map(x => x.columnName),
// data.structure.columns
// );
// if (!preview) {
// rows = removePreviewRowFlags(rows);
// }
// } catch (err) {
// errors.push(`Error processing rows: ${err.message}`);
// }
// return {
// structure: data.structure,
// rows,
// };
// }
// function runTramsformData(
// func,
// macroArgs: {},
// data: FreeTableModel,
// preview: boolean,
// selectedCells: MacroSelectedCell[],
// errors: string[] = []
// ) {
// try {
// let { rows, columns, cols } = func(
// data.rows,
// macroArgs,
// modules,
// selectedCells,
// data.structure.columns.map(x => x.columnName),
// data.structure.columns
// );
// if (cols && !columns) {
// columns = cols.map(columnName => ({ columnName }));
// }
// columns = _.uniqBy(columns, 'columnName');
// if (!preview) {
// rows = removePreviewRowFlags(rows);
// }
// return {
// structure: { columns },
// rows,
// };
// } catch (err) {
// errors.push(`Error processing data: ${err.message}`);
// }
// return data;
// }
// export function runMacro(
// macro: MacroDefinition,
// macroArgs: {},
// data: FreeTableModel,
// preview: boolean,
// selectedCells: MacroSelectedCell[],
// errors: string[] = []
// ): FreeTableModel {
// let func;
// try {
// func = eval(getMacroFunction[macro.type](macro.code));
// } catch (err) {
// errors.push(`Error compiling macro ${macro.name}: ${err.message}`);
// return data;
// }
// if (macro.type == 'transformValue') {
// return runTramsformValue(func, macroArgs, data, preview, selectedCells, errors);
// }
// if (macro.type == 'transformRows') {
// return runTramsformRows(func, macroArgs, data, preview, selectedCells, errors);
// }
// if (macro.type == 'transformData') {
// // @ts-ignore
// return runTramsformData(func, macroArgs, data, preview, selectedCells, errors);
// }
// return data;
// }
export function compileMacroFunction(macro: MacroDefinition, errors = []) {
if (!macro) return null;
let func;

View File

@ -111,24 +111,6 @@
const handleOpenArchive = () => {
openArchive(data.fileName, data.folderName);
};
const handleOpenDataSheet = () => {
openNewTab({
title: data.fileName,
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {
initialArgs: {
functionName: 'archiveReader',
props: {
fileName: data.fileName,
folderName: data.folderName,
},
},
archiveFile: data.fileName,
archiveFolder: data.folderName,
},
});
};
const handleClick = () => {
if (data.fileType == 'jsonl') {
handleOpenArchive();
@ -153,7 +135,6 @@
function createMenu() {
return [
data.fileType == 'jsonl' && { text: 'Open', onClick: handleOpenArchive },
data.fileType == 'jsonl' && { text: 'Open as data sheet', onClick: handleOpenDataSheet },
data.fileType == 'jsonl' && { text: 'Open in text editor', onClick: handleOpenJsonLinesText },
{ text: 'Delete', onClick: handleDelete },
{ text: 'Rename', onClick: handleRename },

View File

@ -102,10 +102,6 @@
isImport: true,
requiresWriteAccess: true,
},
{
label: 'Open as data sheet',
isOpenFreeTable: true,
},
{
label: 'Open active chart',
isActiveChart: true,
@ -176,10 +172,6 @@
isExport: true,
functionName: 'tableReader',
},
{
label: 'Open as data sheet',
isOpenFreeTable: true,
},
{
label: 'Open active chart',
isActiveChart: true,
@ -242,10 +234,6 @@
isExport: true,
functionName: 'tableReader',
},
{
label: 'Open as data sheet',
isOpenFreeTable: true,
},
{
label: 'Open active chart',
isActiveChart: true,
@ -409,27 +397,7 @@
return driver;
};
if (menu.isOpenFreeTable) {
const coninfo = await getConnectionInfo(data);
openNewTab({
title: data.pureName,
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {
initialArgs: {
functionName: 'tableReader',
props: {
connection: {
...coninfo,
database: data.database,
},
schemaName: data.schemaName,
pureName: data.pureName,
},
},
},
});
} else if (menu.isActiveChart) {
if (menu.isActiveChart) {
const driver = await getDriver();
const dmp = driver.createDumper();
dmp.put('^select * from %f', data);

View File

@ -329,21 +329,6 @@ registerCommand({
},
});
registerCommand({
id: 'new.freetable',
category: 'New',
icon: 'img markdown',
name: 'Data sheet',
menuName: 'New data sheet',
onClick: () => {
openNewTab({
title: 'Data #',
icon: 'img free-table',
tabComponent: 'FreeTableTab',
});
},
});
registerCommand({
id: 'new.jsonl',
category: 'New',

View File

@ -63,7 +63,6 @@
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
import ColumnManager from './ColumnManager.svelte';
import ReferenceManager from './ReferenceManager.svelte';
import FreeTableColumnEditor from '../freetable/FreeTableColumnEditor.svelte';
import JsonViewFilters from '../jsonview/JsonViewFilters.svelte';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import _ from 'lodash';
@ -201,7 +200,6 @@
height="40%"
show={freeTableColumn && !isDynamicStructure}
>
<FreeTableColumnEditor {...$$props} {managerSize} />
</WidgetColumnBarItem>
<WidgetColumnBarItem title="Filters" name="filters" height="30%" show={isFormView}>

View File

@ -7,6 +7,7 @@
import CellValue from './CellValue.svelte';
import { showModal } from '../modals/modalTools';
import EditCellDataModal from '../modals/EditCellDataModal.svelte';
import { openJsonLinesData } from '../utility/openJsonLinesData';
export let rowIndex;
export let col;
@ -96,20 +97,7 @@
icon="icon open-in-new"
on:click={() => {
if (_.every(jsonParsedValue || value, x => _.isPlainObject(x))) {
openNewTab(
{
title: 'Data #',
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {},
},
{
editor: {
rows: jsonParsedValue || value,
structure: { __isDynamicStructure: true, columns: [] },
},
}
);
openJsonLinesData(jsonParsedValue || value);
} else {
openJsonDocument(jsonParsedValue || value, undefined, true);
}

View File

@ -161,7 +161,7 @@
registerCommand({
id: 'dataGrid.openJsonArrayInSheet',
category: 'Data grid',
name: 'Open array as data sheet',
name: 'Open array as table',
testEnabled: () => getCurrentDataGrid()?.openJsonArrayInSheetEnabled(),
onClick: () => getCurrentDataGrid().openJsonArrayInSheet(),
});
@ -238,7 +238,7 @@
registerCommand({
id: 'dataGrid.openFreeTable',
category: 'Data grid',
name: 'Edit selection as data sheet',
name: 'Edit selection as table',
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().openFreeTable(),
});
@ -398,6 +398,7 @@
import EditCellDataModal, { shouldOpenMultilineDialog } from '../modals/EditCellDataModal.svelte';
import { getDatabaseInfo, useDatabaseStatus } from '../utility/metadataLoaders';
import { showSnackbarSuccess } from '../utility/snackbar';
import { openJsonLinesData } from '../utility/openJsonLinesData';
export let onLoadNextData = undefined;
export let grider = undefined;
@ -645,15 +646,7 @@
}
export function openFreeTable() {
openNewTab(
{
title: 'Data #',
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {},
},
{ editor: getSelectedFreeData() }
);
openJsonLinesData(getSelectedFreeDataRows());
}
export function openChartFromSelection() {
@ -784,20 +777,7 @@
}
export function openJsonArrayInSheet() {
openNewTab(
{
title: 'Data #',
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {},
},
{
editor: {
rows: getSelectedDataJson(true),
structure: { __isDynamicStructure: true, columns: [] },
},
}
);
openJsonLinesData(getSelectedDataJson(true));
}
export function editJsonEnabled() {
@ -1109,6 +1089,12 @@
};
};
const getSelectedFreeDataRows = () => {
const columns = getSelectedColumns();
const rows = getSelectedRowData().map(row => _.pickBy(row, (v, col) => columns.find(x => x.columnName == col)));
return rows;
};
function getCellsPublished(cells) {
const regular = cellsToRegularCells(cells);
const res = regular

View File

@ -1,82 +0,0 @@
<script context="module">
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),
},
},
});
}
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;
}
</script>
<script>
import _ from 'lodash';
import ManagerInnerContainer from '../elements/ManagerInnerContainer.svelte';
import ColumnManagerRow from './ColumnManagerRow.svelte';
import ColumnNameEditor from './ColumnNameEditor.svelte';
export let modelState;
export let dispatchModel;
export let managerSize;
let editingColumn = null;
$: structure = modelState.value.structure;
</script>
<ManagerInnerContainer width={managerSize}>
{#each structure?.columns || [] as column, index}
{#if 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={() => (editingColumn = null)}
focusOnCreate
blurOnEnter
existingNames={structure?.columns.map(x => x.columnName)}
/>
{:else}
<ColumnManagerRow
{column}
onEdit={() => (editingColumn = 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));
}}
/>
{/if}
{/each}
<ColumnNameEditor
onEnter={columnName => {
dispatchChangeColumns($$props, cols => [...cols, { columnName }]);
}}
placeholder="New column"
existingNames={(structure?.columns || []).map(x => x.columnName)}
/>
</ManagerInnerContainer>

View File

@ -1,84 +0,0 @@
<script context="module" lang="ts">
const getCurrentEditor = () => getActiveComponent('FreeTableGridCore');
registerCommand({
id: 'freeTableGrid.export',
category: 'Data grid',
icon: 'icon export',
name: 'Export',
keyText: 'CtrlOrCommand+E',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().exportGrid(),
});
</script>
<script lang="ts">
import { createGridCache, FreeTableGridDisplay } from 'dbgate-datalib';
import { writable } from 'svelte/store';
import uuidv1 from 'uuid/v1';
import { registerQuickExportHandler } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import DataGridCore from '../datagrid/DataGridCore.svelte';
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import { apiCall } from '../utility/api';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createQuickExportMenu from '../utility/createQuickExportMenu';
import { exportQuickExportFile } from '../utility/exportFileTools';
import FreeTableGrider from './FreeTableGrider';
import MacroPreviewGrider from './MacroPreviewGrider';
export let macroPreview;
export let modelState;
export let dispatchModel;
export let macroValues;
export let config;
export let setConfig;
export let selectedCellsPublished;
export const activator = createActivator('FreeTableGridCore', false);
const cache = writable(createGridCache());
$: grider = macroPreview
? new MacroPreviewGrider(modelState.value, macroPreview, macroValues, selectedCellsPublished())
: new FreeTableGrider(modelState, dispatchModel);
$: display = new FreeTableGridDisplay(grider.model || modelState.value, config, setConfig, $cache, cache.update);
export async function exportGrid() {
const jslid = uuidv1();
await apiCall('jsldata/save-free-table', { jslid, data: modelState.value });
const initialValues: any = {};
initialValues.sourceStorageType = 'jsldata';
initialValues.sourceJslId = jslid;
initialValues.sourceList = ['editor-data'];
initialValues[`columns_editor-data`] = display.getExportColumnMap();
showModal(ImportExportModal, { initialValues: initialValues });
}
const quickExportHandler = fmt => async () => {
const jslid = uuidv1();
await apiCall('jsldata/save-free-table', { jslid, data: modelState.value });
exportQuickExportFile(
'editor-data',
{
functionName: 'jslDataReader',
props: {
jslid,
},
},
fmt,
display.getExportColumnMap()
);
};
registerQuickExportHandler(quickExportHandler);
registerMenu(() => ({
...createQuickExportMenu(quickExportHandler, { command: 'freeTableGrid.export' }),
tag: 'export',
}));
</script>
<DataGridCore {...$$props} {grider} {display} frameSelection={!!macroPreview} bind:selectedCellsPublished />

View File

@ -1,104 +0,0 @@
import type { FreeTableModel } from 'dbgate-datalib';
import Grider 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)),
};
}
}
setRowData(index: number, document: any) {
const model = this.currentModel;
if (model.rows[index]) {
this.currentModel = {
...model,
rows: model.rows.map((row, i) => (index == i ? document : 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;
}
insertDocuments(documents: any[]): number {
const model = this.currentModel;
this.currentModel = {
...model,
rows: [...model.rows, ...documents],
};
return this.currentModel.rows.length - documents.length;
}
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

@ -5,6 +5,7 @@
import openNewTab from '../utility/openNewTab';
import _ from 'lodash';
import { copyTextToClipboard } from '../utility/clipboard';
import { openJsonLinesData } from '../utility/openJsonLinesData';
setContext('json-tree-context-key', {});
@ -49,22 +50,9 @@
if (value && _.isArray(value)) {
res.push({
text: 'Open as data sheet',
text: 'Open as table',
onClick: () => {
openNewTab(
{
title: 'Data #',
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {},
},
{
editor: {
rows: value,
structure: { __isDynamicStructure: true, columns: [] },
},
}
);
openJsonLinesData(value);
},
});
}

View File

@ -1,167 +0,0 @@
<script lang="ts" context="module">
const getCurrentEditor = () => getActiveComponent('FreeTableTab');
registerCommand({
id: 'freeTable.save',
group: 'save',
category: 'Table data',
name: 'Save',
// keyText: 'CtrlOrCommand+S',
toolbar: true,
isRelatedToTab: true,
icon: 'icon save',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().save(),
});
registerCommand({
id: 'freeTable.toggleDynamicStructure',
category: 'Table data',
name: 'Toggle dynamic structure',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().toggleDynamicStructure(),
});
</script>
<script lang="ts">
import {
analyseCollectionDisplayColumns,
createFreeTableModel,
FreeTableGridDisplay,
runMacro,
} from 'dbgate-datalib';
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripExportButton, { createQuickExportHandlerRef } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import DataGrid from '../datagrid/DataGrid.svelte';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import FreeTableGridCore from '../freetable/FreeTableGridCore.svelte';
import { showModal } from '../modals/modalTools';
import SaveArchiveModal from '../modals/SaveArchiveModal.svelte';
import useEditorData from '../query/useEditorData';
import { apiCall } from '../utility/api';
import { changeTab } from '../utility/common';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createUndoReducer from '../utility/createUndoReducer';
import { getLocalStorage, setLocalStorage } from '../utility/storageCache';
import useGridConfig from '../utility/useGridConfig';
export let tabid;
export let initialArgs;
export let archiveFolder;
export let archiveFile;
export const activator = createActivator('FreeTableTab', true);
const config = useGridConfig(tabid);
const [modelState, dispatchModel] = createUndoReducer(createFreeTableModel());
const { setEditorData, editorState } = useEditorData({
tabid,
loadFromArgs: initialArgs && initialArgs.functionName ? () => apiCall('runners/load-reader', initialArgs) : null,
onInitialData: value => {
dispatchModel({ type: 'reset', value });
},
});
$: isLoading = $editorState.isLoading;
$: errorMessage = $editorState.errorMessage;
$: setEditorData($modelState.value);
export function save() {
showModal(SaveArchiveModal, {
folder: archiveFolder,
file: archiveFile,
onSave: doSave,
});
}
const doSave = async (folder, file) => {
await apiCall('archive/save-free-table', { folder, file, data: $modelState.value });
changeTab(tabid, tab => ({
...tab,
title: file,
props: { archiveFile: file, archiveFolder: folder },
archiveFile: file,
archiveFolder: folder,
}));
archiveFile = file;
archiveFolder = folder;
};
function handleRunMacro(macro, params, cells) {
const newModel = runMacro(macro, params, $modelState.value, false, cells);
dispatchModel({ type: 'set', value: newModel });
}
const collapsedLeftColumnStore = writable(getLocalStorage('freeTable_collapsedLeftColumn', false));
setContext('collapsedLeftColumnStore', collapsedLeftColumnStore);
$: setLocalStorage('freeTable_collapsedLeftColumn', $collapsedLeftColumnStore);
export function toggleDynamicStructure() {
let structure = $modelState.value.structure;
structure = { ...structure, __isDynamicStructure: !structure.__isDynamicStructure };
if (!structure.__isDynamicStructure) {
const columns = analyseCollectionDisplayColumns($modelState.value.rows, display);
structure = {
...structure,
columns: columns
.filter(col => col.uniquePath.length == 1)
.map(col => ({
columnName: col.uniqueName,
})),
};
}
dispatchModel({
type: 'set',
value: {
...$modelState.value,
structure,
},
});
}
registerMenu(
{ command: 'freeTable.save', tag: 'save' },
{ command: 'freeTable.toggleDynamicStructure', tag: 'export' }
);
// display is overridden in FreeTableGridCore, this is because of column manager
$: display = new FreeTableGridDisplay($modelState.value, $config, config.update, null, null);
const quickExportHandlerRef = createQuickExportHandlerRef();
</script>
{#if isLoading}
<LoadingInfo wrapper message="Loading data" />
{:else if errorMessage}
<ErrorInfo message={errorMessage} />
{:else}
<ToolStripContainer>
<DataGrid
config={$config}
setConfig={config.update}
modelState={$modelState}
{dispatchModel}
focusOnVisible
gridCoreComponent={FreeTableGridCore}
freeTableColumn
showMacros
expandMacros
onRunMacro={handleRunMacro}
isDynamicStructure={$modelState.value?.structure?.__isDynamicStructure}
{display}
/>
<svelte:fragment slot="toolstrip">
<ToolStripCommandButton command="freeTable.save" />
<ToolStripExportButton command="freeTableGrid.export" {quickExportHandlerRef} />
</svelte:fragment>
</ToolStripContainer>
{/if}

View File

@ -5,7 +5,6 @@ import * as TableStructureTab from './TableStructureTab.svelte';
import * as QueryTab from './QueryTab.svelte';
import * as ShellTab from './ShellTab.svelte';
import * as ArchiveFileTab from './ArchiveFileTab.svelte';
import * as FreeTableTab from './FreeTableTab.svelte';
import * as PluginTab from './PluginTab.svelte';
import * as ChartTab from './ChartTab.svelte';
import * as MarkdownEditorTab from './MarkdownEditorTab.svelte';
@ -38,7 +37,6 @@ export default {
QueryTab,
ShellTab,
ArchiveFileTab,
FreeTableTab,
PluginTab,
ChartTab,
MarkdownEditorTab,

View File

@ -0,0 +1,17 @@
import uuidv1 from 'uuid/v1';
import { apiCall } from './api';
import openNewTab from './openNewTab';
export async function openJsonLinesData(rows) {
const jslid = uuidv1();
await apiCall('jsldata/save-rows', { jslid, rows });
openNewTab({
tabComponent: 'ArchiveFileTab',
icon: 'img archive',
title: 'Data #',
props: {
jslid,
},
});
}

View File

@ -42,30 +42,26 @@
apiCall('archive/refresh-files', { folder });
};
function handleNewDataSheet() {
function handleNewJsonLines() {
showModal(InputTextModal, {
value: '',
label: 'New file name',
header: 'Create new data sheet',
header: 'Create new JSON lines',
onConfirm: async file => {
await apiCall('archive/save-free-table', {
await apiCall('archive/save-rows', {
folder: $currentArchive,
file,
data: createFreeTableModel(),
rows: [
{ id: 1, value: 'val1' },
{ id: 1, value: 'val2' },
],
});
openNewTab({
title: file,
icon: 'img free-table',
tabComponent: 'FreeTableTab',
icon: 'img archive',
tabComponent: 'ArchiveFileTab',
props: {
initialArgs: {
functionName: 'archiveReader',
props: {
fileName: file,
folderName: $currentArchive,
},
},
archiveFile: file,
archiveFolder: $currentArchive,
},
@ -75,7 +71,7 @@
}
function createAddMenu() {
return [{ text: 'New data sheet', onClick: handleNewDataSheet }];
return [{ text: 'New NDJSON file', onClick: handleNewJsonLines }];
}
</script>