Skip to content

Commit

Permalink
Fix the search bar (and add bech32 search) (#60)
Browse files Browse the repository at this point in the history
* (feat) Search instructions

* (fix) Search now works again (erm, I think)
(feat) A help box for search.
(feat) Search by bech32 address

* (fix) Fix search box

* (fix ) prettier

* (fix) Fix variable reference in search.ts
(fix) Fix types in InlineCode
  • Loading branch information
rrw-zilliqa authored Sep 30, 2024
1 parent 0b48919 commit f0c8fc0
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 13 deletions.
10 changes: 10 additions & 0 deletions README.zilliqa.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ ignore changes to them, they are generated by `npm start` as well as

Be warned! If you use `vite` directly, you may end up with analysis
errors due to their absence.

## Starting for development

.. because I keep forgetting!

```
export VITE_ERIGON_URL=<url>
npm run assets-start
npm start
```
117 changes: 116 additions & 1 deletion src/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { faQrcode } from "@fortawesome/free-solid-svg-icons";
import { faQrcode, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { FC, lazy, memo, useContext, useState } from "react";
import { Link } from "react-router-dom";
import PriceBox from "./PriceBox";
import SourcifyMenu from "./SourcifyMenu";
import InlineCode from "./components/InlineCode";
import { useGenericSearch } from "./search/search";
import { RuntimeContext } from "./useRuntime";
// @ts-expect-error
Expand All @@ -12,10 +13,13 @@ import Otter from "./otter.png?w=128&h=128&webp";
const CameraScanner = lazy(() => import("./search/CameraScanner"));
type HeaderProps = { sourcifyPresent: boolean };

// Should really move out to utils

const Header: FC<HeaderProps> = ({ sourcifyPresent }) => {
const { config, provider } = useContext(RuntimeContext);
const [searchRef, handleChange, handleSubmit] = useGenericSearch();
const [isScanning, setScanning] = useState<boolean>(false);
const [isHelpOpen, setHelpOpen] = useState<boolean>(false);

return (
<>
Expand Down Expand Up @@ -79,6 +83,14 @@ const Header: FC<HeaderProps> = ({ sourcifyPresent }) => {
>
<FontAwesomeIcon icon={faQrcode} />
</button>
<button
className="border bg-skin-button-fill px-2 py-1 text-sm text-skin-button hover:bg-skin-button-hover-fill focus:outline-none"
type="button"
onClick={() => setHelpOpen(true)}
title="Help with searching"
>
<FontAwesomeIcon icon={faQuestionCircle} />
</button>
<button
className="rounded-r border-b border-r border-t bg-skin-button-fill px-2 py-1 text-sm text-skin-button hover:bg-skin-button-hover-fill focus:outline-none"
type="submit"
Expand All @@ -91,6 +103,109 @@ const Header: FC<HeaderProps> = ({ sourcifyPresent }) => {
</div>
</div>
</div>
{isHelpOpen && (
<div
className="fixed inset-0 z-10 overflow-y-auto"
aria-labelledby="modal-title"
role="dialog"
aria-modal="true"
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div
className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
aria-hidden="true"
></div>

<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>

<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3
className="text-lg leading-6 font-medium text-gray-900"
id="modal-title"
>
Help Information
</h3>
<div className="mt-2">
<span className="text-sm text-gray-500">
<p>Search terms are interpreted as..</p>
<br />
<ul className="list-disc list-inside mb-6">
<li>
{" "}
A bech32 address if it is in the right format.
</li>
<li>
{" "}
An address if we can (right length, starts with{" "}
<InlineCode>0x</InlineCode> or{" "}
<InlineCode>zil1</InlineCode>).
</li>
<li>
{" "}
If a 32-character hex string we'll try to search as
a transaction id
</li>
<li>
{" "}
If a &gt; 40 character hex string, we'll think it's
probably an address with leading 0s.
</li>
<li>
{" "}
Then we'll attempt an{" "}
<InlineCode>BigInt</InlineCode> and try to find a
block number
</li>
<li>
{" "}
Terms starting with <InlineCode>#</InlineCode> are
treated as a DS block number for ZQ1
</li>
<li>
{" "}
Terms like{" "}
<InlineCode>epoch:&lt;number&gt;</InlineCode> are
epochs.
</li>
<li>
{" "}
Terms like{" "}
<InlineCode>
validator:&lt;number&gt;
</InlineCode>{" "}
are validator searches.
</li>
</ul>
<p>
If the search term does not match any of those rules,
we interpret it as an ENS name.
</p>
</span>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
onClick={() => setHelpOpen(false)}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
</>
);
};
Expand Down
13 changes: 13 additions & 0 deletions src/components/InlineCode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

type InlineCodeProps = React.PropsWithChildren<{
children: React.ReactNode;
}>;

const InlineCode: React.FC<InlineCodeProps> = ({ children }) => (
<code className="px-1 py-0.5 rounded bg-gray-100 text-gray-800 font-mono text-sm">
{children}
</code>
);

export default React.memo(InlineCode);
42 changes: 30 additions & 12 deletions src/search/search.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fromBech32Address } from "@zilliqa-js/crypto";
import {
JsonRpcApiProvider,
TransactionReceiptParams,
Expand Down Expand Up @@ -247,6 +248,24 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
maybeIndex = q.substring(sepIndex + 1);
}

// Tx hash?
if (isHexString(q, 32)) {
console.log(`search: this looks like a txn hash - ${q}`);
navigate(`/tx/${q}`);
return;
} else if (isHexString(`0x${q}`, 32)) {
navigate(`/tx/0x${q}`);
return;
}

// Zilliqa address?
try {
maybeAddress = fromBech32Address(maybeAddress);
console.log(`search: bech32 address to base16 - ${maybeAddress}`);
} catch (e) {
console.log(`search: Not a bech32 address`);
}

// The type checker is convinced that ethers:isAddress() will never say that a string > 40 characters
// long is not an address. I'm not sure why...
if (!isAddress(maybeAddress)) {
Expand All @@ -266,6 +285,7 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {

// Plain address?
if (isAddress(maybeAddress)) {
console.log(`search: maybeAddress ${maybeAddress} is an address ..`);
navigate(
`/address/${maybeAddress}${
maybeIndex !== "" ? `?nonce=${maybeIndex}` : ""
Expand All @@ -274,20 +294,14 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
return;
}

// Tx hash?
if (isHexString(q, 32)) {
navigate(`/tx/${q}`);
return;
} else if (isHexString(`0x${q}`, 32)) {
navigate(`/tx/0x${q}`);
return;
}

// Block number?
// If the number here is very large, parseInt() will return an fp number which
// will cause errors, so ..
try {
const blockNumber = BigInt(q);
let toParse = q;
console.log(`search: try to parse ${toParse} as a block number`);
const blockNumber = BigInt(toParse);
console.log(`search: ${toParse} Parses as a block number ${blockNumber}`);
navigate(`/block/${blockNumber.toString()}`);
return;
} catch (e) {
Expand All @@ -298,6 +312,7 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
if (q.charAt(0) === "#") {
const dsBlockNumber = parseInt(q.substring(1));
if (!isNaN(dsBlockNumber)) {
console.log(`search: # ${dsBlockNumber} - it's a ds block number`);
navigate(`/dsblock/${dsBlockNumber}`);
return;
}
Expand All @@ -308,6 +323,7 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
const mayBeEpoch = q.substring(6);
const epoch = parseInt(mayBeEpoch);
if (!isNaN(epoch)) {
console.log(`search: epoch: ${epoch}`);
navigate(`/epoch/${epoch}`);
return;
}
Expand All @@ -318,17 +334,18 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
const mayBeSlot = q.substring(5);
const slot = parseInt(mayBeSlot);
if (!isNaN(slot)) {
console.log(`search: slot: ${slot}`);
navigate(`/slot/${slot}`);
return;
}
}

// Validator?
if (q.startsWith("validator:")) {
if (q.startsWith("search - validator:")) {
const mayBeValidator = q.substring(10);

// Validator by index
if (mayBeValidator.match(/^\d+$/)) {
console.log(`search: validator: ${mayBeValidator}`);
const validatorIndex = parseInt(mayBeValidator);
navigate(`/validator/${validatorIndex}`);
return;
Expand All @@ -342,6 +359,7 @@ const doSearch = async (q: string, navigate: NavigateFunction) => {
}

// Assume it is an ENS name
console.log(`search: no match: assuming ${maybeAddress} is an ENS name`);
navigate(
`/address/${maybeAddress}${
maybeIndex !== "" ? `?nonce=${maybeIndex}` : ""
Expand Down

0 comments on commit f0c8fc0

Please sign in to comment.