diff --git a/src/commits/commit-list.tsx b/src/commits/commit-list.tsx index 38dce3f..543742e 100644 --- a/src/commits/commit-list.tsx +++ b/src/commits/commit-list.tsx @@ -1,5 +1,5 @@ -import { useMutation, useQuery } from "@apollo/client"; -import { Link, useResponse, useRouter } from '@curi/react-dom'; +import { useMutation, useQuery, useSubscription } from "@apollo/client"; +import { Link, useResponse, useRouter } from "@curi/react-dom"; import { faPlayCircle, faVial } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { @@ -23,19 +23,27 @@ import { Timer, } from "@material-ui/icons"; import { format } from "date-fns"; -import { equals, find, propEq, takeWhile } from "ramda"; -import React, { FC, Fragment, ReactNode, useMemo, useState } from "react"; +import { useSnackbar } from "notistack"; +import { complement, equals, find, propEq, takeWhile } from "ramda"; +import { + FC, + Fragment, + ReactNode, + useCallback, + useMemo, + useState, +} from "react"; import { Commit, CreatePipelineTaskInput, Pipeline, PipelineTask, TaskStatuses, - WorkUnit, PipelineUnits, } from "../generated/graphql"; -import { CREATE_PIPELINE_TASK } from "./muations"; +import { CREATE_PIPELINE_TASK } from "./mutations"; import { COMMITS } from "./queries"; +import { SYNC_COMMITS } from "./subscriptions"; interface Props { pipeline: Pipeline; @@ -51,12 +59,35 @@ const useStyles = makeStyles((theme) => ({ })); export const CommitList: FC = ({ pipeline }) => { - const { data, loading } = useQuery<{ commits: Commit[] }>(COMMITS, { + const { enqueueSnackbar } = useSnackbar(); + + const { data, loading, refetch } = useQuery<{ commits?: Commit[] }>(COMMITS, { variables: { pipelineId: pipeline.id, }, }); + const { loading: syncing } = useSubscription<{ syncCommits: boolean }>( + SYNC_COMMITS, + { + variables: { + pipelineId: pipeline.id, + }, + onSubscriptionData({ subscriptionData: { data, error } }) { + if (error) { + enqueueSnackbar(error.message, { + variant: "warning", + }); + } + if (data?.syncCommits) { + refetch({ + appInstance: data.syncCommits, + }); + } + }, + } + ); + const classes = useStyles(); return ( @@ -67,11 +98,14 @@ export const CommitList: FC = ({ pipeline }) => { } return ( - - {data?.commits.map((commit) => ( - - ))} - +
+ {syncing && } + + {data?.commits?.map((commit) => ( + + ))} + +
); })()} @@ -96,38 +130,42 @@ const Item: FC<{ commit: Commit; pipeline: Pipeline }> = ({ const [isOpen, setOpen] = useState(() => false); const classes = useStyles(); - const [createTask, { loading }] = useMutation< - { createPipelineTask: PipelineTask }, - { task: CreatePipelineTaskInput } - >(CREATE_PIPELINE_TASK); + const [createTask, { loading }] = + useMutation< + { createPipelineTask: PipelineTask }, + { task: CreatePipelineTaskInput } + >(CREATE_PIPELINE_TASK); const units = useMemo( () => pipeline.workUnitMetadata.units.map((unit) => unit.type), [pipeline] ); - const {navigate, url} = useRouter(); + const { navigate, url } = useRouter(); const { response } = useResponse(); - const handleCreateTask = (unit: PipelineUnits) => { - const _units = [...takeWhile(equals(unit), units), unit]; - createTask({ - variables: { - task: { - units: _units, - pipelineId: pipeline.id, - commit: commit.hash, + const handleCreateTask = useCallback( + (unit: PipelineUnits) => { + const _units = [...takeWhile(complement(equals(unit)), units), unit]; + createTask({ + variables: { + task: { + units: _units, + pipelineId: pipeline.id, + commit: commit.hash, + }, }, - }, - }).then(({data}) => { - navigate({ - url: url({ - name: "pipeline-task-detail", - params: { ...response.params, taskId: data?.createPipelineTask.id}, - }), + }).then(({ data }) => { + navigate({ + url: url({ + name: "pipeline-task-detail", + params: { ...response.params, taskId: data?.createPipelineTask.id }, + }), + }); }); - }); - }; + }, + [commit, createTask, navigate, pipeline, response, units, url] + ); const actions = useMemo( () => @@ -136,6 +174,7 @@ const Item: FC<{ commit: Commit; pipeline: Pipeline }> = ({ return ( pair && ( handleCreateTask(unit)} @@ -145,14 +184,14 @@ const Item: FC<{ commit: Commit; pipeline: Pipeline }> = ({ ) ); }), - [units] + [units, handleCreateTask, loading] ); return ( setOpen(!isOpen)}> {actions} @@ -194,7 +233,11 @@ const TaskItem: FC<{ task: PipelineTask }> = ({ task }) => { return ( {statusIcon} - + ); }; diff --git a/src/commits/muations.ts b/src/commits/mutations.ts similarity index 100% rename from src/commits/muations.ts rename to src/commits/mutations.ts diff --git a/src/commits/subscriptions.ts b/src/commits/subscriptions.ts new file mode 100644 index 0000000..087e1c8 --- /dev/null +++ b/src/commits/subscriptions.ts @@ -0,0 +1,28 @@ +import { gql } from "@apollo/client"; + +export const SUBSCRIPTION_COMMITS = gql` + subscription SubscriptionCommits($pipelineId: String!) { + results: listLogsForPipeline(id: $pipelineId) { + all { + hash + date + message + body + author_name + author_email + tasks { + id + units + status + startedAt + endedAt + } + } + } + } +`; +export const SYNC_COMMITS = gql` + subscription SyncCommits($pipelineId: String!) { + syncCommits(pipelineId: $pipelineId) + } +`; diff --git a/src/generated/graphql.schema.json b/src/generated/graphql.schema.json index 294a73f..00cd183 100644 --- a/src/generated/graphql.schema.json +++ b/src/generated/graphql.schema.json @@ -576,83 +576,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "LogList", - "description": null, - "fields": [ - { - "name": "all", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "LogFields", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "total", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "latest", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "LogFields", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "Mutation", @@ -888,6 +811,39 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "stopPipelineTask", + "description": null, + "args": [ + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "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, @@ -895,6 +851,26 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Float", + "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "Boolean", + "description": "The `Boolean` scalar type represents `true` or `false`.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "Pipeline", @@ -1246,16 +1222,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "PipelineTaskLogs", @@ -1649,19 +1615,15 @@ } ], "type": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Commit", - "ofType": null - } + "kind": "OBJECT", + "name": "Commit", + "ofType": null } } }, @@ -1754,11 +1716,23 @@ "description": null, "fields": [ { - "name": "listLogsForPipeline", + "name": "syncCommits", "description": null, "args": [ { - "name": "id", + "name": "appInstance", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pipelineId", "description": null, "type": { "kind": "NON_NULL", @@ -1775,13 +1749,9 @@ } ], "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "LogList", - "ofType": null - } + "kind": "SCALAR", + "name": "String", + "ofType": null }, "isDeprecated": false, "deprecationReason": null diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index a812624..ff60187 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -65,13 +65,6 @@ export type LogFields = { tasks: Array; }; -export type LogList = { - __typename?: 'LogList'; - all: Array; - total: Scalars['Float']; - latest: LogFields; -}; - export type Mutation = { __typename?: 'Mutation'; createProject: Project; @@ -81,6 +74,7 @@ export type Mutation = { updatePipeline: Pipeline; deletePipeline: Scalars['Float']; createPipelineTask: PipelineTask; + stopPipelineTask: Scalars['Boolean']; }; @@ -118,6 +112,11 @@ export type MutationCreatePipelineTaskArgs = { task: CreatePipelineTaskInput; }; + +export type MutationStopPipelineTaskArgs = { + id: Scalars['String']; +}; + export type Pipeline = { __typename?: 'Pipeline'; id: Scalars['ID']; @@ -184,7 +183,7 @@ export type Query = { project: Project; pipelines: Array; pipeline: Pipeline; - commits: Array; + commits?: Maybe>; listPipelineTaskByPipelineId: Array; pipelineTask: PipelineTask; }; @@ -221,14 +220,15 @@ export type QueryPipelineTaskArgs = { export type Subscription = { __typename?: 'Subscription'; - listLogsForPipeline: LogList; + syncCommits?: Maybe; pipelineTaskLog: PipelineTaskLogMessage; pipelineTaskChanged: PipelineTask; }; -export type SubscriptionListLogsForPipelineArgs = { - id: Scalars['String']; +export type SubscriptionSyncCommitsArgs = { + appInstance?: Maybe; + pipelineId: Scalars['String']; };