Skip to content

Commit

Permalink
refactor(core): Reactify the pipeline trigger configuration (#7318)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jammy Louie committed Aug 13, 2019
1 parent 7cc7168 commit bec54df
Show file tree
Hide file tree
Showing 30 changed files with 680 additions and 408 deletions.
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/domain/IPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface IPipeline {
parameterConfig: IParameter[];
disabled?: boolean;
expectedArtifacts?: IExpectedArtifact[];
roles?: any[];
source?: {
id: string;
type: string;
Expand All @@ -39,6 +40,7 @@ export interface IParameter extends ITemplateInheritable {
description: string;
default: string;
hasOptions: boolean;
label?: string;
pinned: boolean;
options: IParameterOption[];
condition?: IParameterCondition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AppNotificationsService } from './AppNotificationsService';
import { NotificationTransformer } from './notification.transformer';
import { EditNotificationModal } from './modal/EditNotificationModal';

export interface INotificationListProps {
export interface INotificationsListProps {
application?: Application;
level: string;
stageType?: string;
Expand All @@ -21,15 +21,15 @@ export interface INotificationListProps {
updateNotifications: (notifications: INotification[]) => void;
}

export interface INotificationListState {
export interface INotificationsListState {
isNotificationsDirty: boolean;
supportedNotificationTypes: string[];
}

export class NotificationList extends React.Component<INotificationListProps, INotificationListState> {
export class NotificationsList extends React.Component<INotificationsListProps, INotificationsListState> {
private destroy$ = new Subject();

constructor(props: INotificationListProps) {
constructor(props: INotificationsListProps) {
super(props);
this.state = {
isNotificationsDirty: false,
Expand Down
1 change: 1 addition & 0 deletions app/scripts/modules/core/src/notification/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './modal';
export * from './notification.transformer';
export * from './selector/NotificationSelector';
export * from './notificationList.module';
export * from './NotificationsList';
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { module } from 'angular';
import { react2angular } from 'react2angular';

import { NotificationList } from './NotificationList';
import { NotificationsList } from './NotificationsList';

export const NOTIFICATION_LIST = 'spinnaker.core.notifications.notificationList';
module(NOTIFICATION_LIST, []).component(
'notificationList',
react2angular(NotificationList, [
react2angular(NotificationsList, [
'application',
'level',
'stageType',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import * as React from 'react';
import * as classNames from 'classnames';

import { IParameter } from 'core/domain';
import { HelpField } from 'core/help';
import { Tooltip } from 'core/presentation';
import { StageConfigField } from 'core/pipeline';
import { SortableHandle } from 'react-sortable-hoc';

export interface IParameter {
name: string;
label: string;
required: boolean;
pinned: boolean;
description: string;
default: string;
hasOptions: boolean;
options: IParameterOption[];
inherited: boolean;
}

export interface IParameterOption {
value: string;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { arrayMove, SortableContainer, SortableContainerProps, SortableElement, SortEnd } from 'react-sortable-hoc';

import { IParameter } from 'core/domain';
import { HelpField } from 'core/help';

import { IParameter, IParameterProps, Parameter } from './Parameter';
import { IParameterProps, Parameter } from './Parameter';

export interface IParametersState {
allParametersPinned: boolean;
Expand Down
11 changes: 10 additions & 1 deletion app/scripts/modules/core/src/pipeline/config/pipelineConfig.less
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ pipeline-configurer {
}
}

triggers {
triggers,
.triggers {
.add-new {
margin: 0;
}
Expand All @@ -214,6 +215,14 @@ triggers {
}
}

.expected-artifact {
display: block;
padding: 10px 20px;
background-color: var(--color-white);
border: 1px solid var(--color-cirrus);
margin-bottom: 15px;
}

.config-section {
padding: 0;
display: inline-block;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const angular = require('angular');
import { CREATE_PIPELINE_COMPONENT } from './createPipeline.component';
import { PIPELINE_GRAPH_COMPONENT } from './graph/pipeline.graph.component';
import { TARGET_SELECT_COMPONENT } from 'core/pipeline/config/targetSelect.component';
import { TRIGGERS } from './triggers/triggers.module';
import './triggers';
import './validation/requiredField.validator';
import './validation/anyFieldRequired.validator';
import './validation/serviceAccountAccess.validator';
Expand All @@ -21,7 +23,7 @@ module.exports = angular.module('spinnaker.core.pipeline.config', [
PIPELINE_GRAPH_COMPONENT,
require('./stages/stage.module').name,
require('./stages/baseProviderStage/baseProviderStage').name,
require('./triggers/trigger.module').name,
TRIGGERS,
require('./parameters/pipeline.module').name,
require('./pipelineConfig.controller').name,
require('./pipelineConfigView').name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
application="application"
field-updated="stageFieldUpdated"
pipeline="pipelineConfig"
update-pipeline-config="updatePipelineConfig"
>
</triggers>
<pipeline-config-stage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = angular
viewState: '=',
pipelineConfig: '=',
stageFieldUpdated: '<',
updatePipelineConfig: '<',
},
templateUrl: require('./pipelineConfigView.html'),
link: function(scope, elem, attrs, pipelineConfigurerCtrl) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ <h3>
pipeline="renderablePipeline"
pipeline-config="pipeline"
stage-field-updated="pipelineConfigurerCtrl.stageFieldUpdated"
update-pipeline-config="pipelineConfigurerCtrl.updatePipelineConfig"
view-state="viewState"
></pipeline-config-view>

Expand Down
58 changes: 34 additions & 24 deletions app/scripts/modules/core/src/pipeline/config/pipelineConfigurer.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,33 +469,33 @@ module.exports = angular
};

this.revertPipelineChanges = () => {
let original = getOriginal();
Object.keys($scope.pipeline).forEach(key => {
delete $scope.pipeline[key];
});
Object.assign($scope.pipeline, original);

if ($scope.isTemplatedPipeline) {
const originalRenderablePipeline = getOriginalRenderablePipeline();
Object.assign($scope.renderablePipeline, originalRenderablePipeline);
Object.keys($scope.renderablePipeline).forEach(key => {
if (!originalRenderablePipeline.hasOwnProperty(key)) {
delete $scope.renderablePipeline[key];
}
});
}
$scope.$applyAsync(() => {
const original = getOriginal();
$scope.pipeline = _.clone(original);
$scope.renderablePipeline = $scope.pipeline;

// if we were looking at a stage that no longer exists, move to the last stage
if ($scope.viewState.section === 'stage') {
var lastStage = $scope.renderablePipeline.stages.length - 1;
if ($scope.viewState.stageIndex > lastStage) {
this.setViewState({ stageIndex: lastStage });
if ($scope.isTemplatedPipeline) {
const originalRenderablePipeline = getOriginalRenderablePipeline();
Object.assign($scope.renderablePipeline, originalRenderablePipeline);
Object.keys($scope.renderablePipeline).forEach(key => {
if (!originalRenderablePipeline.hasOwnProperty(key)) {
delete $scope.renderablePipeline[key];
}
});
}
if (!$scope.renderablePipeline.stages.length) {
this.navigateTo({ section: 'triggers' });

// if we were looking at a stage that no longer exists, move to the last stage
if ($scope.viewState.section === 'stage') {
var lastStage = $scope.renderablePipeline.stages.length - 1;
if ($scope.viewState.stageIndex > lastStage) {
this.setViewState({ stageIndex: lastStage });
}
if (!$scope.renderablePipeline.stages.length) {
this.navigateTo({ section: 'triggers' });
}
}
}
$scope.$broadcast('pipeline-reverted');
$scope.$broadcast('pipeline-reverted');
});
};

var markDirty = () => {
Expand Down Expand Up @@ -572,5 +572,15 @@ module.exports = angular
},
);
};

//update pipeline through a callback for React
this.updatePipelineConfig = changes => {
$scope.$applyAsync(() => {
$scope.pipeline = _.cloneDeep($scope.pipeline);
_.extend($scope.pipeline, changes);
$scope.renderablePipeline = $scope.pipeline;
markDirty();
});
};
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from 'react';

import { IPipeline } from 'core/domain';
import { FormField, TextAreaInput } from 'core/presentation';

export interface IDescriptionPageContentProps {
pipeline: IPipeline;
updatePipelineConfig: (changes: Partial<IPipeline>) => void;
}

export function DescriptionPageContent(props: IDescriptionPageContentProps) {
const { pipeline, updatePipelineConfig } = props;

return (
<div className="row">
<div className="col-md-12">
<FormField
name={'description'}
input={inputProps => (
<TextAreaInput
{...inputProps}
placeholder={
'(Optional) anything that might be helpful to explain the purpose of this pipeline; Markdown is okay'
}
rows={3}
/>
)}
value={pipeline.description}
onChange={event => {
updatePipelineConfig({ description: event.target.value });
}}
/>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';

import { IPipeline } from 'core/domain';
import { CheckboxInput, FormField } from 'core/presentation';
import { HelpField } from 'core/help';

export interface IExecutionOptionsPageContentProps {
pipeline: IPipeline;
updatePipelineConfig: (changes: Partial<IPipeline>) => void;
}

export function ExecutionOptionsPageContent(props: IExecutionOptionsPageContentProps) {
const { pipeline, updatePipelineConfig } = props;
return (
<div className="row">
<div className="col-md-11 col-md-offset-1">
<FormField
input={inputProps => (
<CheckboxInput
{...inputProps}
text={<strong>Disable concurrent pipeline executions (only run one at a time). </strong>}
/>
)}
onChange={() => {
updatePipelineConfig({ limitConcurrent: !pipeline.limitConcurrent });
}}
value={pipeline.limitConcurrent}
/>
{pipeline.limitConcurrent && (
<FormField
input={inputProps => (
<CheckboxInput
{...inputProps}
text={
<>
<strong>Disable concurrent pipeline executions (only run one at a time). </strong>
<HelpField id={'pipeline.config.parallel.cancel.queue'} />
</>
}
/>
)}
onChange={() => {
updatePipelineConfig({ keepWaitingPipelines: !pipeline.keepWaitingPipelines });
}}
value={pipeline.keepWaitingPipelines}
/>
)}
</div>
</div>
);
}
Loading

0 comments on commit bec54df

Please sign in to comment.