Add programs and sysvars to explorer search suggestions (#11467)
This commit is contained in:
parent
40656911a6
commit
3d97b04815
|
@ -3,6 +3,7 @@ import bs58 from "bs58";
|
|||
import { useHistory, useLocation } from "react-router-dom";
|
||||
import Select, { InputActionMeta, ActionMeta, ValueType } from "react-select";
|
||||
import StateManager from "react-select";
|
||||
import { PROGRAM_IDS, SYSVAR_IDS } from "utils/tx";
|
||||
|
||||
export function SearchBar() {
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
@ -10,10 +11,7 @@ export function SearchBar() {
|
|||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
|
||||
const onChange = (
|
||||
{ value: pathname }: ValueType<any>,
|
||||
meta: ActionMeta<any>
|
||||
) => {
|
||||
const onChange = ({ pathname }: ValueType<any>, meta: ActionMeta<any>) => {
|
||||
if (meta.action === "select-option") {
|
||||
history.push({ ...location, pathname });
|
||||
setSearch("");
|
||||
|
@ -24,38 +22,6 @@ export function SearchBar() {
|
|||
if (action === "input-change") setSearch(value);
|
||||
};
|
||||
|
||||
const options = ((searchValue: string) => {
|
||||
try {
|
||||
const decoded = bs58.decode(searchValue);
|
||||
if (decoded.length === 32) {
|
||||
return [
|
||||
{
|
||||
label: "Account",
|
||||
options: [
|
||||
{
|
||||
label: searchValue,
|
||||
value: "/address/" + searchValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
} else if (decoded.length === 64) {
|
||||
return [
|
||||
{
|
||||
label: "Transaction",
|
||||
options: [
|
||||
{
|
||||
label: searchValue,
|
||||
value: "/tx/" + searchValue,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
} catch (err) {}
|
||||
return [];
|
||||
})(search);
|
||||
|
||||
const resetValue = "" as any;
|
||||
return (
|
||||
<div className="container my-4">
|
||||
|
@ -63,7 +29,7 @@ export function SearchBar() {
|
|||
<div className="col">
|
||||
<Select
|
||||
ref={(ref) => (selectRef.current = ref)}
|
||||
options={options}
|
||||
options={buildOptions(search)}
|
||||
noOptionsMessage={() => "No Results"}
|
||||
placeholder="Search by address or signature"
|
||||
value={resetValue}
|
||||
|
@ -81,6 +47,89 @@ export function SearchBar() {
|
|||
);
|
||||
}
|
||||
|
||||
const SEARCHABLE_PROGRAMS = ["Config", "Stake", "System", "Vote", "Token"];
|
||||
|
||||
function buildProgramOptions(search: string) {
|
||||
const matchedPrograms = Object.entries(PROGRAM_IDS).filter(([, name]) => {
|
||||
return (
|
||||
SEARCHABLE_PROGRAMS.includes(name) &&
|
||||
name.toLowerCase().includes(search.toLowerCase())
|
||||
);
|
||||
});
|
||||
|
||||
if (matchedPrograms.length > 0) {
|
||||
return {
|
||||
label: "Programs",
|
||||
options: matchedPrograms.map(([id, name]) => ({
|
||||
label: name,
|
||||
value: name,
|
||||
pathname: "/address/" + id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function buildSysvarOptions(search: string) {
|
||||
const matchedSysvars = Object.entries(SYSVAR_IDS).filter(([, name]) => {
|
||||
return name.toLowerCase().includes(search.toLowerCase());
|
||||
});
|
||||
|
||||
if (matchedSysvars.length > 0) {
|
||||
return {
|
||||
label: "Sysvars",
|
||||
options: matchedSysvars.map(([id, name]) => ({
|
||||
label: name,
|
||||
value: name,
|
||||
pathname: "/address/" + id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function buildOptions(search: string) {
|
||||
if (search.length === 0) return [];
|
||||
|
||||
const options = [];
|
||||
|
||||
const programOptions = buildProgramOptions(search);
|
||||
if (programOptions) {
|
||||
options.push(programOptions);
|
||||
}
|
||||
|
||||
const sysvarOptions = buildSysvarOptions(search);
|
||||
if (sysvarOptions) {
|
||||
options.push(sysvarOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
const decoded = bs58.decode(search);
|
||||
if (decoded.length === 32) {
|
||||
options.push({
|
||||
label: "Account",
|
||||
options: [
|
||||
{
|
||||
label: search,
|
||||
value: search,
|
||||
pathname: "/address/" + search,
|
||||
},
|
||||
],
|
||||
});
|
||||
} else if (decoded.length === 64) {
|
||||
options.push({
|
||||
label: "Transaction",
|
||||
options: [
|
||||
{
|
||||
label: search,
|
||||
value: search,
|
||||
pathname: "/tx/" + search,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
} catch (err) {}
|
||||
return options;
|
||||
}
|
||||
|
||||
function DropdownIndicator() {
|
||||
return (
|
||||
<div className="search-indicator">
|
||||
|
|
|
@ -64,7 +64,7 @@ function OverviewCard({
|
|||
<tr>
|
||||
<td>Address</td>
|
||||
<td className="text-lg-right">
|
||||
<Address pubkey={account.pubkey} alignRight />
|
||||
<Address pubkey={account.pubkey} alignRight raw />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -18,7 +18,7 @@ export function UnknownAccountCard({ account }: { account: Account }) {
|
|||
<tr>
|
||||
<td>Address</td>
|
||||
<td className="text-lg-right">
|
||||
<Address pubkey={account.pubkey} alignRight />
|
||||
<Address pubkey={account.pubkey} alignRight raw />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -10,9 +10,10 @@ type Props = {
|
|||
pubkey: PublicKey | Pubkey;
|
||||
alignRight?: boolean;
|
||||
link?: boolean;
|
||||
raw?: boolean;
|
||||
};
|
||||
|
||||
export function Address({ pubkey, alignRight, link }: Props) {
|
||||
export function Address({ pubkey, alignRight, link, raw }: Props) {
|
||||
const [state, setState] = useState<CopyState>("copy");
|
||||
const address = pubkey.toBase58();
|
||||
|
||||
|
@ -36,9 +37,11 @@ export function Address({ pubkey, alignRight, link }: Props) {
|
|||
<span className="text-monospace">
|
||||
{link ? (
|
||||
<Link className="" to={clusterPath(`/address/${address}`)}>
|
||||
{displayAddress(address)}
|
||||
{raw ? address : displayAddress(address)}
|
||||
<span className="fe fe-external-link ml-2"></span>
|
||||
</Link>
|
||||
) : raw ? (
|
||||
address
|
||||
) : (
|
||||
displayAddress(address)
|
||||
)}
|
||||
|
|
|
@ -32,6 +32,14 @@ code, pre {
|
|||
box-shadow: $card-box-shadow !important;
|
||||
|
||||
.search-bar__option {
|
||||
background-color: $gray-700-dark !important;
|
||||
cursor: pointer;
|
||||
|
||||
&.search-bar__option--is-focused {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $gray-700-dark !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,7 @@ h4.slot-pill {
|
|||
color: hsl(0,0%,60%);
|
||||
display: flex;
|
||||
padding: 8px 10px;
|
||||
padding-left: 14px;
|
||||
transition: color 150ms;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
@ -166,6 +167,7 @@ h4.slot-pill {
|
|||
|
||||
.search-bar__control {
|
||||
border-radius: $border-radius !important;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.search-bar__menu {
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
Transaction,
|
||||
} from "@solana/web3.js";
|
||||
|
||||
const PROGRAM_IDS = {
|
||||
export const PROGRAM_IDS = {
|
||||
Budget1111111111111111111111111111111111111: "Budget",
|
||||
Config1111111111111111111111111111111111111: "Config",
|
||||
Exchange11111111111111111111111111111111111: "Exchange",
|
||||
|
@ -31,8 +31,11 @@ const LOADER_IDS = {
|
|||
[BpfLoader.programId.toBase58()]: "BPF Loader",
|
||||
};
|
||||
|
||||
const SYSVAR_IDS = {
|
||||
const SYSVAR_ID: { [key: string]: string } = {
|
||||
Sysvar1111111111111111111111111111111111111: "SYSVAR",
|
||||
};
|
||||
|
||||
export const SYSVAR_IDS = {
|
||||
[SYSVAR_CLOCK_PUBKEY.toBase58()]: "SYSVAR_CLOCK",
|
||||
SysvarEpochSchedu1e111111111111111111111111: "SYSVAR_EPOCH_SCHEDULE",
|
||||
SysvarFees111111111111111111111111111111111: "SYSVAR_FEES",
|
||||
|
@ -49,6 +52,7 @@ export function displayAddress(address: string): string {
|
|||
PROGRAM_IDS[address] ||
|
||||
LOADER_IDS[address] ||
|
||||
SYSVAR_IDS[address] ||
|
||||
SYSVAR_ID[address] ||
|
||||
address
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue