Implement pagination
This commit is contained in:
parent
4dbee3a7b3
commit
8900443669
|
|
@ -105,6 +105,7 @@ export namespace Components {
|
|||
"propertyModel": ActivityDefinitionProperty;
|
||||
}
|
||||
interface ElsaPager {
|
||||
"history"?: RouterHistory;
|
||||
"page": number;
|
||||
"pageSize": number;
|
||||
"totalCount": number;
|
||||
|
|
@ -483,6 +484,7 @@ declare namespace LocalJSX {
|
|||
"propertyModel"?: ActivityDefinitionProperty;
|
||||
}
|
||||
interface ElsaPager {
|
||||
"history"?: RouterHistory;
|
||||
"page"?: number;
|
||||
"pageSize"?: number;
|
||||
"totalCount"?: number;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {Component, Event, EventEmitter, h, Prop} from '@stencil/core';
|
||||
import {RouterHistory} from "@stencil/router";
|
||||
|
||||
@Component({
|
||||
tag: 'elsa-pager',
|
||||
|
|
@ -9,11 +10,35 @@ export class ElsaPager {
|
|||
@Prop() page: number;
|
||||
@Prop() pageSize: number;
|
||||
@Prop() totalCount: number;
|
||||
@Prop() history?: RouterHistory;
|
||||
|
||||
basePath: string;
|
||||
|
||||
componentWillLoad() {
|
||||
this.basePath = !!this.history ? this.history.location.pathname : document.location.pathname;
|
||||
}
|
||||
|
||||
navigate(path: string) {
|
||||
if (this.history) {
|
||||
this.history.push(path);
|
||||
return;
|
||||
}
|
||||
|
||||
document.location.pathname = path;
|
||||
}
|
||||
|
||||
onNavigateClick(e: Event) {
|
||||
const anchor = e.currentTarget as HTMLAnchorElement;
|
||||
|
||||
e.preventDefault();
|
||||
this.navigate(`${anchor.pathname}${anchor.search}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
const page = this.page;
|
||||
const pageSize = this.pageSize;
|
||||
const totalCount = this.totalCount;
|
||||
const basePath = this.basePath;
|
||||
|
||||
const from = page * pageSize + 1;
|
||||
const to = Math.min(from + pageSize, totalCount);
|
||||
|
|
@ -22,12 +47,14 @@ export class ElsaPager {
|
|||
const maxPageButtons = 10;
|
||||
const fromPage = Math.max(0, page - maxPageButtons / 2);
|
||||
const toPage = Math.min(pageCount, fromPage + maxPageButtons);
|
||||
const self = this;
|
||||
|
||||
const renderPreviousButton = function () {
|
||||
if (page <= 0)
|
||||
return;
|
||||
|
||||
return <a href="#"
|
||||
return <a href={`${basePath}?page=${(page - 1)}&pageSize=${pageSize}`}
|
||||
onClick={e => self.onNavigateClick(e)}
|
||||
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>
|
||||
|
|
@ -37,7 +64,8 @@ export class ElsaPager {
|
|||
if (page >= pageCount)
|
||||
return;
|
||||
|
||||
return <a href="#"
|
||||
return <a href={`/${basePath}?page=${page + 1}&pageSize=${pageSize}`}
|
||||
onClick={e => self.onNavigateClick(e)}
|
||||
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>
|
||||
|
|
@ -48,7 +76,8 @@ export class ElsaPager {
|
|||
return;
|
||||
|
||||
return (
|
||||
<a href={`/workflow-instances?page=${(page - 1)}&pageSize=${pageSize}`}
|
||||
<a href={`${basePath}?page=${(page - 1)}&pageSize=${pageSize}`}
|
||||
onClick={e => self.onNavigateClick(e)}
|
||||
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">
|
||||
|
|
@ -62,8 +91,10 @@ export class ElsaPager {
|
|||
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">
|
||||
<a href={`${basePath}?page=${page + 1}&pageSize=${pageSize}`}
|
||||
onClick={e => self.onNavigateClick(e)}
|
||||
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>
|
||||
|
|
@ -86,7 +117,8 @@ export class ElsaPager {
|
|||
{i + 1}
|
||||
</span>);
|
||||
} else {
|
||||
buttons.push(<a href={`/workflow-instances?page=${i}&pageSize=${pageSize}`}
|
||||
buttons.push(<a href={`${basePath}?page=${i}&pageSize=${pageSize}`}
|
||||
onClick={e => self.onNavigateClick(e)}
|
||||
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>)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
this.selectedWorkflowId = query.workflow;
|
||||
this.selectedWorkflowStatus = query.status;
|
||||
this.selectedOrderBy = query.orderBy ?? OrderBy.Started;
|
||||
this.page = !!query.page ? parseInt(query.page) : 0;
|
||||
this.pageSize = !!query.pageSize ? parseInt(query.pageSize) : 25;
|
||||
}
|
||||
|
||||
async loadWorkflowBlueprints() {
|
||||
|
|
@ -75,6 +77,12 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
|
||||
if (!!orderBy)
|
||||
filters['orderBy'] = orderBy;
|
||||
|
||||
if(!!this.page)
|
||||
filters['page'] = this.page.toString();
|
||||
|
||||
if(!!this.pageSize)
|
||||
filters['pageSize'] = this.pageSize.toString();
|
||||
|
||||
const queryString = collection.map(filters, (v, k) => `${k}=${v}`).join('&');
|
||||
return `/workflow-instances?${queryString}`;
|
||||
|
|
@ -99,7 +107,9 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
}
|
||||
|
||||
async routeChanged(e: LocationSegments) {
|
||||
if (!e.pathname.toLowerCase().indexOf('workflow-instances'))
|
||||
debugger;
|
||||
|
||||
if (e.pathname.toLowerCase().indexOf('workflow-instances') < 0)
|
||||
return;
|
||||
|
||||
this.applyQueryString(e.search);
|
||||
|
|
@ -164,23 +174,27 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
const workflowInstances = this.workflowInstances.items;
|
||||
const workflowBlueprints = this.workflowBlueprints;
|
||||
|
||||
const viewIcon = (
|
||||
<svg class="h-5 w-5 text-gray-500" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
);
|
||||
const renderViewIcon = function () {
|
||||
return (
|
||||
<svg class="h-5 w-5 text-gray-500" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const deleteIcon = (
|
||||
<svg class="h-5 w-5 text-gray-500" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<line x1="4" y1="7" x2="20" y2="7"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"/>
|
||||
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"/>
|
||||
</svg>
|
||||
);
|
||||
const renderDeleteIcon = function () {
|
||||
return (
|
||||
<svg class="h-5 w-5 text-gray-500" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<line x1="4" y1="7" x2="20" y2="7"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"/>
|
||||
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -283,15 +297,15 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
</td>
|
||||
<td class="pr-6">
|
||||
<elsa-context-menu history={this.history} menuItems={[
|
||||
{text: 'View', anchorUrl: viewUrl, icon: viewIcon},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowInstance), icon: deleteIcon}
|
||||
{text: 'View', anchorUrl: viewUrl, icon: renderViewIcon()},
|
||||
{text: 'Delete', clickHandler: e => this.onDeleteClick(e, workflowInstance), icon: renderDeleteIcon()}
|
||||
]}/>
|
||||
</td>
|
||||
</tr>
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<elsa-pager page={this.page} pageSize={this.pageSize} totalCount={this.workflowInstances.totalCount}/>
|
||||
<elsa-pager page={this.page} pageSize={this.pageSize} totalCount={this.workflowInstances.totalCount} history={this.history}/>
|
||||
</div>
|
||||
<elsa-confirm-dialog ref={el => this.confirmDialog = el}/>
|
||||
</div>
|
||||
|
|
@ -323,15 +337,17 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
|
||||
items = [{text: 'All', value: null, url: this.buildFilterUrl(null, selectedWorkflowStatus, SelectedOrderBy), isSelected: !selectedWorkflowId}, ...items];
|
||||
|
||||
const icon = <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<rect x="4" y="4" width="6" height="6" rx="1"/>
|
||||
<rect x="14" y="4" width="6" height="6" rx="1"/>
|
||||
<rect x="4" y="14" width="6" height="6" rx="1"/>
|
||||
<rect x="14" y="14" width="6" height="6" rx="1"/>
|
||||
</svg>;
|
||||
const renderIcon = function () {
|
||||
return <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||
<rect x="4" y="4" width="6" height="6" rx="1"/>
|
||||
<rect x="14" y="4" width="6" height="6" rx="1"/>
|
||||
<rect x="4" y="14" width="6" height="6" rx="1"/>
|
||||
<rect x="14" y="14" width="6" height="6" rx="1"/>
|
||||
</svg>;
|
||||
};
|
||||
|
||||
return <elsa-dropdown-button text={selectedWorkflowText} items={items} icon={icon} origin={DropdownButtonOrigin.TopRight} onItemSelected={e => this.selectedWorkflowId = e.detail.value as string}/>
|
||||
return <elsa-dropdown-button text={selectedWorkflowText} items={items} icon={renderIcon()} origin={DropdownButtonOrigin.TopRight} onItemSelected={e => this.selectedWorkflowId = e.detail.value as string}/>
|
||||
}
|
||||
|
||||
renderStatusFilter() {
|
||||
|
|
@ -344,26 +360,31 @@ export class ElsaWorkflowInstancesListScreen {
|
|||
return ({text: text, url: this.buildFilterUrl(this.selectedWorkflowId, x, this.selectedOrderBy), isSelected: x == selectedWorkflowStatus});
|
||||
});
|
||||
|
||||
const icon = <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polygon points="10 8 16 12 10 16 10 8"/>
|
||||
</svg>;
|
||||
const renderIcon = function () {
|
||||
return <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polygon points="10 8 16 12 10 16 10 8"/>
|
||||
</svg>
|
||||
};
|
||||
|
||||
return <elsa-dropdown-button text={selectedWorkflowStatusText} items={items} icon={icon} origin={DropdownButtonOrigin.TopRight}/>
|
||||
return <elsa-dropdown-button text={selectedWorkflowStatusText} items={items} icon={renderIcon()} origin={DropdownButtonOrigin.TopRight}/>
|
||||
}
|
||||
|
||||
renderOrderByFilter() {
|
||||
const selectedOrderBy = this.selectedOrderBy;
|
||||
const selectedOrderByText = !!selectedOrderBy ? `Sort by: ${selectedOrderBy}` : 'Sort';
|
||||
const orderByValues: Array<OrderBy> = [OrderBy.Finished, OrderBy.LastExecuted, OrderBy.Started];
|
||||
|
||||
const items: Array<DropdownButtonItem> = orderByValues.map(x => {
|
||||
return ({text: x, url: this.buildFilterUrl(this.selectedWorkflowId, this.selectedWorkflowStatus, x), isSelected: x == selectedOrderBy});
|
||||
});
|
||||
|
||||
const icon = <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"/>
|
||||
</svg>;
|
||||
const renderIcon = function () {
|
||||
return <svg class="mr-3 h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4"/>
|
||||
</svg>
|
||||
};
|
||||
|
||||
return <elsa-dropdown-button text={selectedOrderByText} items={items} icon={icon} origin={DropdownButtonOrigin.TopRight}/>
|
||||
return <elsa-dropdown-button text={selectedOrderByText} items={items} icon={renderIcon()} origin={DropdownButtonOrigin.TopRight}/>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,6 +99,12 @@ export const createElsaClient = function (serverUrl: string): ElsaClient {
|
|||
if (!!searchTerm)
|
||||
queryString['searchTerm'] = searchTerm;
|
||||
|
||||
if (!!page)
|
||||
queryString['page'] = page;
|
||||
|
||||
if (!!pageSize)
|
||||
queryString['pageSize'] = pageSize;
|
||||
|
||||
const queryStringItems = collection.map(queryString, (v, k) => `${k}=${v}`);
|
||||
const queryStringText = queryStringItems.length > 0 ? `?${queryStringItems.join('&')}` : '';
|
||||
const response = await httpClient.get<PagedList<WorkflowInstanceSummary>>(`v1/workflow-instances${queryStringText}`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue