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

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