diff --git a/package.json b/package.json index 25d9ed648..0191dc23b 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 5cdf84d93..2c93dc564 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -37,17 +37,6 @@ 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 (
@@ -55,7 +44,7 @@ export const Header: React.FC = () => { navigate={(link) => { navigate(link); }} - appNavigation={calEntryLinks} + appNavigation={entryLinks} dropdownLinks={{ label: 'Kepler', links: externalAppLinks }} rightElement={ <> diff --git a/src/components/IndexerDetails/IndexerDetails.module.less b/src/components/IndexerDetails/IndexerDetails.module.less index e9d9f73a9..a4fd443c1 100644 --- a/src/components/IndexerDetails/IndexerDetails.module.less +++ b/src/components/IndexerDetails/IndexerDetails.module.less @@ -170,6 +170,8 @@ color: #fff; font-size: 18px; margin-bottom: 8px; + display: flex; + align-items: center; } &LimitInfo { diff --git a/src/components/IndexerDetails/IndexerDetails.tsx b/src/components/IndexerDetails/IndexerDetails.tsx index 87ce54705..5fc6683af 100644 --- a/src/components/IndexerDetails/IndexerDetails.tsx +++ b/src/components/IndexerDetails/IndexerDetails.tsx @@ -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'; @@ -16,6 +17,7 @@ import Row from './Row'; type Props = { deploymentId: string | undefined; + project: ProjectDetailsQuery; }; const NoIndexers: React.FC = () => { @@ -31,7 +33,7 @@ const NoIndexers: React.FC = () => { ); }; -const IndexerDetails: React.FC = ({ deploymentId }) => { +const IndexerDetails: React.FC = ({ deploymentId, project }) => { const { t } = useTranslation(); const [loadIndexersLazy, asyncIndexers] = useGetDeploymentIndexersLazyQuery(); @@ -156,7 +158,7 @@ const IndexerDetails: React.FC = ({ deploymentId }) => { .filter(notEmpty) .sort((indexer) => (indexer.status === ServiceStatus.READY ? -1 : 1)) .map((indexer) => ( - + ))}
diff --git a/src/components/IndexerDetails/Row.tsx b/src/components/IndexerDetails/Row.tsx index 1ed089111..c3cbf24ff 100644 --- a/src/components/IndexerDetails/Row.tsx +++ b/src/components/IndexerDetails/Row.tsx @@ -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'; @@ -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'; @@ -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'; @@ -77,7 +80,8 @@ export interface QueryLimit { const ConnectedRow: React.FC<{ indexer: ExcludeNull['nodes'][number]>; deploymentId?: string; -}> = ({ indexer, deploymentId }) => { + type: ProjectType; +}> = ({ indexer, deploymentId, type }) => { const { t } = useTranslation(); const { address: account } = useAccount(); const navigate = useNavigate(); @@ -175,7 +179,6 @@ const ConnectedRow: React.FC<{ ), }, - { width: '13%', render: () => { @@ -211,7 +214,16 @@ const ConnectedRow: React.FC<{ setShowReqTokenConfirmModal(true); }} > - + {type === ProjectType.SUBQUERY ? ( + + ) : ( + + )} Playground ); @@ -332,7 +344,13 @@ const ConnectedRow: React.FC<{ > {t('explorer.flexPlans.requestToken')}} + element={ + + {t('explorer.flexPlans.requestToken', { + type: type === ProjectType.RPC ? 'JSON' : 'Graphql', + })} + + } > @@ -344,7 +362,11 @@ const ConnectedRow: React.FC<{ >
- + {type === ProjectType.SUBQUERY ? ( + + ) : ( + + )} {t('myFlexPlans.playground')} @@ -361,7 +383,10 @@ const ConnectedRow: React.FC<{
- {queryUrl && trailToken && } + {type === ProjectType.SUBQUERY && queryUrl && trailToken && ( + + )} + {type === ProjectType.RPC && } ); diff --git a/src/components/ProjectHeader/ProjectHeader.tsx b/src/components/ProjectHeader/ProjectHeader.tsx index 25cc62b09..f6ee18363 100644 --- a/src/components/ProjectHeader/ProjectHeader.tsx +++ b/src/components/ProjectHeader/ProjectHeader.tsx @@ -71,9 +71,10 @@ const ProjectHeader: React.FC = ({ {isUnsafeDeployment && } - + */}
diff --git a/src/components/RpcPlayground/RpcPlayground.tsx b/src/components/RpcPlayground/RpcPlayground.tsx new file mode 100644 index 000000000..ac353c132 --- /dev/null +++ b/src/components/RpcPlayground/RpcPlayground.tsx @@ -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 = ({ 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 ( +
+
+ + Request + +
+
+ {new Array(enteredRows).fill(0).map((_, index) => ( + {index + 1} + ))} +
+ { + 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." + > +
+ +
+ +
+
+ +
+ + Response + +
+ {responseData} +
+
+
+ ); +}; +export default RpcPlayground; diff --git a/src/components/RpcPlayground/index.module.less b/src/components/RpcPlayground/index.module.less new file mode 100644 index 000000000..9864645b0 --- /dev/null +++ b/src/components/RpcPlayground/index.module.less @@ -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; + + } +} \ No newline at end of file diff --git a/src/components/Spinner/Spinner.tsx b/src/components/Spinner/Spinner.tsx index 5822335d0..466f3427e 100644 --- a/src/components/Spinner/Spinner.tsx +++ b/src/components/Spinner/Spinner.tsx @@ -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'; @@ -12,11 +11,9 @@ type Props = { }; const Spinner: React.FC = ({ size }) => { - const antIcon = ; - return (
- +
); }; diff --git a/src/hooks/useProjectList.module.less b/src/hooks/useProjectList.module.less index 4c8539db9..0e4b7c119 100644 --- a/src/hooks/useProjectList.module.less +++ b/src/hooks/useProjectList.module.less @@ -8,7 +8,7 @@ .typeFilter { display: flex; - justify-content: center; + // justify-content: center; margin-bottom: 40px; :global { diff --git a/src/hooks/useProjectList.tsx b/src/hooks/useProjectList.tsx index 4accda27b..c1e38b08d 100644 --- a/src/hooks/useProjectList.tsx +++ b/src/hooks/useProjectList.tsx @@ -5,12 +5,13 @@ import React, { useMemo, useState } from 'react'; import SearchOutlined from '@ant-design/icons/SearchOutlined'; import { ProjectCard } from '@components'; import { useProjectMetadata } from '@containers'; +import { PublishNewProjectModal } from '@pages/studio/Home/Home'; import { SubqlCheckbox } from '@subql/components'; import { ProjectFieldsFragment, ProjectsOrderBy, ProjectType } from '@subql/network-query'; import { useAsyncMemo, useGetProjectLazyQuery, useGetProjectsLazyQuery } from '@subql/react-hooks'; import { categoriesOptions, notEmpty, rpcCategoriesOptions } from '@utils'; import { useInfiniteScroll, useMount } from 'ahooks'; -import { Input, Radio, Skeleton, Typography } from 'antd'; +import { Button, Input, Radio, Skeleton, Typography } from 'antd'; import { useGetDeploymentManifest } from './useGetDeploymentManifest'; import { useLocalProjects } from './useLocalProjects'; @@ -63,6 +64,7 @@ export const useProjectList = (props: UseProjectListProps = {}) => { // assum there at lease have 11 projects const [total, setTotal] = React.useState(10); const [inSearchMode, setInSearchMode] = React.useState(false); + const [showPublishModal, setShowPublishModal] = React.useState(false); const { getProjectBySearch } = useLocalProjects(); @@ -236,6 +238,23 @@ export const useProjectList = (props: UseProjectListProps = {}) => { buttonStyle="solid" size="large" /> + + + { + setShowPublishModal(val); + }} + >
diff --git a/src/i18n/en/explorer.ts b/src/i18n/en/explorer.ts index c8110ca03..da83cb1ba 100644 --- a/src/i18n/en/explorer.ts +++ b/src/i18n/en/explorer.ts @@ -105,7 +105,7 @@ const translation = { indexer: 'indexer', validityPeriod: 'Validity Period', non: 'There are no flex plans for this project yet.', - requestToken: 'To start testing your queries in the GraphQL playground, simply request a trial token.', + requestToken: 'To start testing your queries in the {{type}} playground, simply request a trial token.', remainLimit: 'Remain requests limit: {{limit}}', expireTime: 'Token expires in {{time}}', }, diff --git a/src/images/rpcPlayground.tsx b/src/images/rpcPlayground.tsx new file mode 100644 index 000000000..934c63f29 --- /dev/null +++ b/src/images/rpcPlayground.tsx @@ -0,0 +1,60 @@ +// Copyright 2020-2022 SubQuery Pte Ltd authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { FC } from 'react'; + +export type Icon = { + color?: string; + width?: number; + height?: number; + style?: React.CSSProperties; +}; + +const RpcPlaygroundIcon: FC = ({ color = '#fff', width = 18, height = 18, style }) => { + return ( + + + + + + + + + + ); +}; + +export default RpcPlaygroundIcon; diff --git a/src/pages/consumer/Playground/AuthPlayground.tsx b/src/pages/consumer/Playground/AuthPlayground.tsx index 285d8deb7..e80a78a8a 100644 --- a/src/pages/consumer/Playground/AuthPlayground.tsx +++ b/src/pages/consumer/Playground/AuthPlayground.tsx @@ -4,7 +4,9 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { BreadcrumbNav } from '@components'; +import RpcPlayground from '@components/RpcPlayground/RpcPlayground'; import { Spinner } from '@subql/components'; +import { ProjectType } from '@subql/network-query'; import { Table } from 'antd'; import { ColumnsType } from 'antd/lib/table'; @@ -33,6 +35,7 @@ interface AuthPlaygroundProps { columns?: ColumnsType; dataSource?: any[]; rowKey?: string; + type: ProjectType; loading?: boolean; requireAuth: boolean; @@ -53,6 +56,7 @@ export const AuthPlayground: React.FC = ({ columns, dataSource, rowKey, + type, loading, requireAuth, @@ -82,7 +86,13 @@ export const AuthPlayground: React.FC = ({
{loading && } {requireAuth && } - {playgroundVisible && } + {type === ProjectType.SUBQUERY && playgroundVisible && } + {type === ProjectType.RPC && playgroundVisible && ( + + )}
); diff --git a/src/pages/consumer/Playground/FlexPlayground.tsx b/src/pages/consumer/Playground/FlexPlayground.tsx index 5290885a6..c86ddf815 100644 --- a/src/pages/consumer/Playground/FlexPlayground.tsx +++ b/src/pages/consumer/Playground/FlexPlayground.tsx @@ -7,7 +7,7 @@ import { useNavigate, useParams } from 'react-router'; import { NotificationType, openNotification } from '@components/Notification'; import { FetcherParams } from '@graphiql/toolkit'; import { Spinner, TableTitle } from '@subql/components'; -import { StateChannelFieldsFragment as ConsumerFlexPlan } from '@subql/network-query'; +import { ProjectType, StateChannelFieldsFragment as ConsumerFlexPlan } from '@subql/network-query'; import { renderAsync, useGetConsumerFlexPlanQuery } from '@subql/react-hooks'; import { TableProps } from 'antd'; import { BigNumber } from 'ethers'; @@ -202,6 +202,7 @@ export const FlexPlayground: React.FC = () => { headerText={t('plans.category.myFlexPlans')} deploymentId={flexPlan?.deployment?.id ?? ''} projectMetadata={flexPlan?.deployment?.project?.metadata} + type={flexPlan.deployment?.project?.type || ProjectType.SUBQUERY} columns={columns} dataSource={[flexPlan]} rowKey={'id'} diff --git a/src/pages/consumer/Playground/SAPlayground.tsx b/src/pages/consumer/Playground/SAPlayground.tsx index 1949741cb..16d219c00 100644 --- a/src/pages/consumer/Playground/SAPlayground.tsx +++ b/src/pages/consumer/Playground/SAPlayground.tsx @@ -7,7 +7,7 @@ import { useLocation, useNavigate } from 'react-router'; import { NotificationType, openNotification } from '@components/Notification'; import { FetcherParams } from '@graphiql/toolkit'; import { useIndexerMetadata } from '@hooks'; -import { ServiceAgreementFieldsFragment as ServiceAgreement } from '@subql/network-query'; +import { ProjectType, ServiceAgreementFieldsFragment as ServiceAgreement } from '@subql/network-query'; import { TableProps } from 'antd'; import i18next from 'i18next'; import moment from 'moment'; @@ -166,12 +166,18 @@ export const SAPlayground: React.FC = () => { const requireAuth = queryable === false && !isCheckingAuth; const showPlayground = !!(queryable && queryUrl && !isCheckingAuth); + if (!serviceAgreement) { + navigate('/consumer/service-agreements'); + return
; + } + console.warn(serviceAgreement); return ( = ({ {t('serviceAgreements.playground.comingSoon')} ); + return (
- { - setShowPublishModal(val); - }} - > ); }; diff --git a/src/pages/explorer/Project/Project.tsx b/src/pages/explorer/Project/Project.tsx index 56d96d521..bcc507515 100644 --- a/src/pages/explorer/Project/Project.tsx +++ b/src/pages/explorer/Project/Project.tsx @@ -45,7 +45,7 @@ const ProjectInner: React.FC = () => { { link: `${OVERVIEW}${location.search}`, label: t('explorer.project.tab1') }, { link: `${INDEXERS}${location.search}`, - label: asyncProject.data?.type === ProjectType.RPC ? 'RPC Endpoints' : t('explorer.project.tab2'), + label: asyncProject.data?.type === ProjectType.RPC ? 'RPC Providers' : t('explorer.project.tab2'), }, { link: `${SERVICE_AGREEMENTS}${location.search}`, label: t('explorer.project.tab3') }, ]; @@ -158,7 +158,10 @@ const ProjectInner: React.FC = () => { /> } /> - } /> + } + /> { }, }); - const [showCreateModal, setShowCreateModal] = React.useState(false); - const enableCreateModal = () => setShowCreateModal(true); - return (
My Projects -
- { - setShowCreateModal(val); - }} - /> - {listsWithSearch}
);