group by in datagrid

This commit is contained in:
Jan Prochazka
2021-03-06 13:02:01 +01:00
parent 7709e24ccd
commit fe5826bc8e
6 changed files with 182 additions and 19 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
export default function fullDisplayName({ schemaName, pureName }) {
if (schemaName) return `${schemaName}.${pureName}`;
return pureName;
}