Skip to content

Commit

Permalink
[explorer] adds pagination to tx data for Address and Object Results …
Browse files Browse the repository at this point in the history
…Pages (MystenLabs#2547)

* lists transactions sent from/to address

* improves wording

* lists transactions as clickable links

* deduplicate transactions list

* creates TxForID component

* creates test and static data

* adds SDK method for getting tx on object

* updates frontend to work with new SDK method

* moves tx into separate section

* WIP ungroup tx in SDK

* tidy up after rebase

* add types to object SDK

* static mode set up to work

* stylize tx for objects

* tidies up

* tx at bottom

* add check to stop errors and add more data to object with tx

* improves small-screen spacing

* widen gap at bottom

* further small-screen space adjustments

* update tests

* adds license

* updates test text to emphasize PaginationWrapper is tested

* CSS refactoring

* removes function duplication
  • Loading branch information
apburnie authored Jun 17, 2022
1 parent 2138257 commit 9c4b188
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 155 deletions.
4 changes: 2 additions & 2 deletions explorer/client/src/__tests__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ describe('End-to-end Tests', () => {
);
});
});
describe('Owned Objects have buttons', () => {
describe('PaginationWrapper has buttons', () => {
it('to go to the next page', async () => {
const address = 'ownsAllAddress';
await page.goto(`${BASE_URL}/addresses/${address}`);
Expand Down Expand Up @@ -404,7 +404,7 @@ describe('End-to-end Tests', () => {
});
describe('Transactions for ID', () => {
const txResults =
'TxIdTxTypeStatusAddressesDa4vHc9IwbvOYblE8LnrVsqXwryt2Kmms+xnJ7Zx5E4=Transfer\u2714From:senderAddressTo:receiv...dressGHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer\u2716From:senderAddressTo:receiv...dressXHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer\u2714From:senderAddressTo:receiv...dress';
'TxIdTxTypeStatusAddressesDa4vHc9IwbvOYblE8LnrVsqXwryt2Kmms+xnJ7Zx5E4=Transfer\u2714From:senderAddressTo:receiv...dressGHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer\u2716From:senderAddressTo:receiv...dressXHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer\u2714From:senderAddressTo:receiv...dressYHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZHTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZITP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZJTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZKTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZLTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZMTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZNTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dressZOTP9gcFmF5KTspnz3KxXjvSH8Bx0jv68KFhdqfpdK8=Transfer✔From:senderAddressTo:receiv...dress';

it('are displayed deduplicated from and to address', async () => {
const address = 'ownsAllAddress';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,6 @@
@apply h-[15vh];
}

.gone {
@apply invisible;
}

.btncontainer,
.pagenumber {
@apply inline-block w-[20%];
}

button.btncontainer {
@apply inline-block px-0 cursor-pointer border-none bg-inherit hover:bg-sui
py-2
text-offblack stroke-offblack
hover:text-white hover:stroke-white
items-center;
}

.pagenumber {
@apply select-none text-center break-normal text-sm;
}

.paginationheading {
@apply block;
}

.paginationheading > button {
@apply block lg:inline mb-2 bg-sui hover:bg-suidark hover:text-white rounded-r-md border-none cursor-pointer p-2;
}

.paginationheading > h2 {
@apply inline lg:ml-5;
}

.gray {
@apply text-slate-500;
}
Expand Down
121 changes: 8 additions & 113 deletions explorer/client/src/components/ownedobjects/OwnedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
trimStdLibPrefix,
} from '../../utils/stringUtils';
import DisplayBox from '../displaybox/DisplayBox';
import PaginationWrapper from '../pagination/PaginationWrapper';

import styles from './OwnedObjects.module.css';

Expand Down Expand Up @@ -161,6 +162,8 @@ function OwnedObjectAPI({ id, byAddress }: { id: string; byAddress: boolean }) {
return <div className={styles.gray}>loading...</div>;
}

const viewFn = (results: any) => <OwnedObjectView results={results} />;

function OwnedObjectLayout({ results }: { results: resultType }) {
const coin_results = results.filter(({ _isCoin }) => _isCoin);
const other_results = results
Expand All @@ -185,7 +188,10 @@ function OwnedObjectLayout({ results }: { results: resultType }) {
{other_results.length > 0 && (
<div id="NFTSection">
<h2>NFTs</h2>
<OwnedObjectSection results={other_results} />
<PaginationWrapper
results={other_results}
viewComponentFn={viewFn}
/>
</div>
)}
</div>
Expand Down Expand Up @@ -262,123 +268,12 @@ function GroupView({ results }: { results: resultType }) {
<button onClick={goBack}>&#60; Back</button>
<h2>{handleCoinType(subObjs[0].Type)}</h2>
</div>
<OwnedObjectSection results={subObjs} />
<PaginationWrapper results={subObjs} viewComponentFn={viewFn} />
</div>
);
}
}
function OwnedObjectSection({ results }: { results: resultType }) {
const [pageIndex, setPageIndex] = useState(0);

const ITEMS_PER_PAGE = 12;

const FINAL_PAGE_NO =
Math.floor(results.length / ITEMS_PER_PAGE) +
(results.length % ITEMS_PER_PAGE !== 0 ? 1 : 0);

const objectSample = results.slice(
pageIndex * ITEMS_PER_PAGE,
(pageIndex + 1) * ITEMS_PER_PAGE
);

const OwnedObjectsRetrieved = (retrieved: resultType) => {
return <OwnedObjectView results={objectSample} />;
};

const handleFirstClick = useCallback(() => setPageIndex(0), []);

const handleBackClick = useCallback(
() => pageIndex - 1 >= 0 && setPageIndex(pageIndex - 1),
[pageIndex]
);

const handleNextClick = useCallback(
() =>
(pageIndex + 1) * ITEMS_PER_PAGE < results.length &&
setPageIndex(pageIndex + 1),
[pageIndex, results.length]
);

const handleLastClick = useCallback(
() => setPageIndex(FINAL_PAGE_NO - 1),
[FINAL_PAGE_NO]
);

return (
<>
{FINAL_PAGE_NO > 1 && (
<>
<span className={pageIndex === 0 ? styles.gone : ''}>
<button
className={styles.btncontainer}
id="backBtn"
onClick={handleBackClick}
disabled={pageIndex === 0}
>
<svg
width="12"
height="12"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M 12 12 L 0 6 L 12 0"
fill="transparent"
/>
</svg>
</button>

<button
className={styles.btncontainer}
id="firstBtn"
onClick={handleFirstClick}
disabled={pageIndex === 0}
>
First
</button>
</span>

<span className={styles.pagenumber}>
Page {pageIndex + 1} of {FINAL_PAGE_NO}
</span>

<span
className={
pageIndex === FINAL_PAGE_NO - 1 ? styles.gone : ''
}
>
<button
id="lastBtn"
disabled={pageIndex === FINAL_PAGE_NO - 1}
onClick={handleLastClick}
className={styles.btncontainer}
>
Last
</button>
<button
id="nextBtn"
className={styles.btncontainer}
disabled={pageIndex === FINAL_PAGE_NO - 1}
onClick={handleNextClick}
>
<svg
width="12"
height="12"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M 0 12 L 12 6 L 0 0"
fill="transparent"
/>
</svg>
</button>
</span>
</>
)}

{OwnedObjectsRetrieved(objectSample)}
</>
);
}
function OwnedObjectView({ results }: { results: resultType }) {
const navigateWithUnknown = useContext(NavigateFunctionContext);
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.gone {
@apply invisible;
}

.btncontainer,
.pagenumber {
@apply inline-block w-[20%] font-mono;
}

button.btncontainer {
@apply inline-block px-0 cursor-pointer border-none bg-inherit hover:bg-sui
py-2
text-offblack stroke-offblack
hover:text-white hover:stroke-white
items-center;
}

.pagenumber {
@apply select-none text-center break-normal text-sm;
}

.paginationheading {
@apply block;
}

.paginationheading > button {
@apply block lg:inline mb-2 bg-sui hover:bg-suidark hover:text-white rounded-r-md border-none cursor-pointer p-2;
}

.paginationheading > h2 {
@apply inline lg:ml-5;
}
120 changes: 120 additions & 0 deletions explorer/client/src/components/pagination/PaginationWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
import { useState, useCallback } from 'react';

import styles from './PaginationWrapper.module.css';

export default function PaginationWrapper({
results,
viewComponentFn,
}: {
results: any;
viewComponentFn: Function;
}) {
const [pageIndex, setPageIndex] = useState(0);

const ITEMS_PER_PAGE = 12;

const FINAL_PAGE_NO =
Math.floor(results.length / ITEMS_PER_PAGE) +
(results.length % ITEMS_PER_PAGE !== 0 ? 1 : 0);

const objectSample = results.slice(
pageIndex * ITEMS_PER_PAGE,
(pageIndex + 1) * ITEMS_PER_PAGE
);

const handleFirstClick = useCallback(() => setPageIndex(0), []);

const handleBackClick = useCallback(
() => pageIndex - 1 >= 0 && setPageIndex(pageIndex - 1),
[pageIndex]
);

const handleNextClick = useCallback(
() =>
(pageIndex + 1) * ITEMS_PER_PAGE < results.length &&
setPageIndex(pageIndex + 1),
[pageIndex, results.length]
);

const handleLastClick = useCallback(
() => setPageIndex(FINAL_PAGE_NO - 1),
[FINAL_PAGE_NO]
);

return (
<>
{FINAL_PAGE_NO > 1 && (
<>
<span className={pageIndex === 0 ? styles.gone : ''}>
<button
className={styles.btncontainer}
id="backBtn"
onClick={handleBackClick}
disabled={pageIndex === 0}
>
<svg
width="12"
height="12"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M 12 12 L 0 6 L 12 0"
fill="transparent"
/>
</svg>
</button>

<button
className={styles.btncontainer}
id="firstBtn"
onClick={handleFirstClick}
disabled={pageIndex === 0}
>
First
</button>
</span>

<span className={styles.pagenumber}>
Page {pageIndex + 1} of {FINAL_PAGE_NO}
</span>

<span
className={
pageIndex === FINAL_PAGE_NO - 1 ? styles.gone : ''
}
>
<button
id="lastBtn"
disabled={pageIndex === FINAL_PAGE_NO - 1}
onClick={handleLastClick}
className={styles.btncontainer}
>
Last
</button>
<button
id="nextBtn"
className={styles.btncontainer}
disabled={pageIndex === FINAL_PAGE_NO - 1}
onClick={handleNextClick}
>
<svg
width="12"
height="12"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M 0 12 L 12 6 L 0 0"
fill="transparent"
/>
</svg>
</button>
</span>
</>
)}

{viewComponentFn(objectSample)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.txresults {
@apply font-mono ml-[1vw] w-[100%];
@apply font-mono mt-2 w-[100%];
}

.txheader {
@apply hidden bg-offblack text-offwhite py-2 md:grid md:grid-cols-12;
}

.txrow {
@apply md:grid md:grid-cols-12;
@apply mb-10 md:grid md:grid-cols-12 md:mb-2;
}

.txheader > div,
Expand Down
Loading

0 comments on commit 9c4b188

Please sign in to comment.