mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-02 00:54:00 +00:00
collection json view
This commit is contained in:
@@ -294,6 +294,20 @@ export abstract class GridDisplay {
|
|||||||
this.reload();
|
this.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showFilter(uniqueName) {
|
||||||
|
this.setConfig(cfg => {
|
||||||
|
if (!cfg.filters.uniqueName)
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
filters: {
|
||||||
|
..._.omitBy(cfg.filters, v => !v),
|
||||||
|
[uniqueName]: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return cfg;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
removeFilter(uniqueName) {
|
removeFilter(uniqueName) {
|
||||||
this.setConfig(cfg => ({
|
this.setConfig(cfg => ({
|
||||||
...cfg,
|
...cfg,
|
||||||
@@ -547,4 +561,11 @@ export abstract class GridDisplay {
|
|||||||
formViewKeyRequested: null,
|
formViewKeyRequested: null,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switchToJsonView() {
|
||||||
|
this.setConfig(cfg => ({
|
||||||
|
...cfg,
|
||||||
|
isJsonView: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script context="module" lang="ts">
|
<script context="module" lang="ts">
|
||||||
function buildCondition(props) {
|
export function buildGridMongoCondition(props) {
|
||||||
const filters = props?.display?.config?.filters;
|
const filters = props?.display?.config?.filters;
|
||||||
|
|
||||||
const conditions = [];
|
const conditions = [];
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadDataPage(props, offset, limit) {
|
export async function loadCollectionDataPage(props, offset, limit) {
|
||||||
const { conid, database } = props;
|
const { conid, database } = props;
|
||||||
|
|
||||||
const response = await axiosInstance.request({
|
const response = await axiosInstance.request({
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
pureName: props.pureName,
|
pureName: props.pureName,
|
||||||
limit,
|
limit,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
condition: buildCondition(props),
|
condition: buildGridMongoCondition(props),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
options: {
|
options: {
|
||||||
pureName: props.pureName,
|
pureName: props.pureName,
|
||||||
countDocuments: true,
|
countDocuments: true,
|
||||||
condition: buildCondition(props),
|
condition: buildGridMongoCondition(props),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
|
|
||||||
<LoadingDataGridCore
|
<LoadingDataGridCore
|
||||||
{...$$props}
|
{...$$props}
|
||||||
{loadDataPage}
|
loadDataPage={loadCollectionDataPage}
|
||||||
{dataPageAvailable}
|
{dataPageAvailable}
|
||||||
{loadRowCount}
|
{loadRowCount}
|
||||||
onExportGrid={exportGrid}
|
onExportGrid={exportGrid}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
export let managerSize;
|
export let managerSize;
|
||||||
export let display: GridDisplay;
|
export let display: GridDisplay;
|
||||||
|
export let isJsonView = false;
|
||||||
|
|
||||||
let filter;
|
let filter;
|
||||||
</script>
|
</script>
|
||||||
@@ -23,6 +24,6 @@
|
|||||||
{#each display
|
{#each display
|
||||||
?.getColumns(filter)
|
?.getColumns(filter)
|
||||||
?.filter(column => filterName(filter, column.columnName)) || [] as column (column.uniqueName)}
|
?.filter(column => filterName(filter, column.columnName)) || [] as column (column.uniqueName)}
|
||||||
<ColumnManagerRow {display} {column} />
|
<ColumnManagerRow {display} {column} {isJsonView} />
|
||||||
{/each}
|
{/each}
|
||||||
</ManagerInnerContainer>
|
</ManagerInnerContainer>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
export let column;
|
export let column;
|
||||||
export let display;
|
export let display;
|
||||||
|
export let isJsonView = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -13,21 +14,25 @@
|
|||||||
on:click={e => {
|
on:click={e => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (e.target.closest('.expandColumnIcon')) return;
|
if (e.target.closest('.expandColumnIcon')) return;
|
||||||
display.focusColumn(column.uniqueName);
|
if (isJsonView) display.showFilter(column.uniqueName);
|
||||||
|
else display.focusColumn(column.uniqueName);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span class="expandColumnIcon">
|
<span class="expandColumnIcon" style={`margin-right: ${5 + (column.uniquePath.length - 1) * 10}px`}>
|
||||||
<FontIcon
|
<FontIcon
|
||||||
icon={column.isExpandable ? plusExpandIcon(display.isExpandedColumn(column.uniqueName)) : 'icon invisible-box'}
|
icon={column.isExpandable ? plusExpandIcon(display.isExpandedColumn(column.uniqueName)) : 'icon invisible-box'}
|
||||||
on:click={() => display.toggleExpandedColumn(column.uniqueName)}
|
on:click={() => display.toggleExpandedColumn(column.uniqueName)}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
{#if isJsonView}
|
||||||
|
<FontIcon icon="img column" />
|
||||||
|
{:else}
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
style={`margin-left: ${5 + (column.uniquePath.length - 1) * 10}px`}
|
|
||||||
checked={column.isChecked}
|
checked={column.isChecked}
|
||||||
on:change={() => display.setColumnVisibility(column.uniquePath, !column.isChecked)}
|
on:change={() => display.setColumnVisibility(column.uniquePath, !column.isChecked)}
|
||||||
/>
|
/>
|
||||||
|
{/if}
|
||||||
<ColumnLabel {...column} />
|
<ColumnLabel {...column} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
|
|
||||||
export let config;
|
export let config;
|
||||||
export let gridCoreComponent;
|
export let gridCoreComponent;
|
||||||
export let formViewComponent;
|
export let formViewComponent = null;
|
||||||
|
export let jsonViewComponent = null;
|
||||||
export let formDisplay;
|
export let formDisplay;
|
||||||
export let display;
|
export let display;
|
||||||
export let changeSetState;
|
export let changeSetState;
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
let managerSize;
|
let managerSize;
|
||||||
|
|
||||||
$: isFormView = !!(formDisplay && formDisplay.config && formDisplay.config.isFormView);
|
$: isFormView = !!(formDisplay && formDisplay.config && formDisplay.config.isFormView);
|
||||||
|
$: isJsonView = !!config.isJsonView;
|
||||||
|
|
||||||
const handleExecuteMacro = () => {
|
const handleExecuteMacro = () => {
|
||||||
onRunMacro($selectedMacro, extractMacroValuesForMacro($macroValues, $selectedMacro), selectedCellsPublished());
|
onRunMacro($selectedMacro, extractMacroValuesForMacro($macroValues, $selectedMacro), selectedCellsPublished());
|
||||||
@@ -83,7 +85,7 @@
|
|||||||
height={showReferences ? '40%' : '60%'}
|
height={showReferences ? '40%' : '60%'}
|
||||||
skip={freeTableColumn || isFormView}
|
skip={freeTableColumn || isFormView}
|
||||||
>
|
>
|
||||||
<ColumnManager {...$$props} {managerSize} />
|
<ColumnManager {...$$props} {managerSize} {isJsonView} />
|
||||||
</WidgetColumnBarItem>
|
</WidgetColumnBarItem>
|
||||||
|
|
||||||
<WidgetColumnBarItem title="Filters" name="jsonFilters" height="30%" skip={!isDynamicStructure}>
|
<WidgetColumnBarItem title="Filters" name="jsonFilters" height="30%" skip={!isDynamicStructure}>
|
||||||
@@ -118,11 +120,14 @@
|
|||||||
<svelte:fragment slot="1">
|
<svelte:fragment slot="1">
|
||||||
{#if isFormView}
|
{#if isFormView}
|
||||||
<svelte:component this={formViewComponent} {...$$props} />
|
<svelte:component this={formViewComponent} {...$$props} />
|
||||||
|
{:else if isJsonView}
|
||||||
|
<svelte:component this={jsonViewComponent} {...$$props} bind:loadedRows />
|
||||||
{:else}
|
{:else}
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={gridCoreComponent}
|
this={gridCoreComponent}
|
||||||
{...$$props}
|
{...$$props}
|
||||||
formViewAvailable={!!formViewComponent && !!formDisplay}
|
formViewAvailable={!!formViewComponent && !!formDisplay}
|
||||||
|
jsonViewAvailable={!!jsonViewComponent}
|
||||||
macroValues={extractMacroValuesForMacro($macroValues, $selectedMacro)}
|
macroValues={extractMacroValuesForMacro($macroValues, $selectedMacro)}
|
||||||
macroPreview={$selectedMacro}
|
macroPreview={$selectedMacro}
|
||||||
bind:loadedRows
|
bind:loadedRows
|
||||||
|
|||||||
@@ -131,6 +131,15 @@
|
|||||||
onClick: () => getCurrentDataGrid().switchToForm(),
|
onClick: () => getCurrentDataGrid().switchToForm(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerCommand({
|
||||||
|
id: 'dataGrid.switchToJson',
|
||||||
|
category: 'Data grid',
|
||||||
|
name: 'Switch to JSON',
|
||||||
|
keyText: 'F4',
|
||||||
|
testEnabled: () => getCurrentDataGrid()?.jsonViewEnabled(),
|
||||||
|
onClick: () => getCurrentDataGrid().switchToJson(),
|
||||||
|
});
|
||||||
|
|
||||||
registerCommand({
|
registerCommand({
|
||||||
id: 'dataGrid.filterSelected',
|
id: 'dataGrid.filterSelected',
|
||||||
category: 'Data grid',
|
category: 'Data grid',
|
||||||
@@ -265,6 +274,7 @@
|
|||||||
export let onOpenQuery = null;
|
export let onOpenQuery = null;
|
||||||
export let onOpenActiveChart = null;
|
export let onOpenActiveChart = null;
|
||||||
export let formViewAvailable = false;
|
export let formViewAvailable = false;
|
||||||
|
export let jsonViewAvailable=false;
|
||||||
export let errorMessage = undefined;
|
export let errorMessage = undefined;
|
||||||
|
|
||||||
export let isLoadedAll;
|
export let isLoadedAll;
|
||||||
@@ -409,12 +419,20 @@
|
|||||||
return formViewAvailable && display.baseTable && display.baseTable.primaryKey;
|
return formViewAvailable && display.baseTable && display.baseTable.primaryKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function jsonViewEnabled() {
|
||||||
|
return jsonViewAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
export function switchToForm() {
|
export function switchToForm() {
|
||||||
const cell = currentCell;
|
const cell = currentCell;
|
||||||
const rowData = isRegularCell(cell) ? grider.getRowData(cell[0]) : null;
|
const rowData = isRegularCell(cell) ? grider.getRowData(cell[0]) : null;
|
||||||
display.switchToFormView(rowData);
|
display.switchToFormView(rowData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function switchToJson() {
|
||||||
|
display.switchToJsonView();
|
||||||
|
}
|
||||||
|
|
||||||
export function filterSelectedValue() {
|
export function filterSelectedValue() {
|
||||||
const flts = {};
|
const flts = {};
|
||||||
for (const cell of selectedCells) {
|
for (const cell of selectedCells) {
|
||||||
@@ -1009,6 +1027,7 @@
|
|||||||
{ command: 'dataGrid.copyToClipboard' },
|
{ command: 'dataGrid.copyToClipboard' },
|
||||||
{ command: 'dataGrid.export' },
|
{ command: 'dataGrid.export' },
|
||||||
{ command: 'dataGrid.switchToForm' },
|
{ command: 'dataGrid.switchToForm' },
|
||||||
|
{ command: 'dataGrid.switchToJson' },
|
||||||
{ divider: true },
|
{ divider: true },
|
||||||
{ command: 'dataGrid.save' },
|
{ command: 'dataGrid.save' },
|
||||||
{ command: 'dataGrid.revertRowChanges' },
|
{ command: 'dataGrid.revertRowChanges' },
|
||||||
|
|||||||
58
packages/web/src/elements/Pager.svelte
Normal file
58
packages/web/src/elements/Pager.svelte
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import InlineButton from '../elements/InlineButton.svelte';
|
||||||
|
import TextField from '../forms/TextField.svelte';
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import keycodes from '../utility/keycodes';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let skip;
|
||||||
|
export let limit;
|
||||||
|
|
||||||
|
function handleKeyDown(e) {
|
||||||
|
if (e.keyCode == keycodes.enter) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
dispatch('load');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<InlineButton
|
||||||
|
on:click={() => {
|
||||||
|
skip -= limit;
|
||||||
|
if (skip < 0) skip = 0;
|
||||||
|
dispatch('load');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontIcon icon="icon arrow-left" />
|
||||||
|
</InlineButton>
|
||||||
|
<span class="label">Start:</span>
|
||||||
|
<TextField type="number" bind:value={skip} on:blur={() => dispatch('load')} on:keydown={handleKeyDown} />
|
||||||
|
<span class="label">Rows:</span>
|
||||||
|
<TextField type="number" bind:value={limit} on:blur={() => dispatch('load')} on:keydown={handleKeyDown} />
|
||||||
|
<InlineButton
|
||||||
|
on:click={() => {
|
||||||
|
skip += limit;
|
||||||
|
dispatch('load');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontIcon icon="icon arrow-right" />
|
||||||
|
</InlineButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper :global(input) {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
setContext(contextKey, {});
|
setContext(contextKey, {});
|
||||||
|
|
||||||
export let key = '',
|
export let key = '';
|
||||||
value;
|
export let value;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
66
packages/web/src/jsonview/CollectionJsonView.svelte
Normal file
66
packages/web/src/jsonview/CollectionJsonView.svelte
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
import { loadCollectionDataPage } from '../datagrid/CollectionDataGridCore.svelte';
|
||||||
|
import InlineButton from '../elements/InlineButton.svelte';
|
||||||
|
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
||||||
|
import Pager from '../elements/Pager.svelte';
|
||||||
|
import TextField from '../forms/TextField.svelte';
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
|
||||||
|
import JSONTree from '../jsontree/JSONTree.svelte';
|
||||||
|
|
||||||
|
export let conid;
|
||||||
|
export let database;
|
||||||
|
export let cache;
|
||||||
|
export let display;
|
||||||
|
|
||||||
|
let isLoading = false;
|
||||||
|
let loadedTime = null;
|
||||||
|
|
||||||
|
export let loadedRows = null;
|
||||||
|
let skip = 0;
|
||||||
|
let limit = 50;
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
isLoading = true;
|
||||||
|
// @ts-ignore
|
||||||
|
loadedRows = await loadCollectionDataPage($$props, parseInt(skip) || 0, parseInt(limit) || 50);
|
||||||
|
isLoading = false;
|
||||||
|
loadedTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (cache?.refreshTime > loadedTime) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flexcol flex1">
|
||||||
|
<div class="toolbar">
|
||||||
|
<Pager bind:skip bind:limit on:load={() => display.reload()} />
|
||||||
|
</div>
|
||||||
|
<div class="json">
|
||||||
|
<JSONTree value={loadedRows} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if isLoading}
|
||||||
|
<LoadingInfo wrapper message="Loading data" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.toolbar {
|
||||||
|
background: var(--theme-bg-3);
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid var(--theme-border);
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
import CollectionDataGridCore from '../datagrid/CollectionDataGridCore.svelte';
|
import CollectionDataGridCore from '../datagrid/CollectionDataGridCore.svelte';
|
||||||
import { useCollectionInfo, useConnectionInfo } from '../utility/metadataLoaders';
|
import { useCollectionInfo, useConnectionInfo } from '../utility/metadataLoaders';
|
||||||
import { extensions } from '../stores';
|
import { extensions } from '../stores';
|
||||||
|
import CollectionJsonView from '../jsonview/CollectionJsonView.svelte';
|
||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
export let conid;
|
export let conid;
|
||||||
@@ -72,5 +73,6 @@
|
|||||||
{changeSetStore}
|
{changeSetStore}
|
||||||
{dispatchChangeSet}
|
{dispatchChangeSet}
|
||||||
gridCoreComponent={CollectionDataGridCore}
|
gridCoreComponent={CollectionDataGridCore}
|
||||||
|
jsonViewComponent={CollectionJsonView}
|
||||||
isDynamicStructure
|
isDynamicStructure
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user