Просмотр исходного кода

Add support for new execution / tasks API statuses

Includes support the full list of statuses like: 'CANCELLING',
'DEADLOCKED', 'SCHEDULED' etc.
Sergiu Miclea 6 лет назад
Родитель
Сommit
2e1c1c379f

+ 56 - 28
src/components/atoms/StatusIcon/StatusIcon.jsx

@@ -25,7 +25,7 @@ import errorImage from './images/error.svg'
 import progressWithBackgroundImage from './images/progress-background.svg'
 import progressWithBackgroundImage from './images/progress-background.svg'
 import progressImage from './images/progress.js'
 import progressImage from './images/progress.js'
 import successImage from './images/success.svg'
 import successImage from './images/success.svg'
-import warningImage from './images/warning.svg'
+import warningImage from './images/warning.js'
 import pendingImage from './images/pending.svg'
 import pendingImage from './images/pending.svg'
 import successHollowImage from './images/success-hollow.svg'
 import successHollowImage from './images/success-hollow.svg'
 import errorHollowImage from './images/error-hollow.svg'
 import errorHollowImage from './images/error-hollow.svg'
@@ -37,37 +37,68 @@ type Props = {
   secondary?: boolean,
   secondary?: boolean,
 }
 }
 
 
-const getRunningImageUrl = (props: Props) => {
-  const smallCircleColor = props.secondary ? Palette.grayscale[0] : Palette.primary
+const getSpinnerUrl = (smallCircleColor: string) => {
+  return css`url('data:image/svg+xml;utf8,${encodeURIComponent(progressImage(Palette.grayscale[3], smallCircleColor))}')`
+}
 
 
+const getRunningImageUrl = (props: Props) => {
   if (props.useBackground) {
   if (props.useBackground) {
     return css`url('${progressWithBackgroundImage}')`
     return css`url('${progressWithBackgroundImage}')`
   }
   }
 
 
-  return css`url('data:image/svg+xml;utf8,${encodeURIComponent(progressImage(Palette.grayscale[3], smallCircleColor))}')`
+  const smallCircleColor = props.secondary ? Palette.grayscale[0] : Palette.primary
+  return getSpinnerUrl(smallCircleColor)
+}
+
+const getWarningUrl = (background: string) => {
+  return css`url('data:image/svg+xml;utf8,${encodeURIComponent(warningImage(background))}')`
 }
 }
 
 
-const statuses = props => {
-  return {
-    COMPLETED: css`
+const statuses = (status, props) => {
+  switch (status) {
+    case 'COMPLETED':
+      return css`
       background-image: url('${props.hollow ? successHollowImage : successImage}');
       background-image: url('${props.hollow ? successHollowImage : successImage}');
-    `,
-    RUNNING: css`
-      background-image: ${getRunningImageUrl(props)};
-      ${StyleProps.animations.rotation}
-    `,
-    ERROR: css`
-      background-image: url('${props.hollow ? errorHollowImage : errorImage}');
-    `,
-    WARNING: css`
-      background-image: url('${warningImage}');
-    `,
-    CANCELED: css`
-      background-image: url('${warningImage}');
-    `,
-    PENDING: css`
-      background-image: url('${pendingImage}');
-    `,
+    `
+    case 'RUNNING':
+    case 'PENDING':
+      return css`
+        background-image: ${getRunningImageUrl(props)};
+        ${StyleProps.animations.rotation}
+      `
+    case 'CANCELLING':
+    case 'CANCELLING_AFTER_COMPLETION':
+      return css`
+        background-image: ${getSpinnerUrl(Palette.warning)};
+        ${StyleProps.animations.rotation}
+      `
+    case 'SCHEDULED':
+      return css`
+        background-image: url('${pendingImage}');
+      `
+    case 'ERROR':
+      return css`
+        background-image: url('${props.hollow ? errorHollowImage : errorImage}');
+      `
+    case 'WARNING':
+    case 'CANCELED':
+    case 'CANCELED_AFTER_COMPLETION':
+    case 'CANCELED_FOR_DEBUGGING':
+    case 'FORCE_CANCELED':
+      return css`
+        background-image: ${getWarningUrl(Palette.warning)};
+      `
+    case 'DEADLOCKED':
+    case 'STRANDED_AFTER_DEADLOCK':
+      return css`
+        background-image: ${getWarningUrl('#424242')};
+      `
+    case 'UNSCHEDULED':
+      return css`
+        background-image: ${getWarningUrl(Palette.grayscale[2])};
+      `
+    default:
+      return null
   }
   }
 }
 }
 
 
@@ -77,16 +108,13 @@ const Wrapper = styled.div`
   height: 16px;
   height: 16px;
   background-repeat: no-repeat;
   background-repeat: no-repeat;
   background-position: center;
   background-position: center;
-  ${props => statuses(props)[props.status]}
+  ${props => statuses(props.status, props)}
 `
 `
 
 
 @observer
 @observer
 class StatusIcon extends React.Component<Props> {
 class StatusIcon extends React.Component<Props> {
   render() {
   render() {
     let status = this.props.status
     let status = this.props.status
-    if (status === 'CANCELED_FOR_DEBUGGING') {
-      status = 'ERROR'
-    }
     return (
     return (
       <Wrapper {...this.props} status={status} />
       <Wrapper {...this.props} status={status} />
     )
     )

+ 4 - 6
src/components/atoms/StatusIcon/images/warning.svg → src/components/atoms/StatusIcon/images/warning.js

@@ -1,15 +1,12 @@
-<?xml version="1.0" encoding="UTF-8"?>
+// @flow
+export default (background: string) => `
 <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
-
-    <desc>Created with Sketch.</desc>
-    <defs></defs>
     <g id="Coriolis" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
     <g id="Coriolis" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
         <g id="202-Replica-Executions" transform="translate(-392.000000, -871.000000)">
         <g id="202-Replica-Executions" transform="translate(-392.000000, -871.000000)">
             <g id="Group-2" transform="translate(360.000000, 240.000000)">
             <g id="Group-2" transform="translate(360.000000, 240.000000)">
                 <g id="Group-3" transform="translate(0.000000, 79.000000)">
                 <g id="Group-3" transform="translate(0.000000, 79.000000)">
                     <g id="Icon/Warning" transform="translate(32.000000, 552.000000)">
                     <g id="Icon/Warning" transform="translate(32.000000, 552.000000)">
-                        <circle id="Oval-2" fill="#FFDC00" fill-rule="evenodd" cx="8" cy="8" r="8"></circle>
+                        <circle fill="${background}" fill-rule="evenodd" cx="8" cy="8" r="8"></circle>
                         <path d="M8,8 L8,4" id="Line-Copy" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round"></path>
                         <path d="M8,8 L8,4" id="Line-Copy" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round"></path>
                         <path d="M8,12.5 C8.69035594,12.5 9.25,11.9403559 9.25,11.25 C9.25,10.5596441 8.69035594,10 8,10 C7.30964406,10 6.75,10.5596441 6.75,11.25 C6.75,11.9403559 7.30964406,12.5 8,12.5 Z" id="Oval-3" fill="#FFFFFF" fill-rule="evenodd"></path>
                         <path d="M8,12.5 C8.69035594,12.5 9.25,11.9403559 9.25,11.25 C9.25,10.5596441 8.69035594,10 8,10 C7.30964406,10 6.75,10.5596441 6.75,11.25 C6.75,11.9403559 7.30964406,12.5 8,12.5 Z" id="Oval-3" fill="#FFFFFF" fill-rule="evenodd"></path>
                     </g>
                     </g>
@@ -18,3 +15,4 @@
         </g>
         </g>
     </g>
     </g>
 </svg>
 </svg>
+`

+ 38 - 17
src/components/atoms/StatusIcon/story.jsx

@@ -12,32 +12,53 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import React from 'react'
 import React from 'react'
+import styled from 'styled-components'
 import { storiesOf } from '@storybook/react'
 import { storiesOf } from '@storybook/react'
 import StatusIcon from '.'
 import StatusIcon from '.'
 
 
+const Wrapper = styled.div`
+  display: flex;
+  flex-wrap: wrap;
+`
+
+const STATUSES = [
+  'SCHEDULED',
+  'UNSCHEDULED',
+  'COMPLETED',
+  'RUNNING',
+  'PENDING',
+  'CANCELLING',
+  'CANCELLING_AFTER_COMPLETION',
+  'CANCELED',
+  'CANCELED_AFTER_COMPLETION',
+  'CANCELED_FOR_DEBUGGING',
+  'FORCE_CANCELED',
+  'WARNING',
+  'ERROR',
+  'DEADLOCKED',
+  'STRANDED_AFTER_DEADLOCK',
+]
+
 storiesOf('StatusIcon', module)
 storiesOf('StatusIcon', module)
-  .add('completed', () => (
-    <StatusIcon status="COMPLETED" />
+  .add('all statuses', () => (
+    <Wrapper>
+      {STATUSES.map(status => (
+        <span style={{ marginLeft: '16px', marginBottom: '16px' }}>
+          {status}
+          <StatusIcon
+            key={status}
+            status={status}
+          />
+        </span>
+      ))}
+    </Wrapper>
   ))
   ))
   .add('completed hollow', () => (
   .add('completed hollow', () => (
     <StatusIcon status="COMPLETED" hollow />
     <StatusIcon status="COMPLETED" hollow />
   ))
   ))
-  .add('running', () => (
-    <StatusIcon status="RUNNING" />
-  ))
-  .add('error', () => (
-    <StatusIcon status="ERROR" />
-  ))
   .add('error hollow', () => (
   .add('error hollow', () => (
     <StatusIcon status="ERROR" hollow />
     <StatusIcon status="ERROR" hollow />
   ))
   ))
-  .add('warning', () => (
-    <StatusIcon status="WARNING" />
-  ))
-  .add('canceled', () => (
-    <StatusIcon status="CANCELED" />
-  ))
-  .add('pending', () => (
-    <StatusIcon status="PENDING" />
-  ))

+ 83 - 37
src/components/atoms/StatusPill/StatusPill.jsx

@@ -21,39 +21,88 @@ import styled, { css } from 'styled-components'
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
 import runningImage from './images/running.svg'
 import runningImage from './images/running.svg'
+import cancellingImage from './images/cancelling.svg'
 
 
-const statuses = {
-  COMPLETED: css`
-    background: ${Palette.success};
-    color: white;
-    border-color: transparent;
-  `,
-  ERROR: css`
-    background: ${Palette.alert};
-    color: white;
-    border-color: transparent;
-  `,
-  CANCELED: css`
-    background: ${Palette.warning};
-    color: ${Palette.black};
-    border-color: transparent;
-  `,
-  PAUSED: css`
-    background: white;
-    color: ${Palette.primary};
-    border-color: ${Palette.primary};
-  `,
-  RUNNING: css`
-    background: url('${runningImage}');
-    animation: bgMotion 1s infinite linear;
-    color: white;
-    border-color: transparent;
-    @keyframes bgMotion {
-      0% { background-position: -12px -1px; }
-      100% { background-position: 0 -1px; }
-    }
-  `,
-  INFO: css``,
+const LABEL_MAP: { [string]: string } = {
+  CANCELED_FOR_DEBUGGING: 'DEBUG',
+  FORCE_CANCELED: 'CANCELED',
+  STRANDED_AFTER_DEADLOCK: 'DEADLOCKED',
+  CANCELED_AFTER_COMPLETION: 'CANCELED',
+  CANCELLING_AFTER_COMPLETION: 'CANCELLING',
+}
+
+const statuses = status => {
+  switch (status) {
+    case 'COMPLETED':
+      return css`
+        background: ${Palette.success};
+        color: white;
+        border-color: transparent;
+      `
+    case 'ERROR':
+      return css`
+        background: ${Palette.alert};
+        color: white;
+        border-color: transparent;
+      `
+    case 'CANCELED':
+    case 'CANCELED_FOR_DEBUGGING':
+    case 'CANCELED_AFTER_COMPLETION':
+    case 'FORCE_CANCELED':
+      return css`
+        background: ${Palette.warning};
+        color: ${Palette.black};
+        border-color: transparent;
+      `
+    case 'PAUSED':
+      return css`
+        background: white;
+        color: ${Palette.primary};
+        border-color: ${Palette.primary};
+      `
+    case 'RUNNING':
+    case 'PENDING':
+      return css`
+        background: url('${runningImage}');
+        animation: bgMotion 1s infinite linear;
+        color: white;
+        border-color: transparent;
+        @keyframes bgMotion {
+          0% { background-position: -12px -1px; }
+          100% { background-position: 0 -1px; }
+        }
+      `
+    case 'CANCELLING':
+    case 'CANCELLING_AFTER_COMPLETION':
+      return css`
+        background: url('${cancellingImage}');
+        animation: bgMotion 1s infinite linear;
+        color: ${Palette.black};
+        border-color: transparent;
+        @keyframes bgMotion {
+          0% { background-position: -12px -1px; }
+          100% { background-position: 0 -1px; }
+        }
+      `
+    case 'STRANDED_AFTER_DEADLOCK':
+    case 'DEADLOCKED':
+      return css`
+        background: #424242;
+        color: white;
+        border-color: transparent;
+      `
+    case 'UNSCHEDULED':
+      return css`
+        background: ${Palette.grayscale[2]};
+        color: ${Palette.black};
+        border-color: transparent;
+      `
+    case 'INFO':
+    case 'SCHEDULED':
+      return null
+    default:
+      return null
+  }
 }
 }
 
 
 const primaryColors = css`
 const primaryColors = css`
@@ -91,7 +140,7 @@ const Wrapper = styled.div`
   font-weight: ${StyleProps.fontWeights.medium};
   font-weight: ${StyleProps.fontWeights.medium};
   text-align: center;
   text-align: center;
   border-radius: 4px;
   border-radius: 4px;
-  ${props => statuses[props.status]}
+  ${props => statuses(props.status)}
   ${props => props.status === 'INFO' ? getInfoStatusColor(props) : ''}
   ${props => props.status === 'INFO' ? getInfoStatusColor(props) : ''}
 `
 `
 
 
@@ -115,10 +164,7 @@ class StatusPill extends React.Component<Props> {
     let label = this.props.label || this.props.status
     let label = this.props.label || this.props.status
     let status = this.props.status
     let status = this.props.status
 
 
-    if (status === 'CANCELED_FOR_DEBUGGING') {
-      status = 'ERROR'
-      label = 'DEBUG'
-    }
+    label = LABEL_MAP[label || ''] || label
 
 
     return (
     return (
       <Wrapper
       <Wrapper

+ 11 - 0
src/components/atoms/StatusPill/images/cancelling.svg

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="128px" height="16px" viewBox="0 0 128 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <defs>
+    <pattern id="pattern-1" width="12.4264706" height="12.4264706" x="-12.4264706" y="-12.4264706" patternUnits="userSpaceOnUse">
+      <use xlink:href="#image-2" transform="scale(0.155330882,0.155330882)"></use>
+    </pattern>
+    <image id="image-2" width="80" height="80" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABGdBTUEAALGPC/xhBQAAAeJJREFUeAHt3FtuwyAQBdCkq/EOmyWkO/RuWk+jtHlgDMMA87h8WUZ3BEdIlozxeV3X75NsuyzL8iVbkl9tm9/nlr7yK+STH/nu6t5QeKQjCRgOTxIwJJ4UYFg8CcDQeK2A4fFaAIFHelvjPIWBd7NjAQLvAY8ua1Yg8F7wagCBl8ArBQTeDl4JIPAyeEeAwDvAywECrwBvDxB4hXgpQOBV4L0CAq8S7xEQeAy8OyDwmHgUOzdkxaO9N4DEB3w6XdQAWsSj3UcVgFbxaEVPB7SMNx3QOt5UQA940wC94E0B9IQ3HNAb3lBAj3jDAL3iDQH0jNcd0DteV8AIeN0Ao+B1AYyEJw4YDU8UMCKeGGBUPBHAyHjNgNHxmgCBR3zMV/rAu+GxAIH3j1cNCLxnvCpA4L3jFQMCL41XBAi8fbxDQODl8bKAwDvG2wUEXhleEhB45XhvgMCrw3sCBF493h8g8Hh4v4DA4+NRko67dvspTdvQkml1H8TXnBdOzmjgTXV429yvVgBV4tHisQCoFs8CoGo87YDq8TQDmsDTCmgGTyOgKTxtgObwNAGaxNMCaBZPA6BpvNmA5vFmArrAmwXoBm8GoCu80YDu8EYCusQbBegWbwSga7zegO7xegKGwCPAH6jFkxG1FP01AAAAAElFTkSuQmCC"></image>
+  </defs>
+  <rect id="Base" stroke="none" fill="#FDC02F" fill-rule="evenodd" x="0" y="0" width="128" height="16"></rect>
+  <rect id="Base" stroke="none" fill="url(#pattern-1)" fill-rule="evenodd" opacity="1" style="mix-blend-mode: luminosity;" x="0" y="0" width="128" height="16"></rect>
+</svg>

+ 42 - 16
src/components/atoms/StatusPill/story.jsx

@@ -12,30 +12,56 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */
 
 
+// @flow
+
 import React from 'react'
 import React from 'react'
+import styled from 'styled-components'
 import { storiesOf } from '@storybook/react'
 import { storiesOf } from '@storybook/react'
 import StatusPill from '.'
 import StatusPill from '.'
 
 
+const Wrapper = styled.div`
+  display: flex;
+  flex-wrap: wrap;
+`
+const STATUSES = [
+  'SCHEDULED',
+  'UNSCHEDULED',
+  'COMPLETED',
+  'RUNNING',
+  'PENDING',
+  'CANCELLING',
+  'CANCELLING_AFTER_COMPLETION',
+  'CANCELED',
+  'CANCELED_AFTER_COMPLETION',
+  'CANCELED_FOR_DEBUGGING',
+  'FORCE_CANCELED',
+  'ERROR',
+  'DEADLOCKED',
+  'STRANDED_AFTER_DEADLOCK',
+]
+
+const renderAllStatuses = (small: ?boolean) => (
+  <Wrapper>
+    {STATUSES.map(status => (
+      <span style={{ marginLeft: '16px', marginBottom: '16px' }} key={status}>
+        {status}
+        <StatusPill
+          key={status}
+          status={status}
+          small={small || false}
+        />
+      </span>
+    ))}
+  </Wrapper>
+)
+
 storiesOf('StatusPill', module)
 storiesOf('StatusPill', module)
-  .add('completed', () => (
-    <StatusPill status="COMPLETED" />
-  ))
-  .add('completed small', () => (
-    <StatusPill status="COMPLETED" small />
-  ))
-  .add('running', () => (
-    <StatusPill status="RUNNING" />
-  ))
-  .add('error', () => (
-    <StatusPill status="ERROR" />
-  ))
-  .add('canceled', () => (
-    <StatusPill status="CANCELED" />
-  ))
+  .add('all statuses', () => renderAllStatuses())
+  .add('all statuses small', () => renderAllStatuses(true))
   .add('paused', () => (
   .add('paused', () => (
     <StatusPill status="PAUSED" />
     <StatusPill status="PAUSED" />
   ))
   ))
-  .add('info primary', () => (
+  .add('info', () => (
     <StatusPill status="INFO" />
     <StatusPill status="INFO" />
   ))
   ))
   .add('info secondary', () => (
   .add('info secondary', () => (

+ 27 - 4
src/components/organisms/Executions/story.jsx

@@ -22,7 +22,7 @@ let tasks = [
       { message: 'the task has a progress of 10%', created_at: new Date() },
       { message: 'the task has a progress of 10%', created_at: new Date() },
     ],
     ],
     exception_details: 'Exception details',
     exception_details: 'Exception details',
-    status: 'COMPLETED',
+    status: 'RUNNING',
     created_at: new Date(),
     created_at: new Date(),
     depends_on: ['depends on id'],
     depends_on: ['depends on id'],
     id: 'abcdefg-abcdefg-abcdefg-abcdefg-abcdefg',
     id: 'abcdefg-abcdefg-abcdefg-abcdefg-abcdefg',
@@ -77,9 +77,32 @@ let tasks = [
       { message: 'the task has a progress of 50%', created_at: new Date() },
       { message: 'the task has a progress of 50%', created_at: new Date() },
       { message: 'the task is almost done', created_at: new Date() },
       { message: 'the task is almost done', created_at: new Date() },
     ],
     ],
-    exception_details: 'Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception details Long Exception',
-    // exception_details: 'NA',
-    status: 'RUNNING',
+    exception_details: 'Exception details',
+    status: 'UNSCHEDULED',
+    created_at: new Date(),
+    depends_on: ['depends on id'],
+    id: 'task-2',
+    task_type: 'Task name 2',
+  },
+  {
+    progress_updates: [
+      { message: 'the task has a progress of 50%', created_at: new Date() },
+      { message: 'the task is almost done', created_at: new Date() },
+    ],
+    exception_details: 'Exception details',
+    status: 'DEADLOCKED',
+    created_at: new Date(),
+    depends_on: ['depends on id'],
+    id: 'task-2',
+    task_type: 'Task name 2',
+  },
+  {
+    progress_updates: [
+      { message: 'the task has a progress of 50%', created_at: new Date() },
+      { message: 'the task is almost done', created_at: new Date() },
+    ],
+    exception_details: 'Exception details',
+    status: 'CANCELLING',
     created_at: new Date(),
     created_at: new Date(),
     depends_on: ['abcdefg-abcdefg-abcdefg-abcdefg-abcdefg', 'hijklmn-hijklmn-hijklmn-hijklmn-hijklmn', 'opqrst-opqrst-opqrst-opqrst-opqrst', 'uvwxyz-uvwxyz-uvwxyz-uvwxyz-uvwxyz', '01234-01234-01234-01234-01234'],
     depends_on: ['abcdefg-abcdefg-abcdefg-abcdefg-abcdefg', 'hijklmn-hijklmn-hijklmn-hijklmn-hijklmn', 'opqrst-opqrst-opqrst-opqrst-opqrst', 'uvwxyz-uvwxyz-uvwxyz-uvwxyz-uvwxyz', '01234-01234-01234-01234-01234'],
     // depends_on: ['', 0, 's'],
     // depends_on: ['', 0, 's'],