Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): Reactify the pipeline trigger configuration #7318

Merged
merged 3 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(() => {
let original = getOriginal();
Jammy-Louie marked this conversation as resolved.
Show resolved Hide resolved
$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