diff --git a/.vscode/settings.json b/.vscode/settings.json index bbf7d45..5a0ffc9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,8 @@ "css.validate": false, "scss.validate": false, "cSpell.words": [ - "Formik" + "Formik", + "autorun", + "wouter" ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index dec5ee3..a5e3eb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15492,11 +15492,6 @@ "pretty-format": "^3.8.0" } }, - "preact-router": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/preact-router/-/preact-router-3.2.1.tgz", - "integrity": "sha512-KEN2VN1DxUlTwzW5IFkF13YIA2OdQ2OvgJTkQREF+AA2NrHRLaGbB68EjS4IeZOa1shvQ1FvEm3bSLta4sXBhg==" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -21144,6 +21139,11 @@ "microevent.ts": "~0.1.1" } }, + "wouter-preact": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/wouter-preact/-/wouter-preact-2.7.4.tgz", + "integrity": "sha512-lYYO3JozPcHB9VP3FrjliADVD04p0TDFRP28wVFWfIGN8l8RxCTWXQxvm9uQ0vFU7CBUA2nOFeCveBPXdZiGLQ==" + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index ef1718a..e12e2bf 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,10 @@ "preact-jsx-chai": "^3.0.0", "preact-markup": "^2.1.1", "preact-render-to-string": "^5.1.18", - "preact-router": "^3.2.1", "ramda": "^0.27.1", "subscriptions-transport-ws": "^0.9.18", - "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.3" + "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.3", + "wouter-preact": "^2.7.4" }, "devDependencies": { "@graphql-codegen/cli": "^1.21.3", diff --git a/src/components/app.tsx b/src/components/app.tsx index cc37bd0..3124882 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -4,7 +4,7 @@ import { ProjectPanel } from './projects/project-panel'; import styles from './app.scss'; import { OverlayContainer } from './commons/overlay/overlay'; import { useObserver } from 'mobx-react'; -import Router, { Route } from 'preact-router'; +import { Router, Route } from 'wouter-preact'; import { createApolloClient } from '../units/apollo-client'; import { ProjectDetails } from './pipeline-tasks/project-details'; import { PipelineEditor } from './pipelines/pipeline-editor'; @@ -25,13 +25,16 @@ const App: FunctionalComponent = () => { const Content = () => { return ; }; + const Board = () => { return useObserver(() => { return (
- + + {params => } + } diff --git a/src/components/commit-actions/commit-actions.tsx b/src/components/commit-actions/commit-actions.tsx index e74a922..8326295 100644 --- a/src/components/commit-actions/commit-actions.tsx +++ b/src/components/commit-actions/commit-actions.tsx @@ -21,7 +21,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { useLocalObservable } from 'mobx-react'; import { PipelineTask, PipelineUnits } from '../../generated/graphql'; -import { route } from 'preact-router'; +import { useLocation } from 'wouter-preact'; const CREATE_PIPELINE_TASK = gql` mutation CreatePipelineTask($task: CreatePipelineTaskInput!) { @@ -42,18 +42,12 @@ interface Props { branch?: string; } -class Store { - constructor() { - makeAutoObservable(this); - } - isTasksWorking = [false, false, false, false]; -} - export const CommitActions = ({ pipeline, commit }: Props) => { const [createTask] = useMutation< { task: PipelineTask }, { task: CreatePipelineTaskInput } >(CREATE_PIPELINE_TASK); + const setLocation = useLocation()[1]; const doWork = async (units: PipelineUnits[]) => { const { data } = await createTask({ @@ -61,9 +55,7 @@ export const CommitActions = ({ pipeline, commit }: Props) => { task: { pipelineId: pipeline.id, commit, units } } }); - route( - `/projects/${pipeline.projectId}/pipelines/${pipeline.id}/tasks/${data?.task.id}` - ); + setLocation(`/tasks/${data?.task.id}`); }; const commitActionsStore = useLocalObservable(() => new CommitActionsStore()); diff --git a/src/components/commit-logs/commit-log-list.tsx b/src/components/commit-logs/commit-log-list.tsx index 1c0c5d5..145258b 100644 --- a/src/components/commit-logs/commit-log-list.tsx +++ b/src/components/commit-logs/commit-log-list.tsx @@ -4,8 +4,8 @@ import { gql, useQuery, useSubscription } from '@apollo/client'; import styles from './commit-log-list.scss'; import { CommitActions } from '../commit-actions/commit-actions'; import { FIND_PIPELINE } from '../pipelines/pipeline-list.constants'; -import { route } from 'preact-router'; import { PipelineTaskStatus } from '../pipeline-tasks/pipeline-task-status'; +import { useLocation } from 'wouter-preact'; const LIST_LOGS = gql` subscription listLogsForPipeline($id: String!) { @@ -41,6 +41,7 @@ export const CommitLogList = ({ pipelineId }: Props) => { id: pipelineId! } }); + const setLocation = useLocation()[1]; const queryResult = useQuery<{ pipeline: Pipeline }>(FIND_PIPELINE, { variables: { id: pipelineId } }); @@ -56,14 +57,7 @@ export const CommitLogList = ({ pipelineId }: Props) => {
    {log.tasks.map(task => ( -
  1. - route( - `/projects/${pipeline?.projectId}/pipelines/${pipeline?.id}/tasks/${task.id}` - ) - } - > +
  2. setLocation(`/tasks/${task.id}`)}> {task.startedAt}
  3. ))} diff --git a/src/components/pipeline-tasks/project-details.tsx b/src/components/pipeline-tasks/project-details.tsx index dd8b129..28899d8 100644 --- a/src/components/pipeline-tasks/project-details.tsx +++ b/src/components/pipeline-tasks/project-details.tsx @@ -6,12 +6,9 @@ import styles from './project-details.scss'; import { createOverlay } from '../../components/commons/overlay/overlay'; import { ProjectEditor } from '../../components/projects/project-editor'; import { CommitLogList } from '../../components/commit-logs/commit-log-list'; -import { makeAutoObservable } from 'mobx'; -import { Observer, useLocalObservable } from 'mobx-react'; -import Router, { RoutableProps, Route } from 'preact-router'; +import { Router, Route } from 'wouter-preact'; import { gql, useQuery } from '@apollo/client'; import { PipelineList } from '../../components/pipelines/pipeline-list'; -import { PipelineTaskList } from '../../components/pipeline-tasks/pipeline-task-list'; import { PipelineTaskDetails } from '../../components/pipeline-tasks/pipeline-task-details'; const FIND_PROJECT = gql` @@ -27,21 +24,11 @@ const FIND_PROJECT = gql` } `; -interface Props extends RoutableProps { - id: string; +interface Props { + projectId: string; } -class Store { - setBranch(branch?: string) { - this.branch = branch; - } - constructor() { - makeAutoObservable(this); - } - branch?: string; -} - -export const ProjectDetails = ({ id, path }: Props) => { +export const ProjectDetails = ({ projectId: id }: Props) => { const { data } = useQuery<{ project: Project }, { id: string }>( FIND_PROJECT, { @@ -53,54 +40,43 @@ export const ProjectDetails = ({ id, path }: Props) => { const project: Project | undefined = data?.project; - const store = useLocalObservable(() => new Store()); const editProject = () => { createOverlay({ content: }); }; - const onSelectBranch = (branch?: string) => { - store.setBranch(branch); - }; - return ( -
    -
    -

    - {project?.name} - {project?.webUrl ? ( - - - - ) : null} -

    - {project?.comment} -
    - -
    -
    - {project ? ( -
    - - - {(): any => ( - - - - - )} - -
    - ) : null} -
    + +
    +
    +

    + {project?.name} + {project?.webUrl ? ( + + + + ) : null} +

    + {project?.comment} +
    + +
    +
    + {project ? ( +
    + + + {({ taskId }) => } + + + {({ pipelineId }) => } + +
    + ) : null} +
    +
    ); }; diff --git a/src/components/pipelines/pipeline-editor.tsx b/src/components/pipelines/pipeline-editor.tsx index 01a6f89..5ce9add 100644 --- a/src/components/pipelines/pipeline-editor.tsx +++ b/src/components/pipelines/pipeline-editor.tsx @@ -1,6 +1,5 @@ import { Field, Form, Formik } from 'formik'; import { h } from 'preact'; -import { RoutableProps } from 'preact-router'; import styles from './pipeline-editor.scss'; import { useOverlay } from '../../components/commons/overlay/overlay'; import { gql, useLazyQuery, useMutation } from '@apollo/client'; @@ -75,7 +74,7 @@ const MODIFY_PIPELINE = gql` } `; -interface Props extends RoutableProps { +interface Props { projectId: string; id?: string; } diff --git a/src/components/pipelines/pipeline-list.tsx b/src/components/pipelines/pipeline-list.tsx index f155c83..98b6b31 100644 --- a/src/components/pipelines/pipeline-list.tsx +++ b/src/components/pipelines/pipeline-list.tsx @@ -1,7 +1,7 @@ import { gql, useQuery, useMutation } from '@apollo/client'; -import { makeAutoObservable, reaction } from 'mobx'; +import { makeAutoObservable } from 'mobx'; import { useLocalObservable } from 'mobx-react-lite'; -import { useMemo } from 'preact/hooks'; +import { useMemo, useState } from 'preact/hooks'; import { h } from 'preact'; import { Pipeline } from '../../generated/graphql'; import styles from './pipeline-list.scss'; @@ -18,7 +18,7 @@ import { createOverlay } from '../commons/overlay/overlay'; import { PipelineEditor } from './pipeline-editor'; import { LIST_PIPELINES } from './pipeline-list.constants'; import { Observer, observer } from 'mobx-react'; -import { route } from 'preact-router'; +import { useLocation, useRoute } from 'wouter-preact'; const DELETE_PIPELINE = gql` mutation DeletePipeline($id: String!) { @@ -32,29 +32,25 @@ interface Props { class Store { pipelines?: Pipeline[]; - currPipelineId?: string; editMode = false; constructor() { makeAutoObservable(this); } refetching = false; - setPipelines(pipelines: any[] | undefined) { + setPipelines(pipelines: Pipeline[] | undefined) { this.pipelines = pipelines; } setRefetching(val: boolean) { this.refetching = val; } - setCurrPipelineId(id: string) { - this.currPipelineId = id; - } toggleEditMode() { this.editMode = !this.editMode; } } export const PipelineList = ({ projectId }: Props) => { - const { data, refetch, loading } = useQuery<{ pipelines: Pipeline[] }>( + const { data, refetch } = useQuery<{ pipelines: Pipeline[] }>( LIST_PIPELINES, { variables: { @@ -67,15 +63,26 @@ export const PipelineList = ({ projectId }: Props) => { const store = useLocalObservable(() => new Store()); - useMemo(() => store.setPipelines(pipelines), [store, pipelines]); - - reaction( - () => store.currPipelineId, - () => { - route(`/projects/${projectId}/pipelines/${store.currPipelineId}`); - } + const [currentPipeline, setCurrentPipeline] = useState( + undefined ); + useMemo(() => store.setPipelines(pipelines), [store, pipelines]); + const params = useRoute('/pipelines/:pipelineId')[1]; + + useMemo(() => { + let pipeline = pipelines?.find( + pipeline => pipeline.id === params?.pipelineId + ); + if (!pipeline) { + pipeline = pipelines?.[0]; + } + if (pipeline === currentPipeline) { + return; + } + setCurrentPipeline(pipeline); + }, [params, pipelines]); + const Header = observer(() => { const addPipeline = () => { createOverlay({ @@ -110,7 +117,13 @@ export const PipelineList = ({ projectId }: Props) => { }); const items = pipelines?.map(pipeline => ( - {(): any => } + {(): any => ( + + )} )); @@ -123,7 +136,16 @@ export const PipelineList = ({ projectId }: Props) => { }; const Item = observer( - ({ pipeline, store }: { pipeline: Pipeline; store: Store }) => { + ({ + pipeline, + store, + currentPipeline + }: { + pipeline: Pipeline; + store: Store; + currentPipeline?: Pipeline; + }) => { + const setLocation = useLocation()[1]; const [remove] = useMutation(DELETE_PIPELINE, { variables: { id: pipeline.id }, update(cache) { @@ -152,7 +174,7 @@ const Item = observer( } }); - const isActive = store.currPipelineId === pipeline.id; + const isActive = currentPipeline?.id === pipeline.id; const openModifyPanel = () => { createOverlay({ content: ( @@ -184,7 +206,7 @@ const Item = observer( }, styles.item )} - onClick={() => store.setCurrPipelineId(pipeline.id)} + onClick={() => setLocation(`/pipelines/${pipeline.id}`)} >

    {pipeline.name}

    diff --git a/src/components/projects/project-panel.tsx b/src/components/projects/project-panel.tsx index abba436..9c07b27 100644 --- a/src/components/projects/project-panel.tsx +++ b/src/components/projects/project-panel.tsx @@ -1,18 +1,8 @@ import { gql, useQuery } from '@apollo/client'; -import { - action, - autorun, - computed, - makeObservable, - observable, - reaction -} from 'mobx'; -import { useLocalObservable, useObserver } from 'mobx-react'; import { h } from 'preact'; -import { route } from 'preact-router'; -import { forwardRef } from 'preact/compat'; +import { forwardRef, useState } from 'preact/compat'; import { useImperativeHandle, useMemo, useRef } from 'preact/hooks'; -import { appStore } from '../../app.store'; +import { useLocation, useRoute } from 'wouter-preact'; import { Project } from '../../generated/graphql'; import { createOverlay } from '../commons/overlay/overlay'; import { ProjectEditor } from './project-editor'; @@ -33,45 +23,6 @@ const FIND_PROJECTS = gql` interface ListRef { refetch: () => void; } - -class Store { - @observable currentProjectId?: string; - @observable projects?: Project[]; - constructor() { - makeObservable(this); - } - @computed - get currentProject() { - return this.projects?.find(it => it.id === this.currentProjectId); - } - - @computed - get list() { - return this.projects?.map(item => ( -
  4. this.setCurrentProjectId(item.id)} - > -

    {item.name}

    - {item.comment} -
  5. - )); - } - - @action - setCurrentProjectId = (id: string) => { - this.currentProjectId = id; - route(`/projects/${id}`); - }; - - @action - setProjects = (projects?: Project[]) => { - this.projects = projects; - }; -} export function ProjectPanel() { const listRef = useRef(); const addProject = () => { @@ -104,14 +55,36 @@ const List = forwardRef((_, ref) => { projects: Project[]; }>(FIND_PROJECTS); const projects = data?.projects; - - const store = useLocalObservable(() => new Store()); + const setLocation = useLocation()[1]; + const params = useRoute('/projects/:projectId/:rest*')[1]; + const [currentProject, setCurrentProject] = useState( + undefined + ); useMemo(() => { - store.setProjects(projects); - }, [projects, store]); + let project = projects?.find(project => params?.projectId === project.id); + if (!project) { + project = projects?.[0]; + } + if (project === currentProject) { + return; + } + setCurrentProject(project); + }, [params, projects]); + const items = projects?.map(item => ( +
  6. setLocation(`/projects/${item.id}`)} + > +

    {item.name}

    + {item.comment} +
  7. + )); useImperativeHandle(ref, () => ({ refetch })); - return useObserver(() =>
      {store.list}
    ); + return
      {items}
    ; }); diff --git a/tsconfig.json b/tsconfig.json index 7a35e6f..a458346 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ /* Basic Options */ "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */, "module": "ESNext" /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, - // "lib": [], /* Specify library files to be included in the compilation: */ + "lib": ["ESNext"], /* Specify library files to be included in the compilation: */ "allowJs": true /* Allow javascript files to be compiled. */, // "checkJs": true, /* Report errors in .js files. */ "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,