mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 19:36:00 +00:00
group by in datagrid
This commit is contained in:
@@ -1,16 +1,6 @@
|
||||
<script lang="ts" context="module">
|
||||
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
|
||||
export const createMatcher = ({ pureName }) => filter => filterName(filter, pureName);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import { currentDatabase, openedConnections } from '../stores';
|
||||
import openNewTab from '../utility/openNewTab';
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
|
||||
export let data;
|
||||
|
||||
const icons = {
|
||||
tables: 'img table',
|
||||
@@ -19,20 +9,85 @@
|
||||
functions: 'img function',
|
||||
};
|
||||
|
||||
const defaultTabs = {
|
||||
tables: 'TableDataTab',
|
||||
views: 'ViewDataTab',
|
||||
};
|
||||
|
||||
export async function openDatabaseObjectDetail(
|
||||
tabComponent,
|
||||
sqlTemplate,
|
||||
{ schemaName, pureName, conid, database, objectTypeField },
|
||||
forceNewTab,
|
||||
initialData
|
||||
) {
|
||||
const connection = await getConnectionInfo({ conid });
|
||||
const tooltip = `${connection.displayName || connection.server}\n${database}\n${fullDisplayName({
|
||||
schemaName,
|
||||
pureName,
|
||||
})}`;
|
||||
|
||||
openNewTab(
|
||||
{
|
||||
title: sqlTemplate ? 'Query #' : pureName,
|
||||
tooltip,
|
||||
icon: sqlTemplate ? 'img sql-file' : icons[objectTypeField],
|
||||
tabComponent: sqlTemplate ? 'QueryTab' : tabComponent,
|
||||
props: {
|
||||
schemaName,
|
||||
pureName,
|
||||
conid,
|
||||
database,
|
||||
objectTypeField,
|
||||
initialArgs: sqlTemplate ? { sqlTemplate } : null,
|
||||
},
|
||||
},
|
||||
initialData,
|
||||
{ forceNewTab }
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import { currentDatabase, openedConnections } from '../stores';
|
||||
import openNewTab from '../utility/openNewTab';
|
||||
import { filterName } from 'dbgate-datalib';
|
||||
import { getConnectionInfo } from '../utility/metadataLoaders';
|
||||
import fullDisplayName from '../utility/fullDisplayName';
|
||||
|
||||
export let data;
|
||||
|
||||
function handleClick() {
|
||||
const { schemaName, pureName, conid, database, objectTypeField } = data;
|
||||
openNewTab({
|
||||
title: data.pureName,
|
||||
icon: 'img table',
|
||||
tabComponent: 'TableDataTab',
|
||||
props: {
|
||||
|
||||
openDatabaseObjectDetail(
|
||||
defaultTabs[objectTypeField],
|
||||
defaultTabs[objectTypeField] ? null : 'CREATE OBJECT',
|
||||
{
|
||||
schemaName,
|
||||
pureName,
|
||||
conid,
|
||||
database,
|
||||
objectTypeField,
|
||||
},
|
||||
});
|
||||
false,
|
||||
null
|
||||
);
|
||||
|
||||
// openNewTab({
|
||||
// title: data.pureName,
|
||||
// icon: 'img table',
|
||||
// tabComponent: 'TableDataTab',
|
||||
// props: {
|
||||
// schemaName,
|
||||
// pureName,
|
||||
// conid,
|
||||
// database,
|
||||
// objectTypeField,
|
||||
// },
|
||||
// });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import splitterDrag from '../utility/splitterDrag';
|
||||
|
||||
import ColumnLabel from './ColumnLabel.svelte';
|
||||
import { isTypeDateTime } from 'dbgate-tools';
|
||||
import { openDatabaseObjectDetail } from '../appobj/DatabaseObjectAppObject.svelte';
|
||||
|
||||
export let column;
|
||||
export let conid = undefined;
|
||||
@@ -12,6 +14,41 @@
|
||||
export let grouping = undefined;
|
||||
export let order = undefined;
|
||||
export let setGrouping;
|
||||
|
||||
const openReferencedTable = () => {
|
||||
openDatabaseObjectDetail('TableDataTab', null, {
|
||||
schemaName: column.foreignKey.refSchemaName,
|
||||
pureName: column.foreignKey.refTableName,
|
||||
conid,
|
||||
database,
|
||||
objectTypeField: 'tables',
|
||||
});
|
||||
};
|
||||
|
||||
function getMenu() {
|
||||
return [
|
||||
{ onClick: () => setSort('ASC'), text: 'Sort ascending' },
|
||||
{ onClick: () => setSort('DESC'), text: 'Sort descending' },
|
||||
|
||||
column.foreignKey && [{ divider: true }, { onClick: openReferencedTable, text: column.foreignKey.refTableName }],
|
||||
|
||||
{ divider: true },
|
||||
{ onClick: () => setGrouping('GROUP'), text: 'Group by' },
|
||||
{ onClick: () => setGrouping('MAX'), text: 'MAX' },
|
||||
{ onClick: () => setGrouping('MIN'), text: 'MIN' },
|
||||
{ onClick: () => setGrouping('SUM'), text: 'SUM' },
|
||||
{ onClick: () => setGrouping('AVG'), text: 'AVG' },
|
||||
{ onClick: () => setGrouping('COUNT'), text: 'COUNT' },
|
||||
{ onClick: () => setGrouping('COUNT DISTINCT'), text: 'COUNT DISTINCT' },
|
||||
|
||||
isTypeDateTime(column.dataType) && [
|
||||
{ divider: true },
|
||||
{ onClick: () => setGrouping('GROUP:YEAR'), text: 'Group by YEAR' },
|
||||
{ onClick: () => setGrouping('GROUP:MONTH'), text: 'Group by MONTH' },
|
||||
{ onClick: () => setGrouping('GROUP:DAY'), text: 'Group by DAY' },
|
||||
],
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
@@ -33,7 +70,7 @@
|
||||
<FontIcon icon="img sort-desc" />
|
||||
</span>
|
||||
{/if}
|
||||
<DropDownButton />
|
||||
<DropDownButton menu={getMenu} />
|
||||
<div class="horizontal-split-handle resizeHandleControl" use:splitterDrag={'clientX'} on:resizeSplitter />
|
||||
</div>
|
||||
|
||||
@@ -51,6 +88,8 @@
|
||||
}
|
||||
.icon {
|
||||
margin-left: 3px;
|
||||
align-self: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
/* .resizer {
|
||||
background-color: var(--theme-border);
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
||||
import DataGridRow from './DataGridRow.svelte';
|
||||
import { getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
|
||||
import stableStringify from 'json-stable-stringify';
|
||||
import { tick } from 'svelte';
|
||||
import {
|
||||
cellIsSelected,
|
||||
@@ -71,6 +72,7 @@
|
||||
export let isLoading = false;
|
||||
export let allRowCount = undefined;
|
||||
export let onReferenceSourceChanged = undefined;
|
||||
export let onReferenceClick = undefined;
|
||||
|
||||
export let isLoadedAll;
|
||||
export let loadedTime;
|
||||
@@ -159,6 +161,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// $: console.log('DISPLAY.config', display.config);
|
||||
$: {
|
||||
if (display.groupColumns && display.baseTable) {
|
||||
onReferenceClick({
|
||||
referenceId: stableStringify(display && display.groupColumns),
|
||||
schemaName: display.baseTable.schemaName,
|
||||
pureName: display.baseTable.pureName,
|
||||
columns: display.groupColumns.map(col => ({
|
||||
baseName: col,
|
||||
refName: col,
|
||||
dataType: _.get(display.baseTable && display.baseTable.columns.find(x => x.columnName == col), 'dataType'),
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function scrollIntoView(cell) {
|
||||
const [row, col] = cell;
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
};
|
||||
|
||||
const handleCloseReference = () => {
|
||||
display.clearGrouping();
|
||||
setChildConfig(null, null);
|
||||
};
|
||||
|
||||
@@ -112,7 +113,13 @@
|
||||
gridCoreComponent={SqlDataGridCore}
|
||||
{display}
|
||||
onReferenceSourceChanged={reference ? handleReferenceSourceChanged : null}
|
||||
onReferenceClick={reference => setChildConfig(createGridConfig(), reference)}
|
||||
onReferenceClick={value => {
|
||||
if (value && value.referenceId && reference && reference.referenceId == value.referenceId) {
|
||||
// reference not changed
|
||||
return;
|
||||
}
|
||||
setChildConfig(createGridConfig(), value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div slot="2" class="reference-container">
|
||||
|
||||
@@ -1,20 +1,60 @@
|
||||
<script context="module">
|
||||
function getElementOffset(element) {
|
||||
var de = document.documentElement;
|
||||
var box = element.getBoundingClientRect();
|
||||
var top = box.top + window.pageYOffset - de.clientTop;
|
||||
var left = box.left + window.pageXOffset - de.clientLeft;
|
||||
return { top: top, left: left };
|
||||
}
|
||||
|
||||
function fixPopupPlacement(element) {
|
||||
const { width, height } = element.getBoundingClientRect();
|
||||
let offset = getElementOffset(element);
|
||||
|
||||
let newLeft = null;
|
||||
let newTop = null;
|
||||
|
||||
if (offset.left + width > window.innerWidth) {
|
||||
newLeft = offset.left - width;
|
||||
}
|
||||
if (offset.top + height > window.innerHeight) {
|
||||
newTop = offset.top - height;
|
||||
}
|
||||
|
||||
if (newLeft != null) element.style.left = `${newLeft}px`;
|
||||
if (newTop != null) element.style.top = `${newTop}px`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import clickOutside from '../utility/clickOutside';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let items;
|
||||
export let top;
|
||||
export let left;
|
||||
|
||||
let element;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function handleClick(item) {
|
||||
dispatch('close');
|
||||
if (item.onClick) item.onClick();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fixPopupPlacement(element);
|
||||
});
|
||||
</script>
|
||||
|
||||
<ul style={`left: ${left}px; top: ${top}px`} use:clickOutside on:clickOutside={() => dispatch('close')}>
|
||||
<ul
|
||||
style={`left: ${left}px; top: ${top}px`}
|
||||
use:clickOutside
|
||||
on:clickOutside={() => dispatch('close')}
|
||||
bind:this={element}
|
||||
>
|
||||
{#each items as item}
|
||||
{#if item.divider}
|
||||
<li class="divider" />
|
||||
|
||||
4
packages/web/src/utility/fullDisplayName.js
Normal file
4
packages/web/src/utility/fullDisplayName.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export default function fullDisplayName({ schemaName, pureName }) {
|
||||
if (schemaName) return `${schemaName}.${pureName}`;
|
||||
return pureName;
|
||||
}
|
||||
Reference in New Issue
Block a user