mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 03:16:01 +00:00
SYNC: Merge pull request #3 from dbgate/feature/zip
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
props?: any;
|
||||
formatter?: any;
|
||||
slot?: number;
|
||||
slotKey?: string;
|
||||
isHighlighted?: Function;
|
||||
sortable?: boolean;
|
||||
filterable?: boolean;
|
||||
@@ -25,12 +26,15 @@
|
||||
import { evalFilterBehaviour } from 'dbgate-tools';
|
||||
import { evaluateCondition } from 'dbgate-sqltree';
|
||||
import { compileCompoudEvalCondition } from 'dbgate-filterparser';
|
||||
import { chevronExpandIcon } from '../icons/expandIcons';
|
||||
|
||||
export let columns: (TableControlColumn | false)[];
|
||||
export let rows;
|
||||
export let rows = null;
|
||||
export let groupedRows = null;
|
||||
export let focusOnCreate = false;
|
||||
export let selectable = false;
|
||||
export let selectedIndex = 0;
|
||||
export let selectedKey = null;
|
||||
export let clickable = false;
|
||||
export let disableFocusOutline = false;
|
||||
export let emptyMessage = null;
|
||||
@@ -41,9 +45,12 @@
|
||||
|
||||
export let checkedKeys = null;
|
||||
export let onSetCheckedKeys = null;
|
||||
export let extractCheckedKey = x => x.id;
|
||||
export let extractTableItemKey = x => x.id;
|
||||
export let itemSupportsCheckbox = x => true;
|
||||
export let filters = null;
|
||||
|
||||
export let selectionMode: 'index' | 'key' = 'index';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: columnList = _.compact(_.flatten(columns));
|
||||
@@ -53,37 +60,120 @@
|
||||
});
|
||||
|
||||
const handleKeyDown = event => {
|
||||
if (event.keyCode == keycodes.downArrow) {
|
||||
selectedIndex = Math.min(selectedIndex + 1, sortedRows.length - 1);
|
||||
const oldSelectedIndex =
|
||||
selectionMode == 'index' ? selectedIndex : _.findIndex(flatRowsShown, x => extractTableItemKey(x) == selectedKey);
|
||||
let newIndex = oldSelectedIndex;
|
||||
|
||||
switch (event.keyCode) {
|
||||
case keycodes.downArrow:
|
||||
newIndex = Math.min(newIndex + 1, flatRowsShown.length - 1);
|
||||
break;
|
||||
case keycodes.upArrow:
|
||||
newIndex = Math.max(0, newIndex - 1);
|
||||
break;
|
||||
case keycodes.home:
|
||||
newIndex = 0;
|
||||
break;
|
||||
case keycodes.end:
|
||||
newIndex = rows.length - 1;
|
||||
break;
|
||||
case keycodes.pageUp:
|
||||
newIndex -= 10;
|
||||
break;
|
||||
case keycodes.pageDown:
|
||||
newIndex += 10;
|
||||
break;
|
||||
}
|
||||
if (event.keyCode == keycodes.upArrow) {
|
||||
selectedIndex = Math.max(0, selectedIndex - 1);
|
||||
if (newIndex < 0) {
|
||||
newIndex = 0;
|
||||
}
|
||||
if (newIndex >= flatRowsShown.length) {
|
||||
newIndex = flatRowsShown.length - 1;
|
||||
}
|
||||
|
||||
if (clickable && oldSelectedIndex != newIndex) {
|
||||
event.preventDefault();
|
||||
domRows[newIndex]?.scrollIntoView();
|
||||
if (clickable) {
|
||||
dispatch('clickrow', flatRowsShown[newIndex]);
|
||||
}
|
||||
if (selectionMode == 'index') {
|
||||
selectedIndex = newIndex;
|
||||
} else {
|
||||
selectedKey = extractTableItemKey(flatRowsShown[newIndex]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function filterRows(rows, filters) {
|
||||
function filterRows(grows, filters) {
|
||||
const condition = compileCompoudEvalCondition(filters);
|
||||
|
||||
if (!condition) return rows;
|
||||
if (!condition) return grows;
|
||||
|
||||
return rows.filter(row => {
|
||||
const newrow = { ...row };
|
||||
for (const col of columnList) {
|
||||
if (col.filteredExpression) {
|
||||
newrow[col.fieldName] = col.filteredExpression(row);
|
||||
}
|
||||
}
|
||||
return evaluateCondition(condition, newrow);
|
||||
});
|
||||
return grows
|
||||
.map(gitem => {
|
||||
return {
|
||||
group: gitem.group,
|
||||
rows: gitem.rows.filter(row => {
|
||||
const newrow = { ...row };
|
||||
for (const col of columnList) {
|
||||
if (col.filteredExpression) {
|
||||
newrow[col.fieldName] = col.filteredExpression(row);
|
||||
}
|
||||
}
|
||||
return evaluateCondition(condition, newrow);
|
||||
}),
|
||||
};
|
||||
})
|
||||
.filter(gitem => gitem.rows.length > 0);
|
||||
}
|
||||
|
||||
// function computeGroupedRows(array) {
|
||||
// if (!extractGroupName) {
|
||||
// return [{ label: null, rows: array }];
|
||||
// }
|
||||
// const res = [];
|
||||
// let lastGroupName = null;
|
||||
// let buildArray = [];
|
||||
// for (const item of array) {
|
||||
// const groupName = extractGroupName(item);
|
||||
// if (lastGroupName != groupName) {
|
||||
// if (buildArray.length > 0) {
|
||||
// res.push({ label: lastGroupName, rows: buildArray });
|
||||
// }
|
||||
// lastGroupName = groupName;
|
||||
// buildArray = [];
|
||||
// }
|
||||
// buildArray.push(item);
|
||||
// }
|
||||
// if (buildArray.length > 0) {
|
||||
// res.push({ label: lastGroupName, rows: buildArray });
|
||||
// }
|
||||
// }
|
||||
|
||||
let sortedByField = null;
|
||||
let sortOrderIsDesc = false;
|
||||
let collapsedGroupIndexes = [];
|
||||
let domRows = {};
|
||||
|
||||
$: filteredRows = filters ? filterRows(rows, $filters) : rows;
|
||||
$: rowsSource = groupedRows ? groupedRows : [{ group: null, rows }];
|
||||
|
||||
$: sortedRowsTmp = sortedByField ? _.sortBy(filteredRows || [], sortedByField) : filteredRows;
|
||||
$: sortedRows = sortOrderIsDesc ? [...sortedRowsTmp].reverse() : sortedRowsTmp;
|
||||
$: filteredRows = filters ? filterRows(rowsSource, $filters) : rowsSource;
|
||||
|
||||
$: sortedRows = sortedByField
|
||||
? filteredRows.map(gitem => {
|
||||
let res = _.sortBy(gitem.rows, sortedByField);
|
||||
if (sortOrderIsDesc) res = [...res].reverse();
|
||||
return { group: gitem.group, rows: res };
|
||||
})
|
||||
: filteredRows;
|
||||
|
||||
// $: console.log('sortedRows', sortedRows);
|
||||
|
||||
$: flatRowsShown = sortedRows.map(gitem => gitem.rows).flat();
|
||||
$: checkableFlatRowsShown = flatRowsShown.filter(x => itemSupportsCheckbox(x));
|
||||
|
||||
// $: groupedRows = computeGroupedRows(sortedRows);
|
||||
</script>
|
||||
|
||||
<table
|
||||
@@ -98,7 +188,16 @@
|
||||
<thead class:stickyHeader>
|
||||
<tr>
|
||||
{#if checkedKeys}
|
||||
<th></th>
|
||||
<th>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checkableFlatRowsShown.every(r => checkedKeys.includes(extractTableItemKey(r)))}
|
||||
on:change={e => {
|
||||
if (e.target['checked']) onSetCheckedKeys(checkableFlatRowsShown.map(r => extractTableItemKey(r)));
|
||||
else onSetCheckedKeys([]);
|
||||
}}
|
||||
/>
|
||||
</th>
|
||||
{/if}
|
||||
{#each columnList as col}
|
||||
<th
|
||||
@@ -129,7 +228,7 @@
|
||||
{#if filters}
|
||||
<tr>
|
||||
{#if checkedKeys}
|
||||
<td></td>
|
||||
<td class="empty-cell"></td>
|
||||
{/if}
|
||||
{#each columnList as col}
|
||||
<td class="filter-cell" class:empty-cell={!col.filterable}>
|
||||
@@ -147,58 +246,91 @@
|
||||
{/if}
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each sortedRows as row, index}
|
||||
<tr
|
||||
class:selected={selectable && selectedIndex == index}
|
||||
class:clickable
|
||||
on:click={() => {
|
||||
if (selectable) {
|
||||
selectedIndex = index;
|
||||
domTable.focus();
|
||||
}
|
||||
if (clickable) {
|
||||
dispatch('clickrow', row);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if checkedKeys}
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checkedKeys.includes(extractCheckedKey(row))}
|
||||
on:change={e => {
|
||||
if (e.target['checked']) onSetCheckedKeys(_.uniq([...checkedKeys, extractCheckedKey(row)]));
|
||||
else onSetCheckedKeys(checkedKeys.filter(x => x != extractCheckedKey(row)));
|
||||
}}
|
||||
/>
|
||||
{#each sortedRows as gitem, groupIndex}
|
||||
{#if gitem.group}
|
||||
<tr class="group-row">
|
||||
<td
|
||||
colspan={columnList.length + (checkedKeys ? 1 : 0)}
|
||||
class="groupcell"
|
||||
on:click={() => {
|
||||
if (collapsedGroupIndexes.includes(groupIndex)) {
|
||||
collapsedGroupIndexes = collapsedGroupIndexes.filter(x => x != groupIndex);
|
||||
} else {
|
||||
collapsedGroupIndexes = [...collapsedGroupIndexes, groupIndex];
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FontIcon icon={chevronExpandIcon(!collapsedGroupIndexes.includes(groupIndex))} padRight />
|
||||
<strong>{gitem.group} ({gitem.rows.length})</strong>
|
||||
</td>
|
||||
{/if}
|
||||
{#each columnList as col}
|
||||
{@const rowProps = { ...col.props, ...(col.getProps ? col.getProps(row) : null) }}
|
||||
<td class:isHighlighted={col.isHighlighted && col.isHighlighted(row)} class:noCellPadding>
|
||||
{#if col.component}
|
||||
<svelte:component this={col.component} {...rowProps} />
|
||||
{:else if col.formatter}
|
||||
{col.formatter(row)}
|
||||
{:else if col.slot != null}
|
||||
{#if col.slot == -1}<slot name="-1" {row} {col} {index} />
|
||||
{:else if col.slot == 0}<slot name="0" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 1}<slot name="1" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 2}<slot name="2" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 3}<slot name="3" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 4}<slot name="4" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 5}<slot name="5" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 6}<slot name="6" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 7}<slot name="7" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 8}<slot name="8" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 9}<slot name="9" {row} {col} {index} {...rowProps} />
|
||||
{/if}
|
||||
{:else}
|
||||
{row[col.fieldName] || ''}
|
||||
</tr>
|
||||
{/if}
|
||||
{#if !collapsedGroupIndexes.includes(groupIndex)}
|
||||
{#each gitem.rows as row}
|
||||
{@const index = _.indexOf(flatRowsShown, row)}
|
||||
<tr
|
||||
class:selected={selectable &&
|
||||
(selectionMode == 'index' ? selectedIndex == index : selectedKey == extractTableItemKey(row))}
|
||||
class:clickable
|
||||
bind:this={domRows[index]}
|
||||
on:click={() => {
|
||||
if (selectable) {
|
||||
if (selectionMode == 'index') {
|
||||
selectedIndex = index;
|
||||
} else {
|
||||
selectedKey = extractTableItemKey(row);
|
||||
}
|
||||
domTable.focus();
|
||||
}
|
||||
if (clickable) {
|
||||
dispatch('clickrow', row);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if checkedKeys}
|
||||
<td>
|
||||
{#if itemSupportsCheckbox(row)}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={checkedKeys.includes(extractTableItemKey(row))}
|
||||
on:change={e => {
|
||||
if (e.target['checked']) onSetCheckedKeys(_.uniq([...checkedKeys, extractTableItemKey(row)]));
|
||||
else onSetCheckedKeys(checkedKeys.filter(x => x != extractTableItemKey(row)));
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
</td>
|
||||
{#each columnList as col}
|
||||
{@const rowProps = { ...col.props, ...(col.getProps ? col.getProps(row) : null) }}
|
||||
<td class:isHighlighted={col.isHighlighted && col.isHighlighted(row)} class:noCellPadding>
|
||||
{#if col.component}
|
||||
<svelte:component this={col.component} {...rowProps} />
|
||||
{:else if col.formatter}
|
||||
{col.formatter(row)}
|
||||
{:else if col.slot != null}
|
||||
{#key row[col.slotKey] || 'key'}
|
||||
{#if col.slot == -1}<slot name="-1" {row} {col} {index} />
|
||||
{:else if col.slot == 0}<slot name="0" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 1}<slot name="1" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 2}<slot name="2" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 3}<slot name="3" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 4}<slot name="4" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 5}<slot name="5" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 6}<slot name="6" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 7}<slot name="7" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 8}<slot name="8" {row} {col} {index} {...rowProps} />
|
||||
{:else if col.slot == 9}<slot name="9" {row} {col} {index} {...rowProps} />
|
||||
{/if}
|
||||
{/key}
|
||||
{:else}
|
||||
{row[col.fieldName] || ''}
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if emptyMessage && sortedRows.length == 0}
|
||||
<tr>
|
||||
@@ -223,6 +355,9 @@
|
||||
background: var(--theme-bg-0);
|
||||
}
|
||||
tbody tr.selected {
|
||||
background: var(--theme-bg-3);
|
||||
}
|
||||
table:focus tbody tr.selected {
|
||||
background: var(--theme-bg-selected);
|
||||
}
|
||||
tbody tr.clickable:hover {
|
||||
@@ -287,4 +422,9 @@
|
||||
.empty-cell {
|
||||
background-color: var(--theme-bg-1);
|
||||
}
|
||||
|
||||
.groupcell {
|
||||
background-color: var(--theme-bg-1);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user