From 61dad695fb40b7004719cdc4829183eab43c5293 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sun, 28 Feb 2021 21:52:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(projects):=20=E6=B7=BB=E5=8A=A0=E6=A3=80?= =?UTF-8?q?=E5=87=BA=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graphql.schema.json | 84 +++++++++++++++++++ package-lock.json | 10 +++ package.json | 2 + .../commit-actions/action-button.scss | 12 +++ .../commit-actions/action-button.scss.d.ts | 10 +++ .../commit-actions/action-button.tsx | 62 ++++++++++++++ .../commit-actions/commit-actions.scss | 3 + .../commit-actions/commit-actions.scss.d.ts | 10 +++ .../commit-actions/commit-actions.store.tsx | 30 +++++++ .../commit-actions/commit-actions.tsx | 69 +++++++++++++++ .../commit-logs/commit-log-list.scss | 5 ++ .../commit-logs/commit-log-list.tsx | 2 + src/components/commons/button/button.scss | 4 + src/components/commons/button/button.tsx | 24 ++++++ src/generated/graphql.tsx | 12 +++ 15 files changed, 339 insertions(+) create mode 100644 src/components/commit-actions/action-button.scss create mode 100644 src/components/commit-actions/action-button.scss.d.ts create mode 100644 src/components/commit-actions/action-button.tsx create mode 100644 src/components/commit-actions/commit-actions.scss create mode 100644 src/components/commit-actions/commit-actions.scss.d.ts create mode 100644 src/components/commit-actions/commit-actions.store.tsx create mode 100644 src/components/commit-actions/commit-actions.tsx create mode 100644 src/components/commons/button/button.scss create mode 100644 src/components/commons/button/button.tsx diff --git a/graphql.schema.json b/graphql.schema.json index 4b2691a..70611a2 100644 --- a/graphql.schema.json +++ b/graphql.schema.json @@ -887,6 +887,39 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "checkout", + "description": null, + "args": [ + { + "name": "checkoutInput", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "CheckoutInput", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -1060,6 +1093,57 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "INPUT_OBJECT", + "name": "CheckoutInput", + "description": null, + "fields": null, + "inputFields": [ + { + "name": "projectId", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "branch", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "commitNumber", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "__Schema", diff --git a/package-lock.json b/package-lock.json index 5cabe8b..13d72cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2949,6 +2949,11 @@ "@types/node": "*" } }, + "@types/classnames": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz", + "integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw==" + }, "@types/enzyme": { "version": "3.10.8", "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.8.tgz", @@ -5181,6 +5186,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", diff --git a/package.json b/package.json index 52d05bb..ce8d6e1 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,9 @@ "@fortawesome/free-solid-svg-icons": "^5.15.2", "@fortawesome/react-fontawesome": "^0.1.14", "@tailwindcss/postcss7-compat": "^2.0.3", + "@types/classnames": "^2.2.11", "autoprefixer": "^9.8.6", + "classnames": "^2.2.6", "formik": "^2.2.6", "graphql": "^15.5.0", "mobx": "^6.1.7", diff --git a/src/components/commit-actions/action-button.scss b/src/components/commit-actions/action-button.scss new file mode 100644 index 0000000..3591b24 --- /dev/null +++ b/src/components/commit-actions/action-button.scss @@ -0,0 +1,12 @@ +.btn { + @apply p-2 w-4 h-4 box-content inline-flex items-center justify-center; + @apply rounded-full; + @apply text-red-500; + @apply hover:bg-red-100; + &[disabled] { + @apply text-red-300; + } + &:global(.waiting) { + @apply text-red-500; + } +} diff --git a/src/components/commit-actions/action-button.scss.d.ts b/src/components/commit-actions/action-button.scss.d.ts new file mode 100644 index 0000000..242a2d0 --- /dev/null +++ b/src/components/commit-actions/action-button.scss.d.ts @@ -0,0 +1,10 @@ +// This file is automatically generated from your CSS. Any edits will be overwritten. +declare namespace ActionButtonScssNamespace { + export interface IActionButtonScss { + btn: string; + } +} + +declare const ActionButtonScssModule: ActionButtonScssNamespace.IActionButtonScss; + +export = ActionButtonScssModule; diff --git a/src/components/commit-actions/action-button.tsx b/src/components/commit-actions/action-button.tsx new file mode 100644 index 0000000..82d4ac7 --- /dev/null +++ b/src/components/commit-actions/action-button.tsx @@ -0,0 +1,62 @@ +import { RenderableProps } from 'preact'; +import { FC } from 'preact/compat'; +import { h } from 'preact'; +import styles from './action-button.scss'; +import { makeAutoObservable, makeObservable } from 'mobx'; +import { observer, useLocalObservable } from 'mobx-react'; +import classNames from 'classnames'; +import { useCommitActionsStore } from './commit-actions.store'; + +interface Props { + onClick?: () => Promise; + waiting?: boolean; + disabled?: boolean; +} + +class Store { + constructor(public waiting: boolean = false) { + makeAutoObservable(this); + } + setWaiting(val: boolean) { + this.waiting = val; + } +} + +export const ActionButton: FC = observer( + ({ onClick, waiting, children }: RenderableProps) => { + const commitActionsStore = useCommitActionsStore(); + const store = useLocalObservable(() => new Store(waiting)); + + const doAction = () => { + if (!onClick) { + return; + } + store.setWaiting(true); + commitActionsStore?.setCurrentWork?.('checkout'); + onClick().finally(() => { + store.setWaiting(false); + commitActionsStore?.clearCurrentWork?.('checkout'); + }); + }; + + return ( + + ); + } +); + +ActionButton.defaultProps = { + waiting: false, + disabled: false +}; diff --git a/src/components/commit-actions/commit-actions.scss b/src/components/commit-actions/commit-actions.scss new file mode 100644 index 0000000..e58e8db --- /dev/null +++ b/src/components/commit-actions/commit-actions.scss @@ -0,0 +1,3 @@ +.component { + @apply inline; +} diff --git a/src/components/commit-actions/commit-actions.scss.d.ts b/src/components/commit-actions/commit-actions.scss.d.ts new file mode 100644 index 0000000..88db04d --- /dev/null +++ b/src/components/commit-actions/commit-actions.scss.d.ts @@ -0,0 +1,10 @@ +// This file is automatically generated from your CSS. Any edits will be overwritten. +declare namespace CommitActionsScssNamespace { + export interface ICommitActionsScss { + component: string; + } +} + +declare const CommitActionsScssModule: CommitActionsScssNamespace.ICommitActionsScss; + +export = CommitActionsScssModule; diff --git a/src/components/commit-actions/commit-actions.store.tsx b/src/components/commit-actions/commit-actions.store.tsx new file mode 100644 index 0000000..9d26216 --- /dev/null +++ b/src/components/commit-actions/commit-actions.store.tsx @@ -0,0 +1,30 @@ +import { makeAutoObservable } from 'mobx'; +import { useContext } from 'preact/hooks'; +import { createContext } from 'preact'; + +type Work = string; + +export class CommitActionsStore { + clearCurrentWork(work: Work) { + if (work === this.currentWork) { + this.currentWork = undefined; + } + } + constructor() { + makeAutoObservable(this); + } + currentWork?: Work; + setCurrentWork(work: Work) { + this.currentWork = work; + } +} + +const commitActionsContext = createContext( + new CommitActionsStore() +); + +export const CommitActionsStoreProvider = commitActionsContext.Provider; + +export const useCommitActionsStore = () => { + return useContext(commitActionsContext); +}; diff --git a/src/components/commit-actions/commit-actions.tsx b/src/components/commit-actions/commit-actions.tsx new file mode 100644 index 0000000..9d91869 --- /dev/null +++ b/src/components/commit-actions/commit-actions.tsx @@ -0,0 +1,69 @@ +import { h } from 'preact'; +import styles from './commit-actions.scss'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { autorun, makeAutoObservable } from 'mobx'; +import { ActionButton } from './action-button'; +import { gql, useMutation } from '@apollo/client'; +import { CheckoutInput, Project } from '../../generated/graphql'; +import { + CommitActionsStoreProvider, + CommitActionsStore +} from './commit-actions.store'; +import { + faCloudDownloadAlt, + faDownload, + faGlobeAsia, + faVial +} from '@fortawesome/free-solid-svg-icons'; +import { useLocalObservable } from 'mobx-react'; + +const CHECKOUT = gql` + mutation Checkout($input: CheckoutInput!) { + checkout(checkoutInput: $input) + } +`; + +interface Props { + project: Project; + commitNumber: string; + branch?: string; +} + +class Store { + constructor() { + makeAutoObservable(this); + } + isTasksWorking = [false, false, false, false]; +} + +export const CommitActions = ({ project, commitNumber }: Props) => { + const [checkout] = useMutation(CHECKOUT); + + const onCheckoutBtnClick = async () => { + await checkout({ + variables: { + input: { projectId: project.id, commitNumber } as CheckoutInput + } + }); + }; + + const commitActionsStore = useLocalObservable(() => new CommitActionsStore()); + return ( +
+ + + + + + + + + + + + + + +
+ ); +}; diff --git a/src/components/commit-logs/commit-log-list.scss b/src/components/commit-logs/commit-log-list.scss index 5160ac4..dd87ffb 100644 --- a/src/components/commit-logs/commit-log-list.scss +++ b/src/components/commit-logs/commit-log-list.scss @@ -5,11 +5,16 @@ @apply bg-gray-100 overflow-auto max-h-full; } .item { + @apply grid grid-cols-2 grid-rows-2; @apply bg-white text-gray-700; @apply py-2 px-4 my-px; @apply hover:bg-gray-50; time { + @apply col-start-1; @apply text-sm text-gray-400; } + :global(.commit-actions) { + @apply col-start-2 row-start-1 row-span-2 justify-self-end self-center; + } } diff --git a/src/components/commit-logs/commit-log-list.tsx b/src/components/commit-logs/commit-log-list.tsx index c546c65..af71001 100644 --- a/src/components/commit-logs/commit-log-list.tsx +++ b/src/components/commit-logs/commit-log-list.tsx @@ -2,6 +2,7 @@ import { LogList, Project, ListLogsArgs } from '../../generated/graphql'; import { h } from 'preact'; import { gql, useQuery } from '@apollo/client'; import styles from './commit-log-list.scss'; +import { CommitActions } from '../commit-actions/commit-actions'; const LIST_LOGS = gql` query ListLogs($args: ListLogsArgs!) { @@ -36,6 +37,7 @@ export const CommitLogList = ({ project, branch }: Props) => {
  • {log.message}

    +
  • ); }); diff --git a/src/components/commons/button/button.scss b/src/components/commons/button/button.scss new file mode 100644 index 0000000..4e41159 --- /dev/null +++ b/src/components/commons/button/button.scss @@ -0,0 +1,4 @@ +.component { + @apply py-2 px-4; + @apply bg-transparent border-gray-400 border rounded-md; +} diff --git a/src/components/commons/button/button.tsx b/src/components/commons/button/button.tsx new file mode 100644 index 0000000..19366d4 --- /dev/null +++ b/src/components/commons/button/button.tsx @@ -0,0 +1,24 @@ +import { FC } from 'preact/compat'; +import { h } from 'preact'; + +interface Props { + loading?: boolean; + title?: string; +} + +export const Button: FC = ({ + loading, + title, + children +}: RenderableProps) => { + const disabled = loading; + return ( + + ); +}; + +Button.defaultProps = { + loading: false +}; diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index 5549ae5..79814cf 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -103,6 +103,7 @@ export type Mutation = { createProject: Project; modifyProject: Project; deleteProject: Scalars['Float']; + checkout: Scalars['Boolean']; }; @@ -121,6 +122,11 @@ export type MutationDeleteProjectArgs = { id: Scalars['String']; }; + +export type MutationCheckoutArgs = { + checkoutInput: CheckoutInput; +}; + export type CreateProjectInput = { name: Scalars['String']; comment: Scalars['String']; @@ -136,3 +142,9 @@ export type UpdateProjectInput = { webUrl?: Maybe; webHookSecret?: Maybe; }; + +export type CheckoutInput = { + projectId: Scalars['String']; + branch?: Maybe; + commitNumber?: Maybe; +};