@spinnaker/amazon 0.11.1 → 0.12.3

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/domain/IAmazonLaunchTemplate.d.ts +1 -1
  3. package/dist/domain/IAmazonServerGroup.d.ts +10 -0
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/instance/awsInstanceType.service.d.ts +10 -2
  7. package/dist/instance/awsInstanceTypes.d.ts +10 -0
  8. package/dist/instance/details/CostFactor.d.ts +6 -0
  9. package/dist/reactShims/aws.react.injector.d.ts +2 -1
  10. package/dist/search/searchResultFormatter.d.ts +2 -2
  11. package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +17 -2
  12. package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +39 -0
  13. package/dist/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.d.ts +3 -4
  14. package/dist/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.d.ts +9 -0
  15. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.d.ts +13 -0
  16. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.d.ts +9 -0
  17. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.d.ts +11 -0
  18. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.d.ts +14 -0
  19. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.d.ts +12 -0
  20. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.d.ts +15 -0
  21. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.d.ts +8 -0
  22. package/dist/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.d.ts +8 -0
  23. package/dist/serverGroup/configure/wizard/pages/ServerGroupInstanceType.d.ts +9 -6
  24. package/dist/serverGroup/serverGroup.transformer.d.ts +2 -1
  25. package/package.json +5 -5
  26. package/src/domain/IAmazonLaunchTemplate.ts +1 -1
  27. package/src/domain/IAmazonServerGroup.ts +11 -0
  28. package/src/function/details/FunctionActions.spec.tsx +10 -9
  29. package/src/help/amazon.help.ts +9 -6
  30. package/src/image/image.reader.spec.ts +75 -0
  31. package/src/instance/awsInstanceType.service.spec.js +37 -71
  32. package/src/instance/awsInstanceType.service.ts +191 -0
  33. package/src/instance/awsInstanceTypes.ts +311 -0
  34. package/src/instance/details/CostFactor.tsx +29 -0
  35. package/src/instance/details/InstanceInformation.spec.tsx +2 -1
  36. package/src/instance/details/instance.details.controller.js +471 -473
  37. package/src/loadBalancer/details/loadBalancerDetails.controller.spec.ts +5 -3
  38. package/src/reactShims/aws.react.injector.ts +2 -1
  39. package/src/search/{searchResultFormatter.js → searchResultFormatter.ts} +5 -4
  40. package/src/serverGroup/configure/AmazonImageSelectInput.spec.tsx +10 -7
  41. package/src/serverGroup/configure/serverGroupCommandBuilder.aws.service.spec.js +302 -1
  42. package/src/serverGroup/configure/{serverGroupCommandBuilder.service.js → serverGroupCommandBuilder.service.ts} +182 -73
  43. package/src/serverGroup/configure/serverGroupCommandBuilder.spec.js +25 -8
  44. package/src/serverGroup/configure/serverGroupConfiguration.service.spec.ts +6 -13
  45. package/src/serverGroup/configure/serverGroupConfiguration.service.ts +53 -0
  46. package/src/serverGroup/configure/wizard/AmazonCloneServerGroupModal.tsx +1 -1
  47. package/src/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.tsx +31 -31
  48. package/src/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.tsx +133 -0
  49. package/src/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.tsx +99 -0
  50. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.tsx +36 -0
  51. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.tsx +144 -0
  52. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.tsx +138 -0
  53. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.tsx +135 -0
  54. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.tsx +137 -0
  55. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.less +5 -0
  56. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.tsx +108 -0
  57. package/src/serverGroup/configure/wizard/instanceType/advancedMode/advancedMode.less +110 -0
  58. package/src/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.tsx +62 -0
  59. package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.tsx +107 -62
  60. package/src/serverGroup/configure/wizard/pages/advancedSettings/ServerGroupAdvancedSettingsCommon.tsx +1 -1
  61. package/src/serverGroup/details/scalingPolicy/scalingPolicySummary.component.ts +6 -2
  62. package/src/serverGroup/details/scalingProcesses/AutoScalingProcessService.spec.ts +1 -2
  63. package/src/serverGroup/details/sections/InstancesDistributionDetailsSection.spec.tsx +8 -5
  64. package/src/serverGroup/details/sections/LaunchTemplateDetailsSection.spec.tsx +8 -5
  65. package/src/serverGroup/serverGroup.transformer.spec.ts +5 -3
  66. package/src/serverGroup/serverGroup.transformer.ts +24 -22
  67. package/src/subnet/SubnetSelectInput.spec.tsx +7 -4
  68. package/src/vpc/{VpcReader.spec.js → VpcReader.spec.ts} +2 -10
  69. package/src/vpc/VpcTag.spec.tsx +37 -0
  70. package/src/vpc/vpc.module.ts +6 -2
  71. package/dist/vpc/vpcTag.directive.d.ts +0 -2
  72. package/src/image/image.reader.spec.js +0 -123
  73. package/src/instance/awsInstanceType.service.js +0 -437
  74. package/src/vpc/vpcTag.directive.js +0 -34
  75. package/src/vpc/vpcTag.directive.spec.js +0 -60
@@ -0,0 +1,135 @@
1
+ import { difference, flatten, keyBy } from 'lodash';
2
+ import React from 'react';
3
+ import type { SortEnd } from 'react-sortable-hoc';
4
+ import { SortableContainer, SortableElement } from 'react-sortable-hoc';
5
+
6
+ import type { IInstanceTypeFamily } from '@spinnaker/core';
7
+
8
+ import { InstanceTypeRow } from './InstanceTypeRow';
9
+ import type { IAmazonPreferredInstanceType } from '../../../../../instance/awsInstanceType.service';
10
+ import type { IAmazonInstanceTypeOverride } from '../../../serverGroupConfiguration.service';
11
+
12
+ export function InstanceTypeTableBody(props: {
13
+ isCustom: boolean;
14
+ profileFamiliesDetails?: IInstanceTypeFamily[];
15
+ selectedInstanceTypesMap: Map<string, IAmazonInstanceTypeOverride>;
16
+ addOrUpdateInstanceType: (instanceType: string, weight: string) => void;
17
+ removeInstanceType: (instanceType: string) => void;
18
+ handleSortEnd: (sortEnd: SortEnd) => void;
19
+ }) {
20
+ return (
21
+ <TableRows
22
+ isCustom={props.isCustom}
23
+ selectedInstanceTypesMap={props.selectedInstanceTypesMap}
24
+ removeInstanceType={props.removeInstanceType}
25
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
26
+ instanceTypeDetails={
27
+ props.isCustom
28
+ ? null
29
+ : new Map(
30
+ Object.entries(
31
+ keyBy(flatten(props.profileFamiliesDetails.map((f: IInstanceTypeFamily) => f.instanceTypes)), 'name'),
32
+ ),
33
+ )
34
+ }
35
+ onSortEnd={(sortEnd) => props.handleSortEnd(sortEnd)}
36
+ distance={1}
37
+ />
38
+ );
39
+ }
40
+
41
+ const TableRows = SortableContainer(
42
+ (props: {
43
+ isCustom: boolean;
44
+ instanceTypeDetails?: Map<string, IAmazonPreferredInstanceType>;
45
+ selectedInstanceTypesMap: Map<string, IAmazonInstanceTypeOverride>;
46
+ removeInstanceType: (typeToRemove: string) => void;
47
+ addOrUpdateInstanceType: (instanceType: string, weight: string) => void;
48
+ }) => {
49
+ const { isCustom, selectedInstanceTypesMap } = props;
50
+
51
+ let selectedRows, unselectedRows;
52
+ if (isCustom) {
53
+ selectedRows =
54
+ selectedInstanceTypesMap.size > 0 &&
55
+ Array.from(selectedInstanceTypesMap.values())
56
+ .sort((i1, i2) => i1.priority - i2.priority)
57
+ .map((selectedType, index: number) => (
58
+ <SortableRow
59
+ key={`${selectedType.instanceType}-${index}`}
60
+ index={index}
61
+ isCustom={true}
62
+ selectedType={selectedType}
63
+ removeInstanceType={props.removeInstanceType}
64
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
65
+ />
66
+ ));
67
+ } else {
68
+ const { instanceTypeDetails } = props;
69
+ const instanceTypesInProfile: string[] = Array.from(instanceTypeDetails?.keys());
70
+ const unselectedInstanceTypes: string[] = difference(
71
+ instanceTypesInProfile,
72
+ Array.from(selectedInstanceTypesMap.keys()),
73
+ );
74
+
75
+ const selectedRowsOrdered: IAmazonInstanceTypeOverride[] = Array.from(selectedInstanceTypesMap.values())
76
+ .filter((selectedType: IAmazonInstanceTypeOverride) =>
77
+ instanceTypesInProfile.includes(selectedType.instanceType),
78
+ )
79
+ .sort((i1, i2) => i1.priority - i2.priority);
80
+
81
+ selectedRows =
82
+ selectedRowsOrdered &&
83
+ selectedRowsOrdered.length > 0 &&
84
+ selectedRowsOrdered.map((selectedType: IAmazonInstanceTypeOverride, index: number) => (
85
+ <SortableRow
86
+ key={`${selectedType.instanceType}-${index}`}
87
+ index={index}
88
+ isCustom={false}
89
+ selectedType={selectedType}
90
+ instanceTypeDetails={instanceTypeDetails}
91
+ removeInstanceType={props.removeInstanceType}
92
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
93
+ />
94
+ ));
95
+
96
+ unselectedRows =
97
+ unselectedInstanceTypes &&
98
+ unselectedInstanceTypes.length > 0 &&
99
+ unselectedInstanceTypes.map((instanceType) => (
100
+ <InstanceTypeRow
101
+ key={instanceType}
102
+ isCustom={false}
103
+ instanceTypeDetails={instanceTypeDetails.get(instanceType)}
104
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
105
+ />
106
+ ));
107
+ }
108
+
109
+ return (
110
+ <tbody>
111
+ {selectedRows}
112
+ {!isCustom ? unselectedRows : null}
113
+ </tbody>
114
+ );
115
+ },
116
+ );
117
+
118
+ const SortableRow = SortableElement(
119
+ (props: {
120
+ isCustom: boolean;
121
+ selectedType: IAmazonInstanceTypeOverride;
122
+ instanceTypeDetails?: Map<string, IAmazonPreferredInstanceType>;
123
+ removeInstanceType: (typeToRemove: string) => void;
124
+ addOrUpdateInstanceType: (instanceType: string, weight: string) => void;
125
+ }) => (
126
+ <InstanceTypeRow
127
+ key={props.selectedType.instanceType}
128
+ isCustom={props.isCustom}
129
+ selectedType={props.selectedType}
130
+ instanceTypeDetails={!props.isCustom ? props.instanceTypeDetails.get(props.selectedType.instanceType) : null}
131
+ removeInstanceType={props.removeInstanceType}
132
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
133
+ />
134
+ ),
135
+ );
@@ -0,0 +1,137 @@
1
+ import React from 'react';
2
+ import type { Option } from 'react-select';
3
+ import Select from 'react-select';
4
+
5
+ import { HelpField } from '@spinnaker/core';
6
+
7
+ export function Heading(props: { isCustom: boolean; profileLabel?: string; profileDescriptionArr?: string[] }) {
8
+ let description;
9
+ if (props.isCustom) {
10
+ description = <p>Choose the instance types that best suit the needs of your application.</p>;
11
+ } else {
12
+ description = (
13
+ <>
14
+ <p>
15
+ <b>{props.profileLabel}</b>
16
+ </p>
17
+ <ul>
18
+ {props.profileDescriptionArr.map((d, index) => (
19
+ <li key={index}>{d}</li>
20
+ ))}
21
+ </ul>
22
+ </>
23
+ );
24
+ }
25
+
26
+ return (
27
+ <div className={'row sub-section'}>
28
+ <h4>Instance Types</h4>
29
+ <div className={'description'}>
30
+ {description}
31
+ <i>
32
+ <b>Note:</b>
33
+ <ul>
34
+ <li>
35
+ The order of instance types sets their priority when On-Demand capacity is launched; instance type at the
36
+ top is prioritized the highest.
37
+ </li>
38
+ <li>Some instance types might not be available for the selected configuration.</li>
39
+ </ul>
40
+ </i>
41
+ </div>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ export function Header(props: { isCustom: boolean; showCpuCredits?: boolean }) {
47
+ let emptyHeaders, instanceTypeHeader, otherHeaders, tailingEmptyHeader;
48
+ if (props.isCustom) {
49
+ emptyHeaders = <th />;
50
+ instanceTypeHeader = (
51
+ <th>
52
+ Instance Type <HelpField id="aws.serverGroup.instanceTypes" />
53
+ </th>
54
+ );
55
+ otherHeaders = null;
56
+ tailingEmptyHeader = <th />;
57
+ } else {
58
+ emptyHeaders = (
59
+ <>
60
+ <th />
61
+ <th />
62
+ </>
63
+ );
64
+ instanceTypeHeader = <th>InstanceType</th>;
65
+ otherHeaders = (
66
+ <>
67
+ <th>vCPU</th>
68
+ <th>Mem (GiB)</th>
69
+ {props.showCpuCredits && <th>CPU Credits</th>}
70
+ <th>
71
+ Storage (GB)
72
+ <HelpField id={'aws.serverGroup.storageType'} />
73
+ </th>
74
+ <th>Cost</th>
75
+ </>
76
+ );
77
+ tailingEmptyHeader = null;
78
+ }
79
+
80
+ return (
81
+ <thead>
82
+ <tr>
83
+ {emptyHeaders}
84
+ {instanceTypeHeader}
85
+ {otherHeaders}
86
+ <th>
87
+ Weight <HelpField id="aws.serverGroup.instanceTypeWeight" />
88
+ </th>
89
+ {tailingEmptyHeader}
90
+ </tr>
91
+ </thead>
92
+ );
93
+ }
94
+
95
+ export function Footer(props: {
96
+ isCustom: boolean;
97
+ availableInstanceTypesList: string[];
98
+ addOrUpdateInstanceType: (type: string, weight: string) => void;
99
+ }) {
100
+ return props.isCustom ? (
101
+ <tfoot>
102
+ <tr>
103
+ <td>
104
+ <span className={'glyphicon glyphicon-plus-sign'} style={{ paddingTop: '8px' }} />
105
+ </td>
106
+ <td colSpan={2}>
107
+ <InstanceTypeSelect
108
+ availableInstanceTypesList={props.availableInstanceTypesList}
109
+ addOrUpdateInstanceType={props.addOrUpdateInstanceType}
110
+ />
111
+ </td>
112
+ <td></td>
113
+ </tr>
114
+ </tfoot>
115
+ ) : null;
116
+ }
117
+
118
+ const InstanceTypeSelect = (props: {
119
+ availableInstanceTypesList: string[];
120
+ addOrUpdateInstanceType: (type: string, weight: string) => void;
121
+ }): JSX.Element => {
122
+ const instanceTypeListOptions = props.availableInstanceTypesList.map((instanceType) => {
123
+ return { label: instanceType, value: instanceType };
124
+ });
125
+
126
+ return (
127
+ <Select
128
+ clearable={false}
129
+ multi={false}
130
+ placeholder={'Select an instance type to add...'}
131
+ removeSelected={true}
132
+ searchable={true}
133
+ options={instanceTypeListOptions}
134
+ onChange={(o: Option<string>) => props.addOrUpdateInstanceType(o.value, undefined)}
135
+ />
136
+ );
137
+ };
@@ -0,0 +1,5 @@
1
+ .InstancesDistribution {
2
+ .StandardFieldLayout_Label {
3
+ min-width: 300px;
4
+ }
5
+ }
@@ -0,0 +1,108 @@
1
+ import type { FormikProps } from 'formik';
2
+ import { get } from 'lodash';
3
+ import React from 'react';
4
+
5
+ import { FormikFormField, HelpField, NumberInput, ReactSelectInput, TextInput, Tooltip } from '@spinnaker/core';
6
+ import type { IAmazonServerGroupCommand } from '../../../serverGroupConfiguration.service';
7
+
8
+ import './InstancesDistribution.less';
9
+
10
+ export interface IInstancesDistributionProps {
11
+ formik: FormikProps<IAmazonServerGroupCommand>;
12
+ }
13
+
14
+ function useDefaultFormikValue(formik: FormikProps<IAmazonServerGroupCommand>, field: string, defaultValue: any) {
15
+ const value = get(formik.values, field);
16
+ React.useEffect(() => {
17
+ if (value === undefined && defaultValue !== undefined) {
18
+ formik.setFieldValue(field, defaultValue);
19
+ }
20
+ }, [field, defaultValue, value]);
21
+ }
22
+
23
+ export function InstancesDistribution(props: IInstancesDistributionProps) {
24
+ const { values: command, setFieldValue } = props.formik;
25
+
26
+ const spotAllocStrategyOptions = [
27
+ { label: 'capacity-optimized (recommended)', value: 'capacity-optimized' },
28
+ { label: 'capacity-optimized-prioritized', value: 'capacity-optimized-prioritized' },
29
+ { label: 'lowest-price', value: 'lowest-price' },
30
+ ];
31
+
32
+ // When allocation strategy toggles to/from lowest-price, update spotInstancePools
33
+ React.useEffect(() => {
34
+ if (command.spotAllocationStrategy !== 'lowest-price') {
35
+ setFieldValue('spotInstancePools', undefined);
36
+ } else if (command.spotInstancePools === undefined) {
37
+ setFieldValue('spotInstancePools', 2);
38
+ }
39
+ }, [command.spotAllocationStrategy]);
40
+
41
+ useDefaultFormikValue(props.formik, 'spotAllocationStrategy', 'capacity-optimized');
42
+
43
+ // prioritized is the only supported strategy for now
44
+ useDefaultFormikValue(props.formik, 'onDemandAllocationStrategy', 'prioritized');
45
+
46
+ // AWS defaults
47
+ useDefaultFormikValue(props.formik, 'onDemandBaseCapacity', 0);
48
+ useDefaultFormikValue(props.formik, 'onDemandPercentageAboveBaseCapacity', 100);
49
+
50
+ return (
51
+ <div className={'InstancesDistribution row sub-section form-group'}>
52
+ <h4>Instances Distribution</h4>
53
+ <div className={'description'}>
54
+ Diversify and distribute instance types across purchase options.{' '}
55
+ <HelpField id={'aws.serverGroup.instancesDistribution'} />
56
+ </div>
57
+ <br />
58
+
59
+ <FormikFormField
60
+ label={'Spot Allocation Strategy'}
61
+ name={'spotAllocationStrategy'}
62
+ help={<HelpField id={'aws.serverGroup.spotAllocationStrategy'} />}
63
+ input={(inputProps) => <ReactSelectInput {...inputProps} mode="PLAIN" options={spotAllocStrategyOptions} />}
64
+ />
65
+
66
+ {props.formik.values.spotAllocationStrategy === 'lowest-price' && (
67
+ <FormikFormField
68
+ label={'Spot Instance Pools Count'}
69
+ name={'spotInstancePools'}
70
+ help={<HelpField id={'aws.serverGroup.spotInstancePoolCount'} />}
71
+ input={(inputProps) => <NumberInput {...inputProps} />}
72
+ />
73
+ )}
74
+
75
+ <FormikFormField
76
+ label={'On-Demand Allocation Strategy'}
77
+ name={'onDemandAllocationStrategy'}
78
+ help={<HelpField id={'aws.serverGroup.odAllocationStrategy'} />}
79
+ input={(inputProps) => <TextInput {...inputProps} disabled={true} />}
80
+ />
81
+
82
+ <FormikFormField
83
+ label={'On-Demand Base Capacity'}
84
+ name={'onDemandBaseCapacity'}
85
+ help={<HelpField id={'aws.serverGroup.odBase'} />}
86
+ input={(inputProps) => <NumberInput {...inputProps} />}
87
+ />
88
+
89
+ <FormikFormField
90
+ label={'On-Demand Percentage Above Base Capacity'}
91
+ name={'onDemandPercentageAboveBaseCapacity'}
92
+ help={<HelpField id={'aws.serverGroup.odPercentAboveBase'} />}
93
+ input={(inputProps) => <NumberInput {...inputProps} />}
94
+ />
95
+
96
+ <FormikFormField
97
+ label={'Spot Max Price'}
98
+ name={'spotPrice'}
99
+ help={<HelpField id={'aws.serverGroup.spotMaxPrice'} />}
100
+ input={(inputProps) => (
101
+ <Tooltip value={'Recommended to leave empty and use AWS default i.e. On-Demand price'}>
102
+ <TextInput {...inputProps} />
103
+ </Tooltip>
104
+ )}
105
+ />
106
+ </div>
107
+ );
108
+ }
@@ -0,0 +1,110 @@
1
+ .advanced-mode-selector {
2
+ .instance-profile-header {
3
+ display: inline-block;
4
+ button {
5
+ width: 100%;
6
+ }
7
+ h4 {
8
+ min-height: 52px;
9
+ }
10
+ .panel-heading {
11
+ padding: 0 0 0 0;
12
+ }
13
+ &.profile-button {
14
+ width: calc(~'25% - 20px');
15
+ margin: 0 10px 15px 10px;
16
+ }
17
+ }
18
+
19
+ .sub-section {
20
+ padding: 0 15px;
21
+ margin-bottom: 5px;
22
+
23
+ .description {
24
+ padding: 0 10px;
25
+ }
26
+
27
+ tr {
28
+ &.unavailable {
29
+ opacity: 0.5;
30
+ }
31
+
32
+ &.sortable {
33
+ .instance-type-drag-handle {
34
+ display: inline-block;
35
+ opacity: 0.9;
36
+ font-size: 100%;
37
+ padding-top: 8px;
38
+ }
39
+ }
40
+ }
41
+
42
+ th {
43
+ font-size: 110%;
44
+ }
45
+ }
46
+ }
47
+
48
+ .custom-profile {
49
+ .select {
50
+ width: 80%;
51
+ }
52
+ }
53
+
54
+ .instance-profile {
55
+ vertical-align: top;
56
+ text-align: left;
57
+ min-height: 100px;
58
+ font-size: 90%;
59
+ border: 1px solid var(--color-silver);
60
+ border-radius: 3px;
61
+ color: var(--color-mineshaft);
62
+ background-color: transparent;
63
+
64
+ &:hover,
65
+ &:focus {
66
+ color: var(--color-mineshaft);
67
+ text-decoration: none;
68
+ }
69
+
70
+ .selected-indicator {
71
+ display: flex;
72
+ width: 100%;
73
+ text-align: right;
74
+ padding-right: 5px;
75
+ font-size: 150%;
76
+ color: var(--color-accent);
77
+
78
+ &.custom {
79
+ margin-top: 5px;
80
+ }
81
+ }
82
+
83
+ h4 {
84
+ margin-top: 0;
85
+ text-align: center;
86
+ word-spacing: 300px;
87
+ }
88
+
89
+ ul {
90
+ font-size: 95%;
91
+ padding-left: 20px;
92
+ }
93
+ .panel-heading {
94
+ padding-top: 0;
95
+ padding-bottom: 0;
96
+ }
97
+ &:hover,
98
+ &:focus,
99
+ &.active {
100
+ outline: 0;
101
+ }
102
+ &.active {
103
+ box-shadow: inset 0 0 3px 2px var(--color-accent);
104
+ border-color: var(--color-accent);
105
+ }
106
+ &:hover,
107
+ &:focus {
108
+ box-shadow: 0 0 8px 2px var(--color-accent);
109
+ }
110
+ }
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+
3
+ import { NgReact } from '@spinnaker/core';
4
+
5
+ import { CpuCreditsToggle } from '../CpuCreditsToggle';
6
+ import { AWSProviderSettings } from '../../../../../aws.settings';
7
+ import type { IAmazonServerGroupCommand } from '../../../serverGroupConfiguration.service';
8
+
9
+ export interface ISimpleModeSelectorProps {
10
+ command: IAmazonServerGroupCommand;
11
+ setUnlimitedCpuCredits: (unlimitedCpuCredits: boolean | undefined) => void;
12
+ setFieldValue: (field: keyof IAmazonServerGroupCommand, value: any, shouldValidate?: boolean) => void;
13
+ }
14
+
15
+ export function SimpleModeSelector(props: ISimpleModeSelectorProps) {
16
+ const { command } = props;
17
+ const { InstanceArchetypeSelector, InstanceTypeSelector } = NgReact;
18
+ const isLaunchTemplatesEnabled = AWSProviderSettings.serverGroups?.enableLaunchTemplates;
19
+ const isCpuCreditsEnabled = AWSProviderSettings.serverGroups?.enableCpuCredits;
20
+
21
+ const instanceProfileChanged = (newProfile: string) => {
22
+ // Instance profile is already set on values.viewState, so just use that value.
23
+ // Once angular is gone from this component tree, we can move all the viewState stuff
24
+ // into react state
25
+ props.setFieldValue('viewState', {
26
+ ...command.viewState,
27
+ instanceProfile: newProfile,
28
+ });
29
+ };
30
+
31
+ const instanceTypeChanged = (type: string) => {
32
+ command.instanceTypeChanged(command);
33
+ props.setFieldValue('instanceType', type);
34
+ };
35
+
36
+ return (
37
+ <div className="container-fluid form-horizontal">
38
+ <div className="row">
39
+ <InstanceArchetypeSelector
40
+ command={command}
41
+ onTypeChanged={instanceTypeChanged}
42
+ onProfileChanged={instanceProfileChanged}
43
+ />
44
+ <div style={{ padding: '0 15px' }}>
45
+ {command.viewState.instanceProfile && command.viewState.instanceProfile !== 'custom' && (
46
+ <InstanceTypeSelector command={command} onTypeChanged={instanceTypeChanged} />
47
+ )}
48
+ </div>
49
+ </div>
50
+ {isLaunchTemplatesEnabled && isCpuCreditsEnabled && (
51
+ <div className="row">
52
+ <CpuCreditsToggle
53
+ unlimitedCpuCredits={command.unlimitedCpuCredits}
54
+ selectedInstanceTypes={[command.instanceType]}
55
+ currentProfile={command.viewState.instanceProfile}
56
+ setUnlimitedCpuCredits={props.setUnlimitedCpuCredits}
57
+ />
58
+ </div>
59
+ )}
60
+ </div>
61
+ );
62
+ }