Selaa lähdekoodia

Update task updates sorting and progress fields

1. The task updates are now sorted by the newly added `index` field
instead of creation date.

2. The progress bar for the task updates is calculated based on newly
added fields with the previous text base parsing method as a fallback.
Sergiu Miclea 5 vuotta sitten
vanhempi
sitoutus
1569a3bf34

+ 1 - 1
package.json

@@ -5,7 +5,7 @@
   "scripts": {
     "start": "node ./server",
     "build": "webpack --config webpack.prod.js",
-    "ui-dev": "webpack-dev-server --config webpack.dev.js",
+    "client-dev": "webpack-dev-server --config webpack.dev.js",
     "server-dev": "nodemon -e ts,js -w server/**/",
     "server-debug": "node --inspect server",
     "tsc": "npx tsc --skipLibCheck",

+ 3 - 0
src/@types/Task.ts

@@ -13,8 +13,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 export type ProgressUpdate = {
+  index: number,
   message: string,
   created_at: Date,
+  total_steps: number | null
+  current_step: number | null
 }
 
 export type Task = {

+ 25 - 13
src/components/atoms/ProgressBar/ProgressBar.tsx

@@ -19,29 +19,41 @@ import styled from 'styled-components'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 
-type Props = {
-  progress: number,
-  width?: number,
-  style?: React.CSSProperties
-}
-
-const Wrapper = styled.div<any>`
+const Wrapper = styled.div`
+  display: flex;
+  align-items: center;
+`
+const ProgressLabel = styled.div`
+  text-align: right;
+  min-width: 36px;
+  font-size: 12px;
+`
+const ProgressBarWrapper = styled.div`
   background: white;
+  flex-grow: 1;
 `
-const Progress = styled.div<any>`
+const Progress = styled.div<{width: number}>`
   height: 2px;
   background: ${Palette.primary};
   transition: all ${StyleProps.animations.swift};
-  width: ${(props: Props) => props.width}%;
+  width: ${props => props.width}%;
 `
-
+type Props = {
+  progress: number,
+  style?: React.CSSProperties
+  useLabel?: boolean
+}
 @observer
 class ProgressBar extends React.Component<Props> {
   render() {
     return (
-      // eslint-disable-next-line react/jsx-props-no-spreading
-      <Wrapper {...this.props}>
-        <Progress data-test-id="progressBar-progress" width={this.props.progress} />
+      <Wrapper>
+        <ProgressBarWrapper style={this.props.style}>
+          <Progress width={this.props.progress} />
+        </ProgressBarWrapper>
+        {this.props.useLabel ? (
+          <ProgressLabel>{this.props.progress} %</ProgressLabel>
+        ) : null}
       </Wrapper>
     )
   }

+ 29 - 9
src/components/molecules/TaskItem/TaskItem.tsx

@@ -17,7 +17,7 @@ import { observer } from 'mobx-react'
 import styled, { css, createGlobalStyle } from 'styled-components'
 import { Collapse } from 'react-collapse'
 
-import type { Task } from '../../../@types/Task'
+import type { ProgressUpdate, Task } from '../../../@types/Task'
 import StatusIcon from '../../atoms/StatusIcon'
 import Arrow from '../../atoms/Arrow'
 import StatusPill from '../../atoms/StatusPill'
@@ -136,7 +136,7 @@ const ExceptionText = styled.div<any>`
 const ProgressUpdates = styled.div<any>`
   color: ${Palette.black};
 `
-const ProgressUpdate = styled.div<any>`
+const ProgressUpdateDiv = styled.div<any>`
   display: flex;
   color: ${props => (props.secondary ? Palette.grayscale[5] : 'inherit')};
 `
@@ -172,9 +172,23 @@ class TaskItem extends React.Component<Props> {
     return message
   }
 
-  getMessageProgress(message: string) {
-    const match = message.match(/.*progress.*?(100|\d{1,2})%/)
-    return match && match[1]
+  getProgressPercentage(progressUpdate: ProgressUpdate): {useLabel: boolean, value: number} | null {
+    if (progressUpdate.total_steps && progressUpdate.current_step) {
+      const currentStep = Math.min(progressUpdate.total_steps, progressUpdate.current_step)
+      return {
+        value: (currentStep * 100) / progressUpdate.total_steps,
+        useLabel: true,
+      }
+    }
+
+    const stringPercentage = progressUpdate.message.match(/.*progress.*?(100|\d{1,2})%/)?.[1]
+    if (!stringPercentage) {
+      return null
+    }
+    return {
+      value: Number(stringPercentage),
+      useLabel: false,
+    }
   }
 
   handleExceptionTextClick(exceptionText: string) {
@@ -250,19 +264,25 @@ class TaskItem extends React.Component<Props> {
           if (!update) {
             return <Value>N/A</Value>
           }
-          const messageProgress = this.getMessageProgress(update.message)
+          const progressPercentage = this.getProgressPercentage(update)
 
           return (
             // eslint-disable-next-line react/no-array-index-key
-            <ProgressUpdate key={i} secondary={i < this.props.item.progress_updates.length - 1 || this.props.item.status !== 'RUNNING'}>
+            <ProgressUpdateDiv key={i} secondary={i < this.props.item.progress_updates.length - 1 || this.props.item.status !== 'RUNNING'}>
               <ProgressUpdateDate width={this.props.columnWidths[0]}>
                 <span>{DateUtils.getLocalTime(update.created_at).format('YYYY-MM-DD HH:mm:ss')}</span>
               </ProgressUpdateDate>
               <ProgressUpdateValue data-test-id={`taskItem-progressUpdateMessage-${i}`}>
                 {update.message}
-                {messageProgress && <ProgressBar style={{ margin: '8px 0' }} progress={Number(messageProgress)} data-test-id={`taskItem-progressBar-${i}`} />}
+                {progressPercentage && (
+                  <ProgressBar
+                    style={{ margin: '8px 0' }}
+                    progress={progressPercentage.value}
+                    useLabel={progressPercentage.useLabel}
+                  />
+                )}
               </ProgressUpdateValue>
-            </ProgressUpdate>
+            </ProgressUpdateDiv>
           )
         })}
       </ProgressUpdates>

+ 12 - 0
src/components/molecules/TaskItem/story.tsx

@@ -20,6 +20,18 @@ const item: any = {
   progress_updates: [
     { message: 'the task has a progress of 50%', created_at: new Date() },
     { message: 'the task is almost done', created_at: new Date() },
+    {
+      message: 'Transferring changed areas of Cinder volume \'ca816553-a616-413e-a078-9a19e1da5326\'',
+      created_at: new Date(),
+      total_steps: 5,
+      current_step: 2,
+    },
+    {
+      message: 'Transferring changed areas of Cinder volume \'ca816553-a616-413e-a078-9a19e1da5326\'',
+      created_at: new Date(),
+      total_steps: 5,
+      current_step: 7,
+    },
   ],
   exception_details: 'Exception details',
   status: 'RUNNING',

+ 4 - 4
src/sources/MigrationSource.ts

@@ -25,21 +25,21 @@ import type { NetworkMap } from '../@types/Network'
 import type { Endpoint, StorageMap } from '../@types/Endpoint'
 
 import configLoader from '../utils/Config'
-import { Task } from '../@types/Task'
+import { ProgressUpdate, Task } from '../@types/Task'
 import { MigrationItem, MigrationItemOptions, MigrationItemDetails } from '../@types/MainItem'
 import { INSTANCE_OSMORPHING_MINION_POOL_MAPPINGS } from '../components/organisms/WizardOptions/WizardOptions'
 
 class MigrationSourceUtils {
-  static sortTaskUpdates(updates: any[]) {
+  static sortTaskUpdates(updates: ProgressUpdate[]) {
     if (!updates) {
       return
     }
-    updates.sort((a: any, b: any) => {
+    updates.sort((a, b) => {
       const sortNull = !a && b ? 1 : a && !b ? -1 : !a && !b ? 0 : false
       if (sortNull !== false) {
         return sortNull
       }
-      return moment(a.created_at).toDate().getTime() - moment(b.created_at).toDate().getTime()
+      return a.index - b.index
     })
   }
 

+ 1 - 5
src/sources/ReplicaSource.ts

@@ -12,8 +12,6 @@ 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/>.
 */
 
-import moment from 'moment'
-
 import Api from '../utils/ApiCaller'
 import { OptionsSchemaPlugin } from '../plugins/endpoint'
 
@@ -92,9 +90,7 @@ export class ReplicaSourceUtils {
     if (!updates) {
       return
     }
-    updates
-      .sort((a, b) => moment(a.created_at)
-        .toDate().getTime() - moment(b.created_at).toDate().getTime())
+    updates.sort((a, b) => a.index - b.index)
   }
 }