Skip to content

Commit

Permalink
refactor(kubernetes): convert scale manifest stage to react (#10151)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt Gogerly <6519811+mattgogerly@users.noreply.github.com>
  • Loading branch information
cristhian-castaneda and mattgogerly authored Dec 2, 2024
1 parent 45bf17d commit 269b738
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 106 deletions.
2 changes: 0 additions & 2 deletions packages/kubernetes/src/kubernetes.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import { KUBERNETES_MANIFEST_STATUS } from './manifest/status/status.component';
import { ManifestWizard } from './manifest/wizard/ManifestWizard';
import './pipelines/stages';
import { KUBERNETES_FIND_ARTIFACTS_FROM_RESOURCE_STAGE } from './pipelines/stages/findArtifactsFromResource/findArtifactsFromResourceStage';
import { KUBERNETES_SCALE_MANIFEST_STAGE } from './pipelines/stages/scaleManifest/scaleManifestStage';
import { KUBERNETES_DISABLE_MANIFEST_STAGE } from './pipelines/stages/traffic/disableManifest.stage';
import { KUBERNETES_ENABLE_MANIFEST_STAGE } from './pipelines/stages/traffic/enableManifest.stage';
import { KUBERNETES_UNDO_ROLLOUT_MANIFEST_STAGE } from './pipelines/stages/undoRolloutManifest/undoRolloutManifestStage';
Expand Down Expand Up @@ -73,7 +72,6 @@ const requires = [
KUBERNETES_MANIFEST_ARTIFACT,
KUBERNETES_LOAD_BALANCER_TRANSFORMER,
KUBERNETES_SECURITY_GROUP_TRANSFORMER,
KUBERNETES_SCALE_MANIFEST_STAGE,
KUBERNETES_UNDO_ROLLOUT_MANIFEST_STAGE,
KUBERNETES_FIND_ARTIFACTS_FROM_RESOURCE_STAGE,
KUBERNETES_MANIFEST_SELECTOR,
Expand Down
43 changes: 43 additions & 0 deletions packages/kubernetes/src/manifest/scale/ScaleSettingsForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from 'react';
import { NumberInput, StageConfigField } from '@spinnaker/core';
import type { IScaleCommand } from './scale.controller';

export interface IScaleSettingsFormProps {
options: IScaleCommand;
onChange(options: IScaleCommand): void;
}

export interface IScaleSettingsFormState {
options: IScaleCommand;
}

export function ScaleSettingsForm({ options, onChange }: IScaleSettingsFormProps) {
const [state, setState] = useState<IScaleSettingsFormState>({
options: options,
});

const updateReplicas = (newReplicas: number) => {
state.options.replicas = newReplicas;
if (onChange) {
onChange(state.options);
}
setState({ options: state.options });
};

return (
<div className="form-horizontal">
<StageConfigField label="Replicas" fieldColumns={4} groupClassName="form-group form-inline">
<div className="input-group">
<NumberInput
inputClassName="input-sm highlight-pristine"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
updateReplicas(e.target.valueAsNumber);
}}
value={options.replicas}
min={0}
/>
</div>
</StageConfigField>
</div>
);
}
17 changes: 11 additions & 6 deletions packages/kubernetes/src/manifest/scale/scale.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IController } from 'angular';
import type { IController, IScope } from 'angular';
import { copy, module } from 'angular';
import type { IModalServiceInstance } from 'angular-ui-bootstrap';

Expand All @@ -7,7 +7,7 @@ import { ManifestWriter, TaskMonitor } from '@spinnaker/core';
import type { IManifestCoordinates } from '../IManifestCoordinates';
import { KUBERNETES_SCALE_MANIFEST_SETTINGS_FORM } from './scaleSettingsForm.component';

interface IScaleCommand {
export interface IScaleCommand {
manifestName: string;
location: string;
account: string;
Expand All @@ -17,13 +17,13 @@ interface IScaleCommand {

class KubernetesManifestScaleController implements IController {
public taskMonitor: TaskMonitor;
public command: IScaleCommand;
public verification = {
verified: false,
};

public static $inject = ['coordinates', 'currentReplicas', '$uibModalInstance', 'application'];
public static $inject = ['$scope', 'coordinates', 'currentReplicas', '$uibModalInstance', 'application'];
constructor(
private $scope: IScope,
coordinates: IManifestCoordinates,
currentReplicas: number,
private $uibModalInstance: IModalServiceInstance,
Expand All @@ -35,13 +35,18 @@ class KubernetesManifestScaleController implements IController {
modalInstance: $uibModalInstance,
});

this.command = {
this.$scope.command = {
manifestName: coordinates.name,
location: coordinates.namespace,
account: coordinates.account,
reason: null,
replicas: currentReplicas,
};

// used by react components to update command fields in parent (angular) scope
this.$scope.onChange = () => {
this.$scope.$applyAsync();
};
}

public isValid(): boolean {
Expand All @@ -54,7 +59,7 @@ class KubernetesManifestScaleController implements IController {

public scale(): void {
this.taskMonitor.submit(() => {
const payload = copy(this.command) as any;
const payload = copy(this.$scope.command) as any;
payload.cloudProvider = 'kubernetes';

return ManifestWriter.scaleManifest(payload, this.application);
Expand Down
13 changes: 9 additions & 4 deletions packages/kubernetes/src/manifest/scale/scale.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
<form role="form" name="scaleForm">
<modal-close dismiss="$dismiss()"></modal-close>
<div class="modal-header">
<h4 class="modal-title">Scale {{ctrl.command.manifestName | robotToHuman}} in {{ctrl.command.location}}</h4>
<h4 class="modal-title">
Scale {{ctrl.$scope.command.manifestName | robotToHuman}} in {{ctrl.$scope.command.location}}
</h4>
</div>
<div class="modal-body confirmation-modal">
<kubernetes-scale-manifest-settings-form settings="ctrl.command"></kubernetes-scale-manifest-settings-form>
<task-reason command="ctrl.command"></task-reason>
<kubernetes-scale-manifest-settings-form
options="ctrl.$scope.command"
on-change="ctrl.$scope.onChange"
></kubernetes-scale-manifest-settings-form>
<task-reason command="ctrl.$scope.command"></task-reason>
</div>
<div class="modal-footer">
<user-verification account="ctrl.command.account" verification="ctrl.verification"></user-verification>
<user-verification account="ctrl.$scope.command.account" verification="ctrl.verification"></user-verification>
<button type="submit" ng-click="ctrl.scale()" style="display: none"></button>
<!-- Allows form submission via enter keypress-->
<button class="btn btn-default" ng-click="ctrl.cancel()">Cancel</button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
import type { IComponentOptions } from 'angular';
import { module } from 'angular';

const kubernetesScaleManifestSettingsFormComponent: IComponentOptions = {
bindings: { settings: '=' },
controllerAs: 'ctrl',
template: `
<div class="form-horizontal">
<div class="form-group form-inline">
<div class="col-md-3 sm-label-right">
Replicas
</div>
<div class="col-md-4">
<input type="text"
class="form-control input-sm highlight-pristine"
ng-model="ctrl.settings.replicas"
min="0"/>
</div>
</div>
</div>
`,
};
import { react2angular } from 'react2angular';
import { withErrorBoundary } from '@spinnaker/core';
import { ScaleSettingsForm } from './ScaleSettingsForm';

export const KUBERNETES_SCALE_MANIFEST_SETTINGS_FORM =
'spinnaker.kubernetes.v2.kubernetes.manifest.scale.settingsForm.component';
module(KUBERNETES_SCALE_MANIFEST_SETTINGS_FORM, []).component(
'kubernetesScaleManifestSettingsForm',
kubernetesScaleManifestSettingsFormComponent,
react2angular(withErrorBoundary(ScaleSettingsForm, 'kubernetesScaleManifestSettingsForm'), ['options', 'onChange']),
);
1 change: 1 addition & 0 deletions packages/kubernetes/src/pipelines/stages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './deployManifest/deployManifestStage';
export * from './patchManifest/patchManifestStage';
export * from './rolloutRestartManifest/rolloutRestartManifestStage';
export * from './runJob/runJobStage';
export * from './scaleManifest/scaleManifestStage';
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { defaults } from 'lodash';
import React, { useEffect } from 'react';

import type { IFormikStageConfigInjectedProps, IStageConfigProps } from '@spinnaker/core';
import { FormikStageConfig } from '@spinnaker/core';

import { ScaleManifestStageForm } from './ScaleManifestStageForm';

export function ScaleManifestStageConfig({
application,
pipeline,
stage,
updateStage,
stageFieldUpdated,
}: IStageConfigProps) {
useEffect(() => {
defaults(stage, {
app: application.name,
cloudProvider: 'kubernetes',
});

if (stage.isNew) {
stage.replicas = 0;
}
}, []);

return (
<FormikStageConfig
application={application}
pipeline={pipeline}
stage={stage}
onChange={updateStage}
render={(props: IFormikStageConfigInjectedProps) => (
<ScaleManifestStageForm {...props} stageFieldUpdated={stageFieldUpdated} />
)}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';

import type { IFormikStageConfigInjectedProps } from '@spinnaker/core';

import type { IScaleCommand } from '../../../manifest';
import { ScaleSettingsForm } from '../../../manifest/scale/ScaleSettingsForm';
import type { IManifestSelector } from '../../../manifest/selector/IManifestSelector';
import { SelectorMode } from '../../../manifest/selector/IManifestSelector';
import { ManifestSelector } from '../../../manifest/selector/ManifestSelector';

interface IScaleManifestStageConfigFormProps {
stageFieldUpdated: () => void;
}

export function ScaleManifestStageForm({
application,
formik,
stageFieldUpdated,
}: IScaleManifestStageConfigFormProps & IFormikStageConfigInjectedProps) {
const stage = formik.values;

const onManifestSelectorChange = () => {
stageFieldUpdated();
};

const onScaleSettingsFormChange = () => {
stageFieldUpdated();
};

return (
<div className="form-horizontal">
<h4>Manifest</h4>
<div className="horizontal-rule" />
<ManifestSelector
application={application}
selector={(stage as unknown) as IManifestSelector}
modes={[SelectorMode.Static, SelectorMode.Dynamic]}
onChange={onManifestSelectorChange}
includeSpinnakerKinds={null}
/>
<h4>Settings</h4>
<div className="horizontal-rule" />
<ScaleSettingsForm options={(stage as unknown) as IScaleCommand} onChange={onScaleSettingsFormChange} />
</div>
);
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import { module } from 'angular';

import type { IStage } from '@spinnaker/core';
import { ExecutionDetailsTasks, Registry } from '@spinnaker/core';

import { manifestExecutionDetails } from '../ManifestExecutionDetails';
import { KUBERNETES_SCALE_MANIFEST_SETTINGS_FORM } from '../../../manifest/scale/scaleSettingsForm.component';
import { KubernetesV2ScaleManifestConfigCtrl } from './scaleManifestConfig.controller';
import { ScaleManifestStageConfig } from './ScaleManifestConfig';
import { manifestSelectorValidators } from '../validators/manifestSelectorValidators';

export const KUBERNETES_SCALE_MANIFEST_STAGE = 'spinnaker.kubernetes.v2.pipeline.stage.scaleManifestStage';
const STAGE_NAME = 'Scale (Manifest)';
const STAGE_KEY = 'scaleManifest';

module(KUBERNETES_SCALE_MANIFEST_STAGE, [KUBERNETES_SCALE_MANIFEST_SETTINGS_FORM])
.config(() => {
Registry.pipeline.registerStage({
label: 'Scale (Manifest)',
description: 'Scale a Kubernetes object created from a manifest.',
key: STAGE_KEY,
cloudProvider: 'kubernetes',
templateUrl: require('./scaleManifestConfig.html'),
controller: 'KubernetesV2ScaleManifestConfigCtrl',
controllerAs: 'ctrl',
executionDetailsSections: [manifestExecutionDetails(STAGE_KEY), ExecutionDetailsTasks],
accountExtractor: (stage: IStage): string[] => (stage.account ? [stage.account] : []),
configAccountExtractor: (stage: any): string[] => (stage.account ? [stage.account] : []),
validators: [
{ type: 'requiredField', fieldName: 'location', fieldLabel: 'Namespace' },
{ type: 'requiredField', fieldName: 'account', fieldLabel: 'Account' },
{ type: 'requiredField', fieldName: 'replicas', fieldLabel: 'Replicas' },
],
});
})
.controller('KubernetesV2ScaleManifestConfigCtrl', KubernetesV2ScaleManifestConfigCtrl);
Registry.pipeline.registerStage({
label: STAGE_NAME,
description: 'Scale a Kubernetes object created from a manifest.',
key: STAGE_KEY,
cloudProvider: 'kubernetes',
component: ScaleManifestStageConfig,
executionDetailsSections: [manifestExecutionDetails(STAGE_KEY), ExecutionDetailsTasks],
validators: [
...manifestSelectorValidators(STAGE_NAME),
{ type: 'requiredField', fieldName: 'replicas', fieldLabel: 'Replicas' },
],
});

0 comments on commit 269b738

Please sign in to comment.