mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 08:03:58 +00:00
removed free table (data sheet) concept
This commit is contained in:
@@ -3,7 +3,6 @@ const readline = require('readline');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
|
const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const { saveFreeTableData } = require('../utility/freeTableStorage');
|
|
||||||
const loadFilesRecursive = require('../utility/loadFilesRecursive');
|
const loadFilesRecursive = require('../utility/loadFilesRecursive');
|
||||||
const getJslFileName = require('../utility/getJslFileName');
|
const getJslFileName = require('../utility/getJslFileName');
|
||||||
const { getLogger } = require('dbgate-tools');
|
const { getLogger } = require('dbgate-tools');
|
||||||
@@ -162,34 +161,6 @@ module.exports = {
|
|||||||
return true;
|
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,
|
saveText_meta: true,
|
||||||
async saveText({ folder, file, text }) {
|
async saveText({ folder, file, text }) {
|
||||||
await fs.writeFile(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), text);
|
await fs.writeFile(path.join(resolveArchiveFolder(folder), `${file}.jsonl`), text);
|
||||||
@@ -206,6 +177,17 @@ module.exports = {
|
|||||||
return true;
|
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 }) {
|
async getNewArchiveFolder({ database }) {
|
||||||
const isLink = database.endsWith(database);
|
const isLink = database.endsWith(database);
|
||||||
const name = isLink ? database.slice(0, -5) : database;
|
const name = isLink ? database.slice(0, -5) : database;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ const lineReader = require('line-reader');
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { __ } = require('lodash/fp');
|
const { __ } = require('lodash/fp');
|
||||||
const DatastoreProxy = require('../utility/DatastoreProxy');
|
const DatastoreProxy = require('../utility/DatastoreProxy');
|
||||||
const { saveFreeTableData } = require('../utility/freeTableStorage');
|
|
||||||
const getJslFileName = require('../utility/getJslFileName');
|
const getJslFileName = require('../utility/getJslFileName');
|
||||||
const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
|
const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
|
||||||
const requirePluginFunction = require('../utility/requirePluginFunction');
|
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,
|
saveText_meta: true,
|
||||||
async saveText({ jslid, text }) {
|
async saveText({ jslid, text }) {
|
||||||
await fs.promises.writeFile(getJslFileName(jslid), text);
|
await fs.promises.writeFile(getJslFileName(jslid), text);
|
||||||
return true;
|
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,
|
extractTimelineChart_meta: true,
|
||||||
async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
|
async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
|
||||||
const timestamp = requirePluginFunction(timestampFunction);
|
const timestamp = requirePluginFunction(timestampFunction);
|
||||||
|
|||||||
@@ -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,
|
|
||||||
};
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { FreeTableModel } from './FreeTableModel';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import uuidv1 from 'uuid/v1';
|
import uuidv1 from 'uuid/v1';
|
||||||
import uuidv4 from 'uuid/v4';
|
import uuidv4 from 'uuid/v4';
|
||||||
@@ -27,160 +26,6 @@ const modules = {
|
|||||||
moment,
|
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 = []) {
|
export function compileMacroFunction(macro: MacroDefinition, errors = []) {
|
||||||
if (!macro) return null;
|
if (!macro) return null;
|
||||||
let func;
|
let func;
|
||||||
|
|||||||
@@ -111,24 +111,6 @@
|
|||||||
const handleOpenArchive = () => {
|
const handleOpenArchive = () => {
|
||||||
openArchive(data.fileName, data.folderName);
|
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 = () => {
|
const handleClick = () => {
|
||||||
if (data.fileType == 'jsonl') {
|
if (data.fileType == 'jsonl') {
|
||||||
handleOpenArchive();
|
handleOpenArchive();
|
||||||
@@ -153,7 +135,6 @@
|
|||||||
function createMenu() {
|
function createMenu() {
|
||||||
return [
|
return [
|
||||||
data.fileType == 'jsonl' && { text: 'Open', onClick: handleOpenArchive },
|
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 },
|
data.fileType == 'jsonl' && { text: 'Open in text editor', onClick: handleOpenJsonLinesText },
|
||||||
{ text: 'Delete', onClick: handleDelete },
|
{ text: 'Delete', onClick: handleDelete },
|
||||||
{ text: 'Rename', onClick: handleRename },
|
{ text: 'Rename', onClick: handleRename },
|
||||||
|
|||||||
@@ -102,10 +102,6 @@
|
|||||||
isImport: true,
|
isImport: true,
|
||||||
requiresWriteAccess: true,
|
requiresWriteAccess: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Open as data sheet',
|
|
||||||
isOpenFreeTable: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Open active chart',
|
label: 'Open active chart',
|
||||||
isActiveChart: true,
|
isActiveChart: true,
|
||||||
@@ -176,10 +172,6 @@
|
|||||||
isExport: true,
|
isExport: true,
|
||||||
functionName: 'tableReader',
|
functionName: 'tableReader',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Open as data sheet',
|
|
||||||
isOpenFreeTable: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Open active chart',
|
label: 'Open active chart',
|
||||||
isActiveChart: true,
|
isActiveChart: true,
|
||||||
@@ -242,10 +234,6 @@
|
|||||||
isExport: true,
|
isExport: true,
|
||||||
functionName: 'tableReader',
|
functionName: 'tableReader',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Open as data sheet',
|
|
||||||
isOpenFreeTable: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Open active chart',
|
label: 'Open active chart',
|
||||||
isActiveChart: true,
|
isActiveChart: true,
|
||||||
@@ -409,27 +397,7 @@
|
|||||||
return driver;
|
return driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (menu.isOpenFreeTable) {
|
if (menu.isActiveChart) {
|
||||||
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) {
|
|
||||||
const driver = await getDriver();
|
const driver = await getDriver();
|
||||||
const dmp = driver.createDumper();
|
const dmp = driver.createDumper();
|
||||||
dmp.put('^select * from %f', data);
|
dmp.put('^select * from %f', data);
|
||||||
|
|||||||
@@ -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({
|
registerCommand({
|
||||||
id: 'new.jsonl',
|
id: 'new.jsonl',
|
||||||
category: 'New',
|
category: 'New',
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
|
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
|
||||||
import ColumnManager from './ColumnManager.svelte';
|
import ColumnManager from './ColumnManager.svelte';
|
||||||
import ReferenceManager from './ReferenceManager.svelte';
|
import ReferenceManager from './ReferenceManager.svelte';
|
||||||
import FreeTableColumnEditor from '../freetable/FreeTableColumnEditor.svelte';
|
|
||||||
import JsonViewFilters from '../jsonview/JsonViewFilters.svelte';
|
import JsonViewFilters from '../jsonview/JsonViewFilters.svelte';
|
||||||
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -201,7 +200,6 @@
|
|||||||
height="40%"
|
height="40%"
|
||||||
show={freeTableColumn && !isDynamicStructure}
|
show={freeTableColumn && !isDynamicStructure}
|
||||||
>
|
>
|
||||||
<FreeTableColumnEditor {...$$props} {managerSize} />
|
|
||||||
</WidgetColumnBarItem>
|
</WidgetColumnBarItem>
|
||||||
|
|
||||||
<WidgetColumnBarItem title="Filters" name="filters" height="30%" show={isFormView}>
|
<WidgetColumnBarItem title="Filters" name="filters" height="30%" show={isFormView}>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import CellValue from './CellValue.svelte';
|
import CellValue from './CellValue.svelte';
|
||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
import EditCellDataModal from '../modals/EditCellDataModal.svelte';
|
import EditCellDataModal from '../modals/EditCellDataModal.svelte';
|
||||||
|
import { openJsonLinesData } from '../utility/openJsonLinesData';
|
||||||
|
|
||||||
export let rowIndex;
|
export let rowIndex;
|
||||||
export let col;
|
export let col;
|
||||||
@@ -96,20 +97,7 @@
|
|||||||
icon="icon open-in-new"
|
icon="icon open-in-new"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (_.every(jsonParsedValue || value, x => _.isPlainObject(x))) {
|
if (_.every(jsonParsedValue || value, x => _.isPlainObject(x))) {
|
||||||
openNewTab(
|
openJsonLinesData(jsonParsedValue || value);
|
||||||
{
|
|
||||||
title: 'Data #',
|
|
||||||
icon: 'img free-table',
|
|
||||||
tabComponent: 'FreeTableTab',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
editor: {
|
|
||||||
rows: jsonParsedValue || value,
|
|
||||||
structure: { __isDynamicStructure: true, columns: [] },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
openJsonDocument(jsonParsedValue || value, undefined, true);
|
openJsonDocument(jsonParsedValue || value, undefined, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@
|
|||||||
registerCommand({
|
registerCommand({
|
||||||
id: 'dataGrid.openJsonArrayInSheet',
|
id: 'dataGrid.openJsonArrayInSheet',
|
||||||
category: 'Data grid',
|
category: 'Data grid',
|
||||||
name: 'Open array as data sheet',
|
name: 'Open array as table',
|
||||||
testEnabled: () => getCurrentDataGrid()?.openJsonArrayInSheetEnabled(),
|
testEnabled: () => getCurrentDataGrid()?.openJsonArrayInSheetEnabled(),
|
||||||
onClick: () => getCurrentDataGrid().openJsonArrayInSheet(),
|
onClick: () => getCurrentDataGrid().openJsonArrayInSheet(),
|
||||||
});
|
});
|
||||||
@@ -238,7 +238,7 @@
|
|||||||
registerCommand({
|
registerCommand({
|
||||||
id: 'dataGrid.openFreeTable',
|
id: 'dataGrid.openFreeTable',
|
||||||
category: 'Data grid',
|
category: 'Data grid',
|
||||||
name: 'Edit selection as data sheet',
|
name: 'Edit selection as table',
|
||||||
testEnabled: () => getCurrentDataGrid() != null,
|
testEnabled: () => getCurrentDataGrid() != null,
|
||||||
onClick: () => getCurrentDataGrid().openFreeTable(),
|
onClick: () => getCurrentDataGrid().openFreeTable(),
|
||||||
});
|
});
|
||||||
@@ -398,6 +398,7 @@
|
|||||||
import EditCellDataModal, { shouldOpenMultilineDialog } from '../modals/EditCellDataModal.svelte';
|
import EditCellDataModal, { shouldOpenMultilineDialog } from '../modals/EditCellDataModal.svelte';
|
||||||
import { getDatabaseInfo, useDatabaseStatus } from '../utility/metadataLoaders';
|
import { getDatabaseInfo, useDatabaseStatus } from '../utility/metadataLoaders';
|
||||||
import { showSnackbarSuccess } from '../utility/snackbar';
|
import { showSnackbarSuccess } from '../utility/snackbar';
|
||||||
|
import { openJsonLinesData } from '../utility/openJsonLinesData';
|
||||||
|
|
||||||
export let onLoadNextData = undefined;
|
export let onLoadNextData = undefined;
|
||||||
export let grider = undefined;
|
export let grider = undefined;
|
||||||
@@ -645,15 +646,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function openFreeTable() {
|
export function openFreeTable() {
|
||||||
openNewTab(
|
openJsonLinesData(getSelectedFreeDataRows());
|
||||||
{
|
|
||||||
title: 'Data #',
|
|
||||||
icon: 'img free-table',
|
|
||||||
tabComponent: 'FreeTableTab',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
{ editor: getSelectedFreeData() }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openChartFromSelection() {
|
export function openChartFromSelection() {
|
||||||
@@ -784,20 +777,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function openJsonArrayInSheet() {
|
export function openJsonArrayInSheet() {
|
||||||
openNewTab(
|
openJsonLinesData(getSelectedDataJson(true));
|
||||||
{
|
|
||||||
title: 'Data #',
|
|
||||||
icon: 'img free-table',
|
|
||||||
tabComponent: 'FreeTableTab',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
editor: {
|
|
||||||
rows: getSelectedDataJson(true),
|
|
||||||
structure: { __isDynamicStructure: true, columns: [] },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editJsonEnabled() {
|
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) {
|
function getCellsPublished(cells) {
|
||||||
const regular = cellsToRegularCells(cells);
|
const regular = cellsToRegularCells(cells);
|
||||||
const res = regular
|
const res = regular
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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 />
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
import openNewTab from '../utility/openNewTab';
|
import openNewTab from '../utility/openNewTab';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { copyTextToClipboard } from '../utility/clipboard';
|
import { copyTextToClipboard } from '../utility/clipboard';
|
||||||
|
import { openJsonLinesData } from '../utility/openJsonLinesData';
|
||||||
|
|
||||||
setContext('json-tree-context-key', {});
|
setContext('json-tree-context-key', {});
|
||||||
|
|
||||||
@@ -49,22 +50,9 @@
|
|||||||
|
|
||||||
if (value && _.isArray(value)) {
|
if (value && _.isArray(value)) {
|
||||||
res.push({
|
res.push({
|
||||||
text: 'Open as data sheet',
|
text: 'Open as table',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openNewTab(
|
openJsonLinesData(value);
|
||||||
{
|
|
||||||
title: 'Data #',
|
|
||||||
icon: 'img free-table',
|
|
||||||
tabComponent: 'FreeTableTab',
|
|
||||||
props: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
editor: {
|
|
||||||
rows: value,
|
|
||||||
structure: { __isDynamicStructure: true, columns: [] },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}
|
|
||||||
@@ -5,7 +5,6 @@ import * as TableStructureTab from './TableStructureTab.svelte';
|
|||||||
import * as QueryTab from './QueryTab.svelte';
|
import * as QueryTab from './QueryTab.svelte';
|
||||||
import * as ShellTab from './ShellTab.svelte';
|
import * as ShellTab from './ShellTab.svelte';
|
||||||
import * as ArchiveFileTab from './ArchiveFileTab.svelte';
|
import * as ArchiveFileTab from './ArchiveFileTab.svelte';
|
||||||
import * as FreeTableTab from './FreeTableTab.svelte';
|
|
||||||
import * as PluginTab from './PluginTab.svelte';
|
import * as PluginTab from './PluginTab.svelte';
|
||||||
import * as ChartTab from './ChartTab.svelte';
|
import * as ChartTab from './ChartTab.svelte';
|
||||||
import * as MarkdownEditorTab from './MarkdownEditorTab.svelte';
|
import * as MarkdownEditorTab from './MarkdownEditorTab.svelte';
|
||||||
@@ -38,7 +37,6 @@ export default {
|
|||||||
QueryTab,
|
QueryTab,
|
||||||
ShellTab,
|
ShellTab,
|
||||||
ArchiveFileTab,
|
ArchiveFileTab,
|
||||||
FreeTableTab,
|
|
||||||
PluginTab,
|
PluginTab,
|
||||||
ChartTab,
|
ChartTab,
|
||||||
MarkdownEditorTab,
|
MarkdownEditorTab,
|
||||||
|
|||||||
17
packages/web/src/utility/openJsonLinesData.ts
Normal file
17
packages/web/src/utility/openJsonLinesData.ts
Normal 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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -42,30 +42,26 @@
|
|||||||
apiCall('archive/refresh-files', { folder });
|
apiCall('archive/refresh-files', { folder });
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleNewDataSheet() {
|
function handleNewJsonLines() {
|
||||||
showModal(InputTextModal, {
|
showModal(InputTextModal, {
|
||||||
value: '',
|
value: '',
|
||||||
label: 'New file name',
|
label: 'New file name',
|
||||||
header: 'Create new data sheet',
|
header: 'Create new JSON lines',
|
||||||
onConfirm: async file => {
|
onConfirm: async file => {
|
||||||
await apiCall('archive/save-free-table', {
|
await apiCall('archive/save-rows', {
|
||||||
folder: $currentArchive,
|
folder: $currentArchive,
|
||||||
file,
|
file,
|
||||||
data: createFreeTableModel(),
|
rows: [
|
||||||
|
{ id: 1, value: 'val1' },
|
||||||
|
{ id: 1, value: 'val2' },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
openNewTab({
|
openNewTab({
|
||||||
title: file,
|
title: file,
|
||||||
icon: 'img free-table',
|
icon: 'img archive',
|
||||||
tabComponent: 'FreeTableTab',
|
tabComponent: 'ArchiveFileTab',
|
||||||
props: {
|
props: {
|
||||||
initialArgs: {
|
|
||||||
functionName: 'archiveReader',
|
|
||||||
props: {
|
|
||||||
fileName: file,
|
|
||||||
folderName: $currentArchive,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
archiveFile: file,
|
archiveFile: file,
|
||||||
archiveFolder: $currentArchive,
|
archiveFolder: $currentArchive,
|
||||||
},
|
},
|
||||||
@@ -75,7 +71,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createAddMenu() {
|
function createAddMenu() {
|
||||||
return [{ text: 'New data sheet', onClick: handleNewDataSheet }];
|
return [{ text: 'New NDJSON file', onClick: handleNewJsonLines }];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user