@spinnaker/cloudrun 2026.2.3 → 2026.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cloudrun.module.d.ts +1 -1
- package/dist/common/ComponentUrlDetails.d.ts +7 -0
- package/dist/common/LoadBalancerMessage.d.ts +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/instance/details/CloudrunInstanceDetails.d.ts +23 -0
- package/dist/loadBalancer/configure/wizard/CloudrunLoadBalancerModal.d.ts +32 -0
- package/dist/loadBalancer/details/CloudrunLoadBalancerActions.d.ts +3 -0
- package/dist/loadBalancer/details/sections.d.ts +7 -0
- package/dist/loadBalancer/details/useCloudrunLoadBalancerDetails.d.ts +4 -0
- package/dist/loadBalancer/index.d.ts +4 -2
- package/dist/loadBalancer/loadBalancerTransformer.d.ts +2 -6
- package/dist/manifest/manifest.service.d.ts +5 -0
- package/dist/manifest/manifestCommandBuilder.service.d.ts +1 -1
- package/dist/pipeline/stages/deployManifest/manifestStatus/DeployStatus.d.ts +1 -0
- package/dist/pipeline/stages/deployManifest/manifestStatus/ManifestDetailsLink.d.ts +6 -3
- package/dist/pipeline/stages/editLoadBalancer/CloudrunEditLoadBalancerExecutionDetails.d.ts +7 -0
- package/dist/pipeline/stages/editLoadBalancer/CloudrunEditLoadBalancerStageConfig.d.ts +30 -0
- package/dist/pipeline/stages/editLoadBalancer/cloudrunEditLoadBalancerStage.d.ts +2 -1
- package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +4 -6
- package/dist/serverGroup/configure/wizard/BasicSettings.d.ts +5 -2
- package/dist/serverGroup/configure/wizard/serverGroupWizard.d.ts +18 -6
- package/dist/serverGroup/details/CloudrunServerGroupActions.d.ts +6 -0
- package/dist/serverGroup/details/cloudrunServerGroupDetailsGetter.d.ts +3 -0
- package/dist/serverGroup/details/sections.d.ts +5 -0
- package/dist/serverGroup/index.d.ts +3 -1
- package/dist/serverGroup/serverGroupTransformer.service.d.ts +1 -5
- package/package.json +4 -11
- package/src/cloudrun.module.spec.ts +22 -0
- package/src/cloudrun.module.ts +54 -59
- package/src/common/ComponentUrlDetails.tsx +25 -0
- package/src/common/LoadBalancerMessage.tsx +17 -0
- package/src/index.ts +2 -1
- package/src/instance/details/CloudrunInstanceDetails.tsx +164 -0
- package/src/loadBalancer/configure/wizard/CloudrunLoadBalancerModal.spec.tsx +85 -0
- package/src/loadBalancer/configure/wizard/CloudrunLoadBalancerModal.tsx +395 -0
- package/src/loadBalancer/details/CloudrunLoadBalancerActions.tsx +66 -0
- package/src/loadBalancer/details/sections.spec.ts +19 -0
- package/src/loadBalancer/details/sections.tsx +91 -0
- package/src/loadBalancer/details/useCloudrunLoadBalancerDetails.ts +56 -0
- package/src/loadBalancer/index.ts +4 -2
- package/src/loadBalancer/loadBalancerTransformer.ts +3 -13
- package/src/manifest/manifest.service.ts +18 -1
- package/src/manifest/manifestCommandBuilder.service.ts +46 -53
- package/src/pipeline/stages/deployManifest/manifestStatus/DeployStatus.tsx +33 -4
- package/src/pipeline/stages/deployManifest/manifestStatus/ManifestDetailsLink.spec.tsx +35 -0
- package/src/pipeline/stages/deployManifest/manifestStatus/ManifestDetailsLink.tsx +10 -5
- package/src/pipeline/stages/editLoadBalancer/CloudrunEditLoadBalancerExecutionDetails.tsx +70 -0
- package/src/pipeline/stages/editLoadBalancer/CloudrunEditLoadBalancerStageConfig.tsx +245 -0
- package/src/pipeline/stages/editLoadBalancer/cloudrunEditLoadBalancerStage.spec.ts +205 -0
- package/src/pipeline/stages/editLoadBalancer/cloudrunEditLoadBalancerStage.ts +14 -71
- package/src/serverGroup/configure/serverGroupCommandBuilder.service.ts +5 -15
- package/src/serverGroup/configure/wizard/BasicSettings.tsx +10 -8
- package/src/serverGroup/configure/wizard/serverGroupWizard.tsx +59 -15
- package/src/serverGroup/details/CloudrunServerGroupActions.tsx +80 -0
- package/src/serverGroup/details/cloudrunServerGroupDetailsGetter.spec.ts +46 -0
- package/src/serverGroup/details/cloudrunServerGroupDetailsGetter.ts +53 -0
- package/src/serverGroup/details/sections.tsx +60 -0
- package/src/serverGroup/index.ts +3 -1
- package/src/serverGroup/routerConsumers.spec.tsx +152 -0
- package/src/serverGroup/serverGroupTransformer.service.ts +2 -12
- package/dist/common/componentUrlDetails.component.d.ts +0 -1
- package/dist/common/conditionalDescriptionListItem.component.d.ts +0 -1
- package/dist/common/loadBalancerMessage.component.d.ts +0 -1
- package/dist/instance/details/details.controller.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/allocationConfigurationRow.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/basicSettings.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.d.ts +0 -1
- package/dist/loadBalancer/configure/wizard/wizard.controller.d.ts +0 -2
- package/dist/loadBalancer/details/details.controller.d.ts +0 -1
- package/dist/pipeline/pipeline.module.d.ts +0 -1
- package/dist/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.controller.d.ts +0 -1
- package/dist/serverGroup/details/details.controller.d.ts +0 -1
- package/src/common/componentUrlDetails.component.ts +0 -22
- package/src/common/conditionalDescriptionListItem.component.ts +0 -37
- package/src/common/loadBalancerMessage.component.html +0 -11
- package/src/common/loadBalancerMessage.component.ts +0 -13
- package/src/instance/details/details.controller.ts +0 -84
- package/src/instance/details/details.html +0 -68
- package/src/loadBalancer/configure/wizard/allocationConfigurationRow.component.ts +0 -70
- package/src/loadBalancer/configure/wizard/basicSettings.component.html +0 -44
- package/src/loadBalancer/configure/wizard/basicSettings.component.ts +0 -86
- package/src/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.html +0 -45
- package/src/loadBalancer/configure/wizard/stageAllocationConfigurationRow.component.ts +0 -84
- package/src/loadBalancer/configure/wizard/wizard.controller.ts +0 -157
- package/src/loadBalancer/configure/wizard/wizard.html +0 -39
- package/src/loadBalancer/configure/wizard/wizard.less +0 -9
- package/src/loadBalancer/details/details.controller.ts +0 -140
- package/src/loadBalancer/details/details.html +0 -89
- package/src/pipeline/pipeline.module.ts +0 -6
- package/src/pipeline/stages/editLoadBalancer/editLoadBalancerExecutionDetails.html +0 -33
- package/src/pipeline/stages/editLoadBalancer/editLoadBalancerStage.html +0 -51
- package/src/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.controller.ts +0 -65
- package/src/pipeline/stages/editLoadBalancer/loadBalancerChoice.modal.html +0 -53
- package/src/serverGroup/details/details.controller.ts +0 -134
- package/src/serverGroup/details/details.html +0 -94
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { cloneDeep } from 'lodash';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ILoadBalancer, IStageConfigProps } from '@spinnaker/core';
|
|
5
|
+
import { AccountTag, ReactModal } from '@spinnaker/core';
|
|
6
|
+
|
|
7
|
+
import { getLoadBalancerCompositeKey } from './CloudrunEditLoadBalancerExecutionDetails';
|
|
8
|
+
import { LoadBalancerMessage } from '../../../common/LoadBalancerMessage';
|
|
9
|
+
import { CloudrunLoadBalancerModal } from '../../../loadBalancer/configure/wizard/CloudrunLoadBalancerModal';
|
|
10
|
+
|
|
11
|
+
export class CloudrunEditLoadBalancerStageConfig extends React.Component<IStageConfigProps> {
|
|
12
|
+
public componentDidMount(): void {
|
|
13
|
+
this.props.updateStage({
|
|
14
|
+
loadBalancers: this.props.stage.loadBalancers || [],
|
|
15
|
+
cloudProvider: 'cloudrun',
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private addLoadBalancer = (): void => {
|
|
20
|
+
CloudrunLoadBalancerChoiceModal.show({ application: this.props.application })
|
|
21
|
+
.then((newLoadBalancer) => {
|
|
22
|
+
this.props.updateStage({ loadBalancers: [...(this.props.stage.loadBalancers || []), newLoadBalancer] });
|
|
23
|
+
})
|
|
24
|
+
.catch(() => undefined);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
private editLoadBalancer = (index: number): void => {
|
|
28
|
+
CloudrunLoadBalancerModal.show({
|
|
29
|
+
app: this.props.application,
|
|
30
|
+
loadBalancer: cloneDeep(this.props.stage.loadBalancers[index]),
|
|
31
|
+
isNew: false,
|
|
32
|
+
forPipelineConfig: true,
|
|
33
|
+
})
|
|
34
|
+
.then((updatedLoadBalancer) => {
|
|
35
|
+
const loadBalancers = [...this.props.stage.loadBalancers];
|
|
36
|
+
loadBalancers[index] = updatedLoadBalancer;
|
|
37
|
+
this.props.updateStage({ loadBalancers });
|
|
38
|
+
})
|
|
39
|
+
.catch(() => undefined);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
private removeLoadBalancer = (index: number): void => {
|
|
43
|
+
const loadBalancers = [...this.props.stage.loadBalancers];
|
|
44
|
+
loadBalancers.splice(index, 1);
|
|
45
|
+
this.props.updateStage({ loadBalancers });
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
public render() {
|
|
49
|
+
const { pipeline, stage } = this.props;
|
|
50
|
+
if (pipeline.strategy) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<div className="well well-sm clearfix">
|
|
55
|
+
<div className="row">
|
|
56
|
+
<div className="col-md-12">
|
|
57
|
+
<h4 className="text-left">Load Balancers</h4>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div className="row">
|
|
61
|
+
<div className="col-md-12">
|
|
62
|
+
<table className="table table-condensed">
|
|
63
|
+
<thead>
|
|
64
|
+
<tr>
|
|
65
|
+
<th>Account</th>
|
|
66
|
+
<th>Name</th>
|
|
67
|
+
<th>Region</th>
|
|
68
|
+
<th>Actions</th>
|
|
69
|
+
</tr>
|
|
70
|
+
</thead>
|
|
71
|
+
<tbody>
|
|
72
|
+
{(stage.loadBalancers || []).map((loadBalancer: ILoadBalancer, index: number) => (
|
|
73
|
+
<tr
|
|
74
|
+
key={`${loadBalancer.credentials || loadBalancer.account}:${loadBalancer.name}:${
|
|
75
|
+
loadBalancer.region
|
|
76
|
+
}`}
|
|
77
|
+
>
|
|
78
|
+
<td>
|
|
79
|
+
<AccountTag account={loadBalancer.credentials || loadBalancer.account} />
|
|
80
|
+
</td>
|
|
81
|
+
<td>{loadBalancer.name}</td>
|
|
82
|
+
<td>{loadBalancer.region}</td>
|
|
83
|
+
<td className="condensed-actions">
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
className="btn btn-sm btn-link"
|
|
87
|
+
onClick={() => this.editLoadBalancer(index)}
|
|
88
|
+
>
|
|
89
|
+
<span className="glyphicon glyphicon-edit" title="Edit" />
|
|
90
|
+
</button>
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
className="btn btn-sm btn-link pad-left"
|
|
94
|
+
onClick={() => this.removeLoadBalancer(index)}
|
|
95
|
+
>
|
|
96
|
+
<span className="glyphicon glyphicon-trash" title="Remove" />
|
|
97
|
+
</button>
|
|
98
|
+
</td>
|
|
99
|
+
</tr>
|
|
100
|
+
))}
|
|
101
|
+
</tbody>
|
|
102
|
+
<tfoot>
|
|
103
|
+
<tr>
|
|
104
|
+
<td colSpan={8}>
|
|
105
|
+
<button type="button" className="btn btn-block btn-sm add-new" onClick={this.addLoadBalancer}>
|
|
106
|
+
<span className="glyphicon glyphicon-plus-sign" /> Add load balancer
|
|
107
|
+
</button>
|
|
108
|
+
</td>
|
|
109
|
+
</tr>
|
|
110
|
+
</tfoot>
|
|
111
|
+
</table>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface ICloudrunLoadBalancerChoiceModalProps {
|
|
120
|
+
application: IStageConfigProps['application'];
|
|
121
|
+
closeModal?: (loadBalancer: ILoadBalancer) => void;
|
|
122
|
+
dismissModal?: () => void;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface ICloudrunLoadBalancerChoiceModalState {
|
|
126
|
+
loading: boolean;
|
|
127
|
+
loadBalancers: ILoadBalancer[];
|
|
128
|
+
selectedLoadBalancer?: ILoadBalancer;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export class CloudrunLoadBalancerChoiceModal extends React.Component<
|
|
132
|
+
ICloudrunLoadBalancerChoiceModalProps,
|
|
133
|
+
ICloudrunLoadBalancerChoiceModalState
|
|
134
|
+
> {
|
|
135
|
+
public static show(props: ICloudrunLoadBalancerChoiceModalProps): Promise<ILoadBalancer> {
|
|
136
|
+
return ReactModal.show(CloudrunLoadBalancerChoiceModal, props);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private mounted = false;
|
|
140
|
+
|
|
141
|
+
public state: ICloudrunLoadBalancerChoiceModalState = { loading: true, loadBalancers: [] };
|
|
142
|
+
|
|
143
|
+
public componentDidMount(): void {
|
|
144
|
+
this.mounted = true;
|
|
145
|
+
this.props.application.loadBalancers
|
|
146
|
+
.ready()
|
|
147
|
+
.then(() => {
|
|
148
|
+
if (!this.mounted) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const loadBalancers = (this.props.application.loadBalancers.data as ILoadBalancer[]).filter(
|
|
152
|
+
(candidate) => candidate.cloudProvider === 'cloudrun',
|
|
153
|
+
);
|
|
154
|
+
this.setState({ loadBalancers, selectedLoadBalancer: loadBalancers[0], loading: false });
|
|
155
|
+
})
|
|
156
|
+
.catch(() => {
|
|
157
|
+
if (this.mounted) {
|
|
158
|
+
this.setState({ loading: false });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public componentWillUnmount(): void {
|
|
164
|
+
this.mounted = false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private submit = (): void => {
|
|
168
|
+
CloudrunLoadBalancerModal.show({
|
|
169
|
+
app: this.props.application,
|
|
170
|
+
loadBalancer: cloneDeep(this.state.selectedLoadBalancer),
|
|
171
|
+
isNew: false,
|
|
172
|
+
forPipelineConfig: true,
|
|
173
|
+
})
|
|
174
|
+
.then(this.props.closeModal)
|
|
175
|
+
.catch(() => undefined);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
public render() {
|
|
179
|
+
const { dismissModal } = this.props;
|
|
180
|
+
const { loading, loadBalancers, selectedLoadBalancer } = this.state;
|
|
181
|
+
return (
|
|
182
|
+
<div>
|
|
183
|
+
<div className="modal-header">
|
|
184
|
+
<button type="button" className="close" onClick={dismissModal}>
|
|
185
|
+
<span>×</span>
|
|
186
|
+
</button>
|
|
187
|
+
<h4 className="modal-title">Select Load Balancer</h4>
|
|
188
|
+
</div>
|
|
189
|
+
<div className="modal-body">
|
|
190
|
+
{loading && (
|
|
191
|
+
<div style={{ height: 200 }} className="horizontal center middle">
|
|
192
|
+
Loading...
|
|
193
|
+
</div>
|
|
194
|
+
)}
|
|
195
|
+
{!loading && loadBalancers.length === 0 && <LoadBalancerMessage showCreateMessage={true} />}
|
|
196
|
+
{!loading && loadBalancers.length > 0 && (
|
|
197
|
+
<div className="form-horizontal">
|
|
198
|
+
<div className="form-group">
|
|
199
|
+
<div className="col-md-3 sm-label-right">
|
|
200
|
+
<b>Load Balancer</b>
|
|
201
|
+
</div>
|
|
202
|
+
<div className="col-md-7">
|
|
203
|
+
<select
|
|
204
|
+
className="form-control input-sm"
|
|
205
|
+
value={getLoadBalancerCompositeKey(selectedLoadBalancer)}
|
|
206
|
+
onChange={(event) =>
|
|
207
|
+
this.setState({
|
|
208
|
+
selectedLoadBalancer: loadBalancers.find(
|
|
209
|
+
(loadBalancer) => getLoadBalancerCompositeKey(loadBalancer) === event.target.value,
|
|
210
|
+
),
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
>
|
|
214
|
+
{loadBalancers.map((loadBalancer) => (
|
|
215
|
+
<option
|
|
216
|
+
key={getLoadBalancerCompositeKey(loadBalancer)}
|
|
217
|
+
value={getLoadBalancerCompositeKey(loadBalancer)}
|
|
218
|
+
>
|
|
219
|
+
{getLoadBalancerOptionLabel(loadBalancer)}
|
|
220
|
+
</option>
|
|
221
|
+
))}
|
|
222
|
+
</select>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
<div className="modal-footer">
|
|
229
|
+
<button type="button" className="btn btn-default" onClick={dismissModal}>
|
|
230
|
+
Cancel
|
|
231
|
+
</button>
|
|
232
|
+
{loadBalancers.length > 0 && (
|
|
233
|
+
<button type="button" className="btn btn-primary" onClick={this.submit}>
|
|
234
|
+
<span className="far fa-check-circle" /> Edit
|
|
235
|
+
</button>
|
|
236
|
+
)}
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function getLoadBalancerOptionLabel(loadBalancer: ILoadBalancer): string {
|
|
244
|
+
return [loadBalancer.account, loadBalancer.name, loadBalancer.region].filter(Boolean).join(' ');
|
|
245
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { mount } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
|
|
5
|
+
import { ExecutionDetailsTasks } from '@spinnaker/core';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
CloudrunEditLoadBalancerExecutionDetails,
|
|
9
|
+
getLoadBalancerCompositeKey,
|
|
10
|
+
} from './CloudrunEditLoadBalancerExecutionDetails';
|
|
11
|
+
import {
|
|
12
|
+
CloudrunEditLoadBalancerStageConfig,
|
|
13
|
+
CloudrunLoadBalancerChoiceModal,
|
|
14
|
+
getLoadBalancerOptionLabel,
|
|
15
|
+
} from './CloudrunEditLoadBalancerStageConfig';
|
|
16
|
+
import { CLOUDRUN_EDIT_LOAD_BALANCER_STAGE_CONFIG } from './cloudrunEditLoadBalancerStage';
|
|
17
|
+
import { CloudrunLoadBalancerModal } from '../../../loadBalancer/configure/wizard/CloudrunLoadBalancerModal';
|
|
18
|
+
import {
|
|
19
|
+
findCloudrunLoadBalancer,
|
|
20
|
+
useCloudrunLoadBalancerDetails,
|
|
21
|
+
} from '../../../loadBalancer/details/useCloudrunLoadBalancerDetails';
|
|
22
|
+
|
|
23
|
+
describe('Cloud Run edit load balancer stage', () => {
|
|
24
|
+
function buildChoiceModal(overrides: any = {}) {
|
|
25
|
+
const props = {
|
|
26
|
+
application: {
|
|
27
|
+
loadBalancers: {
|
|
28
|
+
data: [],
|
|
29
|
+
ready: jasmine.createSpy('ready').and.returnValue(Promise.resolve()),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
closeModal: jasmine.createSpy('closeModal'),
|
|
33
|
+
dismissModal: jasmine.createSpy('dismissModal'),
|
|
34
|
+
...overrides,
|
|
35
|
+
} as any;
|
|
36
|
+
|
|
37
|
+
return new CloudrunLoadBalancerChoiceModal(props);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it('uses a composite key for load balancer selection', () => {
|
|
41
|
+
expect(getLoadBalancerCompositeKey({ name: 'default', account: 'test', region: 'us-central1' } as any)).toBe(
|
|
42
|
+
'default:test:us-central1',
|
|
43
|
+
);
|
|
44
|
+
expect(getLoadBalancerCompositeKey({ name: 'default', account: 'prod', region: 'us-central1' } as any)).toBe(
|
|
45
|
+
'default:prod:us-central1',
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('matches load balancer details by region', () => {
|
|
50
|
+
const loadBalancers = [
|
|
51
|
+
{ name: 'default', account: 'test', region: 'europe-west1' },
|
|
52
|
+
{ name: 'default', account: 'test', region: 'us-central1' },
|
|
53
|
+
] as any;
|
|
54
|
+
|
|
55
|
+
expect(
|
|
56
|
+
findCloudrunLoadBalancer(loadBalancers, {
|
|
57
|
+
name: 'default',
|
|
58
|
+
accountId: 'test',
|
|
59
|
+
region: 'us-central1',
|
|
60
|
+
} as any),
|
|
61
|
+
).toBe(loadBalancers[1]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('includes region in load balancer option labels', () => {
|
|
65
|
+
expect(getLoadBalancerOptionLabel({ name: 'default', account: 'test', region: 'us-central1' } as any)).toBe(
|
|
66
|
+
'test default us-central1',
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('registers React execution details before task details', () => {
|
|
71
|
+
expect(CLOUDRUN_EDIT_LOAD_BALANCER_STAGE_CONFIG.executionDetailsSections).toEqual([
|
|
72
|
+
CloudrunEditLoadBalancerExecutionDetails,
|
|
73
|
+
ExecutionDetailsTasks,
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('stops loading when load balancers fail to load', async () => {
|
|
78
|
+
const modal = buildChoiceModal({
|
|
79
|
+
application: {
|
|
80
|
+
loadBalancers: {
|
|
81
|
+
data: [],
|
|
82
|
+
ready: jasmine.createSpy('ready').and.returnValue(Promise.reject(new Error('load failed'))),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
spyOn(modal, 'setState');
|
|
87
|
+
|
|
88
|
+
modal.componentDidMount();
|
|
89
|
+
await Promise.resolve();
|
|
90
|
+
await Promise.resolve();
|
|
91
|
+
|
|
92
|
+
expect(modal.setState).toHaveBeenCalledWith({ loading: false });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('does not update load balancer choices after unmount', async () => {
|
|
96
|
+
let resolveReady: () => void;
|
|
97
|
+
const ready = new Promise<void>((resolve) => {
|
|
98
|
+
resolveReady = resolve;
|
|
99
|
+
});
|
|
100
|
+
const modal = buildChoiceModal({
|
|
101
|
+
application: {
|
|
102
|
+
loadBalancers: {
|
|
103
|
+
data: [{ name: 'default', account: 'test', region: 'us-central1', cloudProvider: 'cloudrun' }],
|
|
104
|
+
ready: jasmine.createSpy('ready').and.returnValue(ready),
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
spyOn(modal, 'setState');
|
|
109
|
+
|
|
110
|
+
modal.componentDidMount();
|
|
111
|
+
(modal as any).componentWillUnmount?.();
|
|
112
|
+
resolveReady!();
|
|
113
|
+
await ready;
|
|
114
|
+
await Promise.resolve();
|
|
115
|
+
|
|
116
|
+
expect(modal.setState).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('handles dismissal of the load balancer edit modal', () => {
|
|
120
|
+
const catchSpy = jasmine.createSpy('catch');
|
|
121
|
+
const modalResult = { then: jasmine.createSpy('then').and.returnValue({ catch: catchSpy }) };
|
|
122
|
+
spyOn(CloudrunLoadBalancerModal, 'show').and.returnValue(modalResult as any);
|
|
123
|
+
const modal = buildChoiceModal();
|
|
124
|
+
modal.state = { ...modal.state, selectedLoadBalancer: { name: 'default' } as any };
|
|
125
|
+
|
|
126
|
+
(modal as any).submit();
|
|
127
|
+
|
|
128
|
+
expect(catchSpy).toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('handles dismissal of the load balancer choice modal when adding to a stage', () => {
|
|
132
|
+
const catchSpy = jasmine.createSpy('catch');
|
|
133
|
+
const modalResult = { then: jasmine.createSpy('then').and.returnValue({ catch: catchSpy }) };
|
|
134
|
+
spyOn(CloudrunLoadBalancerChoiceModal, 'show').and.returnValue(modalResult as any);
|
|
135
|
+
const stageConfig = new CloudrunEditLoadBalancerStageConfig({
|
|
136
|
+
application: {},
|
|
137
|
+
pipeline: {},
|
|
138
|
+
stage: { loadBalancers: [] },
|
|
139
|
+
updateStage: jasmine.createSpy('updateStage'),
|
|
140
|
+
} as any);
|
|
141
|
+
|
|
142
|
+
(stageConfig as any).addLoadBalancer();
|
|
143
|
+
|
|
144
|
+
expect(catchSpy).toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('handles dismissal of the load balancer edit modal when editing a stage load balancer', () => {
|
|
148
|
+
const catchSpy = jasmine.createSpy('catch');
|
|
149
|
+
const modalResult = { then: jasmine.createSpy('then').and.returnValue({ catch: catchSpy }) };
|
|
150
|
+
spyOn(CloudrunLoadBalancerModal, 'show').and.returnValue(modalResult as any);
|
|
151
|
+
const stageConfig = new CloudrunEditLoadBalancerStageConfig({
|
|
152
|
+
application: {},
|
|
153
|
+
pipeline: {},
|
|
154
|
+
stage: { loadBalancers: [{ name: 'default' }] },
|
|
155
|
+
updateStage: jasmine.createSpy('updateStage'),
|
|
156
|
+
} as any);
|
|
157
|
+
|
|
158
|
+
(stageConfig as any).editLoadBalancer(0);
|
|
159
|
+
|
|
160
|
+
expect(catchSpy).toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('updates details when application load balancer data refreshes', async () => {
|
|
164
|
+
const firstLoadBalancer = { name: 'default', account: 'test', region: 'us-central1', image: 'old' };
|
|
165
|
+
const refreshedLoadBalancer = { name: 'default', account: 'test', region: 'us-central1', image: 'new' };
|
|
166
|
+
const status$ = new BehaviorSubject({
|
|
167
|
+
status: 'FETCHED',
|
|
168
|
+
loaded: true,
|
|
169
|
+
lastRefresh: 1,
|
|
170
|
+
data: [firstLoadBalancer],
|
|
171
|
+
});
|
|
172
|
+
const app = {
|
|
173
|
+
getDataSource: jasmine.createSpy('getDataSource').and.returnValue({
|
|
174
|
+
status$,
|
|
175
|
+
refresh: jasmine.createSpy('refresh'),
|
|
176
|
+
}),
|
|
177
|
+
loadBalancers: {
|
|
178
|
+
data: [firstLoadBalancer],
|
|
179
|
+
ready: jasmine.createSpy('ready').and.returnValue(Promise.resolve()),
|
|
180
|
+
},
|
|
181
|
+
} as any;
|
|
182
|
+
const onChange = jasmine.createSpy('onChange');
|
|
183
|
+
const loadBalancerParams = { name: 'default', accountId: 'test', region: 'us-central1' } as any;
|
|
184
|
+
|
|
185
|
+
function TestComponent() {
|
|
186
|
+
const details = useCloudrunLoadBalancerDetails({
|
|
187
|
+
app,
|
|
188
|
+
loadBalancerParams,
|
|
189
|
+
autoClose: jasmine.createSpy(),
|
|
190
|
+
} as any);
|
|
191
|
+
React.useEffect(() => onChange(details), [details.data, details.loading, details.error]);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const wrapper = mount(React.createElement(TestComponent));
|
|
196
|
+
await Promise.resolve();
|
|
197
|
+
wrapper.setProps({});
|
|
198
|
+
|
|
199
|
+
app.loadBalancers.data = [refreshedLoadBalancer];
|
|
200
|
+
status$.next({ status: 'FETCHED', loaded: true, lastRefresh: 2, data: [refreshedLoadBalancer] });
|
|
201
|
+
wrapper.setProps({});
|
|
202
|
+
|
|
203
|
+
expect(onChange.calls.mostRecent().args[0].data).toBe(refreshedLoadBalancer);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -1,74 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import type { IModalService } from 'angular-ui-bootstrap';
|
|
4
|
-
import { cloneDeep } from 'lodash';
|
|
1
|
+
import type { IStageTypeConfig } from '@spinnaker/core';
|
|
2
|
+
import { ExecutionDetailsTasks, Registry } from '@spinnaker/core';
|
|
5
3
|
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
4
|
+
import { CloudrunEditLoadBalancerExecutionDetails } from './CloudrunEditLoadBalancerExecutionDetails';
|
|
5
|
+
import { CloudrunEditLoadBalancerStageConfig } from './CloudrunEditLoadBalancerStageConfig';
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
export const CLOUDRUN_EDIT_LOAD_BALANCER_STAGE_CONFIG: IStageTypeConfig = {
|
|
8
|
+
label: 'Edit Load Balancer (Cloud Run)',
|
|
9
|
+
description: 'Edits a load balancer',
|
|
10
|
+
key: 'upsertCloudrunLoadBalancers',
|
|
11
|
+
cloudProvider: 'cloudrun',
|
|
12
|
+
component: CloudrunEditLoadBalancerStageConfig,
|
|
13
|
+
executionDetailsSections: [CloudrunEditLoadBalancerExecutionDetails, ExecutionDetailsTasks],
|
|
14
|
+
validators: [],
|
|
15
|
+
};
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
public static $inject = ['$scope', '$uibModal'];
|
|
13
|
-
constructor(public $scope: any, private $uibModal: IModalService) {
|
|
14
|
-
$scope.stage.loadBalancers = $scope.stage.loadBalancers || [];
|
|
15
|
-
$scope.stage.cloudProvider = 'cloudrun';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public addLoadBalancer(): void {
|
|
19
|
-
this.$uibModal
|
|
20
|
-
.open({
|
|
21
|
-
templateUrl: require('./loadBalancerChoice.modal.html'),
|
|
22
|
-
controller: `cloudrunLoadBalancerChoiceModelCtrl as ctrl`,
|
|
23
|
-
resolve: {
|
|
24
|
-
application: () => this.$scope.application,
|
|
25
|
-
},
|
|
26
|
-
})
|
|
27
|
-
.result.then((newLoadBalancer: ILoadBalancer) => {
|
|
28
|
-
this.$scope.stage.loadBalancers.push(newLoadBalancer);
|
|
29
|
-
})
|
|
30
|
-
.catch(() => {});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public editLoadBalancer(index: number) {
|
|
34
|
-
const config = CloudProviderRegistry.getValue('cloudrun', 'loadBalancer');
|
|
35
|
-
this.$uibModal
|
|
36
|
-
.open({
|
|
37
|
-
templateUrl: config.createLoadBalancerTemplateUrl,
|
|
38
|
-
controller: `${config.createLoadBalancerController} as ctrl`,
|
|
39
|
-
size: 'lg',
|
|
40
|
-
resolve: {
|
|
41
|
-
application: () => this.$scope.application,
|
|
42
|
-
loadBalancer: () => cloneDeep(this.$scope.stage.loadBalancers[index]),
|
|
43
|
-
isNew: () => false,
|
|
44
|
-
forPipelineConfig: () => true,
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
.result.then((updatedLoadBalancer: ILoadBalancer) => {
|
|
48
|
-
this.$scope.stage.loadBalancers[index] = updatedLoadBalancer;
|
|
49
|
-
})
|
|
50
|
-
.catch(() => {});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public removeLoadBalancer(index: number): void {
|
|
54
|
-
this.$scope.stage.loadBalancers.splice(index, 1);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const CLOUDRUN_EDIT_LOAD_BALANCER_STAGE = 'spinnaker.cloudrun.pipeline.stage.editLoadBalancerStage';
|
|
59
|
-
module(CLOUDRUN_EDIT_LOAD_BALANCER_STAGE, [CLOUDRUN_LOAD_BALANCER_CHOICE_MODAL_CTRL])
|
|
60
|
-
.config(() => {
|
|
61
|
-
Registry.pipeline.registerStage({
|
|
62
|
-
label: 'Edit Load Balancer (Cloud Run)',
|
|
63
|
-
description: 'Edits a load balancer',
|
|
64
|
-
key: 'upsertCloudrunLoadBalancers',
|
|
65
|
-
cloudProvider: 'cloudrun',
|
|
66
|
-
templateUrl: require('./editLoadBalancerStage.html'),
|
|
67
|
-
executionDetailsUrl: require('./editLoadBalancerExecutionDetails.html'),
|
|
68
|
-
executionConfigSections: ['editLoadBalancerConfig', 'taskStatus'],
|
|
69
|
-
controller: 'cloudrunEditLoadBalancerStageCtrl',
|
|
70
|
-
controllerAs: 'editLoadBalancerStageCtrl',
|
|
71
|
-
validators: [],
|
|
72
|
-
});
|
|
73
|
-
})
|
|
74
|
-
.controller('cloudrunEditLoadBalancerStageCtrl', CloudrunEditLoadBalancerStageCtrl);
|
|
17
|
+
Registry.pipeline.registerStage(CLOUDRUN_EDIT_LOAD_BALANCER_STAGE_CONFIG);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { module } from 'angular';
|
|
2
1
|
import { cloneDeep } from 'lodash';
|
|
3
|
-
import { $q } from 'ngimport';
|
|
4
2
|
|
|
5
3
|
import type {
|
|
6
4
|
Application,
|
|
@@ -91,7 +89,7 @@ const getSubmitButtonLabel = (mode: string): string => {
|
|
|
91
89
|
|
|
92
90
|
export class CloudrunV2ServerGroupCommandBuilder {
|
|
93
91
|
// new add servergroup
|
|
94
|
-
public buildNewServerGroupCommand(app: Application):
|
|
92
|
+
public buildNewServerGroupCommand(app: Application): Promise<ICloudrunServerGroupCommandData> {
|
|
95
93
|
return CloudrunServerGroupCommandBuilder.buildNewServerGroupCommand(app, 'cloudrun', 'create');
|
|
96
94
|
}
|
|
97
95
|
|
|
@@ -113,7 +111,6 @@ export class CloudrunV2ServerGroupCommandBuilder {
|
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
export class CloudrunServerGroupCommandBuilder {
|
|
116
|
-
public static $inject = ['$q'];
|
|
117
114
|
public static ServerGroupCommandIsValid(command: ICloudrunServerGroupCommand): boolean {
|
|
118
115
|
if (!command.moniker) {
|
|
119
116
|
return false;
|
|
@@ -156,7 +153,7 @@ export class CloudrunServerGroupCommandBuilder {
|
|
|
156
153
|
cluster: CloudrunDeployDescription,
|
|
157
154
|
_stage: IStage,
|
|
158
155
|
pipeline: IPipeline,
|
|
159
|
-
):
|
|
156
|
+
): Promise<ICloudrunServerGroupCommandData> {
|
|
160
157
|
return CloudrunServerGroupCommandBuilder.buildNewServerGroupCommand(app, 'cloudrun', 'editPipeline').then(
|
|
161
158
|
(command: ICloudrunServerGroupCommandData) => {
|
|
162
159
|
command = {
|
|
@@ -197,14 +194,14 @@ export class CloudrunServerGroupCommandBuilder {
|
|
|
197
194
|
app: Application,
|
|
198
195
|
sourceAccount: string,
|
|
199
196
|
mode: string,
|
|
200
|
-
):
|
|
197
|
+
): Promise<ICloudrunServerGroupCommandData> {
|
|
201
198
|
const dataToFetch = {
|
|
202
199
|
accounts: AccountService.getAllAccountDetailsForProvider('cloudrun'),
|
|
203
200
|
artifactAccounts: AccountService.getArtifactAccounts(),
|
|
204
201
|
};
|
|
205
202
|
|
|
206
|
-
return
|
|
207
|
-
const { accounts }
|
|
203
|
+
return Promise.all([dataToFetch.accounts, dataToFetch.artifactAccounts]).then(([accounts, artifactAccounts]) => {
|
|
204
|
+
const backingData = { accounts, artifactAccounts };
|
|
208
205
|
|
|
209
206
|
const account = accounts.some((a) => a.name === sourceAccount)
|
|
210
207
|
? accounts.find((a) => a.name === sourceAccount).name
|
|
@@ -245,10 +242,3 @@ export class CloudrunServerGroupCommandBuilder {
|
|
|
245
242
|
});
|
|
246
243
|
}
|
|
247
244
|
}
|
|
248
|
-
|
|
249
|
-
export const CLOUDRUN_SERVER_GROUP_COMMAND_BUILDER = 'spinnaker.cloudrun.serverGroup.commandBuilder.service';
|
|
250
|
-
|
|
251
|
-
module(CLOUDRUN_SERVER_GROUP_COMMAND_BUILDER, []).service(
|
|
252
|
-
'cloudrunV2ServerGroupCommandBuilder',
|
|
253
|
-
CloudrunV2ServerGroupCommandBuilder,
|
|
254
|
-
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { FormikProps } from 'formik';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
import type { Application, IAccount, IServerGroup } from '@spinnaker/core';
|
|
5
|
-
import { AccountSelectInput, HelpField, NameUtils,
|
|
4
|
+
import type { Application, IAccount, IRouterInjectedProps, IServerGroup } from '@spinnaker/core';
|
|
5
|
+
import { AccountSelectInput, HelpField, NameUtils, ServerGroupNamePreview, withRouter } from '@spinnaker/core';
|
|
6
6
|
|
|
7
7
|
import type { ICloudrunServerGroupCommandData } from '../serverGroupCommandBuilder.service';
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ export interface IServerGroupBasicSettingsState {
|
|
|
22
22
|
latestServerGroup: IServerGroup;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export function
|
|
25
|
+
export function ServerGroupBasicSettingsComponent({
|
|
26
26
|
accounts,
|
|
27
27
|
onAccountSelect,
|
|
28
28
|
selectedAccount,
|
|
@@ -30,7 +30,8 @@ export function ServerGroupBasicSettings({
|
|
|
30
30
|
onEnterStack,
|
|
31
31
|
detailsChanged,
|
|
32
32
|
app,
|
|
33
|
-
|
|
33
|
+
stateService,
|
|
34
|
+
}: IServerGroupBasicSettingsProps & IRouterInjectedProps) {
|
|
34
35
|
const { values } = formik;
|
|
35
36
|
const { stack = '', freeFormDetails } = values;
|
|
36
37
|
|
|
@@ -56,11 +57,10 @@ export function ServerGroupBasicSettings({
|
|
|
56
57
|
serverGroup: latestServerGroup.name,
|
|
57
58
|
};
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
$state.go('.serverGroup', params);
|
|
60
|
+
if (stateService.is('home.applications.application.insight.clusters')) {
|
|
61
|
+
stateService.go('.serverGroup', params);
|
|
62
62
|
} else {
|
|
63
|
-
|
|
63
|
+
stateService.go('^.serverGroup', params);
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
|
|
@@ -119,6 +119,8 @@ export function ServerGroupBasicSettings({
|
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
export const ServerGroupBasicSettings = withRouter(ServerGroupBasicSettingsComponent);
|
|
123
|
+
|
|
122
124
|
export interface IWizardServerGroupBasicSettingsProps {
|
|
123
125
|
formik: FormikProps<ICloudrunServerGroupCommandData>;
|
|
124
126
|
app: Application;
|