feat: 提交日志列表添加所属任务列表

This commit is contained in:
Ivan Li 2021-04-04 10:38:51 +08:00
parent a896673035
commit df5a6963e1
6 changed files with 388 additions and 264 deletions

View File

@ -416,196 +416,6 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "OBJECT",
"name": "LogFields",
"description": null,
"fields": [
{
"name": "hash",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "date",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "message",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "refs",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "body",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "author_name",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "author_email",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"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": "OBJECT", "kind": "OBJECT",
"name": "PipelineTaskLogs", "name": "PipelineTaskLogs",
@ -897,6 +707,220 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "OBJECT",
"name": "LogFields",
"description": null,
"fields": [
{
"name": "hash",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "date",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "message",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "refs",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "body",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "author_name",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "author_email",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "tasks",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PipelineTask",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"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": "OBJECT", "kind": "OBJECT",
"name": "PipelineTaskLogMessage", "name": "PipelineTaskLogMessage",
@ -945,6 +969,22 @@
}, },
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
},
{
"name": "isError",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
} }
], ],
"inputFields": null, "inputFields": null,
@ -952,6 +992,16 @@
"enumValues": null, "enumValues": null,
"possibleTypes": 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": "INPUT_OBJECT", "kind": "INPUT_OBJECT",
"name": "WorkUnitInput", "name": "WorkUnitInput",
@ -2005,6 +2055,39 @@
}, },
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
},
{
"name": "pipelineTaskChanged",
"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": "OBJECT",
"name": "PipelineTask",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
} }
], ],
"inputFields": null, "inputFields": null,
@ -2012,16 +2095,6 @@
"enumValues": null, "enumValues": null,
"possibleTypes": 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", "kind": "OBJECT",
"name": "__Schema", "name": "__Schema",

View File

@ -5,16 +5,19 @@
@apply bg-gray-100 overflow-auto max-h-full; @apply bg-gray-100 overflow-auto max-h-full;
} }
.item { .item {
@apply grid grid-cols-2 grid-rows-2; header {
@apply bg-white text-gray-700; @apply relative;
@apply py-2 px-4 my-px; @apply bg-white text-gray-700;
@apply hover:bg-gray-50; @apply py-2 px-4 my-px;
@apply hover:bg-gray-50;
}
time { time {
@apply col-start-1; @apply col-start-1;
@apply text-sm text-gray-400; @apply text-sm text-gray-400;
} }
:global(.commit-actions) { :global(.commit-actions) {
@apply col-start-2 row-start-1 row-span-2 justify-self-end self-center; @apply absolute right-0 top-0 bottom-0;
@apply justify-self-end self-center;
} }
} }

View File

@ -1,14 +1,11 @@
import { import { LogList, Pipeline, LogFields } from '../../generated/graphql';
LogList,
Project,
ListLogsArgs,
Pipeline
} from '../../generated/graphql';
import { h } from 'preact'; import { h } from 'preact';
import { gql, useQuery, useSubscription } from '@apollo/client'; import { gql, useQuery, useSubscription } from '@apollo/client';
import styles from './commit-log-list.scss'; import styles from './commit-log-list.scss';
import { CommitActions } from '../commit-actions/commit-actions'; import { CommitActions } from '../commit-actions/commit-actions';
import { FIND_PIPELINE } from '../pipelines/pipeline-list.constants'; import { FIND_PIPELINE } from '../pipelines/pipeline-list.constants';
import { route } from 'preact-router';
import { PipelineTaskStatus } from '../pipeline-tasks/pipeline-task-status';
const LIST_LOGS = gql` const LIST_LOGS = gql`
subscription listLogsForPipeline($id: String!) { subscription listLogsForPipeline($id: String!) {
@ -18,6 +15,13 @@ const LIST_LOGS = gql`
author_email author_email
message message
hash hash
tasks {
id
status
startedAt
endedAt
units
}
} }
total total
} }
@ -41,17 +45,34 @@ export const CommitLogList = ({ pipelineId }: Props) => {
variables: { id: pipelineId } variables: { id: pipelineId }
}); });
const pipeline = queryResult.data?.pipeline; const pipeline = queryResult.data?.pipeline;
const list = data?.listLogs?.all?.map(log => { const Item = ({ log }: { log: LogFields }) => (
return ( <li className={styles.item}>
<li className={styles.item} key={log.hash}> <header>
<h4>{log.message}</h4> <h4>{log.message}</h4>
<time dateTime={log.date}>{log.date}</time> <time dateTime={log.date}>{log.date}</time>
{pipeline ? ( {pipeline ? (
<CommitActions pipeline={pipeline} commit={log.hash} /> <CommitActions pipeline={pipeline} commit={log.hash} />
) : null} ) : null}
</li> </header>
); <ol>
}); {log.tasks.map(task => (
<li
key={task.id}
onClick={() =>
route(
`/projects/${pipeline?.projectId}/pipelines/${pipeline?.id}/tasks/${task.id}`
)
}
>
<PipelineTaskStatus status={task.status} /> {task.startedAt}
</li>
))}
</ol>
</li>
);
const list = data?.listLogs?.all?.map(log => (
<Item log={log} key={log.hash} />
));
return ( return (
<section className={styles.component}> <section className={styles.component}>

View File

@ -1,14 +1,8 @@
import { h } from 'preact'; import { h } from 'preact';
import styles from './pipeline-tasks.scss'; import styles from './pipeline-tasks.scss';
import { gql, useQuery } from '@apollo/client'; import { gql, useQuery } from '@apollo/client';
import { PipelineTask, TaskStatuses } from '../../generated/graphql'; import { PipelineTask } from '../../generated/graphql';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { PipelineTaskStatus } from './pipeline-task-status';
import {
faCheckCircle,
faClock,
faExclamationCircle,
faRunning
} from '@fortawesome/free-solid-svg-icons';
const LIST_TASKS = gql` const LIST_TASKS = gql`
query ListTasks($pipelineId: String!) { query ListTasks($pipelineId: String!) {
@ -55,7 +49,7 @@ export const PipelineTaskList = ({ pipelineId }: Props) => {
const Item = ({ task }: { task: PipelineTask }) => { const Item = ({ task }: { task: PipelineTask }) => {
return ( return (
<li key={task.id} className={styles.item}> <li key={task.id} className={styles.item}>
<Status status={task.status} /> <PipelineTaskStatus status={task.status} />
<span>{task.id}</span> <span>{task.id}</span>
<span>{task.commit}</span> <span>{task.commit}</span>
<span>{task.startedAt}</span> <span>{task.startedAt}</span>
@ -68,23 +62,3 @@ const Item = ({ task }: { task: PipelineTask }) => {
</li> </li>
); );
}; };
const Status = ({ status }: { status: TaskStatuses }) => {
let icon;
switch (status) {
case TaskStatuses.Failed:
icon = faExclamationCircle;
break;
case TaskStatuses.Success:
icon = faCheckCircle;
break;
case TaskStatuses.Pending:
icon = faClock;
break;
case TaskStatuses.Working:
icon = faRunning;
break;
}
return <FontAwesomeIcon icon={icon} />;
};

View File

@ -0,0 +1,45 @@
import { h } from 'preact';
import { TaskStatuses } from '../../generated/graphql';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faCheckCircle,
faExclamationCircle,
faPauseCircle,
faSpinner
} from '@fortawesome/free-solid-svg-icons';
import classNames from 'classnames';
export const PipelineTaskStatus = ({ status }: { status: TaskStatuses }) => {
switch (status) {
case TaskStatuses.Working:
return (
<FontAwesomeIcon
icon={faSpinner}
className={classNames(['animate-spin', 'text-blue-500'])}
/>
);
case TaskStatuses.Failed:
return (
<FontAwesomeIcon
icon={faExclamationCircle}
className={classNames(['text-red-700'])}
/>
);
case TaskStatuses.Success:
return (
<FontAwesomeIcon
icon={faCheckCircle}
className={classNames(['text-green-500'])}
/>
);
case TaskStatuses.Pending:
return (
<FontAwesomeIcon
icon={faPauseCircle}
className={classNames(['text-yellow-500'])}
/>
);
default:
return null;
}
};

View File

@ -60,24 +60,6 @@ export type Pipeline = {
workUnitMetadata: WorkUnitMetadata; workUnitMetadata: WorkUnitMetadata;
}; };
export type LogFields = {
__typename?: 'LogFields';
hash: Scalars['String'];
date: Scalars['String'];
message: Scalars['String'];
refs: Scalars['String'];
body: Scalars['String'];
author_name: Scalars['String'];
author_email: Scalars['String'];
};
export type LogList = {
__typename?: 'LogList';
all: Array<LogFields>;
total: Scalars['Float'];
latest: LogFields;
};
export type PipelineTaskLogs = { export type PipelineTaskLogs = {
__typename?: 'PipelineTaskLogs'; __typename?: 'PipelineTaskLogs';
unit: PipelineUnits; unit: PipelineUnits;
@ -109,11 +91,31 @@ export type PipelineTask = {
endedAt?: Maybe<Scalars['DateTime']>; endedAt?: Maybe<Scalars['DateTime']>;
}; };
export type LogFields = {
__typename?: 'LogFields';
hash: Scalars['String'];
date: Scalars['String'];
message: Scalars['String'];
refs: Scalars['String'];
body: Scalars['String'];
author_name: Scalars['String'];
author_email: Scalars['String'];
tasks: Array<PipelineTask>;
};
export type LogList = {
__typename?: 'LogList';
all: Array<LogFields>;
total: Scalars['Float'];
latest: LogFields;
};
export type PipelineTaskLogMessage = { export type PipelineTaskLogMessage = {
__typename?: 'PipelineTaskLogMessage'; __typename?: 'PipelineTaskLogMessage';
unit?: Maybe<PipelineUnits>; unit?: Maybe<PipelineUnits>;
time: Scalars['DateTime']; time: Scalars['DateTime'];
message: Scalars['String']; message: Scalars['String'];
isError: Scalars['Boolean'];
}; };
export type WorkUnitInput = { export type WorkUnitInput = {
@ -250,6 +252,7 @@ export type Subscription = {
__typename?: 'Subscription'; __typename?: 'Subscription';
listLogsForPipeline: LogList; listLogsForPipeline: LogList;
pipelineTaskLog: PipelineTaskLogMessage; pipelineTaskLog: PipelineTaskLogMessage;
pipelineTaskChanged: PipelineTask;
}; };
@ -261,3 +264,8 @@ export type SubscriptionListLogsForPipelineArgs = {
export type SubscriptionPipelineTaskLogArgs = { export type SubscriptionPipelineTaskLogArgs = {
taskId: Scalars['String']; taskId: Scalars['String'];
}; };
export type SubscriptionPipelineTaskChangedArgs = {
id: Scalars['String'];
};