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