Incremental work on pager

This commit is contained in:
Sipke Schoorstra 2021-04-09 13:11:03 +02:00
parent c1a5981485
commit 86d958e4e8
3 changed files with 155 additions and 10 deletions

View file

@ -104,6 +104,11 @@ export namespace Components {
"propertyDescriptor": ActivityPropertyDescriptor;
"propertyModel": ActivityDefinitionProperty;
}
interface ElsaPager {
"page": number;
"pageSize": number;
"totalCount": number;
}
interface ElsaPropertyEditor {
"context"?: string;
"editorHeight": string;
@ -284,6 +289,12 @@ declare global {
prototype: HTMLElsaMultiTextPropertyElement;
new (): HTMLElsaMultiTextPropertyElement;
};
interface HTMLElsaPagerElement extends Components.ElsaPager, HTMLStencilElement {
}
var HTMLElsaPagerElement: {
prototype: HTMLElsaPagerElement;
new (): HTMLElsaPagerElement;
};
interface HTMLElsaPropertyEditorElement extends Components.ElsaPropertyEditor, HTMLStencilElement {
}
var HTMLElsaPropertyEditorElement: {
@ -366,6 +377,7 @@ declare global {
"elsa-monaco": HTMLElsaMonacoElement;
"elsa-multi-line-property": HTMLElsaMultiLinePropertyElement;
"elsa-multi-text-property": HTMLElsaMultiTextPropertyElement;
"elsa-pager": HTMLElsaPagerElement;
"elsa-property-editor": HTMLElsaPropertyEditorElement;
"elsa-script-property": HTMLElsaScriptPropertyElement;
"elsa-single-line-property": HTMLElsaSingleLinePropertyElement;
@ -470,6 +482,11 @@ declare namespace LocalJSX {
"propertyDescriptor"?: ActivityPropertyDescriptor;
"propertyModel"?: ActivityDefinitionProperty;
}
interface ElsaPager {
"page"?: number;
"pageSize"?: number;
"totalCount"?: number;
}
interface ElsaPropertyEditor {
"context"?: string;
"editorHeight"?: string;
@ -544,6 +561,7 @@ declare namespace LocalJSX {
"elsa-monaco": ElsaMonaco;
"elsa-multi-line-property": ElsaMultiLineProperty;
"elsa-multi-text-property": ElsaMultiTextProperty;
"elsa-pager": ElsaPager;
"elsa-property-editor": ElsaPropertyEditor;
"elsa-script-property": ElsaScriptProperty;
"elsa-single-line-property": ElsaSingleLineProperty;
@ -581,6 +599,7 @@ declare module "@stencil/core" {
"elsa-monaco": LocalJSX.ElsaMonaco & JSXBase.HTMLAttributes<HTMLElsaMonacoElement>;
"elsa-multi-line-property": LocalJSX.ElsaMultiLineProperty & JSXBase.HTMLAttributes<HTMLElsaMultiLinePropertyElement>;
"elsa-multi-text-property": LocalJSX.ElsaMultiTextProperty & JSXBase.HTMLAttributes<HTMLElsaMultiTextPropertyElement>;
"elsa-pager": LocalJSX.ElsaPager & JSXBase.HTMLAttributes<HTMLElsaPagerElement>;
"elsa-property-editor": LocalJSX.ElsaPropertyEditor & JSXBase.HTMLAttributes<HTMLElsaPropertyEditorElement>;
"elsa-script-property": LocalJSX.ElsaScriptProperty & JSXBase.HTMLAttributes<HTMLElsaScriptPropertyElement>;
"elsa-single-line-property": LocalJSX.ElsaSingleLineProperty & JSXBase.HTMLAttributes<HTMLElsaSingleLinePropertyElement>;

View file

@ -0,0 +1,128 @@
import {Component, Event, EventEmitter, h, Prop} from '@stencil/core';
@Component({
tag: 'elsa-pager',
shadow: false,
})
export class ElsaPager {
@Prop() page: number;
@Prop() pageSize: number;
@Prop() totalCount: number;
render() {
const page = this.page;
const pageSize = this.pageSize;
const totalCount = this.totalCount;
const from = page * pageSize + 1;
const to = Math.min(from + pageSize, totalCount);
const pageCount = Math.round(((totalCount - 1) / pageSize) + 1);
const maxPageButtons = 10;
const fromPage = Math.max(0, page - maxPageButtons / 2);
const toPage = Math.min(pageCount, fromPage + maxPageButtons);
const renderPreviousButton = function () {
if (page <= 0)
return;
return <a href="#"
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Previous
</a>
}
const renderNextButton = function () {
if (page >= pageCount)
return;
return <a href="#"
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Next
</a>
}
const renderChevronLeft = function () {
if (page <= 0)
return;
return (
<a href={`/workflow-instances?page=${(page - 1)}&pageSize=${pageSize}`}
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-500 hover:text-gray-400 focus:z-10 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
aria-label="Previous">
<svg class="h-5 w-5" x-description="Heroicon name: chevron-left" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
</a>);
}
const renderChevronRight = function () {
if (page >= pageCount - 1)
return;
return (
<a href={`/workflow-instances?page=${page + 1}&pageSize=${pageSize}`} class="-ml-px relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-500
hover:text-gray-400 focus:z-10 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150" aria-label="Next">
<svg class="h-5 w-5" x-description="Heroicon name: chevron-right" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
</svg>
</a>
);
}
const renderPagerButtons = function () {
const buttons = [];
for (let i = fromPage; i < toPage; i++) {
const isCurrent = page == i;
const isFirst = i == fromPage;
const isLast = i == toPage - 1;
const leftRoundedClass = isFirst && isCurrent ? "rounded-l-md" : "";
const rightRoundedClass = isLast && isCurrent ? "rounded-r-md" : "";
if (isCurrent) {
buttons.push(<span class={`-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium bg-blue-600 text-white ${leftRoundedClass} ${rightRoundedClass}`}>
{i + 1}
</span>);
} else {
buttons.push(<a href={`/workflow-instances?page=${i}&pageSize=${pageSize}`}
class={`-ml-px relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:z-10 focus:outline-none active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 ${leftRoundedClass}`}>
{i + 1}
</a>)
}
}
return buttons;
}
return (
<div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
<div class="flex-1 flex justify-between sm:hidden">
{renderPreviousButton()}
{renderNextButton()}
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm leading-5 text-gray-700 space-x-0.5">
<span>Showing</span>
<span class="font-medium">{from}</span>
<span>to</span>
<span class="font-medium">{to}</span>
<span>of</span>
<span class="font-medium">{totalCount}</span>
<span>results</span>
</p>
</div>
<div>
<nav class="relative z-0 inline-flex shadow-sm">
{renderChevronLeft()}
{renderPagerButtons()}
{renderChevronRight()}
</nav>
</div>
</div>
</div>
);
}
}

View file

@ -22,6 +22,8 @@ export class ElsaWorkflowInstancesListScreen {
@State() selectedOrderBy?: OrderBy = OrderBy.Started;
@State() selectedWorkflowInstanceIds: Array<string> = [];
@State() selectAllChecked: boolean;
@State() page: number = 0;
@State() pageSize: number = 25;
confirmDialog: HTMLElsaConfirmDialogElement;
@ -50,10 +52,7 @@ export class ElsaWorkflowInstancesListScreen {
async loadWorkflowInstances() {
const elsaClient = this.createClient();
const page = 1;
const pageSize = 25;
this.workflowInstances = await elsaClient.workflowInstancesApi.list(page, pageSize, this.selectedWorkflowId, this.selectedWorkflowStatus, this.selectedOrderBy);
this.workflowInstances = await elsaClient.workflowInstancesApi.list(this.page, this.pageSize, this.selectedWorkflowId, this.selectedWorkflowStatus, this.selectedOrderBy);
}
createClient() {
@ -140,8 +139,8 @@ export class ElsaWorkflowInstancesListScreen {
await elsaClient.workflowInstancesApi.delete(workflowInstance.id);
await this.loadWorkflowInstances();
}
async onBulkDelete(){
async onBulkDelete() {
const result = await this.confirmDialog.show('Delete Selected Workflow Instances', 'Are you sure you wish to permanently delete all selected workflow instances?');
if (!result)
@ -154,9 +153,8 @@ export class ElsaWorkflowInstancesListScreen {
async onBulkActionSelected(e: CustomEvent<DropdownButtonItem>) {
const action = e.detail;
switch(action.name)
{
switch (action.name) {
case 'Delete':
await this.onBulkDelete();
}
@ -293,7 +291,7 @@ export class ElsaWorkflowInstancesListScreen {
})}
</tbody>
</table>
<elsa-pager page="@WorkflowInstances.Page" pageSize="@WorkflowInstances.PageSize" totalCount="@WorkflowInstances.TotalCount"/>
<elsa-pager page={this.page} pageSize={this.pageSize} totalCount={this.workflowInstances.totalCount}/>
</div>
<elsa-confirm-dialog ref={el => this.confirmDialog = el}/>
</div>