Remove clusterUrl url param

This commit is contained in:
Justin Starry 2020-06-03 18:09:05 +08:00 committed by Michael Vines
parent 03f7d28aff
commit 8b95be0ee4
7 changed files with 99 additions and 102 deletions

View File

@ -1263,6 +1263,11 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw=="
},
"@react-hook/debounce": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-2.0.5.tgz",
"integrity": "sha512-WrwQ1e4vx5lxxxEpGPPliMcs6oUJ8cyEb/GL8OEUPhBW4WL8YRSDW5oPnsOqIPqhHDyQMHgMipXWgj7QVmRMKA=="
},
"@sheerun/mutationobserver-shim": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@react-hook/debounce": "^2.0.5",
"@solana/web3.js": "^0.56.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",

View File

@ -1,5 +1,6 @@
import React from "react";
import { Link, useLocation, useHistory } from "react-router-dom";
import { Link, useHistory, useLocation } from "react-router-dom";
import { useDebounceCallback } from "@react-hook/debounce";
import { Location } from "history";
import {
useCluster,
@ -9,10 +10,12 @@ import {
clusterSlug,
CLUSTERS,
Cluster,
useClusterModal
useClusterModal,
useUpdateCustomUrl
} from "../providers/cluster";
import { assertUnreachable } from "../utils";
import Overlay from "./Overlay";
import { useQuery } from "utils/url";
function ClusterModal() {
const [show, setShow] = useClusterModal();
@ -46,34 +49,35 @@ function ClusterModal() {
type InputProps = { activeSuffix: string; active: boolean };
function CustomClusterInput({ activeSuffix, active }: InputProps) {
const { customUrl } = useCluster();
const updateCustomUrl = useUpdateCustomUrl();
const [editing, setEditing] = React.useState(false);
const query = useQuery();
const history = useHistory();
const location = useLocation();
const customClass = (prefix: string) =>
active ? `${prefix}-${activeSuffix}` : "";
const clusterLocation = (location: Location, url: string) => {
const params = new URLSearchParams(location.search);
params.set("clusterUrl", url);
params.delete("cluster");
const clusterLocation = (location: Location) => {
if (customUrl.length > 0) query.set("cluster", "custom");
return {
...location,
search: params.toString()
search: query.toString()
};
};
const updateCustomUrl = React.useCallback(
(url: string) => {
history.push(clusterLocation(location, url));
},
[history, location]
);
const onUrlInput = useDebounceCallback((url: string) => {
updateCustomUrl(url);
if (url.length > 0) {
query.set("cluster", "custom");
history.push({ ...location, search: query.toString() });
}
}, 500);
const inputTextClass = editing ? "" : "text-muted";
return (
<Link
to={location => clusterLocation(location, customUrl)}
to={location => clusterLocation(location)}
className="btn input-group input-group-merge p-0"
>
<input
@ -84,7 +88,7 @@ function CustomClusterInput({ activeSuffix, active }: InputProps) {
)}`}
onFocus={() => setEditing(true)}
onBlur={() => setEditing(false)}
onInput={e => updateCustomUrl(e.currentTarget.value)}
onInput={e => onUrlInput(e.currentTarget.value)}
/>
<div className="input-group-prepend">
<div className={`input-group-text pr-0 ${customClass("border")}`}>
@ -133,14 +137,10 @@ function ClusterToggle() {
const clusterLocation = (location: Location) => {
const params = new URLSearchParams(location.search);
const slug = clusterSlug(net);
if (slug && slug !== "mainnet-beta") {
if (slug !== "mainnet-beta") {
params.set("cluster", slug);
params.delete("clusterUrl");
} else {
params.delete("cluster");
if (slug === "mainnet-beta") {
params.delete("clusterUrl");
}
}
return {
...location,

View File

@ -3,10 +3,9 @@ import {
useFetchTransactionStatus,
useTransactionStatus,
useTransactionDetails,
useDetailsDispatch,
FetchStatus
} from "../providers/transactions";
import { fetchDetails } from "providers/transactions/details";
import { useFetchTransactionDetails } from "providers/transactions/details";
import { useCluster, useClusterModal } from "providers/cluster";
import {
TransactionSignature,
@ -206,12 +205,11 @@ function StatusCard({ signature }: Props) {
function AccountsCard({ signature }: Props) {
const details = useTransactionDetails(signature);
const dispatch = useDetailsDispatch();
const { url } = useCluster();
const fetchStatus = useFetchTransactionStatus();
const fetchDetails = useFetchTransactionDetails();
const refreshStatus = () => fetchStatus(signature);
const refreshDetails = () => fetchDetails(dispatch, signature, url);
const refreshDetails = () => fetchDetails(signature);
const transaction = details?.transaction?.transaction;
const message = React.useMemo(() => {
return transaction?.compileMessage();
@ -308,9 +306,8 @@ function AccountsCard({ signature }: Props) {
function InstructionsSection({ signature }: Props) {
const status = useTransactionStatus(signature);
const details = useTransactionDetails(signature);
const dispatch = useDetailsDispatch();
const { url } = useCluster();
const refreshDetails = () => fetchDetails(dispatch, signature, url);
const fetchDetails = useFetchTransactionDetails();
const refreshDetails = () => fetchDetails(signature);
if (!status || !status.info || !details || !details.transaction) return null;

View File

@ -1,6 +1,7 @@
import React from "react";
import { clusterApiUrl, Connection } from "@solana/web3.js";
import { useQuery } from "../utils/url";
import { useHistory, useLocation } from "react-router-dom";
export enum ClusterStatus {
Connected,
@ -22,7 +23,7 @@ export const CLUSTERS = [
Cluster.Custom
];
export function clusterSlug(cluster: Cluster): string | undefined {
export function clusterSlug(cluster: Cluster): string {
switch (cluster) {
case Cluster.MainnetBeta:
return "mainnet-beta";
@ -31,7 +32,7 @@ export function clusterSlug(cluster: Cluster): string | undefined {
case Cluster.Devnet:
return "devnet";
case Cluster.Custom:
return undefined;
return "custom";
}
}
@ -52,8 +53,20 @@ export const MAINNET_BETA_URL = clusterApiUrl("mainnet-beta");
export const TESTNET_URL = clusterApiUrl("testnet");
export const DEVNET_URL = clusterApiUrl("devnet");
export function clusterUrl(cluster: Cluster, customUrl: string): string {
switch (cluster) {
case Cluster.Devnet:
return DEVNET_URL;
case Cluster.MainnetBeta:
return MAINNET_BETA_URL;
case Cluster.Testnet:
return TESTNET_URL;
case Cluster.Custom:
return customUrl;
}
}
export const DEFAULT_CLUSTER = Cluster.MainnetBeta;
export const DEFAULT_CUSTOM_URL = "http://localhost:8899";
interface State {
cluster: Cluster;
@ -88,51 +101,19 @@ function clusterReducer(state: State, action: Action): State {
}
}
function parseQuery(
query: URLSearchParams
): { cluster: Cluster; customUrl: string } {
function parseQuery(query: URLSearchParams): Cluster {
const clusterParam = query.get("cluster");
const clusterUrlParam = query.get("clusterUrl");
let cluster;
let customUrl = DEFAULT_CUSTOM_URL;
switch (clusterUrlParam) {
case MAINNET_BETA_URL:
cluster = Cluster.MainnetBeta;
break;
case DEVNET_URL:
cluster = Cluster.Devnet;
break;
case TESTNET_URL:
cluster = Cluster.Testnet;
break;
}
switch (clusterParam) {
case "mainnet-beta":
cluster = Cluster.MainnetBeta;
break;
case "custom":
return Cluster.Custom;
case "devnet":
cluster = Cluster.Devnet;
break;
return Cluster.Devnet;
case "testnet":
cluster = Cluster.Testnet;
break;
return Cluster.Testnet;
case "mainnet-beta":
default:
return Cluster.MainnetBeta;
}
if (!cluster) {
if (!clusterUrlParam) {
cluster = DEFAULT_CLUSTER;
} else {
cluster = Cluster.Custom;
customUrl = clusterUrlParam;
}
}
return {
cluster,
customUrl
};
}
type SetShowModal = React.Dispatch<React.SetStateAction<boolean>>;
@ -146,16 +127,28 @@ type ClusterProviderProps = { children: React.ReactNode };
export function ClusterProvider({ children }: ClusterProviderProps) {
const [state, dispatch] = React.useReducer(clusterReducer, {
cluster: DEFAULT_CLUSTER,
customUrl: DEFAULT_CUSTOM_URL,
customUrl: "",
status: ClusterStatus.Connecting
});
const [showModal, setShowModal] = React.useState(false);
const { cluster, customUrl } = parseQuery(useQuery());
const query = useQuery();
const cluster = parseQuery(query);
const history = useHistory();
const location = useLocation();
// Reconnect to cluster when it changes
// Reconnect to cluster when params change
React.useEffect(() => {
updateCluster(dispatch, cluster, customUrl);
}, [cluster, customUrl]);
if (cluster === Cluster.Custom) {
// Remove cluster param if custom url has not been set
if (state.customUrl.length === 0) {
query.delete("cluster");
history.push({ ...location, search: query.toString() });
return;
}
}
updateCluster(dispatch, cluster, state.customUrl);
}, [cluster, state.customUrl]); // eslint-disable-line react-hooks/exhaustive-deps
return (
<StateContext.Provider value={state}>
@ -168,19 +161,6 @@ export function ClusterProvider({ children }: ClusterProviderProps) {
);
}
export function clusterUrl(cluster: Cluster, customUrl: string): string {
switch (cluster) {
case Cluster.Devnet:
return DEVNET_URL;
case Cluster.MainnetBeta:
return MAINNET_BETA_URL;
case Cluster.Testnet:
return TESTNET_URL;
case Cluster.Custom:
return customUrl;
}
}
async function updateCluster(
dispatch: Dispatch,
cluster: Cluster,
@ -207,6 +187,17 @@ async function updateCluster(
}
}
export function useUpdateCustomUrl() {
const dispatch = React.useContext(DispatchContext);
if (!dispatch) {
throw new Error(`useUpdateCustomUrl must be used within a ClusterProvider`);
}
return (customUrl: string) => {
updateCluster(dispatch, Cluster.Custom, customUrl);
};
}
export function useCluster() {
const context = React.useContext(StateContext);
if (!context) {

View File

@ -128,7 +128,7 @@ export function DetailsProvider({ children }: DetailsProviderProps) {
);
}
export async function fetchDetails(
async function fetchDetails(
dispatch: Dispatch,
signature: TransactionSignature,
url: string
@ -151,3 +151,17 @@ export async function fetchDetails(
}
dispatch({ type: ActionType.Update, fetchStatus, signature, transaction });
}
export function useFetchTransactionDetails() {
const dispatch = React.useContext(DispatchContext);
if (!dispatch) {
throw new Error(
`useFetchTransactionDetails must be used within a TransactionsProvider`
);
}
const { url } = useCluster();
return (signature: TransactionSignature) => {
url && fetchDetails(dispatch, signature, url);
};
}

View File

@ -12,8 +12,7 @@ import { useQuery } from "../../utils/url";
import { useCluster, Cluster, ClusterStatus } from "../cluster";
import {
DetailsProvider,
StateContext as DetailsStateContext,
DispatchContext as DetailsDispatchContext
StateContext as DetailsStateContext
} from "./details";
import base58 from "bs58";
import { useFetchAccountInfo } from "../accounts";
@ -308,16 +307,6 @@ export function useTransactionDetails(signature: TransactionSignature) {
return context[signature];
}
export function useDetailsDispatch() {
const context = React.useContext(DetailsDispatchContext);
if (!context) {
throw new Error(
`useDetailsDispatch must be used within a TransactionsProvider`
);
}
return context;
}
export function useFetchTransactionStatus() {
const dispatch = React.useContext(DispatchContext);
if (!dispatch) {