@3mo/fetchable-data-grid
Version:
A fetchable variant of @3mo/data-grid
174 lines (172 loc) • 6.56 kB
JavaScript
import { __decorate } from "tslib";
import { Binder, component, css, event, html, property, bind } from '@a11d/lit';
import { hasChanged } from '@a11d/equals';
import { Localizer } from '@3mo/localization';
import { DataGrid } from '@3mo/data-grid';
import { FetchableDataGridFetcherController } from './FetchableDataGridFetcherController.js';
import './FetchableDataGridRefetchIconButton.js';
Localizer.dictionaries.add('de', {
'Make a filter selection': 'Filterauswahl vornehmen',
});
/**
* @element mo-fetchable-data-grid
*
* @attr fetch - A function that fetches the data from the server.
* @attr silentFetch - If set, the DataGrid's content will not be cleared when the fetch is initiated.
* @attr parameters - The parameters that are passed to the fetch function.
* @attr paginationParameters - The parameters that are passed to the fetch function when the page changes. This enables server-side pagination.
* @attr sortParameters - The parameters that are passed to the fetch function when the sort changes. This enables server-side sorting.
* @attr autoRefetch - The interval in seconds at which the data should be refetched automatically. If set, the DataGrid will automatically refetch the data at the specified interval.
*
* @slot error-no-selection - A slot for displaying an error message when user action is required in order for DataGrid to initiate the fetch.
*
* @fires parametersChange
* @fires dataFetch
*/
let FetchableDataGrid = class FetchableDataGrid extends DataGrid {
constructor() {
super(...arguments);
this.fetch = () => Promise.resolve([]);
this.silentFetch = false;
this.fetcherController = new FetchableDataGridFetcherController(this);
this.parametersBinder = new Binder(this, 'parameters');
}
get hasNextPage() {
return !this.hasServerSidePagination ? super.hasNextPage : this.fetcherController.hasNextPage;
}
get dataLength() {
return !this.hasServerSidePagination ? super.dataLength : this.fetcherController.dataLength;
}
requestFetch(...parameters) {
return this.fetcherController.fetch(...parameters);
}
static get styles() {
return css `
${super.styles}
mo-circular-progress {
position: absolute;
width: 48px;
height: 48px;
inset-inline-start: 50%;
inset-block-start: 50%;
transform: translate(-50%, calc(-50% + var(--mo-data-grid-header-height) / 2));
}
`;
}
get hasServerSidePagination() {
return this.paginationParameters !== undefined;
}
get hasServerSideSort() {
return this.sortParameters !== undefined;
}
setParameters(parameters) {
this.parameters = parameters;
this.parametersChange.dispatch(this.parameters);
}
get dataSkip() {
return !this.hasServerSidePagination ? super.dataSkip : 0;
}
get dataTake() {
return !this.hasServerSidePagination ? super.dataTake : Number.MAX_SAFE_INTEGER;
}
async *getCsvData() {
const data = new Array();
const pageSize = 500;
const parameters = { ...this.parameters };
const sortParameters = this.sortParameters?.() ?? {};
let dataLength = this.dataLength;
let hasNextPage = true;
let page = 1;
while (true) {
const paginationParameters = this.paginationParameters?.({ page, pageSize }) ?? {};
const result = await this.fetch({
...parameters,
...paginationParameters,
...sortParameters,
}) ?? [];
if (result instanceof Array) {
data.push(...result);
hasNextPage = false;
dataLength = data.length;
}
else {
dataLength = result.dataLength ?? 0;
hasNextPage = result.hasNextPage ?? (page < Math.ceil(result.dataLength / pageSize));
data.push(...result.data);
}
page++;
yield Math.min(Math.floor(data.length / dataLength * 100) / 100, 1);
if (!hasNextPage) {
break;
}
}
return [...this.getFlattenedData(data)];
}
get hasPagination() {
return super.hasPagination || this.hasServerSidePagination;
}
get supportsDynamicPageSize() {
return super.supportsDynamicPageSize && !this.hasServerSidePagination;
}
get toolbarActionsTemplate() {
return html `
<mo-fetchable-data-grid-refetch-icon-button
?fetching=${this.fetcherController.pending}
autoRefetch=${bind(this, 'autoRefetch')}
=${() => this.requestFetch()}
></mo-fetchable-data-grid-refetch-icon-button>
${super.toolbarActionsTemplate}
`;
}
get contentTemplate() {
this.toggleAttribute('fetching', this.fetcherController.pending);
switch (true) {
case this.fetcherController.pending && this.fetcherController.silent === false:
return this.fetchingTemplate;
case this.data.length === 0 && this.parameters === undefined:
return this.noSelectionTemplate;
default:
return super.contentTemplate;
}
}
get fetchingTemplate() {
return html `
<mo-circular-progress></mo-circular-progress>
`;
}
get noSelectionTemplate() {
return html `
<slot name='error-no-selection'>
<mo-empty-state icon='touch_app'>${t('Make a filter selection')}</mo-empty-state>
</slot>
`;
}
};
__decorate([
event()
], FetchableDataGrid.prototype, "parametersChange", void 0);
__decorate([
event()
], FetchableDataGrid.prototype, "dataFetch", void 0);
__decorate([
property({ type: Object, hasChanged })
], FetchableDataGrid.prototype, "fetch", void 0);
__decorate([
property({ type: Boolean })
], FetchableDataGrid.prototype, "silentFetch", void 0);
__decorate([
property({ type: Object, hasChanged })
], FetchableDataGrid.prototype, "parameters", void 0);
__decorate([
property({ type: Object, hasChanged })
], FetchableDataGrid.prototype, "paginationParameters", void 0);
__decorate([
property({ type: Object, hasChanged })
], FetchableDataGrid.prototype, "sortParameters", void 0);
__decorate([
property({ type: Number, updated() { this.fetcherController.updateTimer(); } })
], FetchableDataGrid.prototype, "autoRefetch", void 0);
FetchableDataGrid = __decorate([
component('mo-fetchable-data-grid')
], FetchableDataGrid);
export { FetchableDataGrid };