Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import FrequencySelect from '@uikit/Table/FrequencySelect/FrequencySelect';

const ActionsToolbar: React.FC = () => {
const dispatch = useDispatch();
const actions = useStore(({ adh }) => adh.actions.actions);

const totalCount = useStore(({ adh }) => adh.actions.totalCount);
const paginationParams = useStore(({ adh }) => adh.actionsTable.paginationParams);
const requestFrequency = useStore(({ adh }) => adh.actionsTable.requestFrequency);

Expand All @@ -43,8 +44,8 @@ const ActionsToolbar: React.FC = () => {
<FlexGroup gap="20px" className={s.actionsToolbar}>
<ActionsResetFilter />
<Pagination
isNextBtn={actions.length === paginationParams.perPage}
pageData={paginationParams}
totalItems={totalCount}
onChangeData={handlePaginationChange}
frequencyComponent={<FrequencySelect value={requestFrequency} onChange={handleFrequencyChange} />}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import FrequencySelect from '@uikit/Table/FrequencySelect/FrequencySelect';

const AuditEventsToolbar: React.FC = () => {
const dispatch = useDispatch();
const auditEvents = useStore(({ adh }) => adh.auditEvents.auditEvents);

const totalCount = useStore(({ adh }) => adh.auditEvents.totalCount);
const paginationParams = useStore(({ adh }) => adh.auditEventsTable.paginationParams);
const requestFrequency = useStore(({ adh }) => adh.auditEventsTable.requestFrequency);

Expand All @@ -43,8 +44,8 @@ const AuditEventsToolbar: React.FC = () => {
<FlexGroup gap="20px" className={s.auditEventsToolbar}>
<AuditEventsResetFilter />
<Pagination
isNextBtn={auditEvents.length === paginationParams.perPage}
pageData={paginationParams}
totalItems={totalCount}
onChangeData={handlePaginationChange}
frequencyComponent={<FrequencySelect value={requestFrequency} onChange={handleFrequencyChange} />}
/>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 10 additions & 13 deletions smart-frontend/app/src/components/uikit/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { usePagination } from './usePagination';
import type { PaginationDataItem, PaginationProps } from '@uikit/Pagination/Pagination.types';
import { defaultPerPagesList } from '@constants';

const MAX_VISIBLE_ITEMS = 9;
const MAX_VISIBLE_ITEMS = 7;
const DEFAULT_PER_PAGE_ITEMS = 14;

interface renderButtonsProps {
Expand All @@ -49,10 +49,7 @@ const RenderNumberButtons = ({ items, setPageNumber, currentPageNumber }: render
{item.label}
</PaginationNumButton>
) : (
<PaginationDots
key={`dots_${item.key}`}
dotsHandler={() => setPageNumber(currentPageNumber - item.pageNumber)}
>
<PaginationDots key={`dots_${item.key}`} dotsHandler={() => setPageNumber(item.pageNumber)}>
{item.label}
</PaginationDots>
),
Expand Down Expand Up @@ -109,32 +106,32 @@ const Pagination = ({
<div className={paginationWrapperClasses} data-qa={dataTest}>
<div className={s.pagination__buttonWrapper} data-qa="pagination-button-container">
<RenderNumberButtons setPageNumber={setPageNumber} items={pageItems} currentPageNumber={pageNumber} />
{totalPages === 0 && (
{totalPages !== 0 && (
<PaginationStepButton
arrowVariant={'arrowDouble'}
variant={'prev'}
arrowVariant="arrowDouble"
variant="prev"
onClick={() => setPageNumber(0)}
disabled={!hasPrev}
/>
)}
<PaginationStepButton
arrowVariant={'arrowSingle'}
arrowVariant="arrowSingle"
onClick={() => setPageNumber(pageNumber - 1)}
disabled={!hasPrev}
dataTest="pagination-prev-page"
/>
<PaginationStepButton
arrowVariant={'arrowSingle'}
arrowVariant="arrowSingle"
onClick={() => setPageNumber(pageNumber + 1)}
variant={'next'}
variant="next"
disabled={!hasNext}
dataTest="pagination-next-page"
/>
{totalItems !== 0 && (
<PaginationStepButton
arrowVariant={'arrowDouble'}
arrowVariant="arrowDouble"
onClick={() => setPageNumber(totalItems)}
variant={'next'}
variant="next"
disabled={!hasNext}
dataTest="pagination-last-page"
/>
Expand Down
202 changes: 88 additions & 114 deletions smart-frontend/app/src/components/uikit/Pagination/usePagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,134 +59,122 @@ interface Results {
}

export function usePagination(params: UsePaginationParams): Results {
const { pageNumber, totalItems, maxItems, isNextBtn, perPage } = params;
const totalPages = Math.ceil(totalItems / perPage);
const { pageNumber, totalItems, perPage, maxItems, isNextBtn } = params;

const totalPages = Math.max(1, Math.ceil(totalItems / perPage));
const hasNext = typeof isNextBtn === 'boolean' ? isNextBtn : pageNumber < totalPages - 1;
const hasPrev = pageNumber > 0;

const decorationPrev = pageNumber - DECORATION_STEP >= 0 ? DECORATION_STEP : 0;
const decorationNext = pageNumber + DECORATION_STEP <= totalPages - 1 ? -DECORATION_STEP : totalPages - 1;

const linksAt = useMemo<LinksAt>(() => {
// 0 1 2 3 4
// All pages fits, no need for dots
// 1 2 3 4 5 6 7
if (totalPages <= maxItems) {
return 'none';
}

// 0 1 2 3 4 ... 99
const boundary = maxItems - TRAILING_ITEMS_AMOUNT - 1;

// 1 2 3 4 5 … 100
// ^
if (pageNumber < maxItems - TRAILING_ITEMS_AMOUNT - 1) {
if (pageNumber <= boundary) {
return 'start';
}

// 0 ... 49 50 60 ... 99
// 1 … 96 97 98 99 100
// ^
if (
pageNumber >= maxItems - TRAILING_ITEMS_AMOUNT - 1 &&
pageNumber < totalPages - (maxItems - TRAILING_ITEMS_AMOUNT * 2)
) {
return 'center';
if (pageNumber >= totalPages - 1 - boundary) {
return 'end';
}

// 0 ... 95 96 97 98 99
// 1 … 48 49 50 51 52 … 100
// ^
return 'end';
}, [pageNumber, maxItems, totalPages]);
return 'center';
}, [pageNumber, totalPages, maxItems]);

// Dots lead on these pages (±5 from current)
const prevDecorationPage = Math.max(0, pageNumber - DECORATION_STEP);
const nextDecorationPage = Math.min(totalPages - 1, pageNumber + DECORATION_STEP);

const pageItems = useMemo<PaginationDataItem[]>(() => {
const items: PaginationDataItem[] = [];

const addPage = (num: number) => {
items.push({
key: `page-${num}`,
type: 'page',
label: (num + 1).toString(),
pageNumber: num,
});
};

const addDots = (targetPage: number) => {
items.push({
key: `dots-${items.length}`,
type: 'decoration',
label: '...',
pageNumber: targetPage,
});
};

switch (linksAt) {
case 'none': {
const from = 0;
const to = totalPages - 1;
const index = 0;

return getLinks(from, to, index);
for (let i = 0; i < totalPages; i++) {
addPage(i);
}
break;
}

case 'start': {
const from = 0;
const to = maxItems - TRAILING_ITEMS_AMOUNT - 1;
const index = 0;
const startLinks = getLinks(from, to, index);

return [
...startLinks,
{
key: startLinks.length.toString(),
type: 'decoration',
label: '...',
pageNumber: decorationNext,
},
{
key: (startLinks.length + 1).toString(),
type: 'page',
label: totalPages.toString(),
pageNumber: totalPages - 1,
},
];
for (let i = 0; i < maxItems - 1; i++) {
addPage(i);
}
addDots(nextDecorationPage);
addPage(totalPages - 1);
break;
}

case 'center': {
const iterations = maxItems - TRAILING_ITEMS_AMOUNT * 2;
const spot = Math.ceil(iterations / 2);
const from = pageNumber - spot + 1;
const to = from + iterations - 1;
const index = 2;
const midLinks = getLinks(from, to, index);

return [
{
key: '0',
type: 'page',
label: '1',
pageNumber: 0,
},
{
key: '1',
type: 'decoration',
label: '...',
pageNumber: decorationPrev,
},
...midLinks,
{
key: (index + midLinks.length).toString(),
type: 'decoration',
label: '...',
pageNumber: decorationNext,
},
{
key: (index + midLinks.length + 1).toString(),
type: 'page',
label: totalPages.toString(),
pageNumber: totalPages - 1,
},
];
addPage(0);
addDots(prevDecorationPage);

const middleCount = maxItems - 4;
const half = Math.floor(middleCount / 2);
let start = pageNumber - half;
let end = pageNumber + half + (middleCount % 2);

if (start < 2) {
end += 2 - start;
start = 2;
}
if (end > totalPages - 3) {
start -= end - (totalPages - 3);
end = totalPages - 3;
}
start = Math.max(start, 2);
end = Math.min(end, totalPages - 3);

for (let i = start; i <= end; i++) {
addPage(i);
}

addDots(nextDecorationPage);
addPage(totalPages - 1);
break;
}

case 'end': {
const from = totalPages - (maxItems - TRAILING_ITEMS_AMOUNT);
const to = totalPages - 1;
const index = 2;
const endLinks = getLinks(from, to, index);

return [
{
key: '0',
type: 'page',
label: '1',
pageNumber: 0,
},
{
key: '1',
type: 'decoration',
label: '...',
pageNumber: decorationPrev,
},
...endLinks,
];
}
default: {
return [];
addPage(0);
addDots(prevDecorationPage);

for (let i = totalPages - (maxItems - 1); i < totalPages; i++) {
addPage(i);
}
break;
}
}
}, [linksAt, totalPages, maxItems, decorationNext, pageNumber, decorationPrev]);

return items;
}, [linksAt, pageNumber, totalPages, maxItems, prevDecorationPage, nextDecorationPage]);

return {
hasNext,
Expand All @@ -195,17 +183,3 @@ export function usePagination(params: UsePaginationParams): Results {
totalPages,
};
}

function getLinks(from: number, to: number, index: number): PaginationDataItem[] {
const links: PaginationDataItem[] = [];
for (let pageNumber = from; pageNumber <= to; pageNumber += 1) {
links.push({
key: (pageNumber - from + index).toString(),
type: 'page',
label: (pageNumber + 1).toString(),
pageNumber,
});
}

return links;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,23 @@ public interface PaginationElement {
String NEXT_PAGE_BUTTON = ".//*[@data-qa='pagination-next-page']";
String PREV_PAGE_BUTTON = ".//*[@data-qa='pagination-prev-page']";
String LAST_PAGE_BUTTON = ".//*[@data-qa='pagination-last-page']";
String PAGE_BUTTONS = ".//*[contains(@class, 'paginationButton') and not(contains(@class, 'Arrow'))]";
String EXTEND_PAGES_BUTTON = ".//*[contains(@class, 'paginationButton') and .='...']";
String SHOW_PER_PAGE_INPUT = ".//*[contains(@class, 'pagination') and contains(@class, 'commonSelectField')]//input";
ElementsCollection SHOW_PER_PAGE_OPTIONS = $$x(".//*[@data-qa='pagination-per-page-popover']//li");

static SelenideElement getNumberedButtonByPageNum(int pageNum, SelenideElement baseElement) {
return getNumberedButtons(baseElement).find(exactText(String.valueOf(pageNum)));
static ElementsCollection getPageButtons(SelenideElement baseElement) {
return findAllFromBaseElement(baseElement, PAGE_BUTTONS);
}

static ElementsCollection getNumberedButtons(SelenideElement baseElement) {
return findAllFromBaseElement(baseElement, PAGINATION_NUMBERED_BUTTONS);
}

static SelenideElement getNumberedButtonByPageNum(int pageNum, SelenideElement baseElement) {
return getNumberedButtons(baseElement).find(exactText(String.valueOf(pageNum)));
}

static SelenideElement getPerPageInput(SelenideElement baseElement) {
return findFromBaseElement(baseElement, SHOW_PER_PAGE_INPUT);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.restassured.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.smartdata.client.generated.invoker.ApiClient;
import org.smartdata.client.generated.model.ActionInfoDto;
import org.smartdata.client.generated.model.SubmitActionRequestDto;
import org.smartdata.client.generated.model.SubmitRuleRequestDto;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -42,12 +43,11 @@ public ApiStep createRule(String ruleText) {
return this;
}

public ApiStep createAction(String actionText) {
apiClient.actions().submitAction()
public ActionInfoDto createAction(String actionText) {
return apiClient.actions().submitAction()
.body(new SubmitActionRequestDto().action(actionText))
.respSpec(response -> response.expectStatusCode(200))
.executeAs(Response::andReturn);
return this;
}

public ApiClient getRawClient() {
Expand Down
Loading