mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
collection json view
This commit is contained in:
parent
ff52430e1e
commit
554be51546
@ -294,6 +294,20 @@ export abstract class GridDisplay {
|
||||
this.reload();
|
||||
}
|
||||
|
||||
showFilter(uniqueName) {
|
||||
this.setConfig(cfg => {
|
||||
if (!cfg.filters.uniqueName)
|
||||
return {
|
||||
...cfg,
|
||||
filters: {
|
||||
..._.omitBy(cfg.filters, v => !v),
|
||||
[uniqueName]: '',
|
||||
},
|
||||
};
|
||||
return cfg;
|
||||
});
|
||||
}
|
||||
|
||||
removeFilter(uniqueName) {
|
||||
this.setConfig(cfg => ({
|
||||
...cfg,
|
||||
@ -547,4 +561,11 @@ export abstract class GridDisplay {
|
||||
formViewKeyRequested: null,
|
||||
}));
|
||||
}
|
||||
|
||||
switchToJsonView() {
|
||||
this.setConfig(cfg => ({
|
||||
...cfg,
|
||||
isJsonView: true,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script context="module" lang="ts">
|
||||
function buildCondition(props) {
|
||||
export function buildGridMongoCondition(props) {
|
||||
const filters = props?.display?.config?.filters;
|
||||
|
||||
const conditions = [];
|
||||
@ -27,7 +27,7 @@
|
||||
: undefined;
|
||||
}
|
||||
|
||||
async function loadDataPage(props, offset, limit) {
|
||||
export async function loadCollectionDataPage(props, offset, limit) {
|
||||
const { conid, database } = props;
|
||||
|
||||
const response = await axiosInstance.request({
|
||||
@ -42,7 +42,7 @@
|
||||
pureName: props.pureName,
|
||||
limit,
|
||||
skip: offset,
|
||||
condition: buildCondition(props),
|
||||
condition: buildGridMongoCondition(props),
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -72,7 +72,7 @@
|
||||
options: {
|
||||
pureName: props.pureName,
|
||||
countDocuments: true,
|
||||
condition: buildCondition(props),
|
||||
condition: buildGridMongoCondition(props),
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -211,7 +211,7 @@
|
||||
|
||||
<LoadingDataGridCore
|
||||
{...$$props}
|
||||
{loadDataPage}
|
||||
loadDataPage={loadCollectionDataPage}
|
||||
{dataPageAvailable}
|
||||
{loadRowCount}
|
||||
onExportGrid={exportGrid}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
export let managerSize;
|
||||
export let display: GridDisplay;
|
||||
export let isJsonView = false;
|
||||
|
||||
let filter;
|
||||
</script>
|
||||
@ -23,6 +24,6 @@
|
||||
{#each display
|
||||
?.getColumns(filter)
|
||||
?.filter(column => filterName(filter, column.columnName)) || [] as column (column.uniqueName)}
|
||||
<ColumnManagerRow {display} {column} />
|
||||
<ColumnManagerRow {display} {column} {isJsonView} />
|
||||
{/each}
|
||||
</ManagerInnerContainer>
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
export let column;
|
||||
export let display;
|
||||
export let isJsonView = false;
|
||||
</script>
|
||||
|
||||
<div
|
||||
@ -13,21 +14,25 @@
|
||||
on:click={e => {
|
||||
// @ts-ignore
|
||||
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
|
||||
icon={column.isExpandable ? plusExpandIcon(display.isExpandedColumn(column.uniqueName)) : 'icon invisible-box'}
|
||||
on:click={() => display.toggleExpandedColumn(column.uniqueName)}
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
style={`margin-left: ${5 + (column.uniquePath.length - 1) * 10}px`}
|
||||
checked={column.isChecked}
|
||||
on:change={() => display.setColumnVisibility(column.uniquePath, !column.isChecked)}
|
||||
/>
|
||||
{#if isJsonView}
|
||||
<FontIcon icon="img column" />
|
||||
{:else}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={column.isChecked}
|
||||
on:change={() => display.setColumnVisibility(column.uniquePath, !column.isChecked)}
|
||||
/>
|
||||
{/if}
|
||||
<ColumnLabel {...column} />
|
||||
</div>
|
||||
|
||||
|
@ -29,7 +29,8 @@
|
||||
|
||||
export let config;
|
||||
export let gridCoreComponent;
|
||||
export let formViewComponent;
|
||||
export let formViewComponent = null;
|
||||
export let jsonViewComponent = null;
|
||||
export let formDisplay;
|
||||
export let display;
|
||||
export let changeSetState;
|
||||
@ -55,6 +56,7 @@
|
||||
let managerSize;
|
||||
|
||||
$: isFormView = !!(formDisplay && formDisplay.config && formDisplay.config.isFormView);
|
||||
$: isJsonView = !!config.isJsonView;
|
||||
|
||||
const handleExecuteMacro = () => {
|
||||
onRunMacro($selectedMacro, extractMacroValuesForMacro($macroValues, $selectedMacro), selectedCellsPublished());
|
||||
@ -83,7 +85,7 @@
|
||||
height={showReferences ? '40%' : '60%'}
|
||||
skip={freeTableColumn || isFormView}
|
||||
>
|
||||
<ColumnManager {...$$props} {managerSize} />
|
||||
<ColumnManager {...$$props} {managerSize} {isJsonView} />
|
||||
</WidgetColumnBarItem>
|
||||
|
||||
<WidgetColumnBarItem title="Filters" name="jsonFilters" height="30%" skip={!isDynamicStructure}>
|
||||
@ -118,11 +120,14 @@
|
||||
<svelte:fragment slot="1">
|
||||
{#if isFormView}
|
||||
<svelte:component this={formViewComponent} {...$$props} />
|
||||
{:else if isJsonView}
|
||||
<svelte:component this={jsonViewComponent} {...$$props} bind:loadedRows />
|
||||
{:else}
|
||||
<svelte:component
|
||||
this={gridCoreComponent}
|
||||
{...$$props}
|
||||
formViewAvailable={!!formViewComponent && !!formDisplay}
|
||||
jsonViewAvailable={!!jsonViewComponent}
|
||||
macroValues={extractMacroValuesForMacro($macroValues, $selectedMacro)}
|
||||
macroPreview={$selectedMacro}
|
||||
bind:loadedRows
|
||||
|
@ -131,6 +131,15 @@
|
||||
onClick: () => getCurrentDataGrid().switchToForm(),
|
||||
});
|
||||
|
||||
registerCommand({
|
||||
id: 'dataGrid.switchToJson',
|
||||
category: 'Data grid',
|
||||
name: 'Switch to JSON',
|
||||
keyText: 'F4',
|
||||
testEnabled: () => getCurrentDataGrid()?.jsonViewEnabled(),
|
||||
onClick: () => getCurrentDataGrid().switchToJson(),
|
||||
});
|
||||
|
||||
registerCommand({
|
||||
id: 'dataGrid.filterSelected',
|
||||
category: 'Data grid',
|
||||
@ -265,6 +274,7 @@
|
||||
export let onOpenQuery = null;
|
||||
export let onOpenActiveChart = null;
|
||||
export let formViewAvailable = false;
|
||||
export let jsonViewAvailable=false;
|
||||
export let errorMessage = undefined;
|
||||
|
||||
export let isLoadedAll;
|
||||
@ -409,12 +419,20 @@
|
||||
return formViewAvailable && display.baseTable && display.baseTable.primaryKey;
|
||||
}
|
||||
|
||||
export function jsonViewEnabled() {
|
||||
return jsonViewAvailable;
|
||||
}
|
||||
|
||||
export function switchToForm() {
|
||||
const cell = currentCell;
|
||||
const rowData = isRegularCell(cell) ? grider.getRowData(cell[0]) : null;
|
||||
display.switchToFormView(rowData);
|
||||
}
|
||||
|
||||
export function switchToJson() {
|
||||
display.switchToJsonView();
|
||||
}
|
||||
|
||||
export function filterSelectedValue() {
|
||||
const flts = {};
|
||||
for (const cell of selectedCells) {
|
||||
@ -1009,6 +1027,7 @@
|
||||
{ command: 'dataGrid.copyToClipboard' },
|
||||
{ command: 'dataGrid.export' },
|
||||
{ command: 'dataGrid.switchToForm' },
|
||||
{ command: 'dataGrid.switchToJson' },
|
||||
{ divider: true },
|
||||
{ command: 'dataGrid.save' },
|
||||
{ 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, {});
|
||||
|
||||
export let key = '',
|
||||
value;
|
||||
export let key = '';
|
||||
export let value;
|
||||
</script>
|
||||
|
||||
<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 { useCollectionInfo, useConnectionInfo } from '../utility/metadataLoaders';
|
||||
import { extensions } from '../stores';
|
||||
import CollectionJsonView from '../jsonview/CollectionJsonView.svelte';
|
||||
|
||||
export let tabid;
|
||||
export let conid;
|
||||
@ -72,5 +73,6 @@
|
||||
{changeSetStore}
|
||||
{dispatchChangeSet}
|
||||
gridCoreComponent={CollectionDataGridCore}
|
||||
jsonViewComponent={CollectionJsonView}
|
||||
isDynamicStructure
|
||||
/>
|
||||
|
Loading…
Reference in New Issue
Block a user