Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rpc playground #636

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"@subql/contract-sdk": "0.112.0",
"@subql/network-clients": "^0.112.1-1",
"@subql/network-config": "^0.112.0",
"@subql/network-query": "0.112.1-0",
"@subql/react-hooks": "^0.112.1-2",
"@subql/network-query": "0.112.1-1",
"@subql/react-hooks": "^0.112.1-3",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand Down
13 changes: 1 addition & 12 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,14 @@ export interface AppNavigation {
export const Header: React.FC = () => {
const { address: account } = useAccount();
const navigate = useNavigate();
const calEntryLinks = React.useMemo(() => {
return entryLinks.map((entry) => {
if (entry.key === 'explorer') {
return {
...entry,
dropdown: undefined,
};
}
return entry;
});
}, []);

return (
<div className={styles.header}>
<SubqlHeader
navigate={(link) => {
navigate(link);
}}
appNavigation={calEntryLinks}
appNavigation={entryLinks}
dropdownLinks={{ label: 'Kepler', links: externalAppLinks }}
rightElement={
<>
Expand Down
2 changes: 2 additions & 0 deletions src/components/IndexerDetails/IndexerDetails.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@
color: #fff;
font-size: 18px;
margin-bottom: 8px;
display: flex;
align-items: center;
}

&LimitInfo {
Expand Down
6 changes: 4 additions & 2 deletions src/components/IndexerDetails/IndexerDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { EmptyList } from '@components/EmptyList';
import { ProjectDetailsQuery } from '@hooks/useProjectFromQuery';
import { Spinner, TableTitle, Typography } from '@subql/components';
import { ServiceStatus } from '@subql/network-query';
import { renderAsync, useGetDeploymentIndexersLazyQuery, useGetIndexerDeploymentLazyQuery } from '@subql/react-hooks';
Expand All @@ -16,6 +17,7 @@ import Row from './Row';

type Props = {
deploymentId: string | undefined;
project: ProjectDetailsQuery;
};

const NoIndexers: React.FC = () => {
Expand All @@ -31,7 +33,7 @@ const NoIndexers: React.FC = () => {
);
};

const IndexerDetails: React.FC<Props> = ({ deploymentId }) => {
const IndexerDetails: React.FC<Props> = ({ deploymentId, project }) => {
const { t } = useTranslation();

const [loadIndexersLazy, asyncIndexers] = useGetDeploymentIndexersLazyQuery();
Expand Down Expand Up @@ -156,7 +158,7 @@ const IndexerDetails: React.FC<Props> = ({ deploymentId }) => {
.filter(notEmpty)
.sort((indexer) => (indexer.status === ServiceStatus.READY ? -1 : 1))
.map((indexer) => (
<Row indexer={indexer} key={indexer.indexerId} deploymentId={deploymentId} />
<Row type={project.type} indexer={indexer} key={indexer.indexerId} deploymentId={deploymentId} />
))}
</>
<div className={styles.indexersPagination}>
Expand Down
37 changes: 31 additions & 6 deletions src/components/IndexerDetails/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
import { BsChevronDown, BsChevronUp, BsInfoSquare } from 'react-icons/bs';
import { useNavigate } from 'react-router';
import { LazyQueryResult } from '@apollo/client';
import RpcPlayground from '@components/RpcPlayground/RpcPlayground';
import { WalletRoute } from '@components/WalletRoute';
import { useIsLogin } from '@hooks/useIsLogin';
import { useRequestServiceAgreementToken } from '@hooks/useRequestServiceAgreementToken';
Expand All @@ -14,6 +15,7 @@ import { GraphiQL } from '@subql/components/dist/common/GraphiQL';
import {
GetDeploymentIndexersQuery,
PlansNodeFieldsFragment as Plan,
ProjectType,
ServiceStatus as DeploymentStatus,
} from '@subql/network-query';
import { useGetDeploymentPlansLazyQuery } from '@subql/react-hooks';
Expand All @@ -25,6 +27,7 @@ import clsx from 'clsx';
import { t } from 'i18next';
import { useAccount } from 'wagmi';

import RpcPlaygroundIcon from 'src/images/rpcPlayground';
import { useWeb3Store } from 'src/stores';
import { useProjectStore } from 'src/stores/project';

Expand Down Expand Up @@ -77,7 +80,8 @@ export interface QueryLimit {
const ConnectedRow: React.FC<{
indexer: ExcludeNull<ExcludeNull<GetDeploymentIndexersQuery['indexerDeployments']>['nodes'][number]>;
deploymentId?: string;
}> = ({ indexer, deploymentId }) => {
type: ProjectType;
}> = ({ indexer, deploymentId, type }) => {
const { t } = useTranslation();
const { address: account } = useAccount();
const navigate = useNavigate();
Expand Down Expand Up @@ -175,7 +179,6 @@ const ConnectedRow: React.FC<{
</>
),
},

{
width: '13%',
render: () => {
Expand Down Expand Up @@ -211,7 +214,16 @@ const ConnectedRow: React.FC<{
setShowReqTokenConfirmModal(true);
}}
>
<PlaygroundIcon color="var(--sq-blue600)" width={14} height={14} style={{ marginRight: '5px' }} />
{type === ProjectType.SUBQUERY ? (
<PlaygroundIcon color="var(--sq-blue600)" width={14} height={14} style={{ marginRight: '5px' }} />
) : (
<RpcPlaygroundIcon
color="var(--sq-blue600)"
width={14}
height={14}
style={{ marginRight: '5px', marginTop: 3 }}
></RpcPlaygroundIcon>
)}
Playground
</Typography>
);
Expand Down Expand Up @@ -332,7 +344,13 @@ const ConnectedRow: React.FC<{
>
<WalletRoute
componentMode
element={<Typography>{t('explorer.flexPlans.requestToken')}</Typography>}
element={
<Typography>
{t('explorer.flexPlans.requestToken', {
type: type === ProjectType.RPC ? 'JSON' : 'Graphql',
})}
</Typography>
}
></WalletRoute>
</Modal>

Expand All @@ -344,7 +362,11 @@ const ConnectedRow: React.FC<{
>
<div className={styles.playgroundModalHeader}>
<Typography className={styles.playgroundModalTitle}>
<PlaygroundIcon style={{ marginRight: '8px' }} />
{type === ProjectType.SUBQUERY ? (
<PlaygroundIcon style={{ marginRight: '8px' }} />
) : (
<RpcPlaygroundIcon style={{ marginRight: '8px' }}></RpcPlaygroundIcon>
)}
{t('myFlexPlans.playground')}
</Typography>
<Typography className={styles.playgroundModalLimitInfo}>
Expand All @@ -361,7 +383,10 @@ const ConnectedRow: React.FC<{
</span>
</Typography>
</div>
{queryUrl && trailToken && <GraphiQL url={queryUrl} bearToken={trailToken} theme="dark"></GraphiQL>}
{type === ProjectType.SUBQUERY && queryUrl && trailToken && (
<GraphiQL url={queryUrl} bearToken={trailToken} theme="dark"></GraphiQL>
)}
{type === ProjectType.RPC && <RpcPlayground url={queryUrl} trailToken={trailToken}></RpcPlayground>}
</AntdModal>
</>
);
Expand Down
5 changes: 3 additions & 2 deletions src/components/ProjectHeader/ProjectHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ const ProjectHeader: React.FC<Props> = ({
{isUnsafeDeployment && <UnsafeWarn></UnsafeWarn>}
<VersionDropdown />
<span style={{ flex: 1 }}></span>
<Button type="primary" shape="round" size="large">
{/* TODO: finish this */}
{/* <Button type="primary" shape="round" size="large">
Get RPC Endpoint
</Button>
</Button> */}
</div>
<Address address={project.owner} size="small" />

Expand Down
98 changes: 98 additions & 0 deletions src/components/RpcPlayground/RpcPlayground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright 2020-2022 SubQuery Pte Ltd authors & contributors
// SPDX-License-Identifier: Apache-2.0

import React, { FC, useMemo, useState } from 'react';
import { Typography } from '@subql/components';
import { getAuthReqHeader } from '@utils';
import { Button, Input } from 'antd';
import { fetchJson } from 'ethers/lib/utils';

import styles from './index.module.less';

interface IProps {
url?: string;
trailToken: string;
}

const RpcPlayground: FC<IProps> = ({ url, trailToken }) => {
const [val, setVal] = useState('');
const [loading, setLoading] = useState(false);
const enteredRows = useMemo(() => {
return val.split('\n').length;
}, [val]);

const [responseData, setResponseData] = useState('');

const fetchRpc = async () => {
if (!url) return;
try {
setLoading(true);
const res = await fetchJson(
{
url,
headers: {
...getAuthReqHeader(trailToken),
},
},
val,
);

setResponseData(JSON.stringify(res));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
setResponseData(`${e.toString()}`);
} finally {
setLoading(false);
}
};

return (
<div className={styles.rpcPlayground}>
<div className={styles.rpcPlaygroundEditor}>
<Typography style={{ color: '#fff', marginBottom: 8 }} weight={500}>
Request
</Typography>
<div style={{ display: 'flex', gap: 8 }}>
<div className={styles.rows}>
{new Array(enteredRows).fill(0).map((_, index) => (
<span key={index}>{index + 1}</span>
))}
</div>
<Input.TextArea
rows={30}
value={val}
onChange={(e) => {
setVal(e.target.value);
}}
style={{ resize: 'none' }}
placeholder="JSON RPC playground is a simple tool to help you test queries, click to enter you requests."
></Input.TextArea>
</div>

<div style={{ display: 'flex', justifyContent: 'flex-end', position: 'sticky', bottom: 32 }}>
<Button
loading={loading}
shape="round"
size="large"
type="primary"
onClick={() => {
fetchRpc();
}}
>
Send Request
</Button>
</div>
</div>

<div className={styles.rpcPlaygroundResponse}>
<Typography style={{ color: '#fff', marginBottom: 8 }} weight={500}>
Response
</Typography>
<div style={{ overflowWrap: 'anywhere', wordBreak: 'break-all', color: 'var(--sq-gray500)' }}>
{responseData}
</div>
</div>
</div>
);
};
export default RpcPlayground;
46 changes: 46 additions & 0 deletions src/components/RpcPlayground/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.rpcPlayground {
display: flex;
padding: 16px;
border-radius: 0px 0px 16px 16px;
background: #2A3546;

&Editor {
flex: 1;
padding: 16px;
background: #1F2A3B;
border-radius: 10px;
position: relative;

.rows {
display: flex;
flex-direction: column;
color: var(--sq-gray600);
font-size: 14px;
line-height: 1.5714285714285714;
padding-top: 2px;
}

:global {
.ant-input {
background: #1F2A3B;
border: 1px solid #1F2A3B;
color: var(--sq-gray500);
padding: 0;
font-family: var(--sq-font-family);
&:focus {
box-shadow: none;
}

&::placeholder {
color: var(--sq-gary500);
}
}
}
}

&Response {
flex: 1;
padding: 16px;

}
}
7 changes: 2 additions & 5 deletions src/components/Spinner/Spinner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import * as React from 'react';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import { Spin } from 'antd';
import { Spinner as SubqlSpinner } from '@subql/components';

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

Expand All @@ -12,11 +11,9 @@ type Props = {
};

const Spinner: React.FC<Props> = ({ size }) => {
const antIcon = <LoadingOutlined style={{ fontSize: size }} spin />;

return (
<div className={styles.spinner}>
<Spin indicator={antIcon} />
<SubqlSpinner></SubqlSpinner>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useProjectList.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

.typeFilter {
display: flex;
justify-content: center;
// justify-content: center;
margin-bottom: 40px;

:global {
Expand Down
Loading
Loading