Skip to content

Commit

Permalink
[explorer] Adds Search Filter (MystenLabs#1959)
Browse files Browse the repository at this point in the history
* adds unstylised search filter

* stylises the search filter

* handles what happens when try to look up transaction as an object and address

* improves handling when submit object or address in transaction section

* reset category when submit search

* change placeholder text for address and tx search

lint changes

* remove backtick strings in Search

Co-authored-by: Stella Cannefax <[email protected]>
  • Loading branch information
apburnie and Stella Cannefax authored May 13, 2022
1 parent caf3f39 commit 46032fa
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 77 deletions.
24 changes: 24 additions & 0 deletions explorer/client/\
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.form {
@apply flex;
}

.searchbtn {
@apply bg-sui hover:bg-suidark hover:text-white
border-none text-black rounded-r-md
cursor-pointer font-sans
leading-8 flex-initial mr-[1vw] sm:mr-[5vw] ml-0;
}

.disabled {
@apply bg-offblack hover:bg-offblack text-white cursor-text;
}

.searchtext {
@apply border-none rounded-l-md font-mono leading-8 ml-0
flex-1 ml-[1vw] sm:ml-[5vw] w-[5rem]
text-xs mr-0 bg-offwhite;
}

.categoryDropdown, .categoryDropdown > option {
@apply flex-initial font-sans cursor-pointer rounded-none border-none border-l-2 border-black;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
.noobjects {
@apply font-sans tracking-tight font-semibold
bg-amber-300 rounded-l-md
h-[1.5rem] p-2 mt-2;
}

.ownedobjects {
@apply w-[100%] lg:flex lg:flex-wrap lg:justify-between;
}
Expand Down Expand Up @@ -70,5 +64,9 @@ button.btncontainer {
}

.gray {
color: gray;
@apply text-slate-500;
}

.fail {
@apply text-red-600 font-sans font-semibold mt-2;
}
88 changes: 47 additions & 41 deletions explorer/client/src/components/ownedobjects/OwnedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const IS_COIN_TYPE = (typeDesc: string): boolean => /::Coin::/.test(typeDesc);
const lastRowHas2Elements = (itemList: any[]): boolean =>
itemList.length % 3 === 2;

const NoOwnedObjects = () => (
<div className={styles.fail}>Failed to find Owned Objects</div>
);

const OwnedObject = ({ id }: { id: string }) =>
IS_STATIC_ENV ? <OwnedObjectStatic id={id} /> : <OwnedObjectAPI id={id} />;

Expand All @@ -62,61 +66,63 @@ function OwnedObjectStatic({ id }: { id: string }) {

return <OwnedObjectLayout results={results} />;
} else {
return <div />;
return <NoOwnedObjects />;
}
}

function OwnedObjectAPI({ id }: { id: string }) {
const [results, setResults] = useState(DATATYPE_DEFAULT);
const [isLoaded, setIsLoaded] = useState(false);
const [isFail, setIsFail] = useState(false);

// TODO - The below will fail for a large number of owned objects
// due to the number of calls to the API
// Backend changes will be required to enable a scalable solution
// getOwnedObjectRefs will need to return id, type and balance for each owned object
useEffect(() => {
rpc.getOwnedObjectRefs(id).then((objects) => {
const ids = objects.map(({ objectId }) => objectId);
rpc.getObjectInfoBatch(ids).then((results) => {
setResults(
results
.filter(({ status }) => status === 'Exists')
.map(
(resp) => {
const info = getObjectExistsResponse(resp)!;
const contents = getObjectContent(resp);
const url = parseImageURL(info.object);
const balanceValue = (
typeof contents?.fields.balance === 'number'
? contents.fields.balance
: undefined
) as number;
return {
id: info.objectRef.objectId,
Type: parseObjectType(info),
display: url
? processDisplayValue(url)
: undefined,
balance: balanceValue,
};
}
//TO DO - add back version
)
);
setIsLoaded(true);
});
});
setIsFail(false);
setIsLoaded(false);
rpc.getOwnedObjectRefs(id)
.then((objects) => {
const ids = objects.map(({ objectId }) => objectId);
rpc.getObjectInfoBatch(ids).then((results) => {
setResults(
results
.filter(({ status }) => status === 'Exists')
.map(
(resp) => {
const info = getObjectExistsResponse(resp)!;
const contents = getObjectContent(resp);
const url = parseImageURL(info.object);
const balanceValue = (
typeof contents?.fields.balance ===
'number'
? contents.fields.balance
: undefined
) as number;
return {
id: info.objectRef.objectId,
Type: parseObjectType(info),
display: url
? processDisplayValue(url)
: undefined,
balance: balanceValue,
};
}
//TO DO - add back version
)
);
setIsLoaded(true);
});
})
.catch(() => setIsFail(true));
}, [id]);

if (isLoaded) {
return <OwnedObjectLayout results={results} />;
} else {
return results.length > 0 ? (
<div className={styles.gray}>loading...</div>
) : (
<div />
);
}
if (isFail) return <NoOwnedObjects />;

if (isLoaded) return <OwnedObjectLayout results={results} />;

return <div className={styles.gray}>loading...</div>;
}

function OwnedObjectLayout({ results }: { results: resultType }) {
Expand Down
17 changes: 10 additions & 7 deletions explorer/client/src/components/search/Search.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
@apply flex;
}

.searchbtn,
.categorydropdown,
select.categorydropdown > option {
@apply flex-initial font-sans text-xs border-none;
}

.searchbtn {
@apply bg-sui hover:bg-suidark hover:text-white
border-none text-black rounded-r-md
cursor-pointer font-sans
leading-8 flex-initial mr-[5vw] ml-0;
@apply bg-sui hover:bg-suidark hover:text-white rounded-r-md cursor-pointer leading-8 mr-[1vw] sm:mr-[5vw] ml-0;
}

.disabled {
@apply bg-offblack hover:bg-offblack text-white cursor-text;
}

.searchtext {
@apply border-none rounded-l-md font-mono leading-8 flex-1 ml-[5vw]
@apply border-r-2 border-y-0 border-l-0 rounded-l-md
font-mono leading-8
flex-1 ml-[1vw] sm:ml-[5vw] w-[5rem]
text-xs mr-0 bg-offwhite;

padding-left: 0.75rem;
}
47 changes: 42 additions & 5 deletions explorer/client/src/components/search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,22 @@ import { navigateWithUnknown } from '../../utils/searchUtil';

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

type SearchCategory = 'all' | 'transactions' | 'addresses' | 'objects';
function getPlaceholderText(category: SearchCategory) {
switch (category) {
case 'addresses':
return 'Search by address';
case 'transactions':
return 'Search by digest';
case 'objects':
case 'all':
return 'Search by ID';
}
}

function Search() {
const [input, setInput] = useState('');
const [category, setCategory] = useState('all' as SearchCategory);
const navigate = useNavigate();

const [pleaseWaitMode, setPleaseWaitMode] = useState(false);
Expand All @@ -20,20 +34,33 @@ function Search() {
// Prevent empty search
if (!input.length) return;
setPleaseWaitMode(true);
// remove empty char from input
navigateWithUnknown(input.trim(), navigate).then(() => {

if (category === 'all') {
// remove empty char from input
navigateWithUnknown(input.trim(), navigate).then(() => {
setInput('');
setPleaseWaitMode(false);
});
} else {
navigate(`../${category}/${input.trim()}`);
setInput('');
setPleaseWaitMode(false);
});
setCategory('all');
}
},
[input, navigate, setInput]
[input, navigate, category, setInput]
);

const handleTextChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) =>
setInput(e.currentTarget.value),
[setInput]
);
const handleCategoryChange = useCallback(
(e: React.ChangeEvent<HTMLSelectElement>) =>
setCategory(e.currentTarget.value as SearchCategory),
[setCategory]
);

return (
<form
Expand All @@ -44,11 +71,21 @@ function Search() {
<input
className={styles.searchtext}
id="searchText"
placeholder="Search by ID"
placeholder={getPlaceholderText(category)}
value={input}
onChange={handleTextChange}
type="text"
/>
<select
className={styles.categorydropdown}
onChange={handleCategoryChange}
value={category}
>
<option value="all">All</option>
<option value="transactions">Transactions</option>
<option value="objects">Objects</option>
<option value="addresses">Addresses</option>
</select>
<input
type="submit"
id="searchBtn"
Expand Down
2 changes: 1 addition & 1 deletion explorer/client/src/pages/object-result/ObjectResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Fail = ({ objID }: { objID: string | undefined }): JSX.Element => {
return (
<ErrorResult
id={objID}
errorMsg="There was an issue with the data on the following object"
errorMsg="Data could not be extracted on the following specified object ID"
/>
);
};
Expand Down
38 changes: 22 additions & 16 deletions explorer/client/src/pages/transaction-result/TransactionResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ const getCreatedOrMutatedData = (
: [];
};

const FailedToGetTxResults = ({ id }: { id: string }) => (
<ErrorResult
id={id}
errorMsg={
!id
? "Can't search for a transaction without a digest"
: 'Data could not be extracted for the following specified transaction ID'
}
/>
);

const transformTransactionResponse = (
txObj: TransactionEffectsResponse,
id: string
Expand Down Expand Up @@ -151,26 +162,21 @@ const TransactionResultAPI = ({ id }: { id: string }) => {
// For Batch transactions show error
// TODO update Error screen and account for Batch transactions

return (
<ErrorResult
id={id}
errorMsg={
!id
? "Can't search for a transaction without a digest"
: 'There was an issue with the data on the following transaction'
}
/>
);
return <FailedToGetTxResults id={id} />;
};

const TransactionResultStatic = ({ id }: { id: string }) => {
const entry = findDataFromID(id, undefined);

return (
<TransactionResultLoaded
txData={transformTransactionResponse(entry, id)}
/>
);
try {
return (
<TransactionResultLoaded
txData={transformTransactionResponse(entry, id)}
/>
);
} catch (error) {
console.error(error);
return <FailedToGetTxResults id={id} />;
}
};

const TransactionResultLoaded = ({ txData }: { txData: DataType }) => {
Expand Down

0 comments on commit 46032fa

Please sign in to comment.