From 9afd733193a28113c44be275578b3ad7ac7b7ea6 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 26 Mar 2021 12:59:42 +0100 Subject: [PATCH 01/23] Labels for jobs renamed to pipeline jobs --- src/components/app-navbar/index.js | 2 +- src/components/events-list/index.test.js | 2 +- src/components/job-overview/index.js | 7 +++++-- src/components/jobs-list/index.js | 2 +- .../change-config-branch-form.js | 2 +- .../page-deployment/deployment-overview.js | 2 +- src/components/page-job-new/index.js | 21 +++++++++++-------- src/components/page-job/index.js | 2 +- src/components/page-jobs/index.js | 6 +++--- src/components/page-step/index.js | 5 ++++- src/models/job-summary/normaliser.js | 2 +- 11 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/components/app-navbar/index.js b/src/components/app-navbar/index.js index 58b3fad39..a9053965a 100644 --- a/src/components/app-navbar/index.js +++ b/src/components/app-navbar/index.js @@ -98,7 +98,7 @@ export class AppNavbar extends React.Component { /> { @@ -103,7 +106,7 @@ const JobOverview = (props) => {

Summary

- Job {job.status.toLowerCase()};{' '} + Pipeline Job {job.status.toLowerCase()};{' '} {getExecutionState(job.status)} pipeline{' '} {job.pipeline}

diff --git a/src/components/jobs-list/index.js b/src/components/jobs-list/index.js index 40515a393..819b92f2e 100644 --- a/src/components/jobs-list/index.js +++ b/src/components/jobs-list/index.js @@ -25,7 +25,7 @@ const noJobsIcon = ( export const JobsList = ({ appName, jobs, limit }) => (
{jobs.length === 0 && ( - + Push to GitHub to trigger a job )} diff --git a/src/components/page-configuration/change-config-branch-form.js b/src/components/page-configuration/change-config-branch-form.js index 41a76289d..864023d7d 100644 --- a/src/components/page-configuration/change-config-branch-form.js +++ b/src/components/page-configuration/change-config-branch-form.js @@ -75,7 +75,7 @@ export const ChangeConfigBranchForm = (props) => { - Jobs + Pipeline Jobs {' '} to verify that the build-deploy job runs to completion diff --git a/src/components/page-deployment/deployment-overview.js b/src/components/page-deployment/deployment-overview.js index 4f4c247fa..6aad81ec1 100644 --- a/src/components/page-deployment/deployment-overview.js +++ b/src/components/page-deployment/deployment-overview.js @@ -121,7 +121,7 @@ export class DeploymentOverview extends React.Component {

{deployment.createdByJob && (

- Created by job{' '} + Created by pipeline job{' '} - +

-

New job

+

New pipeline job

- Jobs perform different actions in Radix. The pipeline of the job - defines what action to take, and it may require specific + Pipeline jobs perform different actions in Radix. The pipeline of + the job defines what action to take, and it may require specific parameters.

@@ -66,7 +69,7 @@ class PageJobNew extends React.Component { jobName: this.props.creationResult.name, })} > - Job + Pipeline Job ); @@ -76,14 +79,14 @@ class PageJobNew extends React.Component { appName: appName, })} > - jobs + Pipeline Jobs ); return (
- The job "{this.props.creationResult.name}" has been created + The pipeline job "{this.props.creationResult.name}" has been created

View {jobLink} or all {jobsLink} diff --git a/src/components/page-job/index.js b/src/components/page-job/index.js index 9dced18c3..f5f368686 100644 --- a/src/components/page-job/index.js +++ b/src/components/page-job/index.js @@ -11,7 +11,7 @@ import routes from '../../routes'; export const PageJob = ({ appName, jobName }) => { return ( - + - +

- New Job… + New Pipeline Job… diff --git a/src/components/page-step/index.js b/src/components/page-step/index.js index 298fcf9fa..bd117abd5 100644 --- a/src/components/page-step/index.js +++ b/src/components/page-step/index.js @@ -53,7 +53,10 @@ export class PageStep extends React.Component { { const jobSummary = pick(props, Object.keys(model)); From 464cc956909cabb8cb5d668911ab520fbe5cec1c Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 26 Mar 2021 13:03:17 +0100 Subject: [PATCH 02/23] Labels for jobs renamed to pipeline jobs --- src/components/app-overview/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/app-overview/index.js b/src/components/app-overview/index.js index 09acf4428..d84fc96c2 100644 --- a/src/components/app-overview/index.js +++ b/src/components/app-overview/index.js @@ -74,10 +74,10 @@ export class AppOverview extends React.Component { {jobs.length > 0 && ( -

Latest jobs

+

Latest pipeline jobs

From a6a3fb9c54eda8d813343ff40703e44b17873fff Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 29 Mar 2021 15:22:23 +0200 Subject: [PATCH 03/23] Added type to component-summary --- src/models/component-summary/index.js | 2 ++ src/models/component-type/index.js | 3 +++ src/models/component-type/normaliser.js | 0 3 files changed, 5 insertions(+) create mode 100644 src/models/component-type/index.js create mode 100644 src/models/component-type/normaliser.js diff --git a/src/models/component-summary/index.js b/src/models/component-summary/index.js index f98ef12a8..715e5a5b3 100644 --- a/src/models/component-summary/index.js +++ b/src/models/component-summary/index.js @@ -1,6 +1,8 @@ import PropTypes from 'prop-types'; +import ComponentType from '../component-type'; export default Object.freeze({ image: PropTypes.string.isRequired, name: PropTypes.string.isRequired, + type: ComponentType.isRequired, }); diff --git a/src/models/component-type/index.js b/src/models/component-type/index.js new file mode 100644 index 000000000..6d26713e7 --- /dev/null +++ b/src/models/component-type/index.js @@ -0,0 +1,3 @@ +import PropTypes from 'prop-types'; + +export default PropTypes.oneOf(['component', 'job']); diff --git a/src/models/component-type/normaliser.js b/src/models/component-type/normaliser.js new file mode 100644 index 000000000..e69de29bb From a5b0fbb048dd03eb4fd28e2b55f813e7d6ffd07c Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 29 Mar 2021 20:21:50 +0200 Subject: [PATCH 04/23] Split list to components and jobs in job Artefacts --- src/components/job-overview/component-list.js | 26 +++++++++++++++++++ src/components/job-overview/index.js | 10 +++---- src/models/component-type/index.js | 15 +++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/components/job-overview/component-list.js diff --git a/src/components/job-overview/component-list.js b/src/components/job-overview/component-list.js new file mode 100644 index 000000000..3e5199c50 --- /dev/null +++ b/src/components/job-overview/component-list.js @@ -0,0 +1,26 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ComponentItem from '../../models/component-summary'; +import { + getComponentMapByType, + getComponentTypeLabel, +} from '../../models/component-type'; + +export const ComponentList = ({ components }) => { + let componentMap = getComponentMapByType(components); + return Object.keys(componentMap).map((compType) => + componentMap[compType].map((component) => ( +

+ {getComponentTypeLabel(compType)} {component.name} +

+ )) + ); +}; + +ComponentList.propTypes = { + appName: PropTypes.string.isRequired, + jobName: PropTypes.string.isRequired, + components: PropTypes.arrayOf(PropTypes.shape(ComponentItem)).isRequired, +}; + +export default ComponentList; diff --git a/src/components/job-overview/index.js b/src/components/job-overview/index.js index eaab51aa3..ebb6a265c 100644 --- a/src/components/job-overview/index.js +++ b/src/components/job-overview/index.js @@ -27,6 +27,7 @@ import { import routes from '../../routes'; import './style.css'; +import { ComponentList } from './component-list'; const getExecutionState = (status) => { if (status === jobStatuses.PENDING) { @@ -165,12 +166,9 @@ const JobOverview = (props) => {

))} - {job.components && - job.components.map((component) => ( -

- Component {component.name} -

- ))} + {job.components && ( + + )}
{job.steps && ( diff --git a/src/models/component-type/index.js b/src/models/component-type/index.js index 6d26713e7..fa4959a35 100644 --- a/src/models/component-type/index.js +++ b/src/models/component-type/index.js @@ -1,3 +1,18 @@ import PropTypes from 'prop-types'; export default PropTypes.oneOf(['component', 'job']); + +const componentTypeLabel = { component: 'Component', job: 'Job' }; + +export const getComponentTypeLabel = function (type) { + return componentTypeLabel['' + type]; +}; + +export const getComponentMapByType = (components) => { + return components.reduce((componentMap, component) => { + let key = component.type; + componentMap[key] = componentMap[key] || []; + componentMap[key].push(component); + return componentMap; + }, {}); +}; From 8aa236d34229170f6eb67872ca92970d123b6781 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 29 Mar 2021 21:29:15 +0200 Subject: [PATCH 05/23] Split list to components and jobs in environment overview --- .../page-environment/component-list-item.js | 37 +++++++++++++++++++ .../page-environment/component-list.js | 32 ++++++++++++++++ .../page-environment/environment-overview.js | 28 +++----------- src/models/component/index.js | 2 + 4 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 src/components/page-environment/component-list-item.js create mode 100644 src/components/page-environment/component-list.js diff --git a/src/components/page-environment/component-list-item.js b/src/components/page-environment/component-list-item.js new file mode 100644 index 000000000..d8f5c0309 --- /dev/null +++ b/src/components/page-environment/component-list-item.js @@ -0,0 +1,37 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ComponentItem from '../../models/component-summary'; +import { Link } from 'react-router-dom'; +import * as routing from '../../utils/routing'; +import ActiveComponentStatus from './active-component-status'; +import environmentModel from '../../models/environment'; + +export const ComponentListItem = ({ appName, environment, components }) => { + return components.map((component) => ( +

+ + {component.name}{' '} + + +

+ )); +}; + +ComponentListItem.propTypes = { + appName: PropTypes.string.isRequired, + environment: PropTypes.shape(environmentModel), + components: PropTypes.arrayOf(PropTypes.shape(ComponentItem)).isRequired, +}; + +export default ComponentListItem; diff --git a/src/components/page-environment/component-list.js b/src/components/page-environment/component-list.js new file mode 100644 index 000000000..b3b5d228e --- /dev/null +++ b/src/components/page-environment/component-list.js @@ -0,0 +1,32 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ComponentItem from '../../models/component-summary'; +import { + getComponentMapByType, + getComponentTypeLabel, +} from '../../models/component-type'; +import environmentModel from '../../models/environment'; + +export const ComponentList = ({ appName, environment, components }) => { + let componentMap = getComponentMapByType(components); + return Object.keys(componentMap).map((componentType) => { + console.log(componentType); +

Active s

; + //

Active {getComponentTypeLabel(componentType)}s

; + // return ( + // + // ); + }); +}; + +ComponentList.propTypes = { + appName: PropTypes.string.isRequired, + environment: PropTypes.shape(environmentModel), + components: PropTypes.arrayOf(PropTypes.shape(ComponentItem)).isRequired, +}; + +export default ComponentList; diff --git a/src/components/page-environment/environment-overview.js b/src/components/page-environment/environment-overview.js index 04a833853..3ebf4d878 100644 --- a/src/components/page-environment/environment-overview.js +++ b/src/components/page-environment/environment-overview.js @@ -5,7 +5,6 @@ import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import React from 'react'; -import ActiveComponentStatus from './active-component-status'; import Alert from '../alert'; import Button from '../button'; import LinkButton from '../link-button'; @@ -36,6 +35,7 @@ import { keys as configKeys } from '../../utils/config/keys'; import routes from '../../routes'; import './style.css'; +import ComponentList from './component-list'; const eventDateSorter = (a, b) => { if (a.lastTimestamp > b.lastTimestamp) { @@ -197,27 +197,11 @@ export class EnvironmentOverview extends React.Component { {deployment && (
-

Active components

- {deployment.components && - deployment.components.map((component) => ( -

- - {component.name}{' '} - - -

- ))} +
)} diff --git a/src/models/component/index.js b/src/models/component/index.js index dc2214b68..c70129ea6 100644 --- a/src/models/component/index.js +++ b/src/models/component/index.js @@ -2,10 +2,12 @@ import PropTypes from 'prop-types'; import PortModel from '../port'; import ReplicaSummaryModel from '../replica-summary'; +import ComponentType from '../component-type'; export default Object.freeze({ image: PropTypes.string.isRequired, name: PropTypes.string.isRequired, + type: ComponentType.isRequired, status: PropTypes.string.isRequired, ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), From 80e2d312953d6392222918b37be89b945e78db25 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 30 Mar 2021 10:48:32 +0200 Subject: [PATCH 06/23] Split list to components and jobs in environment overview --- .../page-environment/component-list.js | 25 ++++++++++--------- .../page-environment/environment-overview.js | 12 ++++----- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/components/page-environment/component-list.js b/src/components/page-environment/component-list.js index b3b5d228e..d61f7282a 100644 --- a/src/components/page-environment/component-list.js +++ b/src/components/page-environment/component-list.js @@ -6,21 +6,22 @@ import { getComponentTypeLabel, } from '../../models/component-type'; import environmentModel from '../../models/environment'; +import ComponentListItem from './component-list-item'; export const ComponentList = ({ appName, environment, components }) => { let componentMap = getComponentMapByType(components); - return Object.keys(componentMap).map((componentType) => { - console.log(componentType); -

Active s

; - //

Active {getComponentTypeLabel(componentType)}s

; - // return ( - // - // ); - }); + return Object.keys(componentMap).map((componentType) => ( +
+

+ Active {getComponentTypeLabel(componentType)}s +

+ +
+ )); }; ComponentList.propTypes = { diff --git a/src/components/page-environment/environment-overview.js b/src/components/page-environment/environment-overview.js index 3ebf4d878..5eed74cc0 100644 --- a/src/components/page-environment/environment-overview.js +++ b/src/components/page-environment/environment-overview.js @@ -196,13 +196,11 @@ export class EnvironmentOverview extends React.Component { )} {deployment && ( -
- -
+ )}
From 9aa72fab3595978a5a46eab87330ff082fb6a11b Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 30 Mar 2021 11:03:25 +0200 Subject: [PATCH 07/23] Cleanup --- src/components/job-overview/component-list.js | 12 ++++++------ src/components/page-environment/component-list.js | 12 ++++++------ src/models/component-type/index.js | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/job-overview/component-list.js b/src/components/job-overview/component-list.js index 3e5199c50..52d1670b9 100644 --- a/src/components/job-overview/component-list.js +++ b/src/components/job-overview/component-list.js @@ -2,16 +2,16 @@ import PropTypes from 'prop-types'; import React from 'react'; import ComponentItem from '../../models/component-summary'; import { - getComponentMapByType, - getComponentTypeLabel, + buildComponentMap, + buildComponentTypeLabelMap, } from '../../models/component-type'; export const ComponentList = ({ components }) => { - let componentMap = getComponentMapByType(components); - return Object.keys(componentMap).map((compType) => - componentMap[compType].map((component) => ( + let compMap = buildComponentMap(components); + return Object.keys(compMap).map((compType) => + compMap[compType].map((component) => (

- {getComponentTypeLabel(compType)} {component.name} + {buildComponentTypeLabelMap(compType)} {component.name}

)) ); diff --git a/src/components/page-environment/component-list.js b/src/components/page-environment/component-list.js index d61f7282a..7eebb087f 100644 --- a/src/components/page-environment/component-list.js +++ b/src/components/page-environment/component-list.js @@ -2,23 +2,23 @@ import PropTypes from 'prop-types'; import React from 'react'; import ComponentItem from '../../models/component-summary'; import { - getComponentMapByType, - getComponentTypeLabel, + buildComponentMap, + buildComponentTypeLabelMap, } from '../../models/component-type'; import environmentModel from '../../models/environment'; import ComponentListItem from './component-list-item'; export const ComponentList = ({ appName, environment, components }) => { - let componentMap = getComponentMapByType(components); - return Object.keys(componentMap).map((componentType) => ( + const compMap = buildComponentMap(components); + return Object.keys(compMap).map((componentType) => (

- Active {getComponentTypeLabel(componentType)}s + Active {buildComponentTypeLabelMap(componentType)}s

)); diff --git a/src/models/component-type/index.js b/src/models/component-type/index.js index fa4959a35..01e7a07b6 100644 --- a/src/models/component-type/index.js +++ b/src/models/component-type/index.js @@ -4,11 +4,11 @@ export default PropTypes.oneOf(['component', 'job']); const componentTypeLabel = { component: 'Component', job: 'Job' }; -export const getComponentTypeLabel = function (type) { +export const buildComponentTypeLabelMap = (type) => { return componentTypeLabel['' + type]; }; -export const getComponentMapByType = (components) => { +export const buildComponentMap = (components) => { return components.reduce((componentMap, component) => { let key = component.type; componentMap[key] = componentMap[key] || []; From 0a98c9f723c6b0ecf9f7bf2a4fa38193e61a2519 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 30 Mar 2021 18:36:52 +0200 Subject: [PATCH 08/23] Added job logs --- .../active-scheduled-job-overview.js | 313 ++++++++++++++++++ .../page-active-scheduled-job/index.js | 35 ++ .../page-active-scheduled-job/toolbar.js | 140 ++++++++ .../page-environment/component-list-item.js | 52 +-- src/components/page-environment/index.js | 5 + src/components/page-scheduled-jobs/index.js | 113 +++++++ .../page-scheduled-jobs/use-poll-logs.js | 13 + .../use-select-scheduled-job.js | 24 ++ src/components/scheduled-job-status/index.js | 22 ++ src/models/component-type/index.js | 5 + src/routes.js | 2 + src/utils/routing.js | 20 ++ 12 files changed, 725 insertions(+), 19 deletions(-) create mode 100644 src/components/page-active-scheduled-job/active-scheduled-job-overview.js create mode 100644 src/components/page-active-scheduled-job/index.js create mode 100644 src/components/page-active-scheduled-job/toolbar.js create mode 100644 src/components/page-scheduled-jobs/index.js create mode 100644 src/components/page-scheduled-jobs/use-poll-logs.js create mode 100644 src/components/page-scheduled-jobs/use-select-scheduled-job.js create mode 100644 src/components/scheduled-job-status/index.js diff --git a/src/components/page-active-scheduled-job/active-scheduled-job-overview.js b/src/components/page-active-scheduled-job/active-scheduled-job-overview.js new file mode 100644 index 000000000..0c92a4ac5 --- /dev/null +++ b/src/components/page-active-scheduled-job/active-scheduled-job-overview.js @@ -0,0 +1,313 @@ +import { connect } from 'react-redux'; +import { faLink } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Link } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import React from 'react'; +import Alert from '../alert'; + +import Breadcrumb from '../breadcrumb'; +import DockerImage from '../docker-image'; +import EnvironmentBadge from '../environment-badge'; +import ReplicaStatus from '../replica-status'; +import SecretStatus from '../secret-status'; +import AsyncResource from '../async-resource'; +import Toolbar from './toolbar'; + +import { getAppAlias } from '../../state/application'; +import { getComponent, getSecret } from '../../state/environment'; +import { routeWithParams, smallReplicaName } from '../../utils/string'; +import * as routing from '../../utils/routing'; +import * as subscriptionActions from '../../state/subscriptions/action-creators'; +import componentModel from '../../models/component'; +import routes from '../../routes'; +import ScheduledJobStatus from '../scheduled-job-status'; + +const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; + +const Vars = ({ envVarNames, component }) => { + let hasRadixVars = false; + + const varList = envVarNames.map((varName) => { + const isRadixVar = varName.slice(0, 6) === 'RADIX_'; + hasRadixVars = hasRadixVars || isRadixVar; + + if (isRadixVar) { + return ( + +
+ * {varName} +
+
+ {component.variables[varName]} +
+
+ ); + } + + return ( + +
{varName}
+
{component.variables[varName]}
+
+ ); + }); + + return ( +
+
{varList}
+ {hasRadixVars && ( +

+ * automatically added by Radix +

+ )} +
+ ); +}; + +export class ActiveScheduledJobOverview extends React.Component { + componentDidMount() { + this.props.subscribe(this.props.appName, this.props.envName); + } + + componentDidUpdate(prevProps) { + const { appName, envName } = this.props; + + if (appName !== prevProps.appName || envName !== prevProps.envName) { + this.props.unsubscribe(prevProps.appName, prevProps.envName); + this.props.subscribe(appName, envName); + } + } + + componentWillUnmount() { + this.props.unsubscribe(this.props.appName, this.props.envName); + } + + render() { + const { + appAlias, + appName, + envName, + componentName, + component, + getEnvSecret, + } = this.props; + + const envVarNames = component && Object.keys(component.variables); + + const isDefaultAlias = + appAlias && + appAlias.componentName === componentName && + appAlias.environmentName === envName; + + return ( + + , + to: routeWithParams(routes.appEnvironment, { + appName, + envName, + }), + }, + { label: componentName }, + ]} + /> +
+ + {component && ( + + +
+
+

Overview

+

+ Component {component.name} +

+ {component.status === 'Stopped' && ( + + Component has been manually stopped; please note that a + new deployment will cause it to be restarted unless you + set replicas of the component to{' '} + 0 in{' '} + + radixconfig.yaml + + + )} +

+ Status {component.status} +

+ {component.variables[URL_VAR_NAME] && ( +

+ Publically available{' '} + + link + +

+ )} + {isDefaultAlias && ( + + This component is the application{' '} + + default alias{' '} + + + + )} +

+ Image +

+ {component.ports.length > 0 && ( + +

Open ports:

+
    + {component.ports.map((port) => ( +
  • + {port.port} ({port.name}) +
  • + ))} +
+
+ )} + {component.ports.length === 0 &&

No open ports

} +

Environment variables

+ {envVarNames.length === 0 && ( +

This component uses no environment variables

+ )} + {envVarNames.length > 0 && ( + + )} +
+
+ {component.horizontalScalingSummary && ( + +

+ Horizontal scaling +

+
+
Min replicas:
+
+ {component.horizontalScalingSummary.minReplicas} +
+
Max replicas:
+
+ {component.horizontalScalingSummary.maxReplicas} +
+
Current average CPU utilization:
+
+ { + component.horizontalScalingSummary + .currentCPUUtilizationPercentage + } + % +
+
Target average CPU utilization:
+
+ { + component.horizontalScalingSummary + .targetCPUUtilizationPercentage + } + % +
+
+
+ )} +

Scheduled Job

+ {component.replicaList.map((scheduledJob) => ( +

+ + {smallReplicaName(scheduledJob.name)}{' '} + + +

+ ))} +

Secrets

+ {component.secrets.length === 0 && ( +

This job uses no secrets

+ )} + {component.secrets.length > 0 && ( +
    + {component.secrets.map((secretName) => ( +
  • + + {secretName} + {' '} + +
  • + ))} +
+ )} +
+
+
+ )} +
+
+
+ ); + } +} + +ActiveScheduledJobOverview.propTypes = { + appAlias: PropTypes.exact({ + componentName: PropTypes.string.isRequired, + environmentName: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + }), + appName: PropTypes.string.isRequired, + envName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, + component: PropTypes.shape(componentModel), + getEnvSecret: PropTypes.func.isRequired, + subscribe: PropTypes.func.isRequired, + unsubscribe: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state, { componentName }) => ({ + appAlias: getAppAlias(state), + component: getComponent(state, componentName), + getEnvSecret: (secretName) => getSecret(state, componentName, secretName), +}); + +const mapDispatchToProps = (dispatch) => ({ + subscribe: (appName, envName) => { + dispatch(subscriptionActions.subscribeEnvironment(appName, envName)); + dispatch(subscriptionActions.subscribeApplication(appName)); + }, + unsubscribe: (appName, envName) => { + dispatch(subscriptionActions.unsubscribeEnvironment(appName, envName)); + dispatch(subscriptionActions.unsubscribeApplication(appName)); + }, +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ActiveScheduledJobOverview); diff --git a/src/components/page-active-scheduled-job/index.js b/src/components/page-active-scheduled-job/index.js new file mode 100644 index 000000000..a5a86f8bc --- /dev/null +++ b/src/components/page-active-scheduled-job/index.js @@ -0,0 +1,35 @@ +import { Route } from 'react-router'; +import React from 'react'; + +import ActiveComponentOverview from './active-scheduled-job-overview'; + +import DocumentTitle from '../document-title'; +import PageReplica from '../page-replica'; +import PageSecret from '../page-secret'; + +import { mapRouteParamsToProps } from '../../utils/routing'; +import routes from '../../routes'; + +export const PageActiveScheduledJob = ({ appName, envName, componentName }) => ( + + + ( + + )} + /> + + + +); + +export default mapRouteParamsToProps( + ['appName', 'envName', 'componentName'], + PageActiveScheduledJob +); diff --git a/src/components/page-active-scheduled-job/toolbar.js b/src/components/page-active-scheduled-job/toolbar.js new file mode 100644 index 000000000..963e87f0a --- /dev/null +++ b/src/components/page-active-scheduled-job/toolbar.js @@ -0,0 +1,140 @@ +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import React from 'react'; +import Button from '../button'; +import ActionsPage from '../actions-page'; +import Spinner from '../spinner'; + +import { + getStartRequestStatus, + getStartRequestError, + getStopRequestStatus, + getStopRequestError, + getRestartRequestStatus, + getRestartRequestError, +} from '../../state/component'; +import componentStatuses from '../../state/component/component-states'; +import componentActions from '../../state/component/action-creators'; +import requestStatuses from '../../state/state-utils/request-states'; + +export class Toolbar extends React.Component { + constructor() { + super(); + + this.doStartComponent = this.doStartComponent.bind(this); + this.doStopComponent = this.doStopComponent.bind(this); + this.doRestartComponent = this.doRestartComponent.bind(this); + } + + doStartComponent(ev) { + ev.preventDefault(); + this.props.startComponent({ + appName: this.props.appName, + envName: this.props.envName, + componentName: this.props.component.name, + }); + } + + doStopComponent(ev) { + ev.preventDefault(); + this.props.stopComponent({ + appName: this.props.appName, + envName: this.props.envName, + componentName: this.props.component.name, + }); + } + + doRestartComponent(ev) { + ev.preventDefault(); + this.props.restartComponent({ + appName: this.props.appName, + envName: this.props.envName, + componentName: this.props.component.name, + }); + } + + render() { + const { + component, + startRequestStatus, + startRequestMessage, + stopRequestStatus, + stopRequestMessage, + restartRequestStatus, + restartRequestMessage, + } = this.props; + + const isStartEnabled = + component && + component.status === componentStatuses.STOPPED && + startRequestStatus !== requestStatuses.IN_PROGRESS; + + const isStopEnabled = + component && + component.status !== componentStatuses.STOPPED && + component.replicaList.length > 0 && + stopRequestStatus !== requestStatuses.IN_PROGRESS; + + const isRestartEnabled = + component && + component.status === componentStatuses.CONSISTENT && + component.replicaList.length > 0 && + restartRequestStatus !== requestStatuses.IN_PROGRESS; + + const restartInProgress = + restartRequestStatus === requestStatuses.IN_PROGRESS || + (component && + (component.status === componentStatuses.RECONCILING || + component.status === componentStatuses.RESTARTING)); + + return ( + + + {startRequestMessage &&
{startRequestMessage}
} + + {stopRequestMessage &&
{stopRequestMessage}
} + + {restartInProgress && } + {restartRequestMessage &&
{restartRequestMessage}
} +
+ ); + } +} + +Toolbar.propTypes = { + startComponent: PropTypes.func.isRequired, + stopComponent: PropTypes.func.isRequired, + restartComponent: PropTypes.func.isRequired, + startRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), + startRequestMessage: PropTypes.string, + stopRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), + stopRequestMessage: PropTypes.string, + restartRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), + restartRequestMessage: PropTypes.string, +}; + +const mapStateToProps = (state) => ({ + startRequestStatus: getStartRequestStatus(state), + startRequestMessage: getStartRequestError(state), + stopRequestStatus: getStopRequestStatus(state), + stopRequestMessage: getStopRequestError(state), + restartRequestStatus: getRestartRequestStatus(state), + restartRequestMessage: getRestartRequestError(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + startComponent: (component) => + dispatch(componentActions.startComponentRequest(component)), + stopComponent: (component) => + dispatch(componentActions.stopComponentRequest(component)), + restartComponent: (component) => + dispatch(componentActions.restartComponentRequest(component)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Toolbar); diff --git a/src/components/page-environment/component-list-item.js b/src/components/page-environment/component-list-item.js index d8f5c0309..18f17856e 100644 --- a/src/components/page-environment/component-list-item.js +++ b/src/components/page-environment/component-list-item.js @@ -5,29 +5,43 @@ import { Link } from 'react-router-dom'; import * as routing from '../../utils/routing'; import ActiveComponentStatus from './active-component-status'; import environmentModel from '../../models/environment'; +import { componentType } from '../../models/component-type'; export const ComponentListItem = ({ appName, environment, components }) => { - return components.map((component) => ( -

- - {component.name}{' '} - - -

- )); + return components.map((component) => { + let activeComponentUrl = getActiveComponentUrl( + appName, + environment, + component + ); + return ( +

+ {component.name} + +

+ ); + }); }; +function getActiveComponentUrl(appName, environment, component) { + if (component.type === componentType.job) + return routing.getActiveScheduledJobUrl( + appName, + environment.name, + component.name + ); + return routing.getActiveComponentUrl( + appName, + environment.name, + component.name + ); +} + ComponentListItem.propTypes = { appName: PropTypes.string.isRequired, environment: PropTypes.shape(environmentModel), diff --git a/src/components/page-environment/index.js b/src/components/page-environment/index.js index 1da0e7efb..eb8dad97a 100644 --- a/src/components/page-environment/index.js +++ b/src/components/page-environment/index.js @@ -5,6 +5,7 @@ import EnvironmentOverview from './environment-overview'; import DocumentTitle from '../document-title'; import PageActiveComponent from '../page-active-component'; +import PageActiveScheduledJob from '../page-active-scheduled-job'; import { mapRouteParamsToProps } from '../../utils/routing'; import routes from '../../routes'; @@ -21,6 +22,10 @@ export const PageEnvironment = ({ appName, envName }) => { )} /> + ); }; diff --git a/src/components/page-scheduled-jobs/index.js b/src/components/page-scheduled-jobs/index.js new file mode 100644 index 000000000..a17026d57 --- /dev/null +++ b/src/components/page-scheduled-jobs/index.js @@ -0,0 +1,113 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import useGetEnvironment from '../page-environment/use-get-environment'; +import usePollLogs from './use-poll-logs'; +import useSelectScheduledJob from './use-select-scheduled-job'; + +import Breadcrumb from '../breadcrumb'; +import Code from '../code'; +import EnvironmentBadge from '../environment-badge'; +import ReplicaStatus from '../replica-status'; +import AsyncResource from '../async-resource/simple-async-resource'; + +import routes from '../../routes'; +import { mapRouteParamsToProps } from '../../utils/routing'; +import { routeWithParams, smallReplicaName } from '../../utils/string'; +import * as routing from '../../utils/routing'; +import ScheduledJobStatus from '../scheduled-job-status'; + +const STATUS_OK = 'Running'; + +const PageScheduledJob = (props) => { + const { + appName, + envName, + deploymentName, + componentName, + scheduledJobName, + } = props; + + const [getEnvironmentState] = useGetEnvironment(appName, envName); + const [pollLogsState] = usePollLogs( + appName, + deploymentName, + componentName, + scheduledJobName + ); + const replica = useSelectScheduledJob( + getEnvironmentState.data, + componentName, + scheduledJobName + ); + const scheduledJobStatus = replica ? replica.replicaStatus : null; + const scheduledJobLog = pollLogsState && pollLogsState.data; + + return ( + + , + to: routeWithParams(routes.appEnvironment, { + appName, + envName, + }), + }, + { + to: routeWithParams(routes.appActiveScheduledJob, { + appName, + envName, + componentName, + }), + label: componentName, + }, + { label: smallReplicaName(scheduledJobName) }, + ]} + /> +
+ + +
+
+

Overview

+

+ Scheduled Job {smallReplicaName(scheduledJobName)}, + job component {componentName} +

+

+ Status +

+ {scheduledJobStatus && scheduledJobStatus.status !== STATUS_OK && ( + +

Status message is:

+ {replica.statusMessage} +
+ )} +

Log

+ + {scheduledJobLog && {scheduledJobLog}} + +
+
+
+
+
+
+ ); +}; + +PageScheduledJob.propTypes = { + appName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, + deploymentName: PropTypes.string, + envName: PropTypes.string.isRequired, + scheduledJobName: PropTypes.string.isRequired, +}; + +export default mapRouteParamsToProps( + ['appName', 'envName', 'deploymentName', 'componentName', 'scheduledJobName'], + PageScheduledJob +); diff --git a/src/components/page-scheduled-jobs/use-poll-logs.js b/src/components/page-scheduled-jobs/use-poll-logs.js new file mode 100644 index 000000000..17aa14626 --- /dev/null +++ b/src/components/page-scheduled-jobs/use-poll-logs.js @@ -0,0 +1,13 @@ +import { usePollingPlain } from '../../effects'; + +const usePollLogs = (appName, deploymentName, componentName, scheduledJobName) => { + const encAppName = encodeURIComponent(appName); + const encDeployName = encodeURIComponent(deploymentName); + const encComponentName = encodeURIComponent(componentName); + const encScheduledJobName = encodeURIComponent(scheduledJobName); + const path = `/applications/${encAppName}/deployments/${encDeployName}/components/${encComponentName}/scheduledjob/${encScheduledJobName}/logs`; + + return usePollingPlain(path, 5000); +}; + +export default usePollLogs; diff --git a/src/components/page-scheduled-jobs/use-select-scheduled-job.js b/src/components/page-scheduled-jobs/use-select-scheduled-job.js new file mode 100644 index 000000000..9cb11e53a --- /dev/null +++ b/src/components/page-scheduled-jobs/use-select-scheduled-job.js @@ -0,0 +1,24 @@ +import { useState, useEffect } from 'react'; + +const useSelectScheduledJob = (environment, componentName, scheduledJobName) => { + const [scheduledJob, setScheduledJob] = useState(); + + useEffect(() => { + const deployment = environment ? environment.activeDeployment : null; + + const component = + deployment && deployment.components + ? deployment.components.find((comp) => comp.name === componentName) + : null; + + const selectedScheduledJob = + component && component.replicaList + ? component.replicaList.find((scheduledJob) => scheduledJob.name === scheduledJobName) + : null; + setScheduledJob(selectedScheduledJob); + }, [environment, componentName, scheduledJobName]); + + return scheduledJob; +}; + +export default useSelectScheduledJob; diff --git a/src/components/scheduled-job-status/index.js b/src/components/scheduled-job-status/index.js new file mode 100644 index 000000000..e2f073aa4 --- /dev/null +++ b/src/components/scheduled-job-status/index.js @@ -0,0 +1,22 @@ +import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import React from 'react'; + +import Chip, { progressStatusToChipType } from '../chip'; + +const STATUS_FAIL = 'Failing'; + +export const ScheduledJobStatus = ({ scheduledJob: scheduledJob }) => { + const status = scheduledJob ? scheduledJob.status : null; + if (status === STATUS_FAIL) { + return ( + + Failing + + ); + } + + return {status}; +}; + +export default ScheduledJobStatus; diff --git a/src/models/component-type/index.js b/src/models/component-type/index.js index 01e7a07b6..7d7f11f7f 100644 --- a/src/models/component-type/index.js +++ b/src/models/component-type/index.js @@ -2,6 +2,11 @@ import PropTypes from 'prop-types'; export default PropTypes.oneOf(['component', 'job']); +export const componentType = { + component: 'component', + job: 'job', +}; + const componentTypeLabel = { component: 'Component', job: 'Job' }; export const buildComponentTypeLabelMap = (type) => { diff --git a/src/routes.js b/src/routes.js index 8ff50d667..da650b418 100644 --- a/src/routes.js +++ b/src/routes.js @@ -17,6 +17,7 @@ export const routes = { appDeployments: '/applications/:appName/deployments', appEnvironment: '/applications/:appName/envs/:envName', appActiveComponent: '/applications/:appName/envs/:envName/component/:componentName', + appActiveScheduledJob: '/applications/:appName/envs/:envName/scheduledJob/:componentName', appEnvComponent: '/applications/:appName/envs/:envName/component/:componentName', appEnvironments: '/applications/:appName/envs', appJob: '/applications/:appName/jobs/view/:jobName', @@ -25,6 +26,7 @@ export const routes = { appJobStep: '/applications/:appName/jobs/view/:jobName/steps/:stepName', appPod: '/applications/:appName/envs/:envName/component/:componentName/pod/:podName', appReplica: '/applications/:appName/envs/:envName/component/:componentName/replica/:replicaName', + appScheduledJobs: '/applications/:appName/envs/:envName/component/:componentName/scheduledJobs/:scheduledJobName', appSecret: '/applications/:appName/envs/:envName/component/:componentName/secret/:secretName', appCreate: '/applications/new', diff --git a/src/utils/routing.js b/src/utils/routing.js index c26fbfb14..8571a2a0b 100644 --- a/src/utils/routing.js +++ b/src/utils/routing.js @@ -80,6 +80,13 @@ export const getActiveComponentUrl = (appName, envName, componentName) => componentName, }); +export const getActiveScheduledJobUrl = (appName, envName, componentName) => + routeWithParams(routes.appActiveScheduledJob, { + appName, + envName, + componentName, + }); + export const getReplicaUrl = (appName, envName, componentName, replicaName) => routeWithParams(routes.appReplica, { appName, @@ -88,6 +95,19 @@ export const getReplicaUrl = (appName, envName, componentName, replicaName) => replicaName, }); +export const getScheduledJobUrl = ( + appName, + envName, + componentName, + scheduledJobName +) => + routeWithParams(routes.appScheduledJobs, { + appName, + envName, + componentName, + scheduledJobName: scheduledJobName, + }); + export const getSecretUrl = (appName, envName, componentName, secretName) => routeWithParams(routes.appSecret, { appName, From 4f0eecb4cb3f21d505881429ad0d17cc8d8929da Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Wed, 31 Mar 2021 17:23:57 +0200 Subject: [PATCH 09/23] Added job logs --- src/components/configure-application-github/index.js | 2 +- .../active-scheduled-job-overview.js | 1 - src/components/page-active-scheduled-job/index.js | 8 ++++---- .../index.js | 6 +++--- .../use-poll-logs.js | 7 ++++++- .../use-select-scheduled-job.js | 10 ++++++++-- src/components/scheduled-job-status/index.js | 2 +- src/routes.js | 2 +- src/utils/routing.js | 4 ++-- 9 files changed, 26 insertions(+), 16 deletions(-) rename src/components/{page-scheduled-jobs => page-scheduled-job}/index.js (94%) rename src/components/{page-scheduled-jobs => page-scheduled-job}/use-poll-logs.js (84%) rename src/components/{page-scheduled-jobs => page-scheduled-job}/use-select-scheduled-job.js (74%) diff --git a/src/components/configure-application-github/index.js b/src/components/configure-application-github/index.js index 2bbd0f644..74918d2e3 100644 --- a/src/components/configure-application-github/index.js +++ b/src/components/configure-application-github/index.js @@ -76,7 +76,7 @@ export const ConfigureApplicationGithub = (props) => { setSavedSharedSecret(saveState.data.sharedSecret); resetSaveState(); onDeployKeyChange(app.name); - }, [saveState, resetSaveState, onDeployKeyChange]); + }, [saveState, resetSaveState, onDeployKeyChange, app.name]); const saveDeployKeySetting = () => { saveFunc(); diff --git a/src/components/page-active-scheduled-job/active-scheduled-job-overview.js b/src/components/page-active-scheduled-job/active-scheduled-job-overview.js index 0c92a4ac5..209552299 100644 --- a/src/components/page-active-scheduled-job/active-scheduled-job-overview.js +++ b/src/components/page-active-scheduled-job/active-scheduled-job-overview.js @@ -9,7 +9,6 @@ import Alert from '../alert'; import Breadcrumb from '../breadcrumb'; import DockerImage from '../docker-image'; import EnvironmentBadge from '../environment-badge'; -import ReplicaStatus from '../replica-status'; import SecretStatus from '../secret-status'; import AsyncResource from '../async-resource'; import Toolbar from './toolbar'; diff --git a/src/components/page-active-scheduled-job/index.js b/src/components/page-active-scheduled-job/index.js index a5a86f8bc..3b884bcb3 100644 --- a/src/components/page-active-scheduled-job/index.js +++ b/src/components/page-active-scheduled-job/index.js @@ -1,10 +1,10 @@ import { Route } from 'react-router'; import React from 'react'; -import ActiveComponentOverview from './active-scheduled-job-overview'; +import ActiveScheduledJobOverview from './active-scheduled-job-overview'; import DocumentTitle from '../document-title'; -import PageReplica from '../page-replica'; +import PageScheduledJob from '../page-scheduled-job'; import PageSecret from '../page-secret'; import { mapRouteParamsToProps } from '../../utils/routing'; @@ -17,14 +17,14 @@ export const PageActiveScheduledJob = ({ appName, envName, componentName }) => ( exact path={routes.appActiveScheduledJob} render={() => ( - )} /> - + ); diff --git a/src/components/page-scheduled-jobs/index.js b/src/components/page-scheduled-job/index.js similarity index 94% rename from src/components/page-scheduled-jobs/index.js rename to src/components/page-scheduled-job/index.js index a17026d57..29dff322b 100644 --- a/src/components/page-scheduled-jobs/index.js +++ b/src/components/page-scheduled-job/index.js @@ -8,7 +8,6 @@ import useSelectScheduledJob from './use-select-scheduled-job'; import Breadcrumb from '../breadcrumb'; import Code from '../code'; import EnvironmentBadge from '../environment-badge'; -import ReplicaStatus from '../replica-status'; import AsyncResource from '../async-resource/simple-async-resource'; import routes from '../../routes'; @@ -74,8 +73,9 @@ const PageScheduledJob = (props) => {

Overview

- Scheduled Job {smallReplicaName(scheduledJobName)}, - job component {componentName} + Scheduled Job{' '} + {smallReplicaName(scheduledJobName)}, job{' '} + component {componentName}

Status diff --git a/src/components/page-scheduled-jobs/use-poll-logs.js b/src/components/page-scheduled-job/use-poll-logs.js similarity index 84% rename from src/components/page-scheduled-jobs/use-poll-logs.js rename to src/components/page-scheduled-job/use-poll-logs.js index 17aa14626..75dab6180 100644 --- a/src/components/page-scheduled-jobs/use-poll-logs.js +++ b/src/components/page-scheduled-job/use-poll-logs.js @@ -1,6 +1,11 @@ import { usePollingPlain } from '../../effects'; -const usePollLogs = (appName, deploymentName, componentName, scheduledJobName) => { +const usePollLogs = ( + appName, + deploymentName, + componentName, + scheduledJobName +) => { const encAppName = encodeURIComponent(appName); const encDeployName = encodeURIComponent(deploymentName); const encComponentName = encodeURIComponent(componentName); diff --git a/src/components/page-scheduled-jobs/use-select-scheduled-job.js b/src/components/page-scheduled-job/use-select-scheduled-job.js similarity index 74% rename from src/components/page-scheduled-jobs/use-select-scheduled-job.js rename to src/components/page-scheduled-job/use-select-scheduled-job.js index 9cb11e53a..8032bafdf 100644 --- a/src/components/page-scheduled-jobs/use-select-scheduled-job.js +++ b/src/components/page-scheduled-job/use-select-scheduled-job.js @@ -1,6 +1,10 @@ import { useState, useEffect } from 'react'; -const useSelectScheduledJob = (environment, componentName, scheduledJobName) => { +const useSelectScheduledJob = ( + environment, + componentName, + scheduledJobName +) => { const [scheduledJob, setScheduledJob] = useState(); useEffect(() => { @@ -13,7 +17,9 @@ const useSelectScheduledJob = (environment, componentName, scheduledJobName) => const selectedScheduledJob = component && component.replicaList - ? component.replicaList.find((scheduledJob) => scheduledJob.name === scheduledJobName) + ? component.replicaList.find( + (scheduledJob) => scheduledJob.name === scheduledJobName + ) : null; setScheduledJob(selectedScheduledJob); }, [environment, componentName, scheduledJobName]); diff --git a/src/components/scheduled-job-status/index.js b/src/components/scheduled-job-status/index.js index e2f073aa4..176fad4f4 100644 --- a/src/components/scheduled-job-status/index.js +++ b/src/components/scheduled-job-status/index.js @@ -6,7 +6,7 @@ import Chip, { progressStatusToChipType } from '../chip'; const STATUS_FAIL = 'Failing'; -export const ScheduledJobStatus = ({ scheduledJob: scheduledJob }) => { +export const ScheduledJobStatus = ({ scheduledJob }) => { const status = scheduledJob ? scheduledJob.status : null; if (status === STATUS_FAIL) { return ( diff --git a/src/routes.js b/src/routes.js index da650b418..0fd0b446b 100644 --- a/src/routes.js +++ b/src/routes.js @@ -26,7 +26,7 @@ export const routes = { appJobStep: '/applications/:appName/jobs/view/:jobName/steps/:stepName', appPod: '/applications/:appName/envs/:envName/component/:componentName/pod/:podName', appReplica: '/applications/:appName/envs/:envName/component/:componentName/replica/:replicaName', - appScheduledJobs: '/applications/:appName/envs/:envName/component/:componentName/scheduledJobs/:scheduledJobName', + appScheduledJob: '/applications/:appName/envs/:envName/component/:componentName/scheduledJob/:scheduledJobName', appSecret: '/applications/:appName/envs/:envName/component/:componentName/secret/:secretName', appCreate: '/applications/new', diff --git a/src/utils/routing.js b/src/utils/routing.js index 8571a2a0b..bd6f74050 100644 --- a/src/utils/routing.js +++ b/src/utils/routing.js @@ -101,11 +101,11 @@ export const getScheduledJobUrl = ( componentName, scheduledJobName ) => - routeWithParams(routes.appScheduledJobs, { + routeWithParams(routes.appScheduledJob, { appName, envName, componentName, - scheduledJobName: scheduledJobName, + scheduledJobName, }); export const getSecretUrl = (appName, envName, componentName, secretName) => From b1b11483c3ab6ef5b157ad55401e60279ebf7883 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Wed, 31 Mar 2021 20:54:29 +0200 Subject: [PATCH 10/23] Added job list to component summary --- src/components/page-scheduled-job/index.js | 161 +++++++++--------- src/models/component/index.js | 2 + src/models/scheduled-job-summary/index.js | 12 ++ .../scheduled-job-summary/normaliser.js | 18 ++ src/models/scheduled-job-summary/test-data.js | 0 5 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 src/models/scheduled-job-summary/index.js create mode 100644 src/models/scheduled-job-summary/normaliser.js create mode 100644 src/models/scheduled-job-summary/test-data.js diff --git a/src/components/page-scheduled-job/index.js b/src/components/page-scheduled-job/index.js index 29dff322b..ec4ee553c 100644 --- a/src/components/page-scheduled-job/index.js +++ b/src/components/page-scheduled-job/index.js @@ -1,20 +1,20 @@ import React from 'react'; import PropTypes from 'prop-types'; -import useGetEnvironment from '../page-environment/use-get-environment'; -import usePollLogs from './use-poll-logs'; -import useSelectScheduledJob from './use-select-scheduled-job'; - -import Breadcrumb from '../breadcrumb'; -import Code from '../code'; -import EnvironmentBadge from '../environment-badge'; -import AsyncResource from '../async-resource/simple-async-resource'; - -import routes from '../../routes'; +// import useGetEnvironment from '../page-environment/use-get-environment'; +// import usePollLogs from './use-poll-logs'; +// import useSelectScheduledJob from './use-select-scheduled-job'; +// +// import Breadcrumb from '../breadcrumb'; +// import Code from '../code'; +// import EnvironmentBadge from '../environment-badge'; +// import AsyncResource from '../async-resource/simple-async-resource'; +// +// import routes from '../../routes'; import { mapRouteParamsToProps } from '../../utils/routing'; -import { routeWithParams, smallReplicaName } from '../../utils/string'; -import * as routing from '../../utils/routing'; -import ScheduledJobStatus from '../scheduled-job-status'; +// import { routeWithParams, smallReplicaName } from '../../utils/string'; +// import * as routing from '../../utils/routing'; +// import ScheduledJobStatus from '../scheduled-job-status'; const STATUS_OK = 'Running'; @@ -27,75 +27,76 @@ const PageScheduledJob = (props) => { scheduledJobName, } = props; - const [getEnvironmentState] = useGetEnvironment(appName, envName); - const [pollLogsState] = usePollLogs( - appName, - deploymentName, - componentName, - scheduledJobName - ); - const replica = useSelectScheduledJob( - getEnvironmentState.data, - componentName, - scheduledJobName - ); - const scheduledJobStatus = replica ? replica.replicaStatus : null; - const scheduledJobLog = pollLogsState && pollLogsState.data; + // const [getEnvironmentState] = useGetEnvironment(appName, envName); + // const [pollLogsState] = usePollLogs( + // appName, + // deploymentName, + // componentName, + // scheduledJobName + // ); + // const replica = useSelectScheduledJob( + // getEnvironmentState.data, + // componentName, + // scheduledJobName + // ); + // const scheduledJobStatus = replica ? replica.replicaStatus : null; + // const scheduledJobLog = pollLogsState && pollLogsState.data; return ( - - , - to: routeWithParams(routes.appEnvironment, { - appName, - envName, - }), - }, - { - to: routeWithParams(routes.appActiveScheduledJob, { - appName, - envName, - componentName, - }), - label: componentName, - }, - { label: smallReplicaName(scheduledJobName) }, - ]} - /> -

- - -
-
-

Overview

-

- Scheduled Job{' '} - {smallReplicaName(scheduledJobName)}, job{' '} - component {componentName} -

-

- Status -

- {scheduledJobStatus && scheduledJobStatus.status !== STATUS_OK && ( - -

Status message is:

- {replica.statusMessage} -
- )} -

Log

- - {scheduledJobLog && {scheduledJobLog}} - -
-
-
-
-
- +

{appName}

+ // + // , + // to: routeWithParams(routes.appEnvironment, { + // appName, + // envName, + // }), + // }, + // { + // to: routeWithParams(routes.appActiveScheduledJob, { + // appName, + // envName, + // componentName, + // }), + // label: componentName, + // }, + // { label: smallReplicaName(scheduledJobName) }, + // ]} + // /> + //
+ // + // + //
+ //
+ //

Overview

+ //

+ // Scheduled Job{' '} + // {smallReplicaName(scheduledJobName)}, job{' '} + // component {componentName} + //

+ //

+ // Status + //

+ // {scheduledJobStatus && scheduledJobStatus.status !== STATUS_OK && ( + // + //

Status message is:

+ // {replica.statusMessage} + //
+ // )} + //

Log

+ // + // {scheduledJobLog && {scheduledJobLog}} + // + //
+ //
+ //
+ //
+ //
+ //
); }; diff --git a/src/models/component/index.js b/src/models/component/index.js index c70129ea6..d289fc930 100644 --- a/src/models/component/index.js +++ b/src/models/component/index.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import PortModel from '../port'; import ReplicaSummaryModel from '../replica-summary'; +import ScheduledJobSummaryModel from '../scheduled-job-summary'; import ComponentType from '../component-type'; export default Object.freeze({ @@ -11,6 +12,7 @@ export default Object.freeze({ status: PropTypes.string.isRequired, ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), + scheduledJobList: PropTypes.arrayOf(PropTypes.exact(ScheduledJobSummaryModel)), secrets: PropTypes.arrayOf(PropTypes.string), variables: PropTypes.objectOf(PropTypes.string), horizontalScalingSummary: PropTypes.objectOf(PropTypes.number), diff --git a/src/models/scheduled-job-summary/index.js b/src/models/scheduled-job-summary/index.js new file mode 100644 index 000000000..21b5841dc --- /dev/null +++ b/src/models/scheduled-job-summary/index.js @@ -0,0 +1,12 @@ +import PropTypes from 'prop-types'; +import ProgressStatusModel from '../progress-status'; +import ReplicaSummaryModel from '../replica-summary'; + +export default Object.freeze({ + created: PropTypes.instanceOf(Date).isRequired, + ended: PropTypes.instanceOf(Date), + name: PropTypes.string.isRequired, + started: PropTypes.instanceOf(Date), + status: ProgressStatusModel.isRequired, + replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), +}); diff --git a/src/models/scheduled-job-summary/normaliser.js b/src/models/scheduled-job-summary/normaliser.js new file mode 100644 index 000000000..d6313134f --- /dev/null +++ b/src/models/scheduled-job-summary/normaliser.js @@ -0,0 +1,18 @@ +import pick from 'lodash/pick'; + +import model from '.'; + +/** + * Create a Pipeline Job Summary object + */ +export const normaliser = (props) => { + const jobSummary = pick(props, Object.keys(model)); + + jobSummary.started = jobSummary.started ? new Date(jobSummary.started) : null; + jobSummary.ended = jobSummary.ended ? new Date(jobSummary.ended) : null; + jobSummary.created = jobSummary.created ? new Date(jobSummary.created) : null; + + return Object.freeze(jobSummary); +}; + +export default normaliser; diff --git a/src/models/scheduled-job-summary/test-data.js b/src/models/scheduled-job-summary/test-data.js new file mode 100644 index 000000000..e69de29bb From 6ce84801e119a35adc84ffe480540d08ebe9b0b7 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Wed, 7 Apr 2021 11:51:33 +0200 Subject: [PATCH 11/23] Fixed unit-tests --- .../use-select-scheduled-job.js | 4 +- src/models/component-summary/test-data.js | 2 + src/models/component/index.js | 4 +- src/models/job/test-data.js | 2 + src/models/scheduled-job-summary/test-data.js | 46 +++++++++++++++++++ 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/components/page-scheduled-job/use-select-scheduled-job.js b/src/components/page-scheduled-job/use-select-scheduled-job.js index 8032bafdf..dbec393c0 100644 --- a/src/components/page-scheduled-job/use-select-scheduled-job.js +++ b/src/components/page-scheduled-job/use-select-scheduled-job.js @@ -16,8 +16,8 @@ const useSelectScheduledJob = ( : null; const selectedScheduledJob = - component && component.replicaList - ? component.replicaList.find( + component && component.scheduledJobList + ? component.scheduledJobList.find( (scheduledJob) => scheduledJob.name === scheduledJobName ) : null; diff --git a/src/models/component-summary/test-data.js b/src/models/component-summary/test-data.js index ddeeb2d3d..36802a846 100644 --- a/src/models/component-summary/test-data.js +++ b/src/models/component-summary/test-data.js @@ -3,11 +3,13 @@ export const testData = [ __testDescription: 'Normal component', name: 'component-a', image: 'an-image', + type: 'component', }, { __testDescription: 'Missing image', __testIsInvalidSample: true, name: 'component-b', + type: 'component', }, ]; diff --git a/src/models/component/index.js b/src/models/component/index.js index d289fc930..20d961d4a 100644 --- a/src/models/component/index.js +++ b/src/models/component/index.js @@ -12,7 +12,9 @@ export default Object.freeze({ status: PropTypes.string.isRequired, ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), - scheduledJobList: PropTypes.arrayOf(PropTypes.exact(ScheduledJobSummaryModel)), + scheduledJobList: PropTypes.arrayOf( + PropTypes.exact(ScheduledJobSummaryModel) + ), secrets: PropTypes.arrayOf(PropTypes.string), variables: PropTypes.objectOf(PropTypes.string), horizontalScalingSummary: PropTypes.objectOf(PropTypes.number), diff --git a/src/models/job/test-data.js b/src/models/job/test-data.js index f638dd026..1cb3c8f71 100644 --- a/src/models/job/test-data.js +++ b/src/models/job/test-data.js @@ -14,10 +14,12 @@ const normalComponents = Object.freeze([ { name: 'component-a', image: 'an-image', + type: 'component', }, { name: 'component-b', image: 'another-image', + type: 'component', }, ]); diff --git a/src/models/scheduled-job-summary/test-data.js b/src/models/scheduled-job-summary/test-data.js index e69de29bb..9acd3e536 100644 --- a/src/models/scheduled-job-summary/test-data.js +++ b/src/models/scheduled-job-summary/test-data.js @@ -0,0 +1,46 @@ +const normalReplicas = Object.freeze([ + { + __testDescription: 'Running', + name: 'a-replica', + replicaStatus: { status: 'Running' }, + }, + { + __testDescription: 'Starting', + name: 'b-replica', + replicaStatus: { status: 'Pending' }, + }, + { + __testDescription: 'Failing', + name: 'c-replica', + replicaStatus: { status: 'Failing' }, + statusMessage: 'Some error message', + }, + { + __testDescription: 'Wrong status', + __testIsInvalidSample: true, + name: 'd-replica', + replicaStatus: { status: 'Waiting' }, + }, +]); + +export const testData = [ + { + __testDescription: 'Valid Running', + name: 'A Job', + created: '2018-11-19T14:31:23Z', + ended: '2018-11-19T14:32:23Z', + started: '2018-11-19T14:31:23Z', + status: 'Running', + replicaList: normalReplicas, + }, + { + __testDescription: 'Valid Running not ended', + name: 'A Job', + created: '2018-11-19T14:31:23Z', + started: '2018-11-19T14:31:23Z', + status: 'Running', + replicaList: normalReplicas, + }, +]; + +export default testData; From 3d0aa4ac23277dbad13fc54afd9e59b336b66135 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Thu, 8 Apr 2021 18:03:21 +0200 Subject: [PATCH 12/23] Fixed scheduled job form --- proxy/server.dev.conf | 2 +- .../active-job-component-overview.js} | 79 ++------ .../index.js | 22 ++- .../toolbar.js | 0 .../page-environment/component-list-item.js | 2 +- src/components/page-environment/index.js | 6 +- src/components/page-scheduled-job/index.js | 181 ++++++++++-------- .../page-scheduled-job/use-poll-logs.js | 6 +- .../use-select-scheduled-job.js | 6 +- src/components/scheduled-job-status/index.js | 3 +- src/models/scheduled-job-summary/index.js | 2 +- src/routes.js | 4 +- src/utils/routing.js | 12 +- src/utils/string.js | 2 + 14 files changed, 145 insertions(+), 182 deletions(-) rename src/components/{page-active-scheduled-job/active-scheduled-job-overview.js => page-active-job-component/active-job-component-overview.js} (73%) rename src/components/{page-active-scheduled-job => page-active-job-component}/index.js (61%) rename src/components/{page-active-scheduled-job => page-active-job-component}/toolbar.js (100%) diff --git a/proxy/server.dev.conf b/proxy/server.dev.conf index 1660572ef..2384336dc 100644 --- a/proxy/server.dev.conf +++ b/proxy/server.dev.conf @@ -6,7 +6,7 @@ server { error_page 500 502 503 504 /50x.html; location /api/ { - proxy_pass https://server-radix-api-qa.dev.radix.equinor.com; + proxy_pass https://server-radix-api-dev.dev.radix.equinor.com; proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; proxy_set_header x-forwarded-access-token ""; } diff --git a/src/components/page-active-scheduled-job/active-scheduled-job-overview.js b/src/components/page-active-job-component/active-job-component-overview.js similarity index 73% rename from src/components/page-active-scheduled-job/active-scheduled-job-overview.js rename to src/components/page-active-job-component/active-job-component-overview.js index 209552299..1187a8502 100644 --- a/src/components/page-active-scheduled-job/active-scheduled-job-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -13,9 +13,8 @@ import SecretStatus from '../secret-status'; import AsyncResource from '../async-resource'; import Toolbar from './toolbar'; -import { getAppAlias } from '../../state/application'; import { getComponent, getSecret } from '../../state/environment'; -import { routeWithParams, smallReplicaName } from '../../utils/string'; +import { routeWithParams, smallScheduledJobName } from '../../utils/string'; import * as routing from '../../utils/routing'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; @@ -84,21 +83,15 @@ export class ActiveScheduledJobOverview extends React.Component { render() { const { - appAlias, appName, envName, - componentName, + jobComponentName, component, getEnvSecret, } = this.props; const envVarNames = component && Object.keys(component.variables); - const isDefaultAlias = - appAlias && - appAlias.componentName === componentName && - appAlias.environmentName === envName; - return (
@@ -157,15 +150,6 @@ export class ActiveScheduledJobOverview extends React.Component {

)} - {isDefaultAlias && ( - - This component is the application{' '} - - default alias{' '} - - - - )}

Image

@@ -191,53 +175,20 @@ export class ActiveScheduledJobOverview extends React.Component { )}
- {component.horizontalScalingSummary && ( - -

- Horizontal scaling -

-
-
Min replicas:
-
- {component.horizontalScalingSummary.minReplicas} -
-
Max replicas:
-
- {component.horizontalScalingSummary.maxReplicas} -
-
Current average CPU utilization:
-
- { - component.horizontalScalingSummary - .currentCPUUtilizationPercentage - } - % -
-
Target average CPU utilization:
-
- { - component.horizontalScalingSummary - .targetCPUUtilizationPercentage - } - % -
-
-
- )}

Scheduled Job

- {component.replicaList.map((scheduledJob) => ( + {component.scheduledJobList.map((scheduledJob) => (

- {smallReplicaName(scheduledJob.name)}{' '} + {smallScheduledJobName(scheduledJob.name)}{' '} - +

))}

Secrets

@@ -252,7 +203,7 @@ export class ActiveScheduledJobOverview extends React.Component { to={routing.getSecretUrl( appName, envName, - componentName, + jobComponentName, secretName )} > @@ -275,24 +226,18 @@ export class ActiveScheduledJobOverview extends React.Component { } ActiveScheduledJobOverview.propTypes = { - appAlias: PropTypes.exact({ - componentName: PropTypes.string.isRequired, - environmentName: PropTypes.string.isRequired, - url: PropTypes.string.isRequired, - }), appName: PropTypes.string.isRequired, envName: PropTypes.string.isRequired, - componentName: PropTypes.string.isRequired, + jobComponentName: PropTypes.string.isRequired, component: PropTypes.shape(componentModel), getEnvSecret: PropTypes.func.isRequired, subscribe: PropTypes.func.isRequired, unsubscribe: PropTypes.func.isRequired, }; -const mapStateToProps = (state, { componentName }) => ({ - appAlias: getAppAlias(state), - component: getComponent(state, componentName), - getEnvSecret: (secretName) => getSecret(state, componentName, secretName), +const mapStateToProps = (state, { jobComponentName }) => ({ + component: getComponent(state, jobComponentName), + getEnvSecret: (secretName) => getSecret(state, jobComponentName, secretName), }); const mapDispatchToProps = (dispatch) => ({ diff --git a/src/components/page-active-scheduled-job/index.js b/src/components/page-active-job-component/index.js similarity index 61% rename from src/components/page-active-scheduled-job/index.js rename to src/components/page-active-job-component/index.js index 3b884bcb3..c4df5bdff 100644 --- a/src/components/page-active-scheduled-job/index.js +++ b/src/components/page-active-job-component/index.js @@ -1,26 +1,30 @@ import { Route } from 'react-router'; import React from 'react'; -import ActiveScheduledJobOverview from './active-scheduled-job-overview'; +import ActiveJobComponentOverview from './active-job-component-overview'; import DocumentTitle from '../document-title'; -import PageScheduledJob from '../page-scheduled-job'; import PageSecret from '../page-secret'; import { mapRouteParamsToProps } from '../../utils/routing'; import routes from '../../routes'; +import PageScheduledJob from '../page-scheduled-job'; -export const PageActiveScheduledJob = ({ appName, envName, componentName }) => ( +export const PageActiveJobComponent = ({ + appName, + envName, + jobComponentName, +}) => ( - + ( - )} /> @@ -30,6 +34,6 @@ export const PageActiveScheduledJob = ({ appName, envName, componentName }) => ( ); export default mapRouteParamsToProps( - ['appName', 'envName', 'componentName'], - PageActiveScheduledJob + ['appName', 'envName', 'jobComponentName'], + PageActiveJobComponent ); diff --git a/src/components/page-active-scheduled-job/toolbar.js b/src/components/page-active-job-component/toolbar.js similarity index 100% rename from src/components/page-active-scheduled-job/toolbar.js rename to src/components/page-active-job-component/toolbar.js diff --git a/src/components/page-environment/component-list-item.js b/src/components/page-environment/component-list-item.js index 18f17856e..5fbdef102 100644 --- a/src/components/page-environment/component-list-item.js +++ b/src/components/page-environment/component-list-item.js @@ -30,7 +30,7 @@ export const ComponentListItem = ({ appName, environment, components }) => { function getActiveComponentUrl(appName, environment, component) { if (component.type === componentType.job) - return routing.getActiveScheduledJobUrl( + return routing.getActiveJobComponentUrl( appName, environment.name, component.name diff --git a/src/components/page-environment/index.js b/src/components/page-environment/index.js index eb8dad97a..a580d4506 100644 --- a/src/components/page-environment/index.js +++ b/src/components/page-environment/index.js @@ -5,7 +5,7 @@ import EnvironmentOverview from './environment-overview'; import DocumentTitle from '../document-title'; import PageActiveComponent from '../page-active-component'; -import PageActiveScheduledJob from '../page-active-scheduled-job'; +import PageActiveJobComponent from '../page-active-job-component'; import { mapRouteParamsToProps } from '../../utils/routing'; import routes from '../../routes'; @@ -23,8 +23,8 @@ export const PageEnvironment = ({ appName, envName }) => { /> ); diff --git a/src/components/page-scheduled-job/index.js b/src/components/page-scheduled-job/index.js index ec4ee553c..dc489fc10 100644 --- a/src/components/page-scheduled-job/index.js +++ b/src/components/page-scheduled-job/index.js @@ -1,20 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; -// import useGetEnvironment from '../page-environment/use-get-environment'; -// import usePollLogs from './use-poll-logs'; -// import useSelectScheduledJob from './use-select-scheduled-job'; -// -// import Breadcrumb from '../breadcrumb'; -// import Code from '../code'; -// import EnvironmentBadge from '../environment-badge'; -// import AsyncResource from '../async-resource/simple-async-resource'; -// -// import routes from '../../routes'; +import useGetEnvironment from '../page-environment/use-get-environment'; +import usePollLogs from './use-poll-logs'; +import useSelectScheduledJob from './use-select-scheduled-job'; + +import Breadcrumb from '../breadcrumb'; +import Code from '../code'; +import EnvironmentBadge from '../environment-badge'; +import ScheduledJobStatus from '../scheduled-job-status'; +import AsyncResource from '../async-resource/simple-async-resource'; + +import routes from '../../routes'; import { mapRouteParamsToProps } from '../../utils/routing'; -// import { routeWithParams, smallReplicaName } from '../../utils/string'; -// import * as routing from '../../utils/routing'; -// import ScheduledJobStatus from '../scheduled-job-status'; +import { routeWithParams, smallScheduledJobName } from '../../utils/string'; +import * as routing from '../../utils/routing'; +import RelativeToNow from '../time/relative-to-now'; const STATUS_OK = 'Running'; @@ -23,92 +24,104 @@ const PageScheduledJob = (props) => { appName, envName, deploymentName, - componentName, + jobComponentName, scheduledJobName, } = props; - // const [getEnvironmentState] = useGetEnvironment(appName, envName); - // const [pollLogsState] = usePollLogs( - // appName, - // deploymentName, - // componentName, - // scheduledJobName - // ); - // const replica = useSelectScheduledJob( - // getEnvironmentState.data, - // componentName, - // scheduledJobName - // ); - // const scheduledJobStatus = replica ? replica.replicaStatus : null; - // const scheduledJobLog = pollLogsState && pollLogsState.data; + const [getEnvironmentState] = useGetEnvironment(appName, envName); + const [pollLogsState] = usePollLogs( + appName, + deploymentName, + jobComponentName, + scheduledJobName + ); + const scheduledJob = useSelectScheduledJob( + getEnvironmentState.data, + jobComponentName, + scheduledJobName + ); + const scheduledJobStatus = scheduledJob ? scheduledJob.status : null; + const scheduledJobCreated = scheduledJob ? scheduledJob.created : null; + const scheduledJobLog = pollLogsState && pollLogsState.data; return ( -

{appName}

- // - // , - // to: routeWithParams(routes.appEnvironment, { - // appName, - // envName, - // }), - // }, - // { - // to: routeWithParams(routes.appActiveScheduledJob, { - // appName, - // envName, - // componentName, - // }), - // label: componentName, - // }, - // { label: smallReplicaName(scheduledJobName) }, - // ]} - // /> - //
- // - // - //
- //
- //

Overview

- //

- // Scheduled Job{' '} - // {smallReplicaName(scheduledJobName)}, job{' '} - // component {componentName} - //

- //

- // Status - //

- // {scheduledJobStatus && scheduledJobStatus.status !== STATUS_OK && ( - // - //

Status message is:

- // {replica.statusMessage} - //
- // )} - //

Log

- // - // {scheduledJobLog && {scheduledJobLog}} - // - //
- //
- //
- //
- //
- //
+ + , + to: routeWithParams(routes.appEnvironment, { + appName, + envName, + }), + }, + { + to: routeWithParams(routes.appActiveJobComponent, { + appName, + envName, + jobComponentName, + }), + label: jobComponentName, + }, + { label: smallScheduledJobName(scheduledJobName) }, + ]} + /> +
+ + +
+
+

Overview

+

+ Scheduled Job{' '} + {smallScheduledJobName(scheduledJobName)}, + Job {jobComponentName} +

+

+ Status +

+ {scheduledJob && ( +
+

Created: {scheduledJob.created}

+

Started: {scheduledJob.started}

+

Ended: {scheduledJob.ended}

+
+ )} + {scheduledJobLog && ( +

+

Log

+ + {scheduledJobLog && {scheduledJobLog}} + +

+ )} + {!scheduledJobLog &&

No logs

} +
+
+
+
+
+
); }; PageScheduledJob.propTypes = { appName: PropTypes.string.isRequired, - componentName: PropTypes.string.isRequired, + jobComponentName: PropTypes.string.isRequired, deploymentName: PropTypes.string, envName: PropTypes.string.isRequired, scheduledJobName: PropTypes.string.isRequired, }; export default mapRouteParamsToProps( - ['appName', 'envName', 'deploymentName', 'componentName', 'scheduledJobName'], + [ + 'appName', + 'envName', + 'deploymentName', + 'jobComponentName', + 'scheduledJobName', + ], PageScheduledJob ); diff --git a/src/components/page-scheduled-job/use-poll-logs.js b/src/components/page-scheduled-job/use-poll-logs.js index 75dab6180..95e31dfb1 100644 --- a/src/components/page-scheduled-job/use-poll-logs.js +++ b/src/components/page-scheduled-job/use-poll-logs.js @@ -3,14 +3,14 @@ import { usePollingPlain } from '../../effects'; const usePollLogs = ( appName, deploymentName, - componentName, + jobComponentName, scheduledJobName ) => { const encAppName = encodeURIComponent(appName); const encDeployName = encodeURIComponent(deploymentName); - const encComponentName = encodeURIComponent(componentName); + const encJobComponentName = encodeURIComponent(jobComponentName); const encScheduledJobName = encodeURIComponent(scheduledJobName); - const path = `/applications/${encAppName}/deployments/${encDeployName}/components/${encComponentName}/scheduledjob/${encScheduledJobName}/logs`; + const path = `/applications/${encAppName}/deployments/${encDeployName}/jobcomponents/${encJobComponentName}/scheduledjobs/${encScheduledJobName}/logs`; return usePollingPlain(path, 5000); }; diff --git a/src/components/page-scheduled-job/use-select-scheduled-job.js b/src/components/page-scheduled-job/use-select-scheduled-job.js index dbec393c0..03bdf9316 100644 --- a/src/components/page-scheduled-job/use-select-scheduled-job.js +++ b/src/components/page-scheduled-job/use-select-scheduled-job.js @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react'; const useSelectScheduledJob = ( environment, - componentName, + jobComponentName, scheduledJobName ) => { const [scheduledJob, setScheduledJob] = useState(); @@ -12,7 +12,7 @@ const useSelectScheduledJob = ( const component = deployment && deployment.components - ? deployment.components.find((comp) => comp.name === componentName) + ? deployment.components.find((comp) => comp.name === jobComponentName) : null; const selectedScheduledJob = @@ -22,7 +22,7 @@ const useSelectScheduledJob = ( ) : null; setScheduledJob(selectedScheduledJob); - }, [environment, componentName, scheduledJobName]); + }, [environment, jobComponentName, scheduledJobName]); return scheduledJob; }; diff --git a/src/components/scheduled-job-status/index.js b/src/components/scheduled-job-status/index.js index 176fad4f4..908c677d5 100644 --- a/src/components/scheduled-job-status/index.js +++ b/src/components/scheduled-job-status/index.js @@ -6,8 +6,7 @@ import Chip, { progressStatusToChipType } from '../chip'; const STATUS_FAIL = 'Failing'; -export const ScheduledJobStatus = ({ scheduledJob }) => { - const status = scheduledJob ? scheduledJob.status : null; +export const ScheduledJobStatus = ({ status }) => { if (status === STATUS_FAIL) { return ( diff --git a/src/models/scheduled-job-summary/index.js b/src/models/scheduled-job-summary/index.js index 21b5841dc..d5f313e62 100644 --- a/src/models/scheduled-job-summary/index.js +++ b/src/models/scheduled-job-summary/index.js @@ -3,7 +3,7 @@ import ProgressStatusModel from '../progress-status'; import ReplicaSummaryModel from '../replica-summary'; export default Object.freeze({ - created: PropTypes.instanceOf(Date).isRequired, + created: PropTypes.instanceOf(Date), ended: PropTypes.instanceOf(Date), name: PropTypes.string.isRequired, started: PropTypes.instanceOf(Date), diff --git a/src/routes.js b/src/routes.js index 0fd0b446b..1b5afe78e 100644 --- a/src/routes.js +++ b/src/routes.js @@ -17,7 +17,7 @@ export const routes = { appDeployments: '/applications/:appName/deployments', appEnvironment: '/applications/:appName/envs/:envName', appActiveComponent: '/applications/:appName/envs/:envName/component/:componentName', - appActiveScheduledJob: '/applications/:appName/envs/:envName/scheduledJob/:componentName', + appActiveJobComponent: '/applications/:appName/envs/:envName/jobcomponent/:jobComponentName', appEnvComponent: '/applications/:appName/envs/:envName/component/:componentName', appEnvironments: '/applications/:appName/envs', appJob: '/applications/:appName/jobs/view/:jobName', @@ -26,7 +26,7 @@ export const routes = { appJobStep: '/applications/:appName/jobs/view/:jobName/steps/:stepName', appPod: '/applications/:appName/envs/:envName/component/:componentName/pod/:podName', appReplica: '/applications/:appName/envs/:envName/component/:componentName/replica/:replicaName', - appScheduledJob: '/applications/:appName/envs/:envName/component/:componentName/scheduledJob/:scheduledJobName', + appScheduledJob: '/applications/:appName/envs/:envName/jobcomponent/:jobComponentName/scheduledjob/:scheduledJobName', appSecret: '/applications/:appName/envs/:envName/component/:componentName/secret/:secretName', appCreate: '/applications/new', diff --git a/src/utils/routing.js b/src/utils/routing.js index bd6f74050..9a08b3d73 100644 --- a/src/utils/routing.js +++ b/src/utils/routing.js @@ -18,7 +18,7 @@ import routes from '../routes'; * @todo Support object (key => function) as paramsToMap (like mapStateToProps) * * @param {string[]} paramsToMap List of URL parameters to inject as props - * @param {React.Component} Component Component to receive props + * @param {function(*)} Component Component to receive props */ export function mapRouteParamsToProps(paramsToMap, Component) { return withRouter((props) => { @@ -80,11 +80,11 @@ export const getActiveComponentUrl = (appName, envName, componentName) => componentName, }); -export const getActiveScheduledJobUrl = (appName, envName, componentName) => - routeWithParams(routes.appActiveScheduledJob, { +export const getActiveJobComponentUrl = (appName, envName, jobComponentName) => + routeWithParams(routes.appActiveJobComponent, { appName, envName, - componentName, + jobComponentName, }); export const getReplicaUrl = (appName, envName, componentName, replicaName) => @@ -98,13 +98,13 @@ export const getReplicaUrl = (appName, envName, componentName, replicaName) => export const getScheduledJobUrl = ( appName, envName, - componentName, + jobComponentName, scheduledJobName ) => routeWithParams(routes.appScheduledJob, { appName, envName, - componentName, + jobComponentName, scheduledJobName, }); diff --git a/src/utils/string.js b/src/utils/string.js index 144de4b0d..444ef14ae 100644 --- a/src/utils/string.js +++ b/src/utils/string.js @@ -69,3 +69,5 @@ export const smallDeploymentName = (() => { export const smallJobName = (jobName) => jobName.slice(-5); export const smallReplicaName = (replicaName) => replicaName.slice(-5); + +export const smallScheduledJobName = (scheduledJob) => scheduledJob.slice(-8); From a1743b4bac516248faf307c20f00aa51e09bb511 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 9 Apr 2021 13:51:56 +0200 Subject: [PATCH 13/23] Added time and durations --- .../active-component-overview.js | 16 +++++- .../active-job-component-overview.js | 14 +++--- src/components/page-replica/index.js | 36 +++++++++++-- .../page-replica/use-select-replica.js | 3 +- src/components/page-scheduled-job/index.js | 50 +++++++++++++++---- .../use-select-scheduled-job.js | 3 +- src/models/component/normaliser.js | 5 ++ src/models/replica-summary/index.js | 2 + src/models/replica-summary/normaliser.js | 6 +++ 9 files changed, 109 insertions(+), 26 deletions(-) diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index 46c672fd6..0ea9292ff 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -3,7 +3,7 @@ import { faLink } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useState } from 'react'; import Alert from '../alert'; import Breadcrumb from '../breadcrumb'; @@ -21,6 +21,8 @@ import * as routing from '../../utils/routing'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; import routes from '../../routes'; +import RelativeToNow from '../time/relative-to-now'; +import Duration from '../time/duration'; const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; @@ -64,13 +66,15 @@ const Vars = ({ envVarNames, component }) => { ); }; +let now = Date(); + export class ActiveComponentOverview extends React.Component { componentDidMount() { this.props.subscribe(this.props.appName, this.props.envName); } - componentDidUpdate(prevProps) { const { appName, envName } = this.props; + now = new Date(); if (appName !== prevProps.appName || envName !== prevProps.envName) { this.props.unsubscribe(prevProps.appName, prevProps.envName); @@ -238,6 +242,14 @@ export class ActiveComponentOverview extends React.Component { {smallReplicaName(replica.name)}{' '} +    Created{' '} + + + +     Duration{' '} + + +

))}

Secrets

diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 1187a8502..6cc2fe6ba 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -20,6 +20,7 @@ import * as subscriptionActions from '../../state/subscriptions/action-creators' import componentModel from '../../models/component'; import routes from '../../routes'; import ScheduledJobStatus from '../scheduled-job-status'; +import RelativeToNow from '../time/relative-to-now'; const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; @@ -115,16 +116,11 @@ export class ActiveScheduledJobOverview extends React.Component { > {component && ( -

Overview

- Component {component.name} + Job {component.name}

{component.status === 'Stopped' && ( @@ -189,6 +185,12 @@ export class ActiveScheduledJobOverview extends React.Component { {smallScheduledJobName(scheduledJob.name)}{' '} +    Created{' '} + + +

))}

Secrets

diff --git a/src/components/page-replica/index.js b/src/components/page-replica/index.js index 1ee7037ff..acfba82e1 100644 --- a/src/components/page-replica/index.js +++ b/src/components/page-replica/index.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import useGetEnvironment from '../page-environment/use-get-environment'; @@ -15,6 +15,8 @@ import routes from '../../routes'; import { mapRouteParamsToProps } from '../../utils/routing'; import { routeWithParams, smallReplicaName } from '../../utils/string'; import * as routing from '../../utils/routing'; +import RelativeToNow from '../time/relative-to-now'; +import Duration from '../time/duration'; const STATUS_OK = 'Running'; @@ -39,8 +41,9 @@ const PageReplica = (props) => { componentName, replicaName ); - const replicaStatus = replica ? replica.replicaStatus : null; + const [now, setNow] = useState(new Date()); const replicaLog = pollLogsState && pollLogsState.data; + const selectedReplica = replica; return ( @@ -76,15 +79,38 @@ const PageReplica = (props) => { Replica {smallReplicaName(replicaName)}, component {componentName}

+ {selectedReplica && ( +
+

+ Created{' '} + + + +

+

+ Duration{' '} + + + +

+
+ )}

- Status + Status

- {replicaStatus && replicaStatus.status !== STATUS_OK && ( + {selectedReplica && selectedReplica.status !== STATUS_OK && (

Status message is:

- {replica.statusMessage} + {selectedReplica.statusMessage}
)} + {selectedReplica && + selectedReplica.restartCount != NaN && + selectedReplica.restartCount > 0 && ( +

Restarted {selectedReplica.restartCount} times

+ )}

Log

{replicaLog && {replicaLog}} diff --git a/src/components/page-replica/use-select-replica.js b/src/components/page-replica/use-select-replica.js index a8b4460f0..6e8bc03b9 100644 --- a/src/components/page-replica/use-select-replica.js +++ b/src/components/page-replica/use-select-replica.js @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import replicaSummaryNormaliser from '../../models/replica-summary/normaliser'; const useSelectReplica = (environment, componentName, replicaName) => { const [replica, setReplica] = useState(); @@ -15,7 +16,7 @@ const useSelectReplica = (environment, componentName, replicaName) => { component && component.replicaList ? component.replicaList.find((replica) => replica.name === replicaName) : null; - setReplica(selectedReplica); + setReplica(replicaSummaryNormaliser(selectedReplica)); }, [environment, componentName, replicaName]); return replica; diff --git a/src/components/page-scheduled-job/index.js b/src/components/page-scheduled-job/index.js index dc489fc10..0137fad45 100644 --- a/src/components/page-scheduled-job/index.js +++ b/src/components/page-scheduled-job/index.js @@ -16,8 +16,7 @@ import { mapRouteParamsToProps } from '../../utils/routing'; import { routeWithParams, smallScheduledJobName } from '../../utils/string'; import * as routing from '../../utils/routing'; import RelativeToNow from '../time/relative-to-now'; - -const STATUS_OK = 'Running'; +import Duration from '../time/duration'; const PageScheduledJob = (props) => { const { @@ -41,7 +40,6 @@ const PageScheduledJob = (props) => { scheduledJobName ); const scheduledJobStatus = scheduledJob ? scheduledJob.status : null; - const scheduledJobCreated = scheduledJob ? scheduledJob.created : null; const scheduledJobLog = pollLogsState && pollLogsState.data; return ( @@ -75,20 +73,50 @@ const PageScheduledJob = (props) => {

Overview

- Scheduled Job{' '} + Scheduled job{' '} {smallScheduledJobName(scheduledJobName)}, - Job {jobComponentName} -

-

- Status + job {jobComponentName}

{scheduledJob && (
-

Created: {scheduledJob.created}

-

Started: {scheduledJob.started}

-

Ended: {scheduledJob.ended}

+

+ Created{' '} + + + +

+

+ Started{' '} + + + +

+

+ Ended{' '} + + + +

+

+ Duration{' '} + + + +

)} +

+ Status +

{scheduledJobLog && (

Log

diff --git a/src/components/page-scheduled-job/use-select-scheduled-job.js b/src/components/page-scheduled-job/use-select-scheduled-job.js index 03bdf9316..a62604cac 100644 --- a/src/components/page-scheduled-job/use-select-scheduled-job.js +++ b/src/components/page-scheduled-job/use-select-scheduled-job.js @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import scheduledJobSummaryNormaliser from '../../models/scheduled-job-summary/normaliser'; const useSelectScheduledJob = ( environment, @@ -21,7 +22,7 @@ const useSelectScheduledJob = ( (scheduledJob) => scheduledJob.name === scheduledJobName ) : null; - setScheduledJob(selectedScheduledJob); + setScheduledJob(scheduledJobSummaryNormaliser(selectedScheduledJob)); }, [environment, jobComponentName, scheduledJobName]); return scheduledJob; diff --git a/src/models/component/normaliser.js b/src/models/component/normaliser.js index 964e8513a..c8571f469 100644 --- a/src/models/component/normaliser.js +++ b/src/models/component/normaliser.js @@ -2,6 +2,7 @@ import pick from 'lodash/pick'; import portNormaliser from '../port/normaliser'; import replicaSummaryNormaliser from '../replica-summary/normaliser'; +import scheduledJobSummaryNormaliser from '../scheduled-job-summary/normaliser'; import model from '.'; @@ -19,6 +20,10 @@ export const normaliser = (props) => { ? component.replicaList.map(replicaSummaryNormaliser) : null; + component.scheduledJobList = component.scheduledJobList + ? component.scheduledJobList.map(scheduledJobSummaryNormaliser) + : null; + return Object.freeze(component); }; diff --git a/src/models/replica-summary/index.js b/src/models/replica-summary/index.js index 9642d48c9..1cba66d28 100644 --- a/src/models/replica-summary/index.js +++ b/src/models/replica-summary/index.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; export default Object.freeze({ name: PropTypes.string.isRequired, + created: PropTypes.instanceOf(Date).isRequired, status: PropTypes.oneOf([ 'Pending', 'Failing', @@ -9,5 +10,6 @@ export default Object.freeze({ 'Terminated', 'Starting', ]).isRequired, + restartCount: PropTypes.int, statusMessage: PropTypes.string, }); diff --git a/src/models/replica-summary/normaliser.js b/src/models/replica-summary/normaliser.js index 7ace1737e..bc245b6b1 100644 --- a/src/models/replica-summary/normaliser.js +++ b/src/models/replica-summary/normaliser.js @@ -6,9 +6,15 @@ import model from '.'; * Create a Replica object */ export const normaliser = (props) => { + if (props == null) { + return null; + } const replica = pick(props, Object.keys(model)); replica.status = props.replicaStatus.status; + replica.created = replica.created ? new Date(replica.created) : null; + let restartCount = parseInt(replica.restartCount); + replica.restartCount = restartCount === NaN ? 0 : restartCount; return Object.freeze(replica); }; From e91050dc96ca4d42d5a5d8032c0cd338dbd3a520 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 9 Apr 2021 17:07:17 +0200 Subject: [PATCH 14/23] Extracted common logic from active component overview --- .../active-component/component-bred-crumb.js | 34 +++ src/components/component-ports/index.js | 30 +++ src/components/component-secrets/index.js | 59 +++++ src/components/env-variables/index.js | 58 +++++ .../active-component-overview.js | 234 +++--------------- .../page-active-component/default-alias.js | 36 +++ .../horizontal-scaling-summary.js | 44 ++++ .../page-active-component/replica-list.js | 50 ++++ .../active-job-component-overview.js | 159 ++---------- src/models/component/index.js | 1 + src/state/environment/index.js | 8 +- 11 files changed, 376 insertions(+), 337 deletions(-) create mode 100644 src/components/active-component/component-bred-crumb.js create mode 100644 src/components/component-ports/index.js create mode 100644 src/components/component-secrets/index.js create mode 100644 src/components/env-variables/index.js create mode 100644 src/components/page-active-component/default-alias.js create mode 100644 src/components/page-active-component/horizontal-scaling-summary.js create mode 100644 src/components/page-active-component/replica-list.js diff --git a/src/components/active-component/component-bred-crumb.js b/src/components/active-component/component-bred-crumb.js new file mode 100644 index 000000000..c6150b4af --- /dev/null +++ b/src/components/active-component/component-bred-crumb.js @@ -0,0 +1,34 @@ +import Breadcrumb from '../breadcrumb'; +import { routeWithParams } from '../../utils/string'; +import routes from '../../routes'; +import * as routing from '../../utils/routing'; +import EnvironmentBadge from '../environment-badge'; +import React from 'react'; +import PropTypes from 'prop-types'; + +const ComponentBredcrumb = ({ appName, envName, componentName }) => { + return ( + , + to: routeWithParams(routes.appEnvironment, { + appName, + envName, + }), + }, + { label: componentName }, + ]} + /> + ); +}; + +ComponentBredcrumb.propTypes = { + appName: PropTypes.string.isRequired, + envName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, +}; + +export default ComponentBredcrumb; diff --git a/src/components/component-ports/index.js b/src/components/component-ports/index.js new file mode 100644 index 000000000..e79d5c81a --- /dev/null +++ b/src/components/component-ports/index.js @@ -0,0 +1,30 @@ +import componentModel from '../../models/component'; +import PropTypes from 'prop-types'; +import React from 'react'; +import PortModel from '../../models/port'; + +const ComponentPorts = ({ ports }) => { + return ( + + {ports.length > 0 && ( + +

Open ports:

+
    + {ports.map((port) => ( +
  • + {port.port} ({port.name}) +
  • + ))} +
+
+ )} + {ports.length === 0 &&

No open ports

} +
+ ); +}; + +ComponentPorts.propTypes = { + ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), +}; + +export default ComponentPorts; diff --git a/src/components/component-secrets/index.js b/src/components/component-secrets/index.js new file mode 100644 index 000000000..bc0ac7ac9 --- /dev/null +++ b/src/components/component-secrets/index.js @@ -0,0 +1,59 @@ +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; +import * as routing from '../../utils/routing'; +import SecretStatus from '../secret-status'; +import React from 'react'; +import { getEnvironment, getComponentSecret } from '../../state/environment'; +import { connect } from 'react-redux'; +import environmentModel from '../../models/environment'; + +const ComponentSecrets = ({ + appName, + envName, + componentName, + secrets, + environment, +}) => { + return ( + +

Secrets

+ {secrets.length === 0 &&

This component uses no secrets

} + {secrets.length > 0 && ( +
    + {secrets.map((secretName) => { + let envSecret = getComponentSecret(environment, secretName); + return ( +
  • + + {secretName} + {' '} + +
  • + ); + })} +
+ )} +
+ ); +}; + +ComponentSecrets.propTypes = { + appName: PropTypes.string.isRequired, + envName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, + secrets: PropTypes.arrayOf(PropTypes.string), + environment: PropTypes.shape(environmentModel), +}; + +const mapStateToProps = (state) => ({ + environment: getEnvironment(state), +}); + +export default connect(mapStateToProps)(ComponentSecrets); diff --git a/src/components/env-variables/index.js b/src/components/env-variables/index.js new file mode 100644 index 000000000..97f0bcc0d --- /dev/null +++ b/src/components/env-variables/index.js @@ -0,0 +1,58 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import componentModel from '../../models/component'; + +const EnvVariables = ({ component }) => { + let hasRadixVars = false; + const envVarNames = component && Object.keys(component.variables); + + const varList = envVarNames.map((varName) => { + const isRadixVar = varName.slice(0, 6) === 'RADIX_'; + hasRadixVars = hasRadixVars || isRadixVar; + + if (isRadixVar) { + return ( + +
+ * {varName} +
+
+ {(component && component.variables)[varName]} +
+
+ ); + } + + return ( + +
{varName}
+
{(component && component.variables)[varName]}
+
+ ); + }); + + return ( +
+

Environment variables

+ {envVarNames.length === 0 && ( +

This component uses no environment variables

+ )} + {envVarNames.length > 0 && ( +
+
{varList}
+ {hasRadixVars && ( +

+ * automatically added by Radix +

+ )} +
+ )} +
+ ); +}; + +EnvVariables.propTypes = { + component: PropTypes.shape(componentModel), +}; + +export default EnvVariables; diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index 0ea9292ff..228aa99bb 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -1,80 +1,33 @@ import { connect } from 'react-redux'; import { faLink } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; -import React, { useState } from 'react'; +import React from 'react'; import Alert from '../alert'; -import Breadcrumb from '../breadcrumb'; import DockerImage from '../docker-image'; -import EnvironmentBadge from '../environment-badge'; -import ReplicaStatus from '../replica-status'; -import SecretStatus from '../secret-status'; import AsyncResource from '../async-resource'; import Toolbar from './toolbar'; import { getAppAlias } from '../../state/application'; -import { getComponent, getSecret } from '../../state/environment'; -import { routeWithParams, smallReplicaName } from '../../utils/string'; -import * as routing from '../../utils/routing'; +import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import routes from '../../routes'; -import RelativeToNow from '../time/relative-to-now'; -import Duration from '../time/duration'; - +import EnvVariables from '../env-variables'; +import HorizontalScalingSummary from './horizontal-scaling-summary'; +import DefaultAlias from './default-alias'; +import ComponentSecrets from '../component-secrets'; +import ComponentPorts from '../component-ports'; +import ReplicaList from './replica-list'; +import ComponentBredcrumb from '../active-component/component-bred-crumb'; const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; -const Vars = ({ envVarNames, component }) => { - let hasRadixVars = false; - - const varList = envVarNames.map((varName) => { - const isRadixVar = varName.slice(0, 6) === 'RADIX_'; - hasRadixVars = hasRadixVars || isRadixVar; - - if (isRadixVar) { - return ( - -
- * {varName} -
-
- {component.variables[varName]} -
-
- ); - } - - return ( - -
{varName}
-
{component.variables[varName]}
-
- ); - }); - - return ( -
-
{varList}
- {hasRadixVars && ( -

- * automatically added by Radix -

- )} -
- ); -}; - -let now = Date(); - export class ActiveComponentOverview extends React.Component { componentDidMount() { this.props.subscribe(this.props.appName, this.props.envName); } componentDidUpdate(prevProps) { const { appName, envName } = this.props; - now = new Date(); if (appName !== prevProps.appName || envName !== prevProps.envName) { this.props.unsubscribe(prevProps.appName, prevProps.envName); @@ -87,37 +40,13 @@ export class ActiveComponentOverview extends React.Component { } render() { - const { - appAlias, - appName, - envName, - componentName, - component, - getEnvSecret, - } = this.props; - - const envVarNames = component && Object.keys(component.variables); - - const isDefaultAlias = - appAlias && - appAlias.componentName === componentName && - appAlias.environmentName === envName; - + const { appAlias, appName, envName, componentName, component } = this.props; return ( - , - to: routeWithParams(routes.appEnvironment, { - appName, - envName, - }), - }, - { label: componentName }, - ]} +
{component.variables[URL_VAR_NAME] && (

- Publically available{' '} + Publicly available{' '} @@ -161,120 +90,33 @@ export class ActiveComponentOverview extends React.Component {

)} - {isDefaultAlias && ( - - This component is the application{' '} - - default alias{' '} - - - - )} +

Image

- {component.ports.length > 0 && ( - -

Open ports:

-
    - {component.ports.map((port) => ( -
  • - {port.port} ({port.name}) -
  • - ))} -
-
- )} - {component.ports.length === 0 &&

No open ports

} -

Environment variables

- {envVarNames.length === 0 && ( -

This component uses no environment variables

- )} - {envVarNames.length > 0 && ( - - )} + +
- {component.horizontalScalingSummary && ( - -

- Horizontal scaling -

-
-
Min replicas:
-
- {component.horizontalScalingSummary.minReplicas} -
-
Max replicas:
-
- {component.horizontalScalingSummary.maxReplicas} -
-
Current average CPU utilization:
-
- { - component.horizontalScalingSummary - .currentCPUUtilizationPercentage - } - % -
-
Target average CPU utilization:
-
- { - component.horizontalScalingSummary - .targetCPUUtilizationPercentage - } - % -
-
-
- )} -

Replicas

- {component.replicaList.map((replica) => ( -

- - {smallReplicaName(replica.name)}{' '} - - -    Created{' '} - - - -     Duration{' '} - - - -

- ))} -

Secrets

- {component.secrets.length === 0 && ( -

This component uses no secrets

- )} - {component.secrets.length > 0 && ( -
    - {component.secrets.map((secretName) => ( -
  • - - {secretName} - {' '} - -
  • - ))} -
- )} + + +
@@ -296,7 +138,6 @@ ActiveComponentOverview.propTypes = { envName: PropTypes.string.isRequired, componentName: PropTypes.string.isRequired, component: PropTypes.shape(componentModel), - getEnvSecret: PropTypes.func.isRequired, subscribe: PropTypes.func.isRequired, unsubscribe: PropTypes.func.isRequired, }; @@ -304,7 +145,6 @@ ActiveComponentOverview.propTypes = { const mapStateToProps = (state, { componentName }) => ({ appAlias: getAppAlias(state), component: getComponent(state, componentName), - getEnvSecret: (secretName) => getSecret(state, componentName, secretName), }); const mapDispatchToProps = (dispatch) => ({ diff --git a/src/components/page-active-component/default-alias.js b/src/components/page-active-component/default-alias.js new file mode 100644 index 000000000..19ce9c48f --- /dev/null +++ b/src/components/page-active-component/default-alias.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faLink } from '@fortawesome/free-solid-svg-icons'; +import PropTypes from 'prop-types'; + +const DefaultAlias = (props) => { + const { appAlias, envName, componentName } = props; + const isDefaultAlias = + appAlias && + appAlias.componentName === componentName && + appAlias.environmentName === envName; + return ( + + {isDefaultAlias && ( + + This component is the application{' '} + + default alias + + + )} + + ); +}; + +DefaultAlias.propTypes = { + appAlias: PropTypes.exact({ + componentName: PropTypes.string.isRequired, + environmentName: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + }), + envName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, +}; + +export default DefaultAlias; diff --git a/src/components/page-active-component/horizontal-scaling-summary.js b/src/components/page-active-component/horizontal-scaling-summary.js new file mode 100644 index 000000000..6bfe97247 --- /dev/null +++ b/src/components/page-active-component/horizontal-scaling-summary.js @@ -0,0 +1,44 @@ +import componentModel from '../../models/component'; +import PropTypes from 'prop-types'; +import React from 'react'; + +const HorizontalScalingSummary = (props) => { + const { component } = props; + return ( + + {component.horizontalScalingSummary && ( + +

Horizontal scaling

+
+
Min replicas:
+
{component.horizontalScalingSummary.minReplicas}
+
Max replicas:
+
{component.horizontalScalingSummary.maxReplicas}
+
Current average CPU utilization:
+
+ { + component.horizontalScalingSummary + .currentCPUUtilizationPercentage + } + % +
+
Target average CPU utilization:
+
+ { + component.horizontalScalingSummary + .targetCPUUtilizationPercentage + } + % +
+
+
+ )} +
+ ); +}; + +HorizontalScalingSummary.propTypes = { + component: PropTypes.shape(componentModel), +}; + +export default HorizontalScalingSummary; diff --git a/src/components/page-active-component/replica-list.js b/src/components/page-active-component/replica-list.js new file mode 100644 index 000000000..486f3f210 --- /dev/null +++ b/src/components/page-active-component/replica-list.js @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types'; +import ReplicaSummaryModel from '../../models/replica-summary'; +import { Link } from 'react-router-dom'; +import * as routing from '../../utils/routing'; +import { smallReplicaName } from '../../utils/string'; +import ReplicaStatus from '../replica-status'; +import RelativeToNow from '../time/relative-to-now'; +import Duration from '../time/duration'; +import React, { useState } from 'react'; + +const ReplicaList = ({ appName, envName, componentName, replicaList }) => { + const [now] = useState(new Date()); + return ( + +

Replicas

+ {replicaList.map((replica) => ( +

+ + {smallReplicaName(replica.name)}{' '} + + +    Created{' '} + + + +     Duration{' '} + + + +

+ ))} +
+ ); +}; + +ReplicaList.propTypes = { + appName: PropTypes.string.isRequired, + envName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, + replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), +}; + +export default ReplicaList; diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 6cc2fe6ba..c3546bede 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -1,74 +1,28 @@ import { connect } from 'react-redux'; -import { faLink } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import React from 'react'; import Alert from '../alert'; -import Breadcrumb from '../breadcrumb'; import DockerImage from '../docker-image'; -import EnvironmentBadge from '../environment-badge'; -import SecretStatus from '../secret-status'; +import ScheduledJobStatus from '../scheduled-job-status'; import AsyncResource from '../async-resource'; -import Toolbar from './toolbar'; -import { getComponent, getSecret } from '../../state/environment'; -import { routeWithParams, smallScheduledJobName } from '../../utils/string'; +import { getComponent } from '../../state/environment'; +import { smallScheduledJobName } from '../../utils/string'; import * as routing from '../../utils/routing'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import routes from '../../routes'; -import ScheduledJobStatus from '../scheduled-job-status'; import RelativeToNow from '../time/relative-to-now'; - -const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; - -const Vars = ({ envVarNames, component }) => { - let hasRadixVars = false; - - const varList = envVarNames.map((varName) => { - const isRadixVar = varName.slice(0, 6) === 'RADIX_'; - hasRadixVars = hasRadixVars || isRadixVar; - - if (isRadixVar) { - return ( - -
- * {varName} -
-
- {component.variables[varName]} -
-
- ); - } - - return ( - -
{varName}
-
{component.variables[varName]}
-
- ); - }); - - return ( -
-
{varList}
- {hasRadixVars && ( -

- * automatically added by Radix -

- )} -
- ); -}; +import EnvVariables from '../env-variables'; +import ComponentSecrets from '../component-secrets'; +import ComponentPorts from '../component-ports'; +import ComponentBredcrumb from '../active-component/component-bred-crumb'; export class ActiveScheduledJobOverview extends React.Component { componentDidMount() { this.props.subscribe(this.props.appName, this.props.envName); } - componentDidUpdate(prevProps) { const { appName, envName } = this.props; @@ -83,31 +37,14 @@ export class ActiveScheduledJobOverview extends React.Component { } render() { - const { - appName, - envName, - jobComponentName, - component, - getEnvSecret, - } = this.props; - - const envVarNames = component && Object.keys(component.variables); + const { appName, envName, jobComponentName, component } = this.props; return ( - , - to: routeWithParams(routes.appEnvironment, { - appName, - envName, - }), - }, - { label: jobComponentName }, - ]} +
{component.status === 'Stopped' && ( - Component has been manually stopped; please note that a - new deployment will cause it to be restarted unless you - set replicas of the component to{' '} - 0 in{' '} - - radixconfig.yaml - + Job-scheduler has been manually stopped; please note + that new deployment will cause it to be restarted )}

Status {component.status}

- {component.variables[URL_VAR_NAME] && ( -

- Publically available{' '} - - link - -

- )}

Image

- {component.ports.length > 0 && ( - -

Open ports:

-
    - {component.ports.map((port) => ( -
  • - {port.port} ({port.name}) -
  • - ))} -
-
- )} - {component.ports.length === 0 &&

No open ports

} -

Environment variables

- {envVarNames.length === 0 && ( -

This component uses no environment variables

- )} - {envVarNames.length > 0 && ( - - )} + +

Scheduled Job

@@ -193,29 +97,12 @@ export class ActiveScheduledJobOverview extends React.Component {

))} -

Secrets

- {component.secrets.length === 0 && ( -

This job uses no secrets

- )} - {component.secrets.length > 0 && ( -
    - {component.secrets.map((secretName) => ( -
  • - - {secretName} - {' '} - -
  • - ))} -
- )} +
@@ -232,14 +119,12 @@ ActiveScheduledJobOverview.propTypes = { envName: PropTypes.string.isRequired, jobComponentName: PropTypes.string.isRequired, component: PropTypes.shape(componentModel), - getEnvSecret: PropTypes.func.isRequired, subscribe: PropTypes.func.isRequired, unsubscribe: PropTypes.func.isRequired, }; const mapStateToProps = (state, { jobComponentName }) => ({ component: getComponent(state, jobComponentName), - getEnvSecret: (secretName) => getSecret(state, jobComponentName, secretName), }); const mapDispatchToProps = (dispatch) => ({ diff --git a/src/models/component/index.js b/src/models/component/index.js index 20d961d4a..ec4ca0586 100644 --- a/src/models/component/index.js +++ b/src/models/component/index.js @@ -11,6 +11,7 @@ export default Object.freeze({ type: ComponentType.isRequired, status: PropTypes.string.isRequired, ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), + scheduledPorts: PropTypes.arrayOf(PropTypes.exact(PortModel)), replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), scheduledJobList: PropTypes.arrayOf( PropTypes.exact(ScheduledJobSummaryModel) diff --git a/src/state/environment/index.js b/src/state/environment/index.js index efd852536..a36fc5844 100644 --- a/src/state/environment/index.js +++ b/src/state/environment/index.js @@ -119,9 +119,7 @@ export const getActiveDeploymentName = (state) => { return env.activeDeployment.name; }; -export const getSecret = (state, componentName, secretName) => { - const env = getEnvironment(state); - +export const getComponentSecret = (env, secretName, componentName) => { if (!env || !env.activeDeployment) { return null; } @@ -130,3 +128,7 @@ export const getSecret = (state, componentName, secretName) => { (secret) => secret.name === secretName && secret.component === componentName ); }; + +export const getSecret = (state, componentName, secretName) => { + return getComponentSecret(getEnvironment(state), secretName, componentName); +}; From f8c1a222ab2d56ce63e0065f35aa98702d986302 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 9 Apr 2021 17:43:59 +0200 Subject: [PATCH 15/23] Cleanup and fixes --- .../page-active-component/replica-list.js | 53 +++++++++--------- .../active-job-component-overview.js | 50 +++++------------ .../scheduled-job-list.js | 55 +++++++++++++++++++ src/components/time/duration.js | 4 +- 4 files changed, 101 insertions(+), 61 deletions(-) create mode 100644 src/components/page-active-job-component/scheduled-job-list.js diff --git a/src/components/page-active-component/replica-list.js b/src/components/page-active-component/replica-list.js index 486f3f210..ff958f41c 100644 --- a/src/components/page-active-component/replica-list.js +++ b/src/components/page-active-component/replica-list.js @@ -6,36 +6,39 @@ import { smallReplicaName } from '../../utils/string'; import ReplicaStatus from '../replica-status'; import RelativeToNow from '../time/relative-to-now'; import Duration from '../time/duration'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; +import useInterval from '../../effects/use-interval'; const ReplicaList = ({ appName, envName, componentName, replicaList }) => { - const [now] = useState(new Date()); + const [now, setNow] = useState(new Date()); + useInterval(() => setNow(new Date()), 5000); return (

Replicas

- {replicaList.map((replica) => ( -

- - {smallReplicaName(replica.name)}{' '} - - -    Created{' '} - - - -     Duration{' '} - - - -

- ))} + {replicaList && + replicaList.map((replica) => ( +

+ + {smallReplicaName(replica.name)}{' '} + + +    Created{' '} + + + +     Duration{' '} + + + +

+ ))}
); }; diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index c3546bede..0cc23710b 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -1,23 +1,19 @@ import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import React from 'react'; import Alert from '../alert'; import DockerImage from '../docker-image'; -import ScheduledJobStatus from '../scheduled-job-status'; import AsyncResource from '../async-resource'; import { getComponent } from '../../state/environment'; -import { smallScheduledJobName } from '../../utils/string'; -import * as routing from '../../utils/routing'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import RelativeToNow from '../time/relative-to-now'; import EnvVariables from '../env-variables'; import ComponentSecrets from '../component-secrets'; import ComponentPorts from '../component-ports'; import ComponentBredcrumb from '../active-component/component-bred-crumb'; +import ScheduledJobList from './scheduled-job-list'; export class ActiveScheduledJobOverview extends React.Component { componentDidMount() { @@ -59,44 +55,28 @@ export class ActiveScheduledJobOverview extends React.Component {

Job {component.name}

- {component.status === 'Stopped' && ( +

+ Image +

+ +

+ Job-scheduler status {component.status} +

+ {component.status !== 'Consistent' && ( Job-scheduler has been manually stopped; please note that new deployment will cause it to be restarted )} -

- Status {component.status} -

-

- Image -

-
-

Scheduled Job

- {component.scheduledJobList.map((scheduledJob) => ( -

- - {smallScheduledJobName(scheduledJob.name)}{' '} - - -    Created{' '} - - - -

- ))} + { + const [now, setNow] = useState(new Date()); + useInterval(() => setNow(new Date()), 5000); + return ( + +

Scheduled Job

+ {scheduledJobList.map((scheduledJob) => ( +

+ + {smallScheduledJobName(scheduledJob.name)}{' '} + + +    Created{' '} + + + +

+ ))} +
+ ); +}; + +ScheduledJobList.propTypes = { + appName: PropTypes.string.isRequired, + envName: PropTypes.string.isRequired, + jobComponentName: PropTypes.string.isRequired, + scheduledJobList: PropTypes.arrayOf( + PropTypes.exact(ScheduledJobSummaryModel) + ), +}; + +export default ScheduledJobList; diff --git a/src/components/time/duration.js b/src/components/time/duration.js index 2875cc388..06dbadbf6 100644 --- a/src/components/time/duration.js +++ b/src/components/time/duration.js @@ -6,7 +6,9 @@ export const Duration = ({ start, end, title }) => { if (!end) { return null; } - + if (end < start) { + end = start; + } return {differenceInWords(end, start)}; }; From 084cba281cb5ac2e905c5a7c6912471a5bb15d48 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 9 Apr 2021 17:46:33 +0200 Subject: [PATCH 16/23] Cleanup and fixes --- src/components/page-active-component/replica-list.js | 2 +- .../page-active-job-component/scheduled-job-list.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/page-active-component/replica-list.js b/src/components/page-active-component/replica-list.js index ff958f41c..7e539fdc9 100644 --- a/src/components/page-active-component/replica-list.js +++ b/src/components/page-active-component/replica-list.js @@ -6,7 +6,7 @@ import { smallReplicaName } from '../../utils/string'; import ReplicaStatus from '../replica-status'; import RelativeToNow from '../time/relative-to-now'; import Duration from '../time/duration'; -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import useInterval from '../../effects/use-interval'; const ReplicaList = ({ appName, envName, componentName, replicaList }) => { diff --git a/src/components/page-active-job-component/scheduled-job-list.js b/src/components/page-active-job-component/scheduled-job-list.js index dec1d2d95..aa40fb931 100644 --- a/src/components/page-active-job-component/scheduled-job-list.js +++ b/src/components/page-active-job-component/scheduled-job-list.js @@ -1,5 +1,4 @@ -import React, { useState } from 'react'; -import ReplicaSummaryModel from '../../models/replica-summary'; +import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import * as routing from '../../utils/routing'; @@ -7,7 +6,6 @@ import { smallScheduledJobName } from '../../utils/string'; import ScheduledJobStatus from '../scheduled-job-status'; import RelativeToNow from '../time/relative-to-now'; import ScheduledJobSummaryModel from '../../models/scheduled-job-summary'; -import useInterval from '../../effects/use-interval'; const ScheduledJobList = ({ appName, @@ -15,8 +13,6 @@ const ScheduledJobList = ({ jobComponentName, scheduledJobList, }) => { - const [now, setNow] = useState(new Date()); - useInterval(() => setNow(new Date()), 5000); return (

Scheduled Job

From d0987fb4bfbdf0cad73af51efeb527adf67ed3b2 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Fri, 9 Apr 2021 18:08:57 +0200 Subject: [PATCH 17/23] Cleanup and fixes --- .../index.js => active-component/component-ports.js} | 0 .../index.js => active-component/component-secrets.js} | 6 +++++- .../index.js => active-component/env-variables.js} | 0 .../page-active-component/active-component-overview.js | 6 +++--- src/components/page-active-component/replica-list.js | 7 ++++--- .../active-job-component-overview.js | 6 +++--- src/components/page-replica/index.js | 5 ++++- 7 files changed, 19 insertions(+), 11 deletions(-) rename src/components/{component-ports/index.js => active-component/component-ports.js} (100%) rename src/components/{component-secrets/index.js => active-component/component-secrets.js} (91%) rename src/components/{env-variables/index.js => active-component/env-variables.js} (100%) diff --git a/src/components/component-ports/index.js b/src/components/active-component/component-ports.js similarity index 100% rename from src/components/component-ports/index.js rename to src/components/active-component/component-ports.js diff --git a/src/components/component-secrets/index.js b/src/components/active-component/component-secrets.js similarity index 91% rename from src/components/component-secrets/index.js rename to src/components/active-component/component-secrets.js index bc0ac7ac9..ea624bf96 100644 --- a/src/components/component-secrets/index.js +++ b/src/components/active-component/component-secrets.js @@ -21,7 +21,11 @@ const ComponentSecrets = ({ {secrets.length > 0 && (
    {secrets.map((secretName) => { - let envSecret = getComponentSecret(environment, secretName); + let envSecret = getComponentSecret( + environment, + secretName, + componentName + ); return (
  • { const [now, setNow] = useState(new Date()); - useInterval(() => setNow(new Date()), 5000); + useEffect(() => { + setNow(new Date()); + }, [replicaList]); return (

    Replicas

    diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 0cc23710b..2113cbe04 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -9,9 +9,9 @@ import AsyncResource from '../async-resource'; import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import EnvVariables from '../env-variables'; -import ComponentSecrets from '../component-secrets'; -import ComponentPorts from '../component-ports'; +import EnvVariables from '../active-component/env-variables'; +import ComponentSecrets from '../active-component/component-secrets'; +import ComponentPorts from '../active-component/component-ports'; import ComponentBredcrumb from '../active-component/component-bred-crumb'; import ScheduledJobList from './scheduled-job-list'; diff --git a/src/components/page-replica/index.js b/src/components/page-replica/index.js index acfba82e1..2baea9f81 100644 --- a/src/components/page-replica/index.js +++ b/src/components/page-replica/index.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import useGetEnvironment from '../page-environment/use-get-environment'; @@ -42,6 +42,9 @@ const PageReplica = (props) => { replicaName ); const [now, setNow] = useState(new Date()); + useEffect(() => { + setNow(new Date()); + }, [pollLogsState]); const replicaLog = pollLogsState && pollLogsState.data; const selectedReplica = replica; From 1594e4f49eb17299f8d648e4619dc5c6e6d8930b Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 12 Apr 2021 14:49:32 +0200 Subject: [PATCH 18/23] Shown scheduler port and payload --- .../active-component/env-variables.js | 26 ++++++---- .../active-component-overview.js | 5 +- .../active-job-component-overview.js | 18 +++---- .../job-scheduler-details.js | 50 +++++++++++++++++++ src/models/component/index.js | 3 +- 5 files changed, 79 insertions(+), 23 deletions(-) create mode 100644 src/components/page-active-job-component/job-scheduler-details.js diff --git a/src/components/active-component/env-variables.js b/src/components/active-component/env-variables.js index 97f0bcc0d..7e6701d64 100644 --- a/src/components/active-component/env-variables.js +++ b/src/components/active-component/env-variables.js @@ -2,31 +2,35 @@ import React from 'react'; import PropTypes from 'prop-types'; import componentModel from '../../models/component'; -const EnvVariables = ({ component }) => { +const EnvVariables = ({ component, includeRadixVars }) => { let hasRadixVars = false; const envVarNames = component && Object.keys(component.variables); const varList = envVarNames.map((varName) => { const isRadixVar = varName.slice(0, 6) === 'RADIX_'; - hasRadixVars = hasRadixVars || isRadixVar; + hasRadixVars = includeRadixVars && (hasRadixVars || isRadixVar); - if (isRadixVar) { + if (!isRadixVar) { return ( -
    - * {varName} -
    -
    - {(component && component.variables)[varName]} -
    +
    {varName}
    +
    {(component && component.variables)[varName]}
    ); } + if (includeRadixVars !== true) { + return ''; + } + return ( -
    {varName}
    -
    {(component && component.variables)[varName]}
    +
    + * {varName} +
    +
    + {(component && component.variables)[varName]} +
    ); }); diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index a4ede16ff..bb707e87b 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -99,7 +99,10 @@ export class ActiveComponentOverview extends React.Component { Image

    - +

-

- Job-scheduler status {component.status} -

- {component.status !== 'Consistent' && ( - - Job-scheduler has been manually stopped; please note - that new deployment will cause it to be restarted - - )} - + +
{ + return ( + +

Job Scheduler:

+
    +
  • + status {component.status} +
  • +
  • + port {component.schedulerPort} +
  • +
  • + URL{' '} + + http://{component.name}:{component.schedulerPort}/api/v1 + +
  • +
  • + payload{' '} + {component.scheduledJobPayloadPath && + component.scheduledJobPayloadPath.length > 0 && ( + {component.scheduledJobPayloadPath} + )} + {!component.scheduledJobPayloadPath || + (component.scheduledJobPayloadPath.length <= 0 && ( + is empty + ))} +
  • +
+ {component.status !== 'Consistent' && ( + + Job-scheduler has been manually stopped; please note that new + deployment will cause it to be restarted + + )} +
+ ); +}; + +EnvVariables.propTypes = { + component: PropTypes.shape(componentModel), +}; + +export default JobSchedulerDetails; diff --git a/src/models/component/index.js b/src/models/component/index.js index ec4ca0586..91ab05568 100644 --- a/src/models/component/index.js +++ b/src/models/component/index.js @@ -11,7 +11,8 @@ export default Object.freeze({ type: ComponentType.isRequired, status: PropTypes.string.isRequired, ports: PropTypes.arrayOf(PropTypes.exact(PortModel)), - scheduledPorts: PropTypes.arrayOf(PropTypes.exact(PortModel)), + schedulerPort: PropTypes.string, + scheduledJobPayloadPath: PropTypes.string, replicaList: PropTypes.arrayOf(PropTypes.exact(ReplicaSummaryModel)), scheduledJobList: PropTypes.arrayOf( PropTypes.exact(ScheduledJobSummaryModel) From 8344f8906a61879b34898b8c2bb7ae5dc1e19346 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Mon, 12 Apr 2021 18:28:14 +0200 Subject: [PATCH 19/23] logs used env --- src/components/page-replica/index.js | 12 +++--------- src/components/page-replica/use-poll-logs.js | 6 +++--- src/components/page-scheduled-job/index.js | 18 +++--------------- .../page-scheduled-job/use-poll-logs.js | 11 +++-------- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/components/page-replica/index.js b/src/components/page-replica/index.js index 2baea9f81..df9340c78 100644 --- a/src/components/page-replica/index.js +++ b/src/components/page-replica/index.js @@ -21,18 +21,12 @@ import Duration from '../time/duration'; const STATUS_OK = 'Running'; const PageReplica = (props) => { - const { - appName, - envName, - deploymentName, - componentName, - replicaName, - } = props; + const { appName, envName, componentName, replicaName } = props; const [getEnvironmentState] = useGetEnvironment(appName, envName); const [pollLogsState] = usePollLogs( appName, - deploymentName, + envName, componentName, replicaName ); @@ -136,6 +130,6 @@ PageReplica.propTypes = { }; export default mapRouteParamsToProps( - ['appName', 'envName', 'deploymentName', 'componentName', 'replicaName'], + ['appName', 'envName', 'componentName', 'replicaName'], PageReplica ); diff --git a/src/components/page-replica/use-poll-logs.js b/src/components/page-replica/use-poll-logs.js index 02d0f8bee..34a11490c 100644 --- a/src/components/page-replica/use-poll-logs.js +++ b/src/components/page-replica/use-poll-logs.js @@ -1,11 +1,11 @@ import { usePollingPlain } from '../../effects'; -const usePollLogs = (appName, deploymentName, componentName, replicaName) => { +const usePollLogs = (appName, envName, componentName, replicaName) => { const encAppName = encodeURIComponent(appName); - const encDeployName = encodeURIComponent(deploymentName); + const encEnvName = encodeURIComponent(envName); const encComponentName = encodeURIComponent(componentName); const encReplicaName = encodeURIComponent(replicaName); - const path = `/applications/${encAppName}/deployments/${encDeployName}/components/${encComponentName}/replicas/${encReplicaName}/logs`; + const path = `/applications/${encAppName}/environments/${encEnvName}/components/${encComponentName}/replicas/${encReplicaName}/logs`; return usePollingPlain(path, 5000); }; diff --git a/src/components/page-scheduled-job/index.js b/src/components/page-scheduled-job/index.js index 0137fad45..427544d20 100644 --- a/src/components/page-scheduled-job/index.js +++ b/src/components/page-scheduled-job/index.js @@ -19,18 +19,12 @@ import RelativeToNow from '../time/relative-to-now'; import Duration from '../time/duration'; const PageScheduledJob = (props) => { - const { - appName, - envName, - deploymentName, - jobComponentName, - scheduledJobName, - } = props; + const { appName, envName, jobComponentName, scheduledJobName } = props; const [getEnvironmentState] = useGetEnvironment(appName, envName); const [pollLogsState] = usePollLogs( appName, - deploymentName, + envName, jobComponentName, scheduledJobName ); @@ -144,12 +138,6 @@ PageScheduledJob.propTypes = { }; export default mapRouteParamsToProps( - [ - 'appName', - 'envName', - 'deploymentName', - 'jobComponentName', - 'scheduledJobName', - ], + ['appName', 'envName', 'jobComponentName', 'scheduledJobName'], PageScheduledJob ); diff --git a/src/components/page-scheduled-job/use-poll-logs.js b/src/components/page-scheduled-job/use-poll-logs.js index 95e31dfb1..42bb0d600 100644 --- a/src/components/page-scheduled-job/use-poll-logs.js +++ b/src/components/page-scheduled-job/use-poll-logs.js @@ -1,16 +1,11 @@ import { usePollingPlain } from '../../effects'; -const usePollLogs = ( - appName, - deploymentName, - jobComponentName, - scheduledJobName -) => { +const usePollLogs = (appName, envName, jobComponentName, scheduledJobName) => { const encAppName = encodeURIComponent(appName); - const encDeployName = encodeURIComponent(deploymentName); + const encEnvName = encodeURIComponent(envName); const encJobComponentName = encodeURIComponent(jobComponentName); const encScheduledJobName = encodeURIComponent(scheduledJobName); - const path = `/applications/${encAppName}/deployments/${encDeployName}/jobcomponents/${encJobComponentName}/scheduledjobs/${encScheduledJobName}/logs`; + const path = `/applications/${encAppName}/environments/${encEnvName}/jobcomponents/${encJobComponentName}/scheduledjobs/${encScheduledJobName}/logs`; return usePollingPlain(path, 5000); }; From 1e9e54832585122f0d735bb338e2954b84187998 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 13 Apr 2021 12:08:26 +0200 Subject: [PATCH 20/23] extracted common logic --- .../active-component-secrets.js} | 6 +- .../component-bred-crumb.js | 0 .../component-ports.js | 1 - src/components/component/component-secrets.js | 39 ++++ .../env-variables.js | 6 - .../active-component-overview.js | 8 +- .../active-job-component-overview.js | 10 +- .../job-scheduler-details.js | 2 +- src/components/page-application/index.js | 6 +- .../page-component/component-overview.js | 166 ------------------ .../deployment-component-overview.js | 113 ++++++++++++ .../index.js | 16 +- .../deployment-job-component-overview.js | 122 +++++++++++++ .../page-deployment-job-component/index.js | 27 +++ .../page-deployment/deployment-bred-crumb.js | 27 +++ .../deployment-component-bred-crumb.js | 41 +++++ .../deployment-component-list.js | 41 +++++ .../deployment-job-component-list.js | 45 +++++ .../page-deployment/deployment-overview.js | 147 ++++------------ .../page-deployment/deployment-summary.js | 67 +++++++ src/components/page-deployment/index.js | 10 +- .../promote-deployment-action.js | 42 +++++ .../index.js | 6 +- .../{page-job => page-pipeline-job}/index.js | 4 +- .../index.js | 6 +- .../style.css | 0 src/models/component-type/index.js | 5 + src/routes.js | 1 + 28 files changed, 642 insertions(+), 322 deletions(-) rename src/components/{active-component/component-secrets.js => component/active-component-secrets.js} (92%) rename src/components/{active-component => component}/component-bred-crumb.js (100%) rename src/components/{active-component => component}/component-ports.js (92%) create mode 100644 src/components/component/component-secrets.js rename src/components/{active-component => component}/env-variables.js (89%) delete mode 100644 src/components/page-component/component-overview.js create mode 100644 src/components/page-deployment-component/deployment-component-overview.js rename src/components/{page-component => page-deployment-component}/index.js (66%) create mode 100644 src/components/page-deployment-job-component/deployment-job-component-overview.js create mode 100644 src/components/page-deployment-job-component/index.js create mode 100644 src/components/page-deployment/deployment-bred-crumb.js create mode 100644 src/components/page-deployment/deployment-component-bred-crumb.js create mode 100644 src/components/page-deployment/deployment-component-list.js create mode 100644 src/components/page-deployment/deployment-job-component-list.js create mode 100644 src/components/page-deployment/deployment-summary.js create mode 100644 src/components/page-deployment/promote-deployment-action.js rename src/components/{page-job-new => page-pipeline-job-new}/index.js (95%) rename src/components/{page-job => page-pipeline-job}/index.js (81%) rename src/components/{page-jobs => page-pipeline-jobs}/index.js (94%) rename src/components/{page-jobs => page-pipeline-jobs}/style.css (100%) diff --git a/src/components/active-component/component-secrets.js b/src/components/component/active-component-secrets.js similarity index 92% rename from src/components/active-component/component-secrets.js rename to src/components/component/active-component-secrets.js index ea624bf96..a87a01177 100644 --- a/src/components/active-component/component-secrets.js +++ b/src/components/component/active-component-secrets.js @@ -7,7 +7,7 @@ import { getEnvironment, getComponentSecret } from '../../state/environment'; import { connect } from 'react-redux'; import environmentModel from '../../models/environment'; -const ComponentSecrets = ({ +const ActiveComponentSecrets = ({ appName, envName, componentName, @@ -48,7 +48,7 @@ const ComponentSecrets = ({ ); }; -ComponentSecrets.propTypes = { +ActiveComponentSecrets.propTypes = { appName: PropTypes.string.isRequired, envName: PropTypes.string.isRequired, componentName: PropTypes.string.isRequired, @@ -60,4 +60,4 @@ const mapStateToProps = (state) => ({ environment: getEnvironment(state), }); -export default connect(mapStateToProps)(ComponentSecrets); +export default connect(mapStateToProps)(ActiveComponentSecrets); diff --git a/src/components/active-component/component-bred-crumb.js b/src/components/component/component-bred-crumb.js similarity index 100% rename from src/components/active-component/component-bred-crumb.js rename to src/components/component/component-bred-crumb.js diff --git a/src/components/active-component/component-ports.js b/src/components/component/component-ports.js similarity index 92% rename from src/components/active-component/component-ports.js rename to src/components/component/component-ports.js index e79d5c81a..ad3fc3c0d 100644 --- a/src/components/active-component/component-ports.js +++ b/src/components/component/component-ports.js @@ -1,4 +1,3 @@ -import componentModel from '../../models/component'; import PropTypes from 'prop-types'; import React from 'react'; import PortModel from '../../models/port'; diff --git a/src/components/component/component-secrets.js b/src/components/component/component-secrets.js new file mode 100644 index 000000000..f7f8dfd1f --- /dev/null +++ b/src/components/component/component-secrets.js @@ -0,0 +1,39 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { getEnvironment } from '../../state/environment'; +import { connect } from 'react-redux'; +import { buildComponentTypeLabelMap } from '../../models/component-type'; +import Component from '../../models/component'; + +const ComponentSecrets = ({ component }) => { + let componentTypeTitle = component ? getComponentTypeTitle(component) : ''; + return ( +
+

Secrets

+ {component && component.secrets.length === 0 && ( +

This {componentTypeTitle.toLowerCase()} uses no secrets

+ )} + {component && component.secrets.length > 0 && ( +
    + {component.secrets.map((secret) => ( +
  • {secret}
  • + ))} +
+ )} +
+ ); +}; + +function getComponentTypeTitle(component) { + return component ? buildComponentTypeLabelMap(component.type) : undefined; +} + +ComponentSecrets.propTypes = { + component: PropTypes.arrayOf(PropTypes.shape(Component)), +}; + +const mapStateToProps = (state) => ({ + environment: getEnvironment(state), +}); + +export default connect(mapStateToProps)(ComponentSecrets); diff --git a/src/components/active-component/env-variables.js b/src/components/component/env-variables.js similarity index 89% rename from src/components/active-component/env-variables.js rename to src/components/component/env-variables.js index 7e6701d64..fa1dac7ff 100644 --- a/src/components/active-component/env-variables.js +++ b/src/components/component/env-variables.js @@ -1,6 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import componentModel from '../../models/component'; const EnvVariables = ({ component, includeRadixVars }) => { let hasRadixVars = false; @@ -55,8 +53,4 @@ const EnvVariables = ({ component, includeRadixVars }) => { ); }; -EnvVariables.propTypes = { - component: PropTypes.shape(componentModel), -}; - export default EnvVariables; diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index bb707e87b..669adc3cc 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -13,13 +13,13 @@ import { getAppAlias } from '../../state/application'; import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import EnvVariables from '../active-component/env-variables'; +import EnvVariables from '../component/env-variables'; import HorizontalScalingSummary from './horizontal-scaling-summary'; import DefaultAlias from './default-alias'; -import ComponentSecrets from '../active-component/component-secrets'; -import ComponentPorts from '../active-component/component-ports'; +import ComponentSecrets from '../component/component-secrets'; +import ComponentPorts from '../component/component-ports'; import ReplicaList from './replica-list'; -import ComponentBredcrumb from '../active-component/component-bred-crumb'; +import ComponentBredcrumb from '../component/component-bred-crumb'; const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; export class ActiveComponentOverview extends React.Component { diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 5a814401f..7279d378f 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -1,18 +1,16 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import React from 'react'; -import Alert from '../alert'; import DockerImage from '../docker-image'; import AsyncResource from '../async-resource'; - import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; -import EnvVariables from '../active-component/env-variables'; -import ComponentSecrets from '../active-component/component-secrets'; -import ComponentPorts from '../active-component/component-ports'; -import ComponentBredcrumb from '../active-component/component-bred-crumb'; +import EnvVariables from '../component/env-variables'; +import ComponentSecrets from '../component/component-secrets'; +import ComponentPorts from '../component/component-ports'; +import ComponentBredcrumb from '../component/component-bred-crumb'; import ScheduledJobList from './scheduled-job-list'; import JobSchedulerDetails from './job-scheduler-details'; diff --git a/src/components/page-active-job-component/job-scheduler-details.js b/src/components/page-active-job-component/job-scheduler-details.js index 72d3e6418..b8b0ceacf 100644 --- a/src/components/page-active-job-component/job-scheduler-details.js +++ b/src/components/page-active-job-component/job-scheduler-details.js @@ -1,5 +1,5 @@ import componentModel from '../../models/component'; -import EnvVariables from '../active-component/env-variables'; +import EnvVariables from '../component/env-variables'; import PropTypes from 'prop-types'; import React from 'react'; import Alert from '../alert'; diff --git a/src/components/page-application/index.js b/src/components/page-application/index.js index 70ca178d2..613eeb61a 100644 --- a/src/components/page-application/index.js +++ b/src/components/page-application/index.js @@ -16,9 +16,9 @@ import PageEnvironment from '../page-environment'; import PageEnvironments from '../page-environments'; import PageBuildSecret from '../page-build-secret'; import PagePrivateImageHub from '../page-private-image-hub'; -import PageJob from '../page-job'; -import PageJobNew from '../page-job-new'; -import PageJobs from '../page-jobs'; +import PageJob from '../page-pipeline-job'; +import PageJobNew from '../page-pipeline-job-new'; +import PageJobs from '../page-pipeline-jobs'; import { mapRouteParamsToProps } from '../../utils/routing'; import routes from '../../routes'; diff --git a/src/components/page-component/component-overview.js b/src/components/page-component/component-overview.js deleted file mode 100644 index b940ef995..000000000 --- a/src/components/page-component/component-overview.js +++ /dev/null @@ -1,166 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import Breadcrumb from '../breadcrumb'; -import DockerImage from '../docker-image'; -import AsyncResource from '../async-resource'; - -import { getDeployment } from '../../state/deployment'; -import { routeWithParams, smallDeploymentName } from '../../utils/string'; -import * as actionCreators from '../../state/subscriptions/action-creators'; -import routes from '../../routes'; - -/** - * Filter for removing Radix-injected variables; those should not be displayed - * in a deployment coponent (only in a running component under an environment) - */ -const filterRadixVariables = (() => { - const radixVarRegEx = /^RADIX_/; - return (varName) => !varName.match(radixVarRegEx); -})(); - -export class DeploymentOverview extends React.Component { - componentDidMount() { - this.props.subscribe(this.props.appName, this.props.deploymentName); - } - - componentDidUpdate(prevProps) { - const { appName, deploymentName } = this.props; - - if ( - appName !== prevProps.appName || - deploymentName !== prevProps.deploymentName - ) { - this.props.unsubscribe(prevProps.appName, prevProps.deploymentName); - this.props.subscribe(appName, deploymentName); - } - } - - componentWillUnmount() { - this.props.unsubscribe(this.props.appName, this.props.deploymentName); - } - - render() { - const { appName, componentName, deploymentName, deployment } = this.props; - const component = - deployment && - deployment.components && - deployment.components.find((comp) => comp.name === componentName); - const envVarNames = - component && - Object.keys(component.variables).filter(filterRadixVariables); - - return ( - - -
- - {deployment && ( - -
-

Overview

-

- Component {component.name} -

-

- Image -

- {component.ports.length > 0 && ( - -

Open ports:

-
    - {component.ports.map((port) => ( -
  • - {port.port} ({port.name}) -
  • - ))} -
-
- )} - {component.ports.length === 0 &&

No open ports

} -
-
-
-

Environment variables

- {envVarNames.length === 0 && ( -

This component uses no environment variables

- )} - {envVarNames.length > 0 && ( -
- {envVarNames.map((varName) => ( - -
{varName}
-
{component.variables[varName]}
-
- ))} -
- )} -
-
-

Secrets

- {component.secrets.length === 0 && ( -

This component uses no secrets

- )} - {component.secrets.length > 0 && ( -
    - {component.secrets.map((secret) => ( -
  • {secret}
  • - ))} -
- )} -
-
-
- )} -
-
-
- ); - } -} - -DeploymentOverview.propTypes = { - appName: PropTypes.string.isRequired, - componentName: PropTypes.string.isRequired, - deployment: PropTypes.object, - deploymentName: PropTypes.string.isRequired, - subscribe: PropTypes.func.isRequired, - unsubscribe: PropTypes.func.isRequired, -}; - -const mapStateToProps = (state) => ({ - deployment: getDeployment(state), -}); - -const mapDispatchToProps = (dispatch) => ({ - subscribe: (appName, deploymentName) => { - dispatch(actionCreators.subscribeDeployment(appName, deploymentName)); - }, - unsubscribe: (appName, deploymentName) => { - dispatch(actionCreators.unsubscribeDeployment(appName, deploymentName)); - }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(DeploymentOverview); diff --git a/src/components/page-deployment-component/deployment-component-overview.js b/src/components/page-deployment-component/deployment-component-overview.js new file mode 100644 index 000000000..62d791f61 --- /dev/null +++ b/src/components/page-deployment-component/deployment-component-overview.js @@ -0,0 +1,113 @@ +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import React from 'react'; +import DockerImage from '../docker-image'; +import AsyncResource from '../async-resource'; +import { getDeployment } from '../../state/deployment'; +import * as actionCreators from '../../state/subscriptions/action-creators'; +import ComponentSecrets from '../component/component-secrets'; +import EnvVariables from '../component/env-variables'; +import DeploymentComponentBredCrumb from '../page-deployment/deployment-component-bred-crumb'; +import ComponentPorts from '../component/component-ports'; + +export class DeploymentComponentOverview extends React.Component { + componentDidMount() { + this.props.subscribe(this.props.appName, this.props.deploymentName); + } + + componentDidUpdate(prevProps) { + const { appName, deploymentName } = this.props; + + if ( + appName !== prevProps.appName || + deploymentName !== prevProps.deploymentName + ) { + this.props.unsubscribe(prevProps.appName, prevProps.deploymentName); + this.props.subscribe(appName, deploymentName); + } + } + + componentWillUnmount() { + this.props.unsubscribe(this.props.appName, this.props.deploymentName); + } + + render() { + const { appName, deploymentName, componentName, deployment } = this.props; + const component = + deployment && + deployment.components && + deployment.components.find((comp) => comp.name === componentName); + return ( + + +
+ + {deployment && ( + +
+
+

Overview

+

+ component {component.name} +

+

+ Image +

+ {component.ports.length > 0 && ( + + + + )} +
+ +
+
+
+ +
+
+
+ )} +
+
+
+ ); + } +} + +DeploymentComponentOverview.propTypes = { + appName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, + deployment: PropTypes.object, + deploymentName: PropTypes.string.isRequired, + subscribe: PropTypes.func.isRequired, + unsubscribe: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => ({ + deployment: getDeployment(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + subscribe: (appName, deploymentName) => { + dispatch(actionCreators.subscribeDeployment(appName, deploymentName)); + }, + unsubscribe: (appName, deploymentName) => { + dispatch(actionCreators.unsubscribeDeployment(appName, deploymentName)); + }, +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(DeploymentComponentOverview); diff --git a/src/components/page-component/index.js b/src/components/page-deployment-component/index.js similarity index 66% rename from src/components/page-component/index.js rename to src/components/page-deployment-component/index.js index 01dac8cf6..8f52f4e54 100644 --- a/src/components/page-component/index.js +++ b/src/components/page-deployment-component/index.js @@ -1,19 +1,21 @@ import React from 'react'; -import ComponentOverview from './component-overview'; - +import DeploymentComponentOverview from './deployment-component-overview'; import DocumentTitle from '../document-title'; - import { mapRouteParamsToProps } from '../../utils/routing'; -export const PageComponent = ({ appName, deploymentName, componentName }) => { +export const PageDeploymentComponent = ({ + appName, + deploymentName, + componentName, +}) => { return ( - ); @@ -21,5 +23,5 @@ export const PageComponent = ({ appName, deploymentName, componentName }) => { export default mapRouteParamsToProps( ['appName', 'deploymentName', 'componentName'], - PageComponent + PageDeploymentComponent ); diff --git a/src/components/page-deployment-job-component/deployment-job-component-overview.js b/src/components/page-deployment-job-component/deployment-job-component-overview.js new file mode 100644 index 000000000..a61475784 --- /dev/null +++ b/src/components/page-deployment-job-component/deployment-job-component-overview.js @@ -0,0 +1,122 @@ +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import React from 'react'; +import DockerImage from '../docker-image'; +import AsyncResource from '../async-resource'; +import { getDeployment } from '../../state/deployment'; +import * as actionCreators from '../../state/subscriptions/action-creators'; +import ComponentSecrets from '../component/component-secrets'; +import EnvVariables from '../component/env-variables'; +import DeploymentComponentBredCrumb from '../page-deployment/deployment-component-bred-crumb'; +import ComponentPorts from '../component/component-ports'; +import JobSchedulerDetails from '../page-active-job-component/job-scheduler-details'; + +export class DeploymentJobComponentOverview extends React.Component { + componentDidMount() { + this.props.subscribe(this.props.appName, this.props.deploymentName); + } + + componentDidUpdate(prevProps) { + const { appName, deploymentName } = this.props; + + if ( + appName !== prevProps.appName || + deploymentName !== prevProps.deploymentName + ) { + this.props.unsubscribe(prevProps.appName, prevProps.deploymentName); + this.props.subscribe(appName, deploymentName); + } + } + + componentWillUnmount() { + this.props.unsubscribe(this.props.appName, this.props.deploymentName); + } + + render() { + const { + appName, + jobComponentName, + deploymentName, + deployment, + } = this.props; + const component = + deployment && + deployment.components && + deployment.components.find((comp) => comp.name === jobComponentName); + return ( + + +
+ + {deployment && component && ( + +
+
+

Overview

+

+ job {component.name} +

+

+ Image +

+ {component.ports.length > 0 && ( + + + + )} + +
+ +
+
+
+ +
+
+
+ )} +
+
+
+ ); + } +} + +DeploymentJobComponentOverview.propTypes = { + appName: PropTypes.string.isRequired, + jobComponentName: PropTypes.string.isRequired, + deployment: PropTypes.object, + deploymentName: PropTypes.string.isRequired, + subscribe: PropTypes.func.isRequired, + unsubscribe: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => ({ + deployment: getDeployment(state), +}); + +const mapDispatchToProps = (dispatch) => ({ + subscribe: (appName, deploymentName) => { + dispatch(actionCreators.subscribeDeployment(appName, deploymentName)); + }, + unsubscribe: (appName, deploymentName) => { + dispatch(actionCreators.unsubscribeDeployment(appName, deploymentName)); + }, +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(DeploymentJobComponentOverview); diff --git a/src/components/page-deployment-job-component/index.js b/src/components/page-deployment-job-component/index.js new file mode 100644 index 000000000..e39ec7c2e --- /dev/null +++ b/src/components/page-deployment-job-component/index.js @@ -0,0 +1,27 @@ +import React from 'react'; + +import DeploymentJobComponentOverview from './deployment-job-component-overview'; +import DocumentTitle from '../document-title'; +import { mapRouteParamsToProps } from '../../utils/routing'; + +export const PageDeploymentJobComponent = ({ + appName, + deploymentName, + jobComponentName, +}) => { + return ( + + + + + ); +}; + +export default mapRouteParamsToProps( + ['appName', 'deploymentName', 'jobComponentName'], + PageDeploymentJobComponent +); diff --git a/src/components/page-deployment/deployment-bred-crumb.js b/src/components/page-deployment/deployment-bred-crumb.js new file mode 100644 index 000000000..26ae694d4 --- /dev/null +++ b/src/components/page-deployment/deployment-bred-crumb.js @@ -0,0 +1,27 @@ +import Breadcrumb from '../breadcrumb'; +import { routeWithParams, smallDeploymentName } from '../../utils/string'; +import routes from '../../routes'; +import React from 'react'; +import PropTypes from 'prop-types'; + +const DeploymentBredCrumb = ({ appName, deploymentName }) => { + return ( + + ); +}; + +DeploymentBredCrumb.propTypes = { + appName: PropTypes.string.isRequired, + deploymentName: PropTypes.string.isRequired, +}; + +export default DeploymentBredCrumb; diff --git a/src/components/page-deployment/deployment-component-bred-crumb.js b/src/components/page-deployment/deployment-component-bred-crumb.js new file mode 100644 index 000000000..dd09a343c --- /dev/null +++ b/src/components/page-deployment/deployment-component-bred-crumb.js @@ -0,0 +1,41 @@ +import Breadcrumb from '../breadcrumb'; +import { routeWithParams, smallDeploymentName } from '../../utils/string'; +import routes from '../../routes'; +import React from 'react'; +import PropTypes from 'prop-types'; + +const DeploymentComponentBredCrumb = ({ + appName, + deploymentName, + componentName, +}) => { + return ( + + ); +}; + +DeploymentComponentBredCrumb.propTypes = { + appName: PropTypes.string.isRequired, + deploymentName: PropTypes.string.isRequired, + componentName: PropTypes.string.isRequired, +}; + +export default DeploymentComponentBredCrumb; diff --git a/src/components/page-deployment/deployment-component-list.js b/src/components/page-deployment/deployment-component-list.js new file mode 100644 index 000000000..2bb2ea2e0 --- /dev/null +++ b/src/components/page-deployment/deployment-component-list.js @@ -0,0 +1,41 @@ +import Component from '../../models/component'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; +import { routeWithParams } from '../../utils/string'; +import routes from '../../routes'; +import DockerImage from '../docker-image'; +import React from 'react'; + +const DeploymentComponentList = ({ appName, deploymentName, components }) => { + return ( +
+

Components

+ {components && + components.map((component) => { + return ( +

+ + {component.name} + +
+ image +

+ ); + })} +
+ ); +}; + +DeploymentComponentList.propTypes = { + appName: PropTypes.string.isRequired, + deploymentName: PropTypes.string.isRequired, + components: PropTypes.arrayOf(PropTypes.shape(Component)), +}; + +export default DeploymentComponentList; diff --git a/src/components/page-deployment/deployment-job-component-list.js b/src/components/page-deployment/deployment-job-component-list.js new file mode 100644 index 000000000..6e526eb36 --- /dev/null +++ b/src/components/page-deployment/deployment-job-component-list.js @@ -0,0 +1,45 @@ +import Component from '../../models/component'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; +import { routeWithParams } from '../../utils/string'; +import routes from '../../routes'; +import DockerImage from '../docker-image'; +import React from 'react'; + +const DeploymentJobComponentList = ({ + appName, + deploymentName, + components, +}) => { + return ( +
+

Jobs

+ {components && + components.map((component) => { + return ( +

+ + {component.name} + +
+ image +

+ ); + })} +
+ ); +}; + +DeploymentJobComponentList.propTypes = { + appName: PropTypes.string.isRequired, + deploymentName: PropTypes.string.isRequired, + components: PropTypes.arrayOf(PropTypes.shape(Component)), +}; + +export default DeploymentJobComponentList; diff --git a/src/components/page-deployment/deployment-overview.js b/src/components/page-deployment/deployment-overview.js index 6aad81ec1..d362cfc3b 100644 --- a/src/components/page-deployment/deployment-overview.js +++ b/src/components/page-deployment/deployment-overview.js @@ -1,30 +1,19 @@ import { connect } from 'react-redux'; import { faInfoCircle } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import React from 'react'; - -import ActionsPage from '../actions-page'; import Alert from '../alert'; import AsyncResource from '../async-resource'; -import Breadcrumb from '../breadcrumb'; -import DockerImage from '../docker-image'; -import LinkButton from '../link-button'; -import RelativeToNow from '../time/relative-to-now'; - -import { - routeWithParams, - smallDeploymentName, - smallJobName, -} from '../../utils/string'; import { getDeployment } from '../../state/deployment'; import * as actionCreators from '../../state/subscriptions/action-creators'; import deploymentModel from '../../models/deployment'; -import configHandler from '../../utils/config'; -import { keys as configKeys } from '../../utils/config/keys'; - -import routes from '../../routes'; +import DeploymentSummary from './deployment-summary'; +import { buildComponentMap, componentType } from '../../models/component-type'; +import DeploymentComponentList from './deployment-component-list'; +import DeploymentJobComponentList from './deployment-job-component-list'; +import DeploymentBredCrumb from '../page-deployment/deployment-bred-crumb'; +import PromoteDeploymentAction from './promote-deployment-action'; export class DeploymentOverview extends React.Component { componentDidMount() { @@ -49,38 +38,23 @@ export class DeploymentOverview extends React.Component { render() { const { appName, deploymentName, deployment } = this.props; + let componentMap; + if (deployment) { + componentMap = buildComponentMap(deployment.components); + } return ( - + - {deployment && - configHandler.getConfig(configKeys.FLAGS).enablePromotionPipeline && ( - - - Promote deployment… - - - )} -
+
-
-

Summary

-

- {!deployment.activeTo && ( - - Currently deployed on environment{' '} - - )} - {deployment.activeTo && ( - - Was deployed to environment{' '} - - )} - - {deployment.environment} - -

- {deployment.createdByJob && ( -

- Created by pipeline job{' '} - - {smallJobName(deployment.createdByJob)} - -

- )} -

- Active from{' '} - - - -

- {deployment.activeTo && ( -

- Active until{' '} - - - -

- )} -
-
-

Components

- {deployment.components && - deployment.components.map((component) => ( -

- - {component.name} - -
- image -

- ))} -
+ + +
)} diff --git a/src/components/page-deployment/deployment-summary.js b/src/components/page-deployment/deployment-summary.js new file mode 100644 index 000000000..d2f536a7c --- /dev/null +++ b/src/components/page-deployment/deployment-summary.js @@ -0,0 +1,67 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { routeWithParams, smallJobName } from '../../utils/string'; +import routes from '../../routes'; +import RelativeToNow from '../time/relative-to-now'; +import deploymentModel from '../../models/deployment'; +import PropTypes from 'prop-types'; + +const DeploymentSummary = ({ appName, deployment }) => { + return ( +
+

Summary

+

+ {!deployment.activeTo && ( + + Currently deployed on environment{' '} + + )} + {deployment.activeTo && ( + Was deployed to environment + )} + + {deployment.environment} + +

+ {deployment.createdByJob && ( +

+ Created by pipeline job{' '} + + {smallJobName(deployment.createdByJob)} + +

+ )} +

+ Active from{' '} + + + +

+ {deployment.activeTo && ( +

+ Active until{' '} + + + +

+ )} +
+ ); +}; + +DeploymentSummary.propTypes = { + appName: PropTypes.string.isRequired, + deployment: PropTypes.exact(deploymentModel), +}; + +export default DeploymentSummary; diff --git a/src/components/page-deployment/index.js b/src/components/page-deployment/index.js index 666bb2eb7..6184bc981 100644 --- a/src/components/page-deployment/index.js +++ b/src/components/page-deployment/index.js @@ -4,11 +4,11 @@ import React from 'react'; import DeploymentOverview from './deployment-overview'; import DocumentTitle from '../document-title'; -import PageComponent from '../page-component'; - import { mapRouteParamsToProps } from '../../utils/routing'; import { smallDeploymentName } from '../../utils/string'; import routes from '../../routes'; +import PageDeploymentComponent from '../page-deployment-component'; +import PageDeploymentJobComponent from '../page-deployment-job-component'; export const PageDeployment = ({ appName, deploymentName }) => { return ( @@ -26,7 +26,11 @@ export const PageDeployment = ({ appName, deploymentName }) => { /> )} /> - + + ); }; diff --git a/src/components/page-deployment/promote-deployment-action.js b/src/components/page-deployment/promote-deployment-action.js new file mode 100644 index 000000000..75a7ee768 --- /dev/null +++ b/src/components/page-deployment/promote-deployment-action.js @@ -0,0 +1,42 @@ +import deploymentModel from '../../models/deployment'; +import PropTypes from 'prop-types'; +import configHandler from '../../utils/config'; +import { keys as configKeys } from '../../utils/config/keys'; +import ActionsPage from '../actions-page'; +import LinkButton from '../link-button'; +import { routeWithParams } from '../../utils/string'; +import routes from '../../routes'; +import React from 'react'; + +const PromoteDeploymentAction = ({ appName, deploymentName, deployment }) => { + return ( + + {deployment && + configHandler.getConfig(configKeys.FLAGS).enablePromotionPipeline && ( + + + Promote deployment… + + + )} + + ); +}; + +PromoteDeploymentAction.propTypes = { + appName: PropTypes.string.isRequired, + deploymentName: PropTypes.string.isRequired, + deployment: PropTypes.exact(deploymentModel), +}; + +export default PromoteDeploymentAction; diff --git a/src/components/page-job-new/index.js b/src/components/page-pipeline-job-new/index.js similarity index 95% rename from src/components/page-job-new/index.js rename to src/components/page-pipeline-job-new/index.js index c1b939ebb..a465ba07e 100644 --- a/src/components/page-job-new/index.js +++ b/src/components/page-pipeline-job-new/index.js @@ -17,7 +17,7 @@ import routes from '../../routes'; import jobActions from '../../state/job-creation/action-creators'; import { getCreationResult, getCreationState } from '../../state/job-creation'; -class PageJobNew extends React.Component { +class PagePipelineJobNew extends React.Component { componentWillUnmount() { this.props.resetCreate(); } @@ -96,7 +96,7 @@ class PageJobNew extends React.Component { } } -PageJobNew.propTypes = { +PagePipelineJobNew.propTypes = { appName: PropTypes.string.isRequired, creationState: PropTypes.oneOf(Object.values(requestStates)).isRequired, resetCreate: PropTypes.func.isRequired, @@ -113,5 +113,5 @@ const mapDispatchToProps = (dispatch) => ({ export default mapRouteParamsToProps( ['appName'], - connect(mapStateToProps, mapDispatchToProps)(PageJobNew) + connect(mapStateToProps, mapDispatchToProps)(PagePipelineJobNew) ); diff --git a/src/components/page-job/index.js b/src/components/page-pipeline-job/index.js similarity index 81% rename from src/components/page-job/index.js rename to src/components/page-pipeline-job/index.js index f5f368686..9e28de456 100644 --- a/src/components/page-job/index.js +++ b/src/components/page-pipeline-job/index.js @@ -8,7 +8,7 @@ import PageStep from '../page-step'; import { mapRouteParamsToProps } from '../../utils/routing'; import routes from '../../routes'; -export const PageJob = ({ appName, jobName }) => { +export const PipelinePageJob = ({ appName, jobName }) => { return ( @@ -22,4 +22,4 @@ export const PageJob = ({ appName, jobName }) => { ); }; -export default mapRouteParamsToProps(['appName', 'jobName'], PageJob); +export default mapRouteParamsToProps(['appName', 'jobName'], PipelinePageJob); diff --git a/src/components/page-jobs/index.js b/src/components/page-pipeline-jobs/index.js similarity index 94% rename from src/components/page-jobs/index.js rename to src/components/page-pipeline-jobs/index.js index 2d53bb175..5d0999187 100644 --- a/src/components/page-jobs/index.js +++ b/src/components/page-pipeline-jobs/index.js @@ -18,7 +18,7 @@ import routes from '../../routes'; import './style.css'; -class PageJobs extends React.Component { +class PipelinePageJobs extends React.Component { componentDidMount() { const { subscribeJobs, appName, envName } = this.props; subscribeJobs(appName, envName); @@ -64,7 +64,7 @@ class PageJobs extends React.Component { } } -PageJobs.propTypes = { +PipelinePageJobs.propTypes = { appName: PropTypes.string.isRequired, jobs: PropTypes.arrayOf(PropTypes.shape(jobSummaryModel)).isRequired, }; @@ -82,5 +82,5 @@ const mapDispatchToProps = (dispatch) => ({ export default mapRouteParamsToProps( ['appName'], - connect(mapStateToProps, mapDispatchToProps)(PageJobs) + connect(mapStateToProps, mapDispatchToProps)(PipelinePageJobs) ); diff --git a/src/components/page-jobs/style.css b/src/components/page-pipeline-jobs/style.css similarity index 100% rename from src/components/page-jobs/style.css rename to src/components/page-pipeline-jobs/style.css diff --git a/src/models/component-type/index.js b/src/models/component-type/index.js index 7d7f11f7f..e545ce828 100644 --- a/src/models/component-type/index.js +++ b/src/models/component-type/index.js @@ -8,11 +8,16 @@ export const componentType = { }; const componentTypeLabel = { component: 'Component', job: 'Job' }; +const componentTypeLabelPlural = { component: 'Components', job: 'Jobs' }; export const buildComponentTypeLabelMap = (type) => { return componentTypeLabel['' + type]; }; +export const buildComponentTypeLabelPluralMap = (type) => { + return componentTypeLabelPlural['' + type]; +}; + export const buildComponentMap = (components) => { return components.reduce((componentMap, component) => { let key = component.type; diff --git a/src/routes.js b/src/routes.js index 1b5afe78e..8a700f142 100644 --- a/src/routes.js +++ b/src/routes.js @@ -13,6 +13,7 @@ export const routes = { appPrivateImageHub: '/applications/:appName/config/imagehubs/:imageHubName', appBuildSecret: '/applications/:appName/config/buildsecrets/:secretName', appComponent: '/applications/:appName/deployments/:deploymentName/component/:componentName', + appJobComponent: '/applications/:appName/deployments/:deploymentName/jobcomponent/:jobComponentName', appDeployment: '/applications/:appName/deployments/:deploymentName', appDeployments: '/applications/:appName/deployments', appEnvironment: '/applications/:appName/envs/:envName', From cad8e3b0a20e8160f4306aa0c853a7be714b4324 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 13 Apr 2021 13:00:21 +0200 Subject: [PATCH 21/23] fixed layouts --- .../component/active-component-secrets.js | 4 +- src/components/component/component-ports.js | 4 +- src/components/component/component-secrets.js | 36 ++--- src/components/component/env-variables.js | 4 +- .../job-scheduler-details.js | 0 .../active-component-overview.js | 52 +------ .../page-active-component/default-alias.js | 4 +- .../horizontal-scaling-summary.js | 4 +- .../page-active-component/overview.js | 63 ++++++++ .../page-active-component/replica-list.js | 4 +- .../active-job-component-overview.js | 18 +-- .../page-active-job-component/overview.js | 24 +++ .../scheduled-job-list.js | 4 +- .../page-active-job-component/toolbar.js | 140 ------------------ .../deployment-component-overview.js | 23 +-- .../deployment-job-component-overview.js | 29 ++-- 16 files changed, 150 insertions(+), 263 deletions(-) rename src/components/{page-active-job-component => component}/job-scheduler-details.js (100%) create mode 100644 src/components/page-active-component/overview.js create mode 100644 src/components/page-active-job-component/overview.js delete mode 100644 src/components/page-active-job-component/toolbar.js diff --git a/src/components/component/active-component-secrets.js b/src/components/component/active-component-secrets.js index a87a01177..c85bdc9a3 100644 --- a/src/components/component/active-component-secrets.js +++ b/src/components/component/active-component-secrets.js @@ -15,7 +15,7 @@ const ActiveComponentSecrets = ({ environment, }) => { return ( - +

Secrets

{secrets.length === 0 &&

This component uses no secrets

} {secrets.length > 0 && ( @@ -44,7 +44,7 @@ const ActiveComponentSecrets = ({ })} )} -
+
); }; diff --git a/src/components/component/component-ports.js b/src/components/component/component-ports.js index ad3fc3c0d..b2592206e 100644 --- a/src/components/component/component-ports.js +++ b/src/components/component/component-ports.js @@ -4,7 +4,7 @@ import PortModel from '../../models/port'; const ComponentPorts = ({ ports }) => { return ( - + {ports.length > 0 && (

Open ports:

@@ -18,7 +18,7 @@ const ComponentPorts = ({ ports }) => {
)} {ports.length === 0 &&

No open ports

} -
+ ); }; diff --git a/src/components/component/component-secrets.js b/src/components/component/component-secrets.js index f7f8dfd1f..431c0fec0 100644 --- a/src/components/component/component-secrets.js +++ b/src/components/component/component-secrets.js @@ -6,28 +6,28 @@ import { buildComponentTypeLabelMap } from '../../models/component-type'; import Component from '../../models/component'; const ComponentSecrets = ({ component }) => { - let componentTypeTitle = component ? getComponentTypeTitle(component) : ''; + let componentTypeTitle = component + ? buildComponentTypeLabelMap(component.type) + : ''; return ( -
-

Secrets

- {component && component.secrets.length === 0 && ( -

This {componentTypeTitle.toLowerCase()} uses no secrets

- )} - {component && component.secrets.length > 0 && ( -
    - {component.secrets.map((secret) => ( -
  • {secret}
  • - ))} -
- )} -
+ +
+

Secrets

+ {component && component.secrets.length === 0 && ( +

This {componentTypeTitle.toLowerCase()} uses no secrets

+ )} + {component && component.secrets.length > 0 && ( +
    + {component.secrets.map((secret) => ( +
  • {secret}
  • + ))} +
+ )} +
+
); }; -function getComponentTypeTitle(component) { - return component ? buildComponentTypeLabelMap(component.type) : undefined; -} - ComponentSecrets.propTypes = { component: PropTypes.arrayOf(PropTypes.shape(Component)), }; diff --git a/src/components/component/env-variables.js b/src/components/component/env-variables.js index fa1dac7ff..4f48f55d3 100644 --- a/src/components/component/env-variables.js +++ b/src/components/component/env-variables.js @@ -34,7 +34,7 @@ const EnvVariables = ({ component, includeRadixVars }) => { }); return ( -
+

Environment variables

{envVarNames.length === 0 && (

This component uses no environment variables

@@ -49,7 +49,7 @@ const EnvVariables = ({ component, includeRadixVars }) => { )}
)} - + ); }; diff --git a/src/components/page-active-job-component/job-scheduler-details.js b/src/components/component/job-scheduler-details.js similarity index 100% rename from src/components/page-active-job-component/job-scheduler-details.js rename to src/components/component/job-scheduler-details.js diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index 669adc3cc..147d9cdaa 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -1,26 +1,20 @@ import { connect } from 'react-redux'; -import { faLink } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import PropTypes from 'prop-types'; import React from 'react'; -import Alert from '../alert'; -import DockerImage from '../docker-image'; import AsyncResource from '../async-resource'; import Toolbar from './toolbar'; - import { getAppAlias } from '../../state/application'; import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; import EnvVariables from '../component/env-variables'; import HorizontalScalingSummary from './horizontal-scaling-summary'; -import DefaultAlias from './default-alias'; -import ComponentSecrets from '../component/component-secrets'; import ComponentPorts from '../component/component-ports'; import ReplicaList from './replica-list'; import ComponentBredcrumb from '../component/component-bred-crumb'; -const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; +import Overview from './overview'; +import ActiveComponentSecrets from '../component/active-component-secrets'; export class ActiveComponentOverview extends React.Component { componentDidMount() { @@ -62,42 +56,12 @@ export class ActiveComponentOverview extends React.Component { />
-

Overview

-

- Component {component.name} -

- {component.status === 'Stopped' && ( - - Component has been manually stopped; please note that a - new deployment will cause it to be restarted unless you - set replicas of the component to{' '} - 0 in{' '} - - radixconfig.yaml - - - )} -

- Status {component.status} -

- {component.variables[URL_VAR_NAME] && ( -

- Publicly available{' '} - - link - -

- )} - -

- Image -

+ componentName={componentName} + component={component} + /> - + >
diff --git a/src/components/page-active-component/default-alias.js b/src/components/page-active-component/default-alias.js index 19ce9c48f..779ac2735 100644 --- a/src/components/page-active-component/default-alias.js +++ b/src/components/page-active-component/default-alias.js @@ -10,7 +10,7 @@ const DefaultAlias = (props) => { appAlias.componentName === componentName && appAlias.environmentName === envName; return ( - + {isDefaultAlias && ( This component is the application{' '} @@ -19,7 +19,7 @@ const DefaultAlias = (props) => { )} - + ); }; diff --git a/src/components/page-active-component/horizontal-scaling-summary.js b/src/components/page-active-component/horizontal-scaling-summary.js index 6bfe97247..3c37fed0e 100644 --- a/src/components/page-active-component/horizontal-scaling-summary.js +++ b/src/components/page-active-component/horizontal-scaling-summary.js @@ -5,7 +5,7 @@ import React from 'react'; const HorizontalScalingSummary = (props) => { const { component } = props; return ( - + {component.horizontalScalingSummary && (

Horizontal scaling

@@ -33,7 +33,7 @@ const HorizontalScalingSummary = (props) => {
)} -
+ ); }; diff --git a/src/components/page-active-component/overview.js b/src/components/page-active-component/overview.js new file mode 100644 index 000000000..8ab1e6b0c --- /dev/null +++ b/src/components/page-active-component/overview.js @@ -0,0 +1,63 @@ +import Alert from '../alert'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faLink } from '@fortawesome/free-solid-svg-icons'; +import DefaultAlias from './default-alias'; +import DockerImage from '../docker-image'; +import React from 'react'; +import componentModel from '../../models/component'; +import PropTypes from 'prop-types'; + +const URL_VAR_NAME = 'RADIX_PUBLIC_DOMAIN_NAME'; + +const Overview = ({ appAlias, envName, component }) => { + return ( + +

Overview

+

+ Component {component.name} +

+ {component.status === 'Stopped' && ( + + Component has been manually stopped; please note that a new deployment + will cause it to be restarted unless you set replicas of + the component to 0 in{' '} + + radixconfig.yaml + + + )} +

+ Status {component.status} +

+ {component.variables[URL_VAR_NAME] && ( +

+ Publicly available{' '} + + link + +

+ )} + {appAlias && ( + + )} +

+ Image +

+
+ ); +}; + +Overview.propTypes = { + appAlias: PropTypes.exact({ + environmentName: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + }), + envName: PropTypes.string.isRequired, + component: PropTypes.shape(componentModel), +}; + +export default Overview; diff --git a/src/components/page-active-component/replica-list.js b/src/components/page-active-component/replica-list.js index 325fc68af..ef121b8ba 100644 --- a/src/components/page-active-component/replica-list.js +++ b/src/components/page-active-component/replica-list.js @@ -14,7 +14,7 @@ const ReplicaList = ({ appName, envName, componentName, replicaList }) => { setNow(new Date()); }, [replicaList]); return ( - +

Replicas

{replicaList && replicaList.map((replica) => ( @@ -40,7 +40,7 @@ const ReplicaList = ({ appName, envName, componentName, replicaList }) => {

))} -
+ ); }; diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 7279d378f..174be0a1b 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -2,17 +2,17 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import React from 'react'; -import DockerImage from '../docker-image'; import AsyncResource from '../async-resource'; import { getComponent } from '../../state/environment'; import * as subscriptionActions from '../../state/subscriptions/action-creators'; import componentModel from '../../models/component'; import EnvVariables from '../component/env-variables'; -import ComponentSecrets from '../component/component-secrets'; import ComponentPorts from '../component/component-ports'; import ComponentBredcrumb from '../component/component-bred-crumb'; import ScheduledJobList from './scheduled-job-list'; -import JobSchedulerDetails from './job-scheduler-details'; +import JobSchedulerDetails from '../component/job-scheduler-details'; +import Overview from './overview'; +import ActiveComponentSecrets from '../component/active-component-secrets'; export class ActiveScheduledJobOverview extends React.Component { componentDidMount() { @@ -50,13 +50,7 @@ export class ActiveScheduledJobOverview extends React.Component {
-

Overview

-

- Job {component.name} -

-

- Image -

+ - + >
diff --git a/src/components/page-active-job-component/overview.js b/src/components/page-active-job-component/overview.js new file mode 100644 index 000000000..8d5f10363 --- /dev/null +++ b/src/components/page-active-job-component/overview.js @@ -0,0 +1,24 @@ +import DockerImage from '../docker-image'; +import React from 'react'; +import componentModel from '../../models/component'; +import PropTypes from 'prop-types'; + +const Overview = ({ component }) => { + return ( + +

Overview

+

+ Job {component.name} +

+

+ Image +

+
+ ); +}; + +Overview.propTypes = { + component: PropTypes.shape(componentModel), +}; + +export default Overview; diff --git a/src/components/page-active-job-component/scheduled-job-list.js b/src/components/page-active-job-component/scheduled-job-list.js index aa40fb931..9c9a118be 100644 --- a/src/components/page-active-job-component/scheduled-job-list.js +++ b/src/components/page-active-job-component/scheduled-job-list.js @@ -14,7 +14,7 @@ const ScheduledJobList = ({ scheduledJobList, }) => { return ( - +

Scheduled Job

{scheduledJobList.map((scheduledJob) => (

@@ -35,7 +35,7 @@ const ScheduledJobList = ({

))} -
+ ); }; diff --git a/src/components/page-active-job-component/toolbar.js b/src/components/page-active-job-component/toolbar.js deleted file mode 100644 index 963e87f0a..000000000 --- a/src/components/page-active-job-component/toolbar.js +++ /dev/null @@ -1,140 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import React from 'react'; -import Button from '../button'; -import ActionsPage from '../actions-page'; -import Spinner from '../spinner'; - -import { - getStartRequestStatus, - getStartRequestError, - getStopRequestStatus, - getStopRequestError, - getRestartRequestStatus, - getRestartRequestError, -} from '../../state/component'; -import componentStatuses from '../../state/component/component-states'; -import componentActions from '../../state/component/action-creators'; -import requestStatuses from '../../state/state-utils/request-states'; - -export class Toolbar extends React.Component { - constructor() { - super(); - - this.doStartComponent = this.doStartComponent.bind(this); - this.doStopComponent = this.doStopComponent.bind(this); - this.doRestartComponent = this.doRestartComponent.bind(this); - } - - doStartComponent(ev) { - ev.preventDefault(); - this.props.startComponent({ - appName: this.props.appName, - envName: this.props.envName, - componentName: this.props.component.name, - }); - } - - doStopComponent(ev) { - ev.preventDefault(); - this.props.stopComponent({ - appName: this.props.appName, - envName: this.props.envName, - componentName: this.props.component.name, - }); - } - - doRestartComponent(ev) { - ev.preventDefault(); - this.props.restartComponent({ - appName: this.props.appName, - envName: this.props.envName, - componentName: this.props.component.name, - }); - } - - render() { - const { - component, - startRequestStatus, - startRequestMessage, - stopRequestStatus, - stopRequestMessage, - restartRequestStatus, - restartRequestMessage, - } = this.props; - - const isStartEnabled = - component && - component.status === componentStatuses.STOPPED && - startRequestStatus !== requestStatuses.IN_PROGRESS; - - const isStopEnabled = - component && - component.status !== componentStatuses.STOPPED && - component.replicaList.length > 0 && - stopRequestStatus !== requestStatuses.IN_PROGRESS; - - const isRestartEnabled = - component && - component.status === componentStatuses.CONSISTENT && - component.replicaList.length > 0 && - restartRequestStatus !== requestStatuses.IN_PROGRESS; - - const restartInProgress = - restartRequestStatus === requestStatuses.IN_PROGRESS || - (component && - (component.status === componentStatuses.RECONCILING || - component.status === componentStatuses.RESTARTING)); - - return ( - - - {startRequestMessage &&
{startRequestMessage}
} - - {stopRequestMessage &&
{stopRequestMessage}
} - - {restartInProgress && } - {restartRequestMessage &&
{restartRequestMessage}
} -
- ); - } -} - -Toolbar.propTypes = { - startComponent: PropTypes.func.isRequired, - stopComponent: PropTypes.func.isRequired, - restartComponent: PropTypes.func.isRequired, - startRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), - startRequestMessage: PropTypes.string, - stopRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), - stopRequestMessage: PropTypes.string, - restartRequestStatus: PropTypes.oneOf(Object.values(requestStatuses)), - restartRequestMessage: PropTypes.string, -}; - -const mapStateToProps = (state) => ({ - startRequestStatus: getStartRequestStatus(state), - startRequestMessage: getStartRequestError(state), - stopRequestStatus: getStopRequestStatus(state), - stopRequestMessage: getStopRequestError(state), - restartRequestStatus: getRestartRequestStatus(state), - restartRequestMessage: getRestartRequestError(state), -}); - -const mapDispatchToProps = (dispatch) => ({ - startComponent: (component) => - dispatch(componentActions.startComponentRequest(component)), - stopComponent: (component) => - dispatch(componentActions.stopComponentRequest(component)), - restartComponent: (component) => - dispatch(componentActions.restartComponentRequest(component)), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Toolbar); diff --git a/src/components/page-deployment-component/deployment-component-overview.js b/src/components/page-deployment-component/deployment-component-overview.js index 62d791f61..7bb5665b1 100644 --- a/src/components/page-deployment-component/deployment-component-overview.js +++ b/src/components/page-deployment-component/deployment-component-overview.js @@ -1,7 +1,6 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import React from 'react'; -import DockerImage from '../docker-image'; import AsyncResource from '../async-resource'; import { getDeployment } from '../../state/deployment'; import * as actionCreators from '../../state/subscriptions/action-creators'; @@ -9,6 +8,7 @@ import ComponentSecrets from '../component/component-secrets'; import EnvVariables from '../component/env-variables'; import DeploymentComponentBredCrumb from '../page-deployment/deployment-component-bred-crumb'; import ComponentPorts from '../component/component-ports'; +import Overview from '../page-active-component/overview'; export class DeploymentComponentOverview extends React.Component { componentDidMount() { @@ -53,27 +53,20 @@ export class DeploymentComponentOverview extends React.Component {
-

Overview

-

- component {component.name} -

-

- Image -

- {component.ports.length > 0 && ( - - - - )} + +
- +
+ />
diff --git a/src/components/page-deployment-job-component/deployment-job-component-overview.js b/src/components/page-deployment-job-component/deployment-job-component-overview.js index a61475784..77c75bd20 100644 --- a/src/components/page-deployment-job-component/deployment-job-component-overview.js +++ b/src/components/page-deployment-job-component/deployment-job-component-overview.js @@ -9,7 +9,8 @@ import ComponentSecrets from '../component/component-secrets'; import EnvVariables from '../component/env-variables'; import DeploymentComponentBredCrumb from '../page-deployment/deployment-component-bred-crumb'; import ComponentPorts from '../component/component-ports'; -import JobSchedulerDetails from '../page-active-job-component/job-scheduler-details'; +import JobSchedulerDetails from '../component/job-scheduler-details'; +import Overview from '../page-active-job-component/overview'; export class DeploymentJobComponentOverview extends React.Component { componentDidMount() { @@ -57,32 +58,20 @@ export class DeploymentJobComponentOverview extends React.Component { > {deployment && component && ( -
+
-

Overview

-

- job {component.name} -

-

- Image -

- {component.ports.length > 0 && ( - - - - )} - + + +
- +
-
+
+ />
From a4070d03589d7176c4275e15e3a8109df49a9543 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 13 Apr 2021 13:16:49 +0200 Subject: [PATCH 22/23] fixed layouts --- .../deployment-component-list.js | 45 ++++++++++--------- .../deployment-job-component-list.js | 45 ++++++++++--------- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/components/page-deployment/deployment-component-list.js b/src/components/page-deployment/deployment-component-list.js index 2bb2ea2e0..770772961 100644 --- a/src/components/page-deployment/deployment-component-list.js +++ b/src/components/page-deployment/deployment-component-list.js @@ -8,27 +8,30 @@ import React from 'react'; const DeploymentComponentList = ({ appName, deploymentName, components }) => { return ( -
-

Components

- {components && - components.map((component) => { - return ( -

- - {component.name} - -
- image -

- ); - })} -
+ + {components && ( +
+

Components

+ {components.map((component) => { + return ( +

+ + {component.name} + +
+ image +

+ ); + })} +
+ )} +
); }; diff --git a/src/components/page-deployment/deployment-job-component-list.js b/src/components/page-deployment/deployment-job-component-list.js index 6e526eb36..311b656aa 100644 --- a/src/components/page-deployment/deployment-job-component-list.js +++ b/src/components/page-deployment/deployment-job-component-list.js @@ -12,27 +12,30 @@ const DeploymentJobComponentList = ({ components, }) => { return ( -
-

Jobs

- {components && - components.map((component) => { - return ( -

- - {component.name} - -
- image -

- ); - })} -
+ + {components && ( +
+

Jobs

+ {components.map((component) => { + return ( +

+ + {component.name} + +
+ image +

+ ); + })} +
+ )} +
); }; From 72e2a0847db30e876baf91bcacc28bbf4204c606 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Tue, 13 Apr 2021 14:35:48 +0200 Subject: [PATCH 23/23] fixed names and tests --- ...ponent-bred-crumb.js => component-bread-crumb.js} | 6 +++--- .../active-component-overview.js | 12 +++++------- .../active-job-component-overview.js | 4 ++-- .../deployment-component-overview.js | 4 ++-- .../deployment-job-component-overview.js | 4 ++-- ...yment-bred-crumb.js => deployment-bread-crumb.js} | 6 +++--- ...-crumb.js => deployment-component-bread-crumb.js} | 6 +++--- .../page-deployment/deployment-overview.js | 4 ++-- src/components/page-environment/component-list.js | 4 ++-- src/models/replica-summary/index.js | 2 +- src/models/replica-summary/test-data.js | 4 ++++ 11 files changed, 29 insertions(+), 27 deletions(-) rename src/components/component/{component-bred-crumb.js => component-bread-crumb.js} (85%) rename src/components/page-deployment/{deployment-bred-crumb.js => deployment-bread-crumb.js} (82%) rename src/components/page-deployment/{deployment-component-bred-crumb.js => deployment-component-bread-crumb.js} (87%) diff --git a/src/components/component/component-bred-crumb.js b/src/components/component/component-bread-crumb.js similarity index 85% rename from src/components/component/component-bred-crumb.js rename to src/components/component/component-bread-crumb.js index c6150b4af..38ad47301 100644 --- a/src/components/component/component-bred-crumb.js +++ b/src/components/component/component-bread-crumb.js @@ -6,7 +6,7 @@ import EnvironmentBadge from '../environment-badge'; import React from 'react'; import PropTypes from 'prop-types'; -const ComponentBredcrumb = ({ appName, envName, componentName }) => { +const ComponentBreadCrumb = ({ appName, envName, componentName }) => { return ( { ); }; -ComponentBredcrumb.propTypes = { +ComponentBreadCrumb.propTypes = { appName: PropTypes.string.isRequired, envName: PropTypes.string.isRequired, componentName: PropTypes.string.isRequired, }; -export default ComponentBredcrumb; +export default ComponentBreadCrumb; diff --git a/src/components/page-active-component/active-component-overview.js b/src/components/page-active-component/active-component-overview.js index 147d9cdaa..709441f83 100644 --- a/src/components/page-active-component/active-component-overview.js +++ b/src/components/page-active-component/active-component-overview.js @@ -12,7 +12,7 @@ import EnvVariables from '../component/env-variables'; import HorizontalScalingSummary from './horizontal-scaling-summary'; import ComponentPorts from '../component/component-ports'; import ReplicaList from './replica-list'; -import ComponentBredcrumb from '../component/component-bred-crumb'; +import ComponentBreadCrumb from '../component/component-bread-crumb'; import Overview from './overview'; import ActiveComponentSecrets from '../component/active-component-secrets'; @@ -37,7 +37,7 @@ export class ActiveComponentOverview extends React.Component { const { appAlias, appName, envName, componentName, component } = this.props; return ( -
- + + /> + />
diff --git a/src/components/page-active-job-component/active-job-component-overview.js b/src/components/page-active-job-component/active-job-component-overview.js index 174be0a1b..718768fb8 100644 --- a/src/components/page-active-job-component/active-job-component-overview.js +++ b/src/components/page-active-job-component/active-job-component-overview.js @@ -8,7 +8,7 @@ import * as subscriptionActions from '../../state/subscriptions/action-creators' import componentModel from '../../models/component'; import EnvVariables from '../component/env-variables'; import ComponentPorts from '../component/component-ports'; -import ComponentBredcrumb from '../component/component-bred-crumb'; +import ComponentBreadCrumb from '../component/component-bread-crumb'; import ScheduledJobList from './scheduled-job-list'; import JobSchedulerDetails from '../component/job-scheduler-details'; import Overview from './overview'; @@ -36,7 +36,7 @@ export class ActiveScheduledJobOverview extends React.Component { return ( - comp.name === componentName); return ( - comp.name === jobComponentName); return ( - { +const DeploymentBreadCrumb = ({ appName, deploymentName }) => { return ( { ); }; -DeploymentBredCrumb.propTypes = { +DeploymentBreadCrumb.propTypes = { appName: PropTypes.string.isRequired, deploymentName: PropTypes.string.isRequired, }; -export default DeploymentBredCrumb; +export default DeploymentBreadCrumb; diff --git a/src/components/page-deployment/deployment-component-bred-crumb.js b/src/components/page-deployment/deployment-component-bread-crumb.js similarity index 87% rename from src/components/page-deployment/deployment-component-bred-crumb.js rename to src/components/page-deployment/deployment-component-bread-crumb.js index dd09a343c..77b35d69a 100644 --- a/src/components/page-deployment/deployment-component-bred-crumb.js +++ b/src/components/page-deployment/deployment-component-bread-crumb.js @@ -4,7 +4,7 @@ import routes from '../../routes'; import React from 'react'; import PropTypes from 'prop-types'; -const DeploymentComponentBredCrumb = ({ +const DeploymentComponentBreadCrumb = ({ appName, deploymentName, componentName, @@ -32,10 +32,10 @@ const DeploymentComponentBredCrumb = ({ ); }; -DeploymentComponentBredCrumb.propTypes = { +DeploymentComponentBreadCrumb.propTypes = { appName: PropTypes.string.isRequired, deploymentName: PropTypes.string.isRequired, componentName: PropTypes.string.isRequired, }; -export default DeploymentComponentBredCrumb; +export default DeploymentComponentBreadCrumb; diff --git a/src/components/page-deployment/deployment-overview.js b/src/components/page-deployment/deployment-overview.js index d362cfc3b..99bf02a04 100644 --- a/src/components/page-deployment/deployment-overview.js +++ b/src/components/page-deployment/deployment-overview.js @@ -12,7 +12,7 @@ import DeploymentSummary from './deployment-summary'; import { buildComponentMap, componentType } from '../../models/component-type'; import DeploymentComponentList from './deployment-component-list'; import DeploymentJobComponentList from './deployment-job-component-list'; -import DeploymentBredCrumb from '../page-deployment/deployment-bred-crumb'; +import DeploymentBreadcrumb from '../page-deployment/deployment-bread-crumb'; import PromoteDeploymentAction from './promote-deployment-action'; export class DeploymentOverview extends React.Component { @@ -45,7 +45,7 @@ export class DeploymentOverview extends React.Component { return ( - diff --git a/src/components/page-environment/component-list.js b/src/components/page-environment/component-list.js index 7eebb087f..d4d4ebda6 100644 --- a/src/components/page-environment/component-list.js +++ b/src/components/page-environment/component-list.js @@ -3,7 +3,7 @@ import React from 'react'; import ComponentItem from '../../models/component-summary'; import { buildComponentMap, - buildComponentTypeLabelMap, + buildComponentTypeLabelPluralMap, } from '../../models/component-type'; import environmentModel from '../../models/environment'; import ComponentListItem from './component-list-item'; @@ -13,7 +13,7 @@ export const ComponentList = ({ appName, environment, components }) => { return Object.keys(compMap).map((componentType) => (

- Active {buildComponentTypeLabelMap(componentType)}s + Active {buildComponentTypeLabelPluralMap(componentType)}