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: upgrade & home #623

Merged
merged 2 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@sentry/react": "^7.57.0",
"@subql/apollo-links": "^1.2.3",
"@subql/components": "1.0.3-22",
"@subql/contract-sdk": "^0.100.3",
"@subql/contract-sdk": "0.111.0",
"@subql/network-clients": "^0.100.0",
"@subql/network-config": "^0.100.0",
"@subql/network-query": "0.100.3-0",
Expand Down
73 changes: 45 additions & 28 deletions src/hooks/useProjectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const useProjectList = (props: UseProjectListProps = {}) => {
variables: { offset: 0 },
});

const [getProject, { error: topError }] = useGetProjectLazyQuery();
const [getProject, { error: topError, loading: topLoading }] = useGetProjectLazyQuery();

const [searchKeywords, setSearchKeywords] = React.useState('');
const [filterCategories, setFilterCategories] = useState<string[]>([]);
Expand Down Expand Up @@ -121,6 +121,7 @@ export const useProjectList = (props: UseProjectListProps = {}) => {
// filter once or twice is the same.
const nonEmptyProjects = res.data.projects?.nodes.filter(notEmpty).filter(notEmpty);
const mergered = options?.refresh ? [...nonEmptyProjects] : [...fetchedProejcts.current, ...nonEmptyProjects];
// TODO: filter by backend.
setProjects(mergered.filter((proj) => (account ? account.toLowerCase() === proj.owner.toLowerCase() : true)));
fetchedProejcts.current = mergered;
updatedLength = mergered.length;
Expand All @@ -143,8 +144,8 @@ export const useProjectList = (props: UseProjectListProps = {}) => {
});

const topProjectItem = useMemo(() => {
if (!showTopProject) return '';
if (!inSearchMode && topProject)
if (!showTopProject || inSearchMode) return '';
if (topProject)
return (
<ProjectItem
project={topProject}
Expand All @@ -155,33 +156,53 @@ export const useProjectList = (props: UseProjectListProps = {}) => {
/>
);

if (!inSearchMode) return <Skeleton paragraph={{ rows: 7 }} style={{ width: 236, height: 400 }} active></Skeleton>;
if (topLoading) return <Skeleton paragraph={{ rows: 7 }} style={{ width: 236, height: 400 }} active></Skeleton>;

return '';
}, [inSearchMode, topProject, showTopProject, onProjectClick]);
}, [inSearchMode, topProject, topLoading, showTopProject, onProjectClick]);

const projectListItems = useMemo(() => {
if (loading) {
return new Array(projects.length + 10 <= total ? 10 : total - projects.length).fill(0).map((_, i) => {
return <Skeleton paragraph={{ rows: 7 }} active key={i} style={{ width: 236, height: 400 }}></Skeleton>;
});
}
const loadingItems = new Array(projects.length + 10 <= total ? 10 : total - projects.length).fill(0).map((_, i) => {
return <Skeleton paragraph={{ rows: 7 }} active key={i} style={{ width: 236, height: 400 }}></Skeleton>;
});
if (projects.length) {
return projects.map((project) => (
<ProjectItem
project={project}
key={project.id}
onClick={() => {
onProjectClick?.(project.id);
}}
/>
));
return (
<>
{projects.map((project) => (
<ProjectItem
project={project}
key={project.id}
onClick={() => {
onProjectClick?.(project.id);
}}
/>
))}
{loading && loadingItems}
</>
);
} else {
if (loading) return loadingItems;
}

if (inSearchMode) return '';
// TODO: ui
return 'No Projects';
}, [inSearchMode, loading, projects]);
return '';
}, [inSearchMode, loading, projects, onProjectClick]);

const emptyResult = useMemo(() => {
if (loading || topLoading) return '';
if (inSearchMode && !projects.length)
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Typography>No projects match your search</Typography>
</div>
);

if (!inSearchMode && !projects.length && !topProject)
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Typography>No projects</Typography>
</div>
);
}, [loading, inSearchMode, projects, topProject, showTopProject, topLoading]);

const listsWithSearch = useMemo(() => {
return (
Expand Down Expand Up @@ -228,11 +249,7 @@ export const useProjectList = (props: UseProjectListProps = {}) => {
{projectListItems}
</div>

{inSearchMode && !loading && !projects.length && (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Typography>No projects match your search</Typography>
</div>
)}
{emptyResult}

{(error || topError) && <span>{`We have an error: ${error?.message || topError?.message}`}</span>}
</>
Expand Down
2 changes: 0 additions & 2 deletions src/pages/explorer/Home/Home.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

.header {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
margin-bottom: 72px;
}
Expand Down
28 changes: 25 additions & 3 deletions src/pages/explorer/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router';
import { useProjectList } from '@hooks/useProjectList';
import { PublishNewProjectModal } from '@pages/studio/Home/Home';
import { Typography } from '@subql/components';
import { Button } from 'antd';

import { ROUTES } from '../../../utils';
import styles from './Home.module.css';
Expand All @@ -15,12 +17,32 @@ const { PROJECT_NAV } = ROUTES;
// TODO move to components
export const Header: React.FC = () => {
const { t } = useTranslation();
const [showPublishModal, setShowPublishModal] = React.useState(false);

return (
<div className={styles.header}>
<Typography variant="h3">{t('explorer.home.header')}</Typography>
<Typography style={{ width: 439, textAlign: 'center', marginTop: 16 }} type="secondary">
{t('explorer.home.headerDesc')}
</Typography>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography style={{ width: 565, marginTop: 16 }} type="secondary">
{t('explorer.home.headerDesc')}
</Typography>
<Button
type="primary"
shape="round"
size="large"
onClick={() => {
setShowPublishModal(true);
}}
>
Publish New Project
</Button>
</div>
<PublishNewProjectModal
value={showPublishModal}
onChange={(val) => {
setShowPublishModal(val);
}}
></PublishNewProjectModal>
</div>
);
};
Expand Down
112 changes: 67 additions & 45 deletions src/pages/studio/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import * as React from 'react';
import { useNavigate } from 'react-router';
import { useProjectList } from '@hooks/useProjectList';
import { usePropsValue } from '@hooks/usePropsValue';
import { Modal, Typography } from '@subql/components';
import { Button, Form, Input } from 'antd';
import { useForm } from 'antd/es/form/Form';
Expand All @@ -13,6 +14,67 @@ import { ROUTES } from '../../../utils';

const { STUDIO_CREATE_NAV, STUDIO_PROJECT_NAV } = ROUTES;

export const PublishNewProjectModal: React.FC<{ value: boolean; onChange: (val: boolean) => void }> = ({
value,
onChange,
}) => {
const navigate = useNavigate();
const [form] = useForm();
const [showCreateModal, setShowCreateModal] = usePropsValue<boolean>({
value,
onChange,
defaultValue: false,
});
const handleCreateProject = () => {
navigate(
`${STUDIO_CREATE_NAV}?name=${encodeURI(form.getFieldValue('projectName'))}&deploymentId=${form.getFieldValue(
'deploymentId',
)}`,
);
};

return (
<Modal
title="Publish New Project to the Decentralised Network"
width={572}
open={showCreateModal}
onCancel={() => setShowCreateModal(false)}
onOk={async () => {
await form.validateFields();

handleCreateProject();
}}
okText={'Next'}
okButtonProps={{
shape: 'round',
size: 'large',
}}
cancelButtonProps={{
style: { display: 'none' },
}}
>
<div style={{ display: 'flex', flexDirection: 'column', gap: 24, padding: '24px 0' }}>
<Typography style={{ color: 'var(--sq-gray700)' }}>
Please enter the deployment ID of your SubQuery project below. To get the deployment ID, run subql publish
from your project code to publish it to IPFS. Learn how to publish a SubQuery project here.
</Typography>

<Form layout="vertical" form={form}>
<Form.Item label="Deployment ID" name="deploymentId" rules={[{ required: true }]}>
<Input placeholder="Deployment ID" size="large"></Input>
</Form.Item>
<div>
<Form.Item label="Project Name" name="projectName" rules={[{ required: true }]}>
<Input placeholder="Project Name" size="large"></Input>
</Form.Item>
<Typography variant="medium">Project names should be unique, you can edit this later.</Typography>
</div>
</Form>
</div>
</Modal>
);
};

const Home: React.FC = () => {
const { account } = useWeb3();
const navigate = useNavigate();
Expand All @@ -23,15 +85,7 @@ const Home: React.FC = () => {
},
});

const [form] = useForm();
const [showCreateModal, setShowCreateModal] = React.useState<boolean>(false);
const handleCreateProject = () => {
navigate(
`${STUDIO_CREATE_NAV}?name=${encodeURI(form.getFieldValue('projectName'))}&deploymentId=${form.getFieldValue(
'deploymentId',
)}`,
);
};
const enableCreateModal = () => setShowCreateModal(true);

return (
Expand All @@ -43,44 +97,12 @@ const Home: React.FC = () => {
</Button>
</div>

<Modal
title="Publish New Project to the Decentralised Network"
width={572}
open={showCreateModal}
onCancel={() => setShowCreateModal(false)}
onOk={async () => {
await form.validateFields();

handleCreateProject();
<PublishNewProjectModal
value={showCreateModal}
onChange={(val) => {
setShowCreateModal(val);
}}
okText={'Next'}
okButtonProps={{
shape: 'round',
size: 'large',
}}
cancelButtonProps={{
style: { display: 'none' },
}}
>
<div style={{ display: 'flex', flexDirection: 'column', gap: 24, padding: '24px 0' }}>
<Typography style={{ color: 'var(--sq-gray700)' }}>
Please enter the deployment ID of your SubQuery project below. To get the deployment ID, run subql publish
from your project code to publish it to IPFS. Learn how to publish a SubQuery project here.
</Typography>

<Form layout="vertical" form={form}>
<Form.Item label="Deployment ID" name="deploymentId" rules={[{ required: true }]}>
<Input placeholder="Deployment ID" size="large"></Input>
</Form.Item>
<div>
<Form.Item label="Project Name" name="projectName" rules={[{ required: true }]}>
<Input placeholder="Project Name" size="large"></Input>
</Form.Item>
<Typography variant="medium">Project names should be unique, you can edit this later.</Typography>
</div>
</Form>
</div>
</Modal>
/>

{listsWithSearch}
</div>
Expand Down
Loading
Loading