@spinnaker/kubernetes 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.
Files changed (158) hide show
  1. package/dist/index.d.ts +1 -2
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/instance/details/KubernetesInstanceDetails.d.ts +54 -0
  5. package/dist/instance/details/kubernetesInstanceDetails.utils.d.ts +13 -0
  6. package/dist/instance/index.d.ts +1 -1
  7. package/dist/kubernetes.module.d.ts +5 -1
  8. package/dist/loadBalancer/transformer.d.ts +1 -1
  9. package/dist/manifest/AnnotationCustomSections.d.ts +3 -2
  10. package/dist/manifest/ManifestKindSearch.d.ts +1 -1
  11. package/dist/manifest/delete/Delete.d.ts +0 -1
  12. package/dist/manifest/delete/DeleteModal.d.ts +1 -1
  13. package/dist/manifest/delete/delete.types.d.ts +4 -0
  14. package/dist/manifest/index.d.ts +3 -6
  15. package/dist/manifest/manifest.service.d.ts +5 -0
  16. package/dist/manifest/manifestCommandBuilder.service.d.ts +1 -1
  17. package/dist/manifest/rollout/PauseRollout.d.ts +0 -1
  18. package/dist/manifest/rollout/ResumeRollout.d.ts +0 -1
  19. package/dist/manifest/rollout/RollingRestart.d.ts +4 -4
  20. package/dist/manifest/rollout/UndoRollout.d.ts +0 -1
  21. package/dist/manifest/scale/Scale.d.ts +1 -2
  22. package/dist/manifest/scale/ScaleModal.d.ts +3 -3
  23. package/dist/manifest/scale/ScaleSettingsForm.d.ts +7 -1
  24. package/dist/manifest/selector/ManifestSelector.d.ts +1 -1
  25. package/dist/manifest/traffic/ManifestTrafficService.d.ts +2 -2
  26. package/dist/pipelines/stages/deleteManifest/DeleteManifestOptionsForm.d.ts +1 -1
  27. package/dist/pipelines/stages/deployManifest/manifestStatus/DeployStatus.d.ts +1 -0
  28. package/dist/pipelines/stages/deployManifest/manifestStatus/ManifestDetailsLink.d.ts +6 -3
  29. package/dist/pipelines/stages/traffic/disableManifest.stage.d.ts +2 -1
  30. package/dist/pipelines/stages/traffic/enableManifest.stage.d.ts +2 -1
  31. package/dist/rawResource/index.d.ts +3 -1
  32. package/dist/rawResource/rawResource.dataSource.d.ts +1 -1
  33. package/dist/rawResource/rawResource.states.d.ts +4 -1
  34. package/dist/resources/resources.state.d.ts +2 -1
  35. package/dist/securityGroup/details/KubernetesSecurityGroupDetails.d.ts +49 -0
  36. package/dist/securityGroup/index.d.ts +3 -1
  37. package/dist/securityGroup/transformer.d.ts +4 -1
  38. package/dist/serverGroup/serverGroupCommandBuilder.d.ts +1 -1
  39. package/dist/serverGroup/serverGroupTransformer.d.ts +1 -1
  40. package/dist/serverGroupManager/details/ServerGroupManagerDetails.d.ts +7 -3
  41. package/package.json +3 -12
  42. package/src/help/kubernetes.help.ts +2 -0
  43. package/src/index.ts +2 -2
  44. package/src/instance/details/KubernetesInstanceDetails.spec.tsx +451 -0
  45. package/src/instance/details/KubernetesInstanceDetails.tsx +342 -0
  46. package/src/instance/details/kubernetesInstanceDetails.utils.ts +77 -0
  47. package/src/instance/index.ts +1 -1
  48. package/src/kubernetes.module.spec.ts +25 -0
  49. package/src/kubernetes.module.ts +23 -87
  50. package/src/loadBalancer/details/KubernetesLoadBalancerActions.tsx +30 -35
  51. package/src/loadBalancer/details/sections/LoadBalancerAnnotationCustomSection.tsx +2 -3
  52. package/src/loadBalancer/transformer.ts +1 -1
  53. package/src/manifest/AnnotationCustomSections.spec.tsx +178 -0
  54. package/src/manifest/AnnotationCustomSections.tsx +179 -2
  55. package/src/manifest/ManifestKindSearch.tsx +1 -1
  56. package/src/manifest/delete/Delete.tsx +0 -9
  57. package/src/manifest/delete/DeleteModal.tsx +69 -72
  58. package/src/manifest/delete/delete.types.ts +4 -0
  59. package/src/manifest/index.ts +3 -6
  60. package/src/manifest/manifest.service.ts +18 -1
  61. package/src/manifest/manifestCommandBuilder.service.spec.ts +41 -0
  62. package/src/manifest/manifestCommandBuilder.service.ts +45 -59
  63. package/src/manifest/rollout/PauseRollout.tsx +1 -9
  64. package/src/manifest/rollout/ResumeRollout.tsx +2 -10
  65. package/src/manifest/rollout/RollingRestart.tsx +16 -22
  66. package/src/manifest/rollout/UndoRollout.tsx +1 -10
  67. package/src/manifest/rollout/UndoRolloutModal.tsx +5 -1
  68. package/src/manifest/scale/Scale.tsx +12 -11
  69. package/src/manifest/scale/ScaleModal.tsx +43 -31
  70. package/src/manifest/scale/ScaleSettingsForm.tsx +8 -1
  71. package/src/manifest/selector/ManifestSelector.spec.tsx +89 -46
  72. package/src/manifest/selector/ManifestSelector.tsx +4 -5
  73. package/src/manifest/traffic/ManifestTrafficService.ts +2 -2
  74. package/src/manifest/wizard/ManifestWizard.tsx +1 -1
  75. package/src/pipelines/stages/deleteManifest/DeleteManifestOptionsForm.tsx +1 -1
  76. package/src/pipelines/stages/deleteManifest/DeleteManifestStageConfig.tsx +1 -1
  77. package/src/pipelines/stages/deployManifest/DeployManifestStageForm.tsx +16 -0
  78. package/src/pipelines/stages/deployManifest/ManifestCopier.spec.ts +52 -77
  79. package/src/pipelines/stages/deployManifest/ManifestDeploymentOptions.spec.tsx +2 -0
  80. package/src/pipelines/stages/deployManifest/manifestStatus/DeployStatus.tsx +39 -4
  81. package/src/pipelines/stages/deployManifest/manifestStatus/ManifestDetailsLink.spec.tsx +35 -0
  82. package/src/pipelines/stages/deployManifest/manifestStatus/ManifestDetailsLink.tsx +10 -5
  83. package/src/pipelines/stages/traffic/ManifestTrafficStageRegistration.spec.ts +34 -0
  84. package/src/pipelines/stages/traffic/disableManifest.stage.ts +17 -19
  85. package/src/pipelines/stages/traffic/enableManifest.stage.ts +17 -19
  86. package/src/rawResource/index.ts +18 -1
  87. package/src/rawResource/rawResource.dataSource.ts +5 -8
  88. package/src/rawResource/rawResource.states.ts +50 -51
  89. package/src/resources/resources.state.spec.ts +138 -0
  90. package/src/resources/resources.state.ts +30 -35
  91. package/src/securityGroup/details/KubernetesSecurityGroupDetails.spec.tsx +292 -0
  92. package/src/securityGroup/details/KubernetesSecurityGroupDetails.tsx +304 -0
  93. package/src/securityGroup/index.ts +3 -1
  94. package/src/securityGroup/transformer.ts +2 -10
  95. package/src/serverGroup/details/KubernetesServerGroupActions.tsx +31 -61
  96. package/src/serverGroup/details/kubernetesServerGroupDetailsGetter.ts +1 -1
  97. package/src/serverGroup/details/sections/ServerGroupAnnotationCustomSection.tsx +2 -3
  98. package/src/serverGroup/serverGroupCommandBuilder.ts +1 -1
  99. package/src/serverGroup/serverGroupTransformer.ts +1 -1
  100. package/src/serverGroupManager/details/ServerGroupManagerActions.tsx +48 -128
  101. package/src/serverGroupManager/details/ServerGroupManagerDetails.spec.ts +12 -0
  102. package/src/serverGroupManager/details/ServerGroupManagerDetails.tsx +19 -8
  103. package/src/serverGroupManager/details/sections/ServerGroupManagerAnnotationCustomSection.tsx +2 -3
  104. package/src/serverGroupManager/details/useKubernetesServerGroupManagerDetails.spec.tsx +112 -0
  105. package/src/serverGroupManager/details/useKubernetesServerGroupManagerDetails.tsx +50 -29
  106. package/dist/instance/details/details.controller.d.ts +0 -1
  107. package/dist/manifest/annotationCustomSections.component.d.ts +0 -3
  108. package/dist/manifest/delete/delete.controller.d.ts +0 -12
  109. package/dist/manifest/delete/deleteOptionsForm.component.d.ts +0 -1
  110. package/dist/manifest/editor/json/jsonEditor.component.d.ts +0 -1
  111. package/dist/manifest/manifestEvents.component.d.ts +0 -1
  112. package/dist/manifest/manifestImageDetails.component.d.ts +0 -1
  113. package/dist/manifest/manifestLabels.component.d.ts +0 -1
  114. package/dist/manifest/manifestQos.component.d.ts +0 -1
  115. package/dist/manifest/manifestResources.component.d.ts +0 -1
  116. package/dist/manifest/rollout/pause.controller.d.ts +0 -1
  117. package/dist/manifest/rollout/resume.controller.d.ts +0 -1
  118. package/dist/manifest/rollout/undo.controller.d.ts +0 -5
  119. package/dist/manifest/scale/scale.controller.d.ts +0 -8
  120. package/dist/manifest/scale/scaleSettingsForm.component.d.ts +0 -1
  121. package/dist/manifest/selector/selector.component.d.ts +0 -1
  122. package/dist/manifest/status/condition.component.d.ts +0 -1
  123. package/dist/manifest/status/status.component.d.ts +0 -1
  124. package/dist/rawResource/rawResource.module.d.ts +0 -1
  125. package/dist/reactShims/index.d.ts +0 -1
  126. package/dist/reactShims/kubernetes.react.injector.d.ts +0 -11
  127. package/dist/reactShims/kubernetes.react.module.d.ts +0 -1
  128. package/dist/securityGroup/details/details.controller.d.ts +0 -1
  129. package/src/instance/details/details.controller.ts +0 -186
  130. package/src/instance/details/details.html +0 -80
  131. package/src/manifest/annotationCustomSections.component.ts +0 -114
  132. package/src/manifest/delete/delete.controller.ts +0 -80
  133. package/src/manifest/delete/delete.html +0 -42
  134. package/src/manifest/delete/deleteOptionsForm.component.ts +0 -52
  135. package/src/manifest/editor/json/jsonEditor.component.ts +0 -12
  136. package/src/manifest/manifestEvents.component.ts +0 -12
  137. package/src/manifest/manifestImageDetails.component.ts +0 -12
  138. package/src/manifest/manifestLabels.component.ts +0 -12
  139. package/src/manifest/manifestQos.component.ts +0 -12
  140. package/src/manifest/manifestResources.component.ts +0 -12
  141. package/src/manifest/rollout/pause.controller.ts +0 -66
  142. package/src/manifest/rollout/pause.html +0 -28
  143. package/src/manifest/rollout/resume.controller.ts +0 -66
  144. package/src/manifest/rollout/resume.html +0 -28
  145. package/src/manifest/rollout/undo.controller.ts +0 -74
  146. package/src/manifest/rollout/undo.html +0 -44
  147. package/src/manifest/scale/scale.controller.ts +0 -75
  148. package/src/manifest/scale/scale.html +0 -32
  149. package/src/manifest/scale/scaleSettingsForm.component.ts +0 -11
  150. package/src/manifest/selector/selector.component.ts +0 -17
  151. package/src/manifest/status/condition.component.ts +0 -12
  152. package/src/manifest/status/status.component.ts +0 -11
  153. package/src/rawResource/rawResource.module.ts +0 -8
  154. package/src/reactShims/index.ts +0 -1
  155. package/src/reactShims/kubernetes.react.injector.ts +0 -30
  156. package/src/reactShims/kubernetes.react.module.ts +0 -12
  157. package/src/securityGroup/details/details.controller.ts +0 -118
  158. package/src/securityGroup/details/details.html +0 -91
@@ -2,17 +2,14 @@ import React from 'react';
2
2
  import { Dropdown, MenuItem } from 'react-bootstrap';
3
3
 
4
4
  import type { IOwnerOption, IServerGroupActionsProps } from '@spinnaker/core';
5
- import {
6
- AddEntityTagLinks,
7
- ClusterTargetBuilder,
8
- ConfirmationModalService,
9
- ModalInjector,
10
- robotToHuman,
11
- SETTINGS,
12
- } from '@spinnaker/core';
5
+ import { ConfirmationModalService } from '@spinnaker/core';
6
+ import { AddEntityTagLinks, ClusterTargetBuilder, robotToHuman, SETTINGS } from '@spinnaker/core';
13
7
 
14
8
  import type { IKubernetesServerGroupView } from '../../interfaces';
15
9
  import { KubernetesManifestCommandBuilder } from '../../manifest';
10
+ import { Delete } from '../../manifest/delete/Delete';
11
+ import { RollingRestart } from '../../manifest/rollout/RollingRestart';
12
+ import { Scale } from '../../manifest/scale/Scale';
16
13
  import { ManifestTrafficService } from '../../manifest/traffic/ManifestTrafficService';
17
14
  import { ManifestWizard } from '../../manifest/wizard/ManifestWizard';
18
15
  import { useManifest } from './useManifest';
@@ -31,22 +28,6 @@ export function KubernetesServerGroupActions({ app, serverGroup }: IKubernetesSe
31
28
  return serverGroup.kind !== 'daemonSet' && manifestController === null;
32
29
  };
33
30
 
34
- const scaleServerGroup = () => {
35
- ModalInjector.modalService.open({
36
- templateUrl: require('../../manifest/scale/scale.html'),
37
- controller: 'kubernetesV2ManifestScaleCtrl as ctrl',
38
- resolve: {
39
- coordinates: {
40
- name: serverGroup.name,
41
- namespace: serverGroup.namespace,
42
- account: serverGroup.account,
43
- },
44
- currentReplicas: manifest.manifest.spec.replicas,
45
- application: app,
46
- },
47
- });
48
- };
49
-
50
31
  const canEditServerGroup = (): boolean => {
51
32
  return manifestController === null;
52
33
  };
@@ -62,22 +43,6 @@ export function KubernetesServerGroupActions({ app, serverGroup }: IKubernetesSe
62
43
  });
63
44
  };
64
45
 
65
- const deleteServerGroup = () => {
66
- ModalInjector.modalService.open({
67
- templateUrl: require('../../manifest/delete/delete.html'),
68
- controller: 'kubernetesV2ManifestDeleteCtrl as ctrl',
69
- resolve: {
70
- coordinates: {
71
- name: serverGroup.name,
72
- namespace: serverGroup.namespace,
73
- account: serverGroup.account,
74
- },
75
- manifestController: () => manifestController,
76
- application: app,
77
- },
78
- });
79
- };
80
-
81
46
  const canDisable = () => ManifestTrafficService.canDisableServerGroup(serverGroup);
82
47
 
83
48
  const disableServerGroup = (): void => {
@@ -113,26 +78,31 @@ export function KubernetesServerGroupActions({ app, serverGroup }: IKubernetesSe
113
78
  };
114
79
 
115
80
  return (
116
- <Dropdown className="dropdown" id="server-group-actions-dropdown">
117
- <Dropdown.Toggle className="btn btn-sm btn-primary dropdown-toggle">
118
- {robotToHuman(serverGroup.kind)} Actions
119
- </Dropdown.Toggle>
120
- <Dropdown.Menu>
121
- {canEditServerGroup() && <MenuItem onClick={editServerGroup}>Edit</MenuItem>}
122
- {canScaleServerGroup() && <MenuItem onClick={scaleServerGroup}>Scale</MenuItem>}
123
- {canEnable() && <MenuItem onClick={enableServerGroup}>Enable</MenuItem>}
124
- {canDisable() && <MenuItem onClick={disableServerGroup}>Disable</MenuItem>}
125
- <MenuItem onClick={deleteServerGroup}>Delete</MenuItem>
126
- {showEntityTags && (
127
- <AddEntityTagLinks
128
- component={serverGroup}
129
- application={app}
130
- entityType="serverGroup"
131
- ownerOptions={entityTagTargets}
132
- onUpdate={() => app.serverGroups.refresh()}
133
- />
134
- )}
135
- </Dropdown.Menu>
136
- </Dropdown>
81
+ <>
82
+ <Dropdown className="dropdown" id="server-group-actions-dropdown">
83
+ <Dropdown.Toggle className="btn btn-sm btn-primary dropdown-toggle">
84
+ {robotToHuman(serverGroup.kind)} Actions
85
+ </Dropdown.Toggle>
86
+ <Dropdown.Menu>
87
+ {canEditServerGroup() && <MenuItem onClick={editServerGroup}>Edit</MenuItem>}
88
+ {canScaleServerGroup() && (
89
+ <Scale application={app} resource={serverGroup} currentReplicas={manifest.manifest.spec.replicas} />
90
+ )}
91
+ {canEnable() && <MenuItem onClick={enableServerGroup}>Enable</MenuItem>}
92
+ {canDisable() && <MenuItem onClick={disableServerGroup}>Disable</MenuItem>}
93
+ <Delete application={app} resource={serverGroup} manifestController={manifestController} />
94
+ {!manifest.status.paused.state && <RollingRestart application={app} serverGroup={serverGroup} />}
95
+ {showEntityTags && (
96
+ <AddEntityTagLinks
97
+ component={serverGroup}
98
+ application={app}
99
+ entityType="serverGroup"
100
+ ownerOptions={entityTagTargets}
101
+ onUpdate={() => app.serverGroups.refresh()}
102
+ />
103
+ )}
104
+ </Dropdown.Menu>
105
+ </Dropdown>
106
+ </>
137
107
  );
138
108
  }
@@ -5,7 +5,7 @@ import type { IManifest, IServerGroupDetailsProps } from '@spinnaker/core';
5
5
  import { ManifestReader, ServerGroupReader } from '@spinnaker/core';
6
6
  import type { IKubernetesLoadBalancer, IKubernetesServerGroup, IKubernetesServerGroupView } from '../../interfaces';
7
7
 
8
- function extractServerGroupSummary(props: IServerGroupDetailsProps): PromiseLike<IKubernetesServerGroup> {
8
+ function extractServerGroupSummary(props: IServerGroupDetailsProps): Promise<IKubernetesServerGroup> {
9
9
  const { app, serverGroup } = props;
10
10
  return app.ready().then(() => {
11
11
  let summary: IKubernetesServerGroup = app.serverGroups.data.find((toCheck: IKubernetesServerGroup) => {
@@ -1,11 +1,10 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { IKubernetesServerGroupDetailsSectionProps } from './IKubernetesServerGroupDetailsSectionProps';
4
- import { KubernetesReactInjector } from '../../../reactShims';
4
+ import { AnnotationCustomSections } from '../../../manifest/AnnotationCustomSections';
5
5
 
6
6
  export function ServerGroupAnnotationCustomSection({ serverGroup }: IKubernetesServerGroupDetailsSectionProps) {
7
7
  const { manifest } = serverGroup;
8
- const { KubernetesAnnotationCustomSections } = KubernetesReactInjector;
9
8
 
10
- return <KubernetesAnnotationCustomSections manifest={manifest.manifest} resource={serverGroup} />;
9
+ return <AnnotationCustomSections manifest={manifest.manifest} resource={serverGroup} />;
11
10
  }
@@ -3,7 +3,7 @@ import type { IKubernetesManifestCommandData } from '../manifest/manifestCommand
3
3
  import { KubernetesManifestCommandBuilder } from '../manifest/manifestCommandBuilder.service';
4
4
 
5
5
  export class KubernetesV2ServerGroupCommandBuilder {
6
- public buildNewServerGroupCommand(app: Application): PromiseLike<IKubernetesManifestCommandData> {
6
+ public buildNewServerGroupCommand(app: Application): Promise<IKubernetesManifestCommandData> {
7
7
  return KubernetesManifestCommandBuilder.buildNewManifestCommand(app);
8
8
  }
9
9
  }
@@ -5,7 +5,7 @@ export class KubernetesV2ServerGroupTransformer {
5
5
  public normalizeServerGroup(
6
6
  serverGroup: IKubernetesServerGroup,
7
7
  application: Application,
8
- ): PromiseLike<IKubernetesServerGroup> {
8
+ ): Promise<IKubernetesServerGroup> {
9
9
  return application
10
10
  .getDataSource('serverGroupManagers')
11
11
  .ready()
@@ -1,22 +1,19 @@
1
- import { orderBy } from 'lodash';
2
1
  import React from 'react';
3
2
  import { Dropdown, MenuItem } from 'react-bootstrap';
4
3
 
5
4
  import type { Application, IManifest } from '@spinnaker/core';
6
- import {
7
- AddEntityTagLinks,
8
- ClusterTargetBuilder,
9
- IfFeatureEnabled,
10
- ModalInjector,
11
- NameUtils,
12
- robotToHuman,
13
- SETTINGS,
14
- } from '@spinnaker/core';
5
+ import { AddEntityTagLinks, ClusterTargetBuilder, IfFeatureEnabled, robotToHuman, SETTINGS } from '@spinnaker/core';
15
6
 
16
7
  import type { IKubernetesServerGroupManager } from '../../interfaces';
17
8
  import { KubernetesManifestCommandBuilder } from '../../manifest';
9
+ import { Delete } from '../../manifest/delete/Delete';
10
+ import { PauseRollout } from '../../manifest/rollout/PauseRollout';
11
+ import { ResumeRollout } from '../../manifest/rollout/ResumeRollout';
18
12
  import { RollingRestart } from '../../manifest/rollout/RollingRestart';
13
+ import { UndoRollout } from '../../manifest/rollout/UndoRollout';
14
+ import { Scale } from '../../manifest/scale/Scale';
19
15
  import { ManifestWizard } from '../../manifest/wizard/ManifestWizard';
16
+ import { useManifest } from '../../serverGroup/details/useManifest';
20
17
 
21
18
  export interface IServerGroupManagerActionsProps {
22
19
  application: Application;
@@ -31,79 +28,12 @@ export function ServerGroupManagerActions({
31
28
  }: IServerGroupManagerActionsProps) {
32
29
  const isEnabled = SETTINGS.kubernetesAdHocInfraWritesEnabled;
33
30
  const entityTagTargets = ClusterTargetBuilder.buildManagerClusterTargets(serverGroupManager);
34
-
35
- const pauseRolloutServerGroupManager = (): void => {
36
- ModalInjector.modalService.open({
37
- templateUrl: require('../../manifest/rollout/pause.html'),
38
- controller: 'kubernetesV2ManifestPauseRolloutCtrl as ctrl',
39
- resolve: {
40
- coordinates: {
41
- name: serverGroupManager.name,
42
- namespace: serverGroupManager.namespace,
43
- account: serverGroupManager.account,
44
- },
45
- application: application,
46
- },
47
- });
48
- };
49
-
50
- const resumeRolloutServerGroupManager = (): void => {
51
- ModalInjector.modalService.open({
52
- templateUrl: require('../../manifest/rollout/resume.html'),
53
- controller: 'kubernetesV2ManifestResumeRolloutCtrl as ctrl',
54
- resolve: {
55
- coordinates: {
56
- name: serverGroupManager.name,
57
- namespace: serverGroupManager.namespace,
58
- account: serverGroupManager.account,
59
- },
60
- application: application,
61
- },
62
- });
63
- };
31
+ const { manifestController } = useManifest({ manifest });
64
32
 
65
33
  const canUndoRolloutServerGroupManager = (): boolean => {
66
34
  return serverGroupManager && serverGroupManager.serverGroups && serverGroupManager.serverGroups.length > 0;
67
35
  };
68
36
 
69
- const undoRolloutServerGroupManager = (): void => {
70
- ModalInjector.modalService.open({
71
- templateUrl: require('../../manifest/rollout/undo.html'),
72
- controller: 'kubernetesV2ManifestUndoRolloutCtrl as ctrl',
73
- resolve: {
74
- coordinates: {
75
- name: serverGroupManager.name,
76
- namespace: serverGroupManager.namespace,
77
- account: serverGroupManager.account,
78
- },
79
- revisions: () => {
80
- const [, ...rest] = orderBy(serverGroupManager.serverGroups, ['moniker.sequence'], ['desc']);
81
- return rest.map((serverGroup, index) => ({
82
- label: `${NameUtils.getSequence(serverGroup.moniker.sequence)}${index > 0 ? '' : ' - previous revision'}`,
83
- revision: serverGroup.moniker.sequence,
84
- }));
85
- },
86
- application: application,
87
- },
88
- });
89
- };
90
-
91
- const scaleServerGroupManager = () => {
92
- ModalInjector.modalService.open({
93
- templateUrl: require('../../manifest/scale/scale.html'),
94
- controller: 'kubernetesV2ManifestScaleCtrl as ctrl',
95
- resolve: {
96
- coordinates: {
97
- name: serverGroupManager.name,
98
- namespace: serverGroupManager.namespace,
99
- account: serverGroupManager.account,
100
- },
101
- currentReplicas: manifest.manifest.spec.replicas,
102
- application: application,
103
- },
104
- });
105
- };
106
-
107
37
  const editServerGroupManager = (): void => {
108
38
  KubernetesManifestCommandBuilder.buildNewManifestCommand(
109
39
  application,
@@ -115,57 +45,47 @@ export function ServerGroupManagerActions({
115
45
  });
116
46
  };
117
47
 
118
- const deleteServerGroupManager = (): void => {
119
- ModalInjector.modalService.open({
120
- templateUrl: require('../../manifest/delete/delete.html'),
121
- controller: 'kubernetesV2ManifestDeleteCtrl as ctrl',
122
- resolve: {
123
- coordinates: {
124
- name: serverGroupManager.name,
125
- namespace: serverGroupManager.namespace,
126
- account: serverGroupManager.account,
127
- },
128
- application: application,
129
- manifestController: (): string => null,
130
- },
131
- });
132
- };
133
-
134
48
  return (
135
- <Dropdown className="dropdown" id="server-group-manager-actions-dropdown">
136
- {isEnabled && (
137
- <Dropdown.Toggle className="btn btn-sm btn-primary dropdown-toggle">
138
- {robotToHuman(serverGroupManager.kind)} Actions
139
- </Dropdown.Toggle>
140
- )}
141
- <Dropdown.Menu>
142
- <MenuItem onClick={scaleServerGroupManager}>Scale</MenuItem>
143
- {canUndoRolloutServerGroupManager() && (
144
- <MenuItem onClick={undoRolloutServerGroupManager}>Undo Rollout</MenuItem>
145
- )}
146
- {manifest.status.paused.state && <MenuItem onClick={resumeRolloutServerGroupManager}>Resume Rollout</MenuItem>}
147
- {!manifest.status.paused.state && !manifest.status.stable.state && (
148
- <MenuItem onClick={pauseRolloutServerGroupManager}>Pause Rollout</MenuItem>
149
- )}
150
- {!manifest.status.paused.state && (
151
- <RollingRestart application={application} serverGroupManager={serverGroupManager} />
49
+ <>
50
+ <Dropdown className="dropdown" id="server-group-manager-actions-dropdown">
51
+ {isEnabled && (
52
+ <Dropdown.Toggle className="btn btn-sm btn-primary dropdown-toggle">
53
+ {robotToHuman(serverGroupManager.kind)} Actions
54
+ </Dropdown.Toggle>
152
55
  )}
153
- <MenuItem className="divider" />
154
- <MenuItem onClick={editServerGroupManager}>Edit</MenuItem>
155
- <MenuItem onClick={deleteServerGroupManager}>Delete</MenuItem>
156
- <IfFeatureEnabled
157
- feature="entityTags"
158
- render={
159
- <AddEntityTagLinks
160
- component={serverGroupManager}
161
- application={application}
162
- entityType="serverGroupManager"
163
- ownerOptions={entityTagTargets}
164
- onUpdate={() => application.serverGroupManagers.refresh()}
165
- />
166
- }
167
- />
168
- </Dropdown.Menu>
169
- </Dropdown>
56
+ <Dropdown.Menu>
57
+ <Scale
58
+ application={application}
59
+ resource={serverGroupManager}
60
+ currentReplicas={manifest.manifest.spec.replicas}
61
+ />
62
+ {canUndoRolloutServerGroupManager() && (
63
+ <UndoRollout application={application} resource={serverGroupManager} />
64
+ )}
65
+ {manifest.status.paused.state && <ResumeRollout application={application} resource={serverGroupManager} />}
66
+ {!manifest.status.paused.state && !manifest.status.stable.state && (
67
+ <PauseRollout application={application} resource={serverGroupManager} />
68
+ )}
69
+ {!manifest.status.paused.state && (
70
+ <RollingRestart application={application} serverGroupManager={serverGroupManager} />
71
+ )}
72
+ <MenuItem className="divider" />
73
+ <MenuItem onClick={editServerGroupManager}>Edit</MenuItem>
74
+ <Delete application={application} resource={serverGroupManager} manifestController={manifestController} />
75
+ <IfFeatureEnabled
76
+ feature="entityTags"
77
+ render={
78
+ <AddEntityTagLinks
79
+ component={serverGroupManager}
80
+ application={application}
81
+ entityType="serverGroupManager"
82
+ ownerOptions={entityTagTargets}
83
+ onUpdate={() => application.serverGroupManagers.refresh()}
84
+ />
85
+ }
86
+ />
87
+ </Dropdown.Menu>
88
+ </Dropdown>
89
+ </>
170
90
  );
171
91
  }
@@ -0,0 +1,12 @@
1
+ import { closeServerGroupManagerDetails } from './ServerGroupManagerDetails';
2
+
3
+ describe('closeServerGroupManagerDetails', () => {
4
+ it('replaces details through the injected state service', () => {
5
+ const stateService = { go: jasmine.createSpy('go'), params: {} };
6
+
7
+ closeServerGroupManagerDetails(stateService as any);
8
+
9
+ expect(stateService.params.allowModalToStayOpen).toBe(true);
10
+ expect(stateService.go).toHaveBeenCalledWith('^', null, { location: 'replace' });
11
+ });
12
+ });
@@ -1,7 +1,12 @@
1
1
  import React from 'react';
2
2
 
3
- import type { Application, IServerGroupManagerDetailsProps, IServerGroupManagerStateParams } from '@spinnaker/core';
4
- import { CloudProviderLogo, Details, EntityNotifications, IfFeatureEnabled, ReactInjector } from '@spinnaker/core';
3
+ import type {
4
+ Application,
5
+ IRouterInjectedProps,
6
+ IServerGroupManagerDetailsProps,
7
+ IServerGroupManagerStateParams,
8
+ } from '@spinnaker/core';
9
+ import { CloudProviderLogo, Details, EntityNotifications, IfFeatureEnabled, withRouter } from '@spinnaker/core';
5
10
 
6
11
  import { ServerGroupManagerActions } from './ServerGroupManagerActions';
7
12
  import {
@@ -20,14 +25,18 @@ export interface IKubernetesServerGroupManagerDetailsProps extends IServerGroupM
20
25
  serverGroupManager: IServerGroupManagerStateParams;
21
26
  }
22
27
 
23
- export function ServerGroupManagerDetails(props: IKubernetesServerGroupManagerDetailsProps) {
24
- const autoClose = () => {
25
- ReactInjector.$state.params.allowModalToStayOpen = true;
26
- ReactInjector.$state.go('^', null, { location: 'replace' });
27
- };
28
+ export function closeServerGroupManagerDetails(stateService: IRouterInjectedProps['stateService']): void {
29
+ stateService.params.allowModalToStayOpen = true;
30
+ stateService.go('^', null, { location: 'replace' });
31
+ }
32
+
33
+ export function ServerGroupManagerDetailsComponent(
34
+ props: IKubernetesServerGroupManagerDetailsProps & IRouterInjectedProps,
35
+ ) {
36
+ const autoClose = () => closeServerGroupManagerDetails(props.stateService);
28
37
  const [serverGroupManager, manifest, loading] = useKubernetesServerGroupManagerDetails(props, autoClose);
29
38
 
30
- if (loading) return <Details loading={loading} />;
39
+ if (loading || !serverGroupManager || !manifest) return <Details loading={true} />;
31
40
 
32
41
  return (
33
42
  <Details loading={loading}>
@@ -70,3 +79,5 @@ export function ServerGroupManagerDetails(props: IKubernetesServerGroupManagerDe
70
79
  </Details>
71
80
  );
72
81
  }
82
+
83
+ export const ServerGroupManagerDetails = withRouter(ServerGroupManagerDetailsComponent);
@@ -1,12 +1,11 @@
1
1
  import React from 'react';
2
2
 
3
3
  import type { IKubernetesServerGroupManagerDetailsSectionProps } from './IKubernetesServerGroupManagerDetailsSectionProps';
4
- import { KubernetesReactInjector } from '../../../reactShims';
4
+ import { AnnotationCustomSections } from '../../../manifest/AnnotationCustomSections';
5
5
 
6
6
  export function ServerGroupManagerAnnotationCustomSection({
7
7
  serverGroupManager,
8
8
  manifest,
9
9
  }: IKubernetesServerGroupManagerDetailsSectionProps) {
10
- const { KubernetesAnnotationCustomSections } = KubernetesReactInjector;
11
- return <KubernetesAnnotationCustomSections manifest={manifest.manifest} resource={serverGroupManager} />;
10
+ return <AnnotationCustomSections manifest={manifest.manifest} resource={serverGroupManager} />;
12
11
  }
@@ -0,0 +1,112 @@
1
+ import { mount } from 'enzyme';
2
+ import React from 'react';
3
+
4
+ import { ManifestReader } from '@spinnaker/core';
5
+
6
+ import { useKubernetesServerGroupManagerDetails } from './useKubernetesServerGroupManagerDetails';
7
+ import type { IKubernetesServerGroupManagerDetailsProps } from './ServerGroupManagerDetails';
8
+
9
+ describe('useKubernetesServerGroupManagerDetails', () => {
10
+ beforeEach(() => {
11
+ spyOn(ManifestReader, 'getManifest').and.returnValue(Promise.resolve(manifestDetails()) as any);
12
+ });
13
+
14
+ it('waits for the server group manager data source before loading manifest details', async () => {
15
+ let resolveReady: () => void;
16
+ const ready = new Promise<void>((resolve) => {
17
+ resolveReady = resolve;
18
+ });
19
+ const autoClose = jasmine.createSpy('autoClose');
20
+ const dataSource = {
21
+ data: [] as any[],
22
+ ready: jasmine.createSpy('ready').and.returnValue(ready),
23
+ };
24
+ const component = mount(<HookHarness {...props(dataSource)} autoClose={autoClose} />);
25
+
26
+ await settle();
27
+ component.update();
28
+
29
+ expect(dataSource.ready).toHaveBeenCalled();
30
+ expect(autoClose).not.toHaveBeenCalled();
31
+ expect(ManifestReader.getManifest).not.toHaveBeenCalled();
32
+ expect(component.find('.hook-state').prop('data-loading')).toBe(true);
33
+
34
+ dataSource.data = [serverGroupManagerDetails()];
35
+ resolveReady!();
36
+ await settle();
37
+ await settle();
38
+ component.update();
39
+
40
+ expect(ManifestReader.getManifest).toHaveBeenCalledWith('k8s-local', 'dev', 'deployment backend');
41
+ expect(component.find('.hook-state').prop('data-loading')).toBe(false);
42
+ expect(component.find('.hook-state').prop('data-manager')).toBe('backend');
43
+ expect(component.find('.hook-state').prop('data-manifest')).toBe('deployment backend');
44
+ });
45
+
46
+ it('auto-closes when manifest details fail to load', async () => {
47
+ (ManifestReader.getManifest as jasmine.Spy).and.returnValue(Promise.reject(new Error('manifest failed')));
48
+ spyOn(console, 'error').and.stub();
49
+ const autoClose = jasmine.createSpy('autoClose');
50
+ const dataSource = {
51
+ data: [serverGroupManagerDetails()],
52
+ ready: jasmine.createSpy('ready').and.returnValue(Promise.resolve()),
53
+ };
54
+
55
+ const component = mount(<HookHarness {...props(dataSource)} autoClose={autoClose} />);
56
+
57
+ await settle();
58
+ await settle();
59
+ component.update();
60
+
61
+ expect(autoClose).toHaveBeenCalled();
62
+
63
+ component.unmount();
64
+ });
65
+ });
66
+
67
+ function HookHarness({ autoClose, ...props }: IKubernetesServerGroupManagerDetailsProps & { autoClose: () => void }) {
68
+ const [serverGroupManager, manifest, loading] = useKubernetesServerGroupManagerDetails(props, autoClose);
69
+
70
+ return (
71
+ <div
72
+ className="hook-state"
73
+ data-loading={loading}
74
+ data-manager={serverGroupManager?.displayName || ''}
75
+ data-manifest={manifest?.name || ''}
76
+ />
77
+ );
78
+ }
79
+
80
+ function props(dataSource: any): IKubernetesServerGroupManagerDetailsProps {
81
+ return {
82
+ app: {
83
+ getDataSource: () => dataSource,
84
+ } as any,
85
+ serverGroupManager: {
86
+ accountId: 'k8s-local',
87
+ provider: 'kubernetes',
88
+ region: 'dev',
89
+ name: 'deployment backend',
90
+ },
91
+ } as IKubernetesServerGroupManagerDetailsProps;
92
+ }
93
+
94
+ function serverGroupManagerDetails() {
95
+ return {
96
+ account: 'k8s-local',
97
+ cloudProvider: 'kubernetes',
98
+ displayName: 'backend',
99
+ name: 'deployment backend',
100
+ region: 'dev',
101
+ } as any;
102
+ }
103
+
104
+ function manifestDetails() {
105
+ return {
106
+ account: 'k8s-local',
107
+ location: 'dev',
108
+ name: 'deployment backend',
109
+ } as any;
110
+ }
111
+
112
+ const settle = () => new Promise((resolve) => setTimeout(resolve));
@@ -6,48 +6,69 @@ import { ManifestReader } from '@spinnaker/core';
6
6
  import type { IKubernetesServerGroupManagerDetailsProps } from './ServerGroupManagerDetails';
7
7
  import type { IKubernetesServerGroupManager } from '../../interfaces';
8
8
 
9
+ interface IServerGroupManagerDetailsState {
10
+ serverGroupManager?: IKubernetesServerGroupManager;
11
+ manifest?: IManifest;
12
+ loading: boolean;
13
+ }
14
+
9
15
  export function useKubernetesServerGroupManagerDetails(
10
16
  props: IKubernetesServerGroupManagerDetailsProps,
11
17
  autoClose: () => void,
12
18
  ): [IKubernetesServerGroupManager | undefined, IManifest | undefined, boolean] {
13
- const [serverGroupManager, setServerGroupManager] = useState<IKubernetesServerGroupManager | undefined>();
14
- const [manifest, setManifest] = useState<IManifest | undefined>();
15
- const [loading, setLoading] = useState(true);
19
+ const [state, setState] = useState<IServerGroupManagerDetailsState>({ loading: true });
20
+ const { serverGroupManager: params, app } = props;
21
+ const { accountId, region, name } = params;
22
+ const loadedRequestedManager =
23
+ state.serverGroupManager?.name === name &&
24
+ state.serverGroupManager?.region === region &&
25
+ state.serverGroupManager?.account === accountId;
16
26
 
17
27
  useEffect(() => {
18
- if (serverGroupManager) {
19
- return;
28
+ if (loadedRequestedManager) {
29
+ return undefined;
20
30
  }
21
31
 
22
- const { serverGroupManager: params, app } = props;
23
- const { accountId, region, name } = params;
32
+ let cancelled = false;
33
+ const dataSource = app.getDataSource('serverGroupManagers');
34
+
35
+ setState((current) =>
36
+ current.loading && !current.serverGroupManager && !current.manifest ? current : { loading: true },
37
+ );
24
38
 
25
- setLoading(true);
39
+ dataSource.ready().then(() => {
40
+ if (cancelled) {
41
+ return;
42
+ }
26
43
 
27
- const serverGroupManagerDetails = app
28
- .getDataSource('serverGroupManagers')
29
- .data.find(
44
+ const serverGroupManagerDetails = dataSource.data.find(
30
45
  (manager: IServerGroupManager) =>
31
46
  manager.name === name && manager.region === region && manager.account === accountId,
32
47
  );
33
48
 
34
- if (!serverGroupManagerDetails) {
35
- autoClose();
36
- return;
37
- }
49
+ if (!serverGroupManagerDetails) {
50
+ autoClose();
51
+ return;
52
+ }
53
+
54
+ ManifestReader.getManifest(accountId, region, name)
55
+ .then((manifest: IManifest) => {
56
+ if (!cancelled) {
57
+ setState({ manifest, serverGroupManager: serverGroupManagerDetails, loading: false });
58
+ }
59
+ })
60
+ .catch((error) => {
61
+ if (!cancelled) {
62
+ console.error('Error fetching manifest:', error);
63
+ autoClose();
64
+ }
65
+ });
66
+ });
67
+
68
+ return () => {
69
+ cancelled = true;
70
+ };
71
+ }, [accountId, app, autoClose, loadedRequestedManager, name, region]);
38
72
 
39
- ManifestReader.getManifest(accountId, region, name)
40
- .then((manifest: IManifest) => {
41
- setManifest(manifest);
42
- setServerGroupManager(serverGroupManagerDetails);
43
- })
44
- .catch((error) => {
45
- console.error('Error fetching manifest:', error);
46
- })
47
- .finally(() => {
48
- setLoading(false);
49
- });
50
- }, [autoClose, props, serverGroupManager]);
51
-
52
- return [serverGroupManager, manifest, loading];
73
+ return [state.serverGroupManager, state.manifest, state.loading];
53
74
  }
@@ -1 +0,0 @@
1
- export declare const KUBERNETES_INSTANCE_DETAILS_CTRL = "spinnaker.kubernetes.instanceDetails.controller";