mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 20:46:01 +00:00
cell data view
This commit is contained in:
@@ -45,6 +45,7 @@
|
|||||||
"file-selector": "^0.2.4",
|
"file-selector": "^0.2.4",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"sirv-cli": "^1.0.0",
|
"sirv-cli": "^1.0.0",
|
||||||
|
"svelte-json-tree": "^0.1.0",
|
||||||
"svelte-markdown": "^0.1.4",
|
"svelte-markdown": "^0.1.4",
|
||||||
"svelte-select": "^3.17.0"
|
"svelte-select": "^3.17.0"
|
||||||
}
|
}
|
||||||
|
|||||||
41
packages/web/src/celldata/JsonCellView.svelte
Normal file
41
packages/web/src/celldata/JsonCellView.svelte
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import JSONTree from 'svelte-json-tree';
|
||||||
|
import ErrorInfo from '../elements/ErrorInfo.svelte';
|
||||||
|
|
||||||
|
export let selection;
|
||||||
|
|
||||||
|
let json = null;
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
$: try {
|
||||||
|
json = JSON.parse(selection[0].value);
|
||||||
|
error = null;
|
||||||
|
} catch (err) {
|
||||||
|
error = err.message;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<ErrorInfo message="Error parsing JSON" />
|
||||||
|
{:else}
|
||||||
|
<div class="outer">
|
||||||
|
<div class="inner">
|
||||||
|
<JSONTree value={json} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.outer {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.inner {
|
||||||
|
overflow: scroll;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
5
packages/web/src/celldata/TextCellViewNoWrap.svelte
Normal file
5
packages/web/src/celldata/TextCellViewNoWrap.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let selection;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<textarea class="flex1" wrap="no" readonly value={selection[0].value} />
|
||||||
5
packages/web/src/celldata/TextCellViewWrap.svelte
Normal file
5
packages/web/src/celldata/TextCellViewWrap.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
export let selection;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<textarea class="flex1" wrap="hard" readonly value={selection[0].value} />
|
||||||
@@ -234,7 +234,7 @@
|
|||||||
import DataFilterControl from './DataFilterControl.svelte';
|
import DataFilterControl from './DataFilterControl.svelte';
|
||||||
import createReducer from '../utility/createReducer';
|
import createReducer from '../utility/createReducer';
|
||||||
import keycodes from '../utility/keycodes';
|
import keycodes from '../utility/keycodes';
|
||||||
import { activeTabId, getActiveTabId, nullStore } from '../stores';
|
import { activeTabId, getActiveTabId, nullStore, selectedCellsCallback } from '../stores';
|
||||||
import memberStore from '../utility/memberStore';
|
import memberStore from '../utility/memberStore';
|
||||||
import axiosInstance from '../utility/axiosInstance';
|
import axiosInstance from '../utility/axiosInstance';
|
||||||
import { copyTextToClipboard } from '../utility/clipboard';
|
import { copyTextToClipboard } from '../utility/clipboard';
|
||||||
@@ -563,16 +563,13 @@
|
|||||||
domFocusField.focus();
|
domFocusField.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastPublishledRef = createRef('');
|
const lastPublishledSelectedCellsRef = createRef('');
|
||||||
$: if (onSelectionChanged) {
|
$: {
|
||||||
const published = getCellsPublished(selectedCells);
|
const stringified = stableStringify(selectedCells);
|
||||||
const stringified = stableStringify(published);
|
if (lastPublishledSelectedCellsRef.get() != stringified) {
|
||||||
if (lastPublishledRef.get() != stringified) {
|
lastPublishledSelectedCellsRef.set(stringified);
|
||||||
// console.log('PUBLISH', published);
|
if (onSelectionChanged) onSelectionChanged(getCellsPublished(selectedCells));
|
||||||
// console.log('lastPublishledRef.current', lastPublishledRef.current);
|
$selectedCellsCallback = () => getCellsPublished(selectedCells);
|
||||||
// console.log('stringified', stringified);
|
|
||||||
lastPublishledRef.set(stringified);
|
|
||||||
onSelectionChanged(published);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,13 +586,20 @@
|
|||||||
|
|
||||||
function getCellsPublished(cells) {
|
function getCellsPublished(cells) {
|
||||||
const regular = cellsToRegularCells(cells);
|
const regular = cellsToRegularCells(cells);
|
||||||
// @ts-ignore
|
const res = regular
|
||||||
return regular
|
.map(cell => {
|
||||||
.map(cell => ({
|
const row = cell[0];
|
||||||
row: cell[0],
|
const rowData = grider.getRowData(row);
|
||||||
column: realColumnUniqueNames[cell[1]],
|
const column = realColumnUniqueNames[cell[1]];
|
||||||
}))
|
return {
|
||||||
|
row,
|
||||||
|
rowData,
|
||||||
|
column,
|
||||||
|
value: rowData && rowData[column],
|
||||||
|
};
|
||||||
|
})
|
||||||
.filter(x => x.column);
|
.filter(x => x.column);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollIntoView(cell) {
|
function scrollIntoView(cell) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
'icon share': 'mdi mdi-share-variant',
|
'icon share': 'mdi mdi-share-variant',
|
||||||
'icon add': 'mdi mdi-plus-circle',
|
'icon add': 'mdi mdi-plus-circle',
|
||||||
'icon connection': 'mdi mdi-connection',
|
'icon connection': 'mdi mdi-connection',
|
||||||
|
'icon cell-data': 'mdi mdi-details',
|
||||||
|
|
||||||
'icon database': 'mdi mdi-database',
|
'icon database': 'mdi mdi-database',
|
||||||
'icon server': 'mdi mdi-server',
|
'icon server': 'mdi mdi-server',
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export const openedModals = writable([]);
|
|||||||
export const nullStore = readable(null, () => {});
|
export const nullStore = readable(null, () => {});
|
||||||
export const currentArchive = writable('default');
|
export const currentArchive = writable('default');
|
||||||
export const isFileDragActive = writable(false);
|
export const isFileDragActive = writable(false);
|
||||||
|
export const selectedCellsCallback = writable(null);
|
||||||
|
|
||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
|
|
||||||
|
|||||||
113
packages/web/src/widgets/CellDataWidget.svelte
Normal file
113
packages/web/src/widgets/CellDataWidget.svelte
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
const formats = [
|
||||||
|
{
|
||||||
|
type: 'textWrap',
|
||||||
|
title: 'Text (wrap)',
|
||||||
|
component: TextCellViewWrap,
|
||||||
|
single: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
title: 'Text (no wrap)',
|
||||||
|
component: TextCellViewNoWrap,
|
||||||
|
single: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'json',
|
||||||
|
title: 'Json',
|
||||||
|
component: JsonCellView,
|
||||||
|
single: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function autodetect(selection) {
|
||||||
|
const value = selection.length == 1 ? selection[0].value : null;
|
||||||
|
if (_.isString(value)) {
|
||||||
|
if (value.startsWith('[') || value.startsWith('{')) return 'json';
|
||||||
|
}
|
||||||
|
return 'textWrap';
|
||||||
|
}
|
||||||
|
|
||||||
|
let cellSelectionListener = null;
|
||||||
|
|
||||||
|
export const getCellSelectionListener = () => cellSelectionListener;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
import JsonCellView from '../celldata/JsonCellView.svelte';
|
||||||
|
import TextCellViewNoWrap from '../celldata/TextCellViewNoWrap.svelte';
|
||||||
|
import TextCellViewWrap from '../celldata/TextCellViewWrap.svelte';
|
||||||
|
import ErrorInfo from '../elements/ErrorInfo.svelte';
|
||||||
|
import SelectField from '../forms/SelectField.svelte';
|
||||||
|
import { selectedCellsCallback } from '../stores';
|
||||||
|
import WidgetTitle from './WidgetTitle.svelte';
|
||||||
|
|
||||||
|
let selectedFormatType = 'autodetect';
|
||||||
|
|
||||||
|
export let selection = undefined;
|
||||||
|
|
||||||
|
$: autodetectFormatType = autodetect(selection);
|
||||||
|
$: autodetectFormat = formats.find(x => x.type == autodetectFormatType);
|
||||||
|
|
||||||
|
$: usedFormatType = selectedFormatType == 'autodetect' ? autodetectFormatType : selectedFormatType;
|
||||||
|
$: usedFormat = formats.find(x => x.type == usedFormatType);
|
||||||
|
|
||||||
|
$: selection = $selectedCellsCallback();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<WidgetTitle>Cell data view</WidgetTitle>
|
||||||
|
<div class="main">
|
||||||
|
<div class="toolbar">
|
||||||
|
Format:
|
||||||
|
<SelectField
|
||||||
|
isNative
|
||||||
|
value={selectedFormatType}
|
||||||
|
on:change={e => (selectedFormatType = e.detail)}
|
||||||
|
options={[
|
||||||
|
{ value: 'autodetect', label: `Autodetect - ${autodetectFormat.title}` },
|
||||||
|
...formats.map(fmt => ({ label: fmt.title, value: fmt.type })),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="data">
|
||||||
|
{#if usedFormat.single && selection?.length != 1}
|
||||||
|
<ErrorInfo message="Must be selected one cell" />
|
||||||
|
{:else if usedFormat == null}
|
||||||
|
<ErrorInfo message="Format not selected" />
|
||||||
|
{:else if !selection || selection.length == 0}
|
||||||
|
<ErrorInfo message="No data selected" />
|
||||||
|
{:else}
|
||||||
|
<svelte:component this={usedFormat?.component} {selection} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
background: var(--theme-bg-1);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
import FilesWidget from './FilesWidget.svelte';
|
import FilesWidget from './FilesWidget.svelte';
|
||||||
import PluginsWidget from './PluginsWidget.svelte';
|
import PluginsWidget from './PluginsWidget.svelte';
|
||||||
import FavoritesWidget from './FavoritesWidget.svelte';
|
import FavoritesWidget from './FavoritesWidget.svelte';
|
||||||
|
import CellDataWidget from './CellDataWidget.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $selectedWidget == 'database'}
|
{#if $selectedWidget == 'database'}
|
||||||
@@ -22,3 +23,6 @@
|
|||||||
{#if $selectedWidget == 'favorites'}
|
{#if $selectedWidget == 'favorites'}
|
||||||
<FavoritesWidget />
|
<FavoritesWidget />
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $selectedWidget == 'cell-data'}
|
||||||
|
<CellDataWidget />
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -33,6 +33,11 @@
|
|||||||
name: 'favorites',
|
name: 'favorites',
|
||||||
title: 'Favorites',
|
title: 'Favorites',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'icon cell-data',
|
||||||
|
name: 'cell-data',
|
||||||
|
title: 'Selected cell data detail view',
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// icon: 'fa-cog',
|
// icon: 'fa-cog',
|
||||||
// name: 'settings',
|
// name: 'settings',
|
||||||
@@ -56,7 +61,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{#each widgets as item}
|
{#each widgets as item}
|
||||||
<div class="wrapper" class:selected={item.name == $selectedWidget} on:click={() => handleChangeWidget(item.name)}>
|
<div class="wrapper" class:selected={item.name == $selectedWidget} on:click={() => handleChangeWidget(item.name)}>
|
||||||
<FontIcon icon={item.icon} />
|
<FontIcon icon={item.icon} title={item.title} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
|||||||
@@ -7022,6 +7022,11 @@ svelte-check@^1.0.0:
|
|||||||
svelte-preprocess "^4.0.0"
|
svelte-preprocess "^4.0.0"
|
||||||
typescript "*"
|
typescript "*"
|
||||||
|
|
||||||
|
svelte-json-tree@^0.1.0:
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte-json-tree/-/svelte-json-tree-0.1.0.tgz#2711e36162046a10766dfbef69739168a5eaafa6"
|
||||||
|
integrity sha512-ufKWvS94z5m6Je9Hu0yosvdALy0mOPcaexbTcQQ/jW+3Rzi4oaHkOeg4RQ3cNpOlOQlIs0lfsF9FBlyquZ7XuQ==
|
||||||
|
|
||||||
svelte-markdown@^0.1.4:
|
svelte-markdown@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/svelte-markdown/-/svelte-markdown-0.1.4.tgz#03bec6dcd8ff1c09126e7c62c8a5a481905881d7"
|
resolved "https://registry.yarnpkg.com/svelte-markdown/-/svelte-markdown-0.1.4.tgz#03bec6dcd8ff1c09126e7c62c8a5a481905881d7"
|
||||||
|
|||||||
Reference in New Issue
Block a user