From f27e59788454a1bb2f259d59c4e7803acbb08ddb Mon Sep 17 00:00:00 2001 From: noah Date: Sun, 3 Apr 2022 21:24:46 +0900 Subject: [PATCH 1/6] Separate the state from the `home` view --- ui/src/views/home/RepoList.tsx | 19 ++++--------- ui/src/views/home/index.tsx | 52 +++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/ui/src/views/home/RepoList.tsx b/ui/src/views/home/RepoList.tsx index 1f71626e..49aaa34a 100644 --- a/ui/src/views/home/RepoList.tsx +++ b/ui/src/views/home/RepoList.tsx @@ -1,27 +1,18 @@ -import { shallowEqual } from 'react-redux' import { List, Typography } from 'antd' import moment from "moment" -import { useAppSelector } from '../../redux/hooks' -import { Deployment } from '../../models' +import { Repo, Deployment } from '../../models' import UserAvatar from '../../components/UserAvatar' import DeploymentStatusBadge from "../../components/DeploymentStatusBadge" import DeploymentRefCode from "../../components/DeploymentRefCode" -import Spin from '../../components/Spin' const { Text, Paragraph } = Typography -export default function RepoList(): JSX.Element { - const { loading, repos } = useAppSelector(state => state.home, shallowEqual) - - if (loading) { - return ( -
- -
- ) - } +export interface RepoListProps { + repos: Repo[] +} +export default function RepoList({repos}: RepoListProps): JSX.Element { return ( state.home, shallowEqual) +// Binding the state to the deployment page. +export default ():JSX.Element => { + const { loading, repos, page, syncing } = useAppSelector(state => state.home, shallowEqual) const dispatch = useAppDispatch() useEffect(() => { @@ -57,6 +59,43 @@ export default function Home(): JSX.Element { f() } + return ( +
+ +
+ ) +} + +interface HomeProps extends RepoListProps { + loading: boolean + syncing: RequestStatus + page: number + search(q: string): void + onClickSync(): void + onClickPrev(): void + onClickNext(): void +} + +function Home({ + loading, + page, + syncing, + repos, + search, + onClickSync, + onClickPrev, + onClickNext, +}: HomeProps): JSX.Element { + return (
@@ -82,7 +121,12 @@ export default function Home(): JSX.Element {
- + {(loading)? +
+ +
+ : + }
Date: Sun, 3 Apr 2022 21:48:55 +0900 Subject: [PATCH 2/6] Separate the state from the `main` view --- ui/src/views/home/index.tsx | 4 +- ui/src/views/main/Content.tsx | 30 +++++----- ui/src/views/main/Header.tsx | 23 ++++---- ui/src/views/main/LicenseWarningFooter.tsx | 11 ++-- ui/src/views/main/index.tsx | 65 +++++++++++++++++++--- 5 files changed, 92 insertions(+), 41 deletions(-) diff --git a/ui/src/views/home/index.tsx b/ui/src/views/home/index.tsx index 2ec2a46b..136e9500 100644 --- a/ui/src/views/home/index.tsx +++ b/ui/src/views/home/index.tsx @@ -97,7 +97,7 @@ function Home({ }: HomeProps): JSX.Element { return ( -
+ <> Home @@ -136,6 +136,6 @@ function Home({ onClickNext={onClickNext} />
-
+ ) } \ No newline at end of file diff --git a/ui/src/views/main/Content.tsx b/ui/src/views/main/Content.tsx index ec1e3bbb..1e2378a8 100644 --- a/ui/src/views/main/Content.tsx +++ b/ui/src/views/main/Content.tsx @@ -1,22 +1,22 @@ -import { shallowEqual } from "react-redux" import { Row, Col, Result, Button} from "antd" -import { useAppSelector, useAppDispatch } from "../../redux/hooks" -import { mainSlice as slice } from "../../redux/main" import React from "react" -export default function Content(props: React.PropsWithChildren): JSX.Element { - const { - available, - authorized, - expired, - } = useAppSelector(state => state.main, shallowEqual) - const dispatch = useAppDispatch() +export interface ContentProps { + available: boolean + authorized: boolean + expired: boolean + onClickRetry(): void +} + +export default function Content({ + available, + authorized, + expired, + children, + onClickRetry, +}: React.PropsWithChildren): JSX.Element { - const onClickRetry = () => { - dispatch(slice.actions.setAvailable(true)) - dispatch(slice.actions.setExpired(false)) - } let content: React.ReactNode if (!available) { @@ -44,7 +44,7 @@ export default function Content(props: React.PropsWithChildren): JSX.Elemen extra={[]} /> } else { - content = props.children + content = children } return ( diff --git a/ui/src/views/main/Header.tsx b/ui/src/views/main/Header.tsx index fc60c83e..9b6ab446 100644 --- a/ui/src/views/main/Header.tsx +++ b/ui/src/views/main/Header.tsx @@ -1,22 +1,23 @@ import { useState } from "react" -import { shallowEqual } from "react-redux" import { Menu, Row, Col, Button, Drawer, Avatar, Dropdown, Badge, Space} from "antd" import { SettingFilled } from "@ant-design/icons" -import { useAppSelector } from "../../redux/hooks" - +import { Deployment, User, Review } from "../../models" import RecentActivities from "../../components/RecentActivities" import Logo from "../../logo.svg" -export default function Header(): JSX.Element { - const { - authorized, - user, - deployments, - reviews, - } = useAppSelector(state => state.main, shallowEqual) +export interface HeaderProps { + user: User | undefined + deployments: Deployment[] + reviews: Review[] +} +export default function Header({ + user, + deployments, + reviews, +}: HeaderProps): JSX.Element { const activitiesCount = deployments.length + reviews.length const [ isRecentActivitiesVisible, setRecentActivitiesVisible ] = useState(false) @@ -63,7 +64,7 @@ export default function Header(): JSX.Element { reviews={reviews} /> - {(authorized) ? + {(user) ? diff --git a/ui/src/views/main/LicenseWarningFooter.tsx b/ui/src/views/main/LicenseWarningFooter.tsx index 531646be..2eb5944d 100644 --- a/ui/src/views/main/LicenseWarningFooter.tsx +++ b/ui/src/views/main/LicenseWarningFooter.tsx @@ -1,11 +1,14 @@ import moment from "moment" -import { shallowEqual } from "react-redux" -import { useAppSelector } from "../../redux/hooks" +import { License } from "../../models" -export default function LicenseWarningFooter(): JSX.Element { - const { license } = useAppSelector(state => state.main, shallowEqual) +export interface LicenseWarningFooterProps { + license?: License +} +export default function LicenseWarningFooter({ + license +}: LicenseWarningFooterProps): JSX.Element { if (!license) { return <> } diff --git a/ui/src/views/main/index.tsx b/ui/src/views/main/index.tsx index 5e15806b..d00599a1 100644 --- a/ui/src/views/main/index.tsx +++ b/ui/src/views/main/index.tsx @@ -16,18 +16,22 @@ import { mainSlice as slice } from "../../redux/main" -import MainHeader from "./Header" -import MainContent from "./Content" -import LicenseWarning from "./LicenseWarningFooter" +import MainHeader, { HeaderProps } from "./Header" +import MainContent, { ContentProps } from "./Content" +import LicenseWarning, { LicenseWarningFooterProps } from "./LicenseWarningFooter" const { Header, Content, Footer } = Layout -// eslint-disable-next-line -export default function Main(props: React.PropsWithChildren<{}>) { +export default (props: React.PropsWithChildren): JSX.Element => { const { + authorized, + available, + expired, + user, deployments, reviews, } = useAppSelector(state => state.main, shallowEqual) + const dispatch = useAppDispatch() useEffect(() => { @@ -48,6 +52,38 @@ export default function Main(props: React.PropsWithChildren<{}>) { } }, [dispatch]) + const onClickRetry = () => { + dispatch(slice.actions.setAvailable(true)) + dispatch(slice.actions.setExpired(false)) + } + + return ( +
+ ) +} + +interface MainProps extends HeaderProps, ContentProps, LicenseWarningFooterProps {} + +function Main({ + authorized, + available, + expired, + user, + deployments, + reviews, + license, + children, + onClickRetry +}: React.PropsWithChildren) { return ( @@ -58,16 +94,27 @@ export default function Main(props: React.PropsWithChildren<{}>) { }
- +
- - {props.children} + + {children}
- +
Gitploy ©{moment().format("YYYY")} Created by Gitploy.IO From 43979074223ea29d63eb618289ae04041c9a184d Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Apr 2022 21:01:38 +0900 Subject: [PATCH 3/6] Separatet the state from the members --- ui/src/views/members/MemberList.tsx | 27 ++++++---------- ui/src/views/members/index.tsx | 50 ++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/ui/src/views/members/MemberList.tsx b/ui/src/views/members/MemberList.tsx index f833560a..ec3d8bbc 100644 --- a/ui/src/views/members/MemberList.tsx +++ b/ui/src/views/members/MemberList.tsx @@ -1,27 +1,18 @@ -import { shallowEqual } from "react-redux" import { List, Switch, Button, Avatar } from "antd" -import { useAppSelector, useAppDispatch } from "../../redux/hooks" -import { updateUser, deleteUser } from "../../redux/members" - import { User } from "../../models" -export default function MemberList(): JSX.Element { - const { users } = useAppSelector(state => state.members, shallowEqual) - const dispatch = useAppDispatch() - - const onChangeSwitch = (user: User, checked: boolean) => { - dispatch(updateUser({user, admin: checked})) - } - - const onClickDelete = (user: User) => { - dispatch(deleteUser(user)) - } +export interface MemberListProps { + users: User[] + onChangeSwitch(user: User, checked: boolean): void + onClickDelete(user: User): void +} +export default function MemberList(props: MemberListProps): JSX.Element { return ( ( {onChangeSwitch(user, checked)}} + onChange={(checked) => {props.onChangeSwitch(user, checked)}} />, diff --git a/ui/src/views/members/index.tsx b/ui/src/views/members/index.tsx index d3718304..059ca56e 100644 --- a/ui/src/views/members/index.tsx +++ b/ui/src/views/members/index.tsx @@ -4,15 +4,16 @@ import { Input } from "antd" import { Helmet } from "react-helmet" import { useAppSelector, useAppDispatch } from "../../redux/hooks" -import { membersSlice as slice, fetchUsers, perPage } from "../../redux/members" +import { membersSlice as slice, fetchUsers, perPage, updateUser, deleteUser } from "../../redux/members" +import { User } from "../../models" import Main from '../main' -import MemberList from "./MemberList" +import MemberList, { MemberListProps } from "./MemberList" import Pagination from "../../components/Pagination" const { Search } = Input -export default function Members(): JSX.Element { +export default (): JSX.Element => { const { users, page } = useAppSelector(state => state.members, shallowEqual) const dispatch = useAppDispatch() @@ -20,6 +21,14 @@ export default function Members(): JSX.Element { dispatch(fetchUsers()) }, [dispatch]) + const onChangeSwitch = (user: User, checked: boolean) => { + dispatch(updateUser({user, admin: checked})) + } + + const onClickDelete = (user: User) => { + dispatch(deleteUser(user)) + } + const onSearch = (value: string) => { dispatch(slice.actions.setQuery(value)) dispatch(fetchUsers()) @@ -35,6 +44,35 @@ export default function Members(): JSX.Element { dispatch(fetchUsers()) } + return ( + + ) +} + +interface MembersProps extends MemberListProps { + page: number + onClickPrev(): void + onClickNext(): void + onSearch(value: string): void +} + +function Members({ + users, + page, + onChangeSwitch, + onClickDelete, + onClickNext, + onClickPrev, + onSearch, +}: MembersProps): JSX.Element { return (
@@ -47,7 +85,11 @@ export default function Members(): JSX.Element {
- +
Date: Mon, 4 Apr 2022 21:17:39 +0900 Subject: [PATCH 4/6] Separate the state from the repoHome view --- ui/src/components/Pagination.tsx | 2 +- ui/src/views/repoHome/ActivityLogs.tsx | 13 +++--- ui/src/views/repoHome/index.tsx | 59 ++++++++++++++++++++------ 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/ui/src/components/Pagination.tsx b/ui/src/components/Pagination.tsx index 8fd39864..a3583ffa 100644 --- a/ui/src/components/Pagination.tsx +++ b/ui/src/components/Pagination.tsx @@ -1,6 +1,6 @@ import { Button } from 'antd' -interface PaginationProps { +export interface PaginationProps { disabledPrev: boolean disabledNext: boolean onClickPrev(): void diff --git a/ui/src/views/repoHome/ActivityLogs.tsx b/ui/src/views/repoHome/ActivityLogs.tsx index 4f1f4fb0..6b5754e5 100644 --- a/ui/src/views/repoHome/ActivityLogs.tsx +++ b/ui/src/views/repoHome/ActivityLogs.tsx @@ -1,22 +1,19 @@ -import { shallowEqual } from "react-redux"; import { Timeline, Typography } from 'antd' import { SyncOutlined } from '@ant-design/icons' import moment from "moment" -import { useAppSelector } from '../../redux/hooks' -import { DeploymentStatusEnum } from "../../models" - +import { Deployment, DeploymentStatusEnum } from "../../models" import DeploymentStatusBadge from "../../components/DeploymentStatusBadge" import UserAvatar from '../../components/UserAvatar' import DeploymentRefCode from '../../components/DeploymentRefCode' const { Text } = Typography -export default function ActivityLogs(): JSX.Element { - const { - deployments, - } = useAppSelector(state => state.repoHome, shallowEqual) +export interface ActivityLogsProps { + deployments: Deployment[] +} +export default function ActivityLogs({ deployments }: ActivityLogsProps): JSX.Element { return ( {deployments.map((d, idx) => { diff --git a/ui/src/views/repoHome/index.tsx b/ui/src/views/repoHome/index.tsx index 2ad9a8f7..355b72b3 100644 --- a/ui/src/views/repoHome/index.tsx +++ b/ui/src/views/repoHome/index.tsx @@ -7,25 +7,25 @@ import { useAppSelector, useAppDispatch } from '../../redux/hooks' import { repoHomeSlice as slice, fetchEnvs, fetchDeployments, perPage } from '../../redux/repoHome' import { subscribeEvents } from "../../apis" -import ActivityLogs from './ActivityLogs' +import ActivityLogs, { ActivityLogsProps } from './ActivityLogs' import Spin from '../../components/Spin' -import Pagination from '../../components/Pagination' +import Pagination, { PaginationProps } from '../../components/Pagination' const { Option } = Select -interface Params { - namespace: string - name: string -} +export default (): JSX.Element => { + const { namespace, name } = useParams<{ + namespace: string, + name: string + }>() -export default function RepoHome(): JSX.Element { - const { namespace, name } = useParams() const { loading, deployments, envs, - page + page, } = useAppSelector(state => state.repoHome, shallowEqual) + const dispatch = useAppDispatch() useEffect(() => { @@ -60,6 +60,39 @@ export default function RepoHome(): JSX.Element { dispatch(slice.actions.increasePage()) dispatch(fetchDeployments()) } + return ( + + ) +} + +interface RepoHomeProps extends ActivityLogsProps, PaginationProps{ + loading: boolean + envs: string[] + onChangeEnv(env: string): void +} + +export function RepoHome({ + // Deployments + loading, + deployments, + // Environment Selector + envs, + onChangeEnv, + // Pagination + disabledPrev, + disabledNext, + onClickNext, + onClickPrev, +}: RepoHomeProps): JSX.Element { return (
@@ -80,13 +113,15 @@ export default function RepoHome(): JSX.Element { {(loading)?
: - + }
From a54373e00ecd6f04838de41ee566651a62e67755 Mon Sep 17 00:00:00 2001 From: noah Date: Mon, 4 Apr 2022 21:32:42 +0900 Subject: [PATCH 5/6] Separate the state from the repoSettings view --- ui/src/views/members/index.tsx | 24 +++++---- ui/src/views/repoSettings/SettingsForm.tsx | 31 ++++++------ ui/src/views/repoSettings/index.tsx | 58 ++++++++++++++++++---- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/ui/src/views/members/index.tsx b/ui/src/views/members/index.tsx index 059ca56e..86292613 100644 --- a/ui/src/views/members/index.tsx +++ b/ui/src/views/members/index.tsx @@ -45,15 +45,17 @@ export default (): JSX.Element => { } return ( - +
+ +
) } @@ -74,7 +76,7 @@ function Members({ onSearch, }: MembersProps): JSX.Element { return ( -
+ <> Members @@ -99,6 +101,6 @@ function Members({ onClickNext={onClickNext} />
-
+ ) } \ No newline at end of file diff --git a/ui/src/views/repoSettings/SettingsForm.tsx b/ui/src/views/repoSettings/SettingsForm.tsx index 2b9aae29..3f5dbf1d 100644 --- a/ui/src/views/repoSettings/SettingsForm.tsx +++ b/ui/src/views/repoSettings/SettingsForm.tsx @@ -1,14 +1,20 @@ -import { shallowEqual } from "react-redux"; import { Form, Input, Button, Space, Typography } from "antd" -import { useAppSelector, useAppDispatch } from "../../redux/hooks" -import { save, deactivate, repoSettingsSlice as slice } from "../../redux/repoSettings" -import { RequestStatus } from "../../models" +import { Repo } from "../../models" -export default function RepoSettingForm(): JSX.Element { - const { repo, saving } = useAppSelector(state => state.repoSettings, shallowEqual) - const dispatch = useAppDispatch() +export interface SettingFormProps { + saving: boolean + repo?: Repo + onClickFinish(values: any): void + onClickDeactivate(): void +} +export default function SettingForm({ + saving, + repo, + onClickFinish, + onClickDeactivate, +}: SettingFormProps): JSX.Element { const layout = { labelCol: { span: 5}, wrapperCol: { span: 12 }, @@ -18,15 +24,6 @@ export default function RepoSettingForm(): JSX.Element { wrapperCol: { offset: 5, span: 12 }, }; - const onClickFinish = (values: any) => { - dispatch(slice.actions.setConfigPath(values.config)) - dispatch(save()) - } - - const onClickDeactivate = () => { - dispatch(deactivate()) - } - const initialValues = { "config": repo?.configPath } @@ -57,7 +54,7 @@ export default function RepoSettingForm(): JSX.Element {