@spinnaker/core 0.14.0 → 0.15.1

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 (218) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/config/settings.d.ts +1 -1
  3. package/dist/core.module.d.ts +1 -1
  4. package/dist/index.js +89 -47
  5. package/dist/index.js.map +1 -1
  6. package/dist/instance/instanceType.service.d.ts +3 -2
  7. package/dist/managed/artifactActions/ArtifactActions.d.ts +24 -0
  8. package/dist/managed/constraints/registry.d.ts +13 -2
  9. package/dist/managed/environmentBaseElements/EnvironmentItem.d.ts +3 -2
  10. package/dist/managed/graphql/graphql-sdk.d.ts +123 -11
  11. package/dist/managed/overview/Resource.d.ts +5 -2
  12. package/dist/managed/overview/artifact/Artifact.d.ts +2 -1
  13. package/dist/managed/overview/artifact/ArtifactActionModal.d.ts +20 -9
  14. package/dist/managed/overview/artifact/ArtifactCollapsibleSection.d.ts +7 -0
  15. package/dist/managed/overview/artifact/ArtifactVersions.d.ts +9 -0
  16. package/dist/managed/overview/artifact/CurrentVersion.d.ts +7 -6
  17. package/dist/managed/overview/artifact/VersionTitle.d.ts +9 -0
  18. package/dist/managed/overview/artifact/hooks.d.ts +6 -11
  19. package/dist/managed/overview/artifact/useCreateRollbackActions.hook.d.ts +3 -0
  20. package/dist/managed/overview/artifact/utils.d.ts +15 -14
  21. package/dist/managed/overview/useIsUpdatingResources.hook.d.ts +1 -0
  22. package/dist/managed/resources/ResourceTitle.d.ts +3 -3
  23. package/dist/managed/resources/resourceRegistry.d.ts +1 -1
  24. package/dist/managed/utils/ActionModal.d.ts +1 -0
  25. package/dist/managed/utils/defaults.d.ts +1 -0
  26. package/dist/managed/versionMetadata/MetadataComponents.d.ts +18 -19
  27. package/dist/managed/versionMetadata/VersionMetadata.d.ts +6 -2
  28. package/dist/search/infrastructure/infrastructureSearch.service.d.ts +2 -1
  29. package/dist/securityGroup/index.d.ts +2 -1
  30. package/package.json +7 -7
  31. package/src/account/AccountSelectInput.spec.tsx +9 -4
  32. package/src/account/AccountService.spec.ts +6 -6
  33. package/src/api/ApiService.spec.ts +2 -2
  34. package/src/api/ApiServiceDeprecated.spec.ts +5 -2
  35. package/src/application/application.model.spec.ts +78 -79
  36. package/src/application/config/applicationAttributes.directive.html +6 -2
  37. package/src/application/config/applicationAttributes.directive.js +4 -0
  38. package/src/application/config/applicationConfig.view.html +14 -1
  39. package/src/application/config/customBanner/CustomBannerConfig.spec.tsx +3 -3
  40. package/src/application/config/dataSources/applicationDataSourceEditor.component.spec.ts +4 -3
  41. package/src/application/config/footer/configSectionFooter.component.spec.ts +2 -1
  42. package/src/application/listExtractor/AppListExtractor.spec.ts +4 -4
  43. package/src/application/modal/PermissionsConfigurer.spec.tsx +3 -2
  44. package/src/application/modal/editApplication.controller.modal.js +1 -0
  45. package/src/application/modal/editApplication.html +2 -2
  46. package/src/application/modal/validation/ApplicationNameValidator.spec.ts +2 -1
  47. package/src/application/modal/validation/validateApplicationName.directive.spec.ts +3 -2
  48. package/src/application/nav/ApplicationNavigation.spec.tsx +12 -11
  49. package/src/application/nav/NavItem.spec.tsx +7 -5
  50. package/src/application/nav/NavSection.spec.tsx +3 -2
  51. package/src/application/service/ApplicationReader.spec.ts +13 -8
  52. package/src/application/service/ApplicationWriter.spec.ts +4 -2
  53. package/src/application/service/InferredApplicationWarningService.spec.ts +2 -3
  54. package/src/artifact/expectedArtifact.service.spec.ts +2 -1
  55. package/src/artifact/react/ExpectedArtifactSelector.spec.tsx +2 -3
  56. package/src/authentication/AuthenticationInitializer.spec.ts +2 -1
  57. package/src/authentication/AuthenticationService.spec.ts +2 -1
  58. package/src/authentication/authentication.interceptor.spec.ts +4 -2
  59. package/src/cache/cacheInitializer.service.spec.ts +7 -4
  60. package/src/cache/infrastructureCaches.spec.ts +4 -4
  61. package/src/chaosMonkey/chaosMonkeyExceptions.component.spec.ts +4 -2
  62. package/src/cloudProvider/providerSelection/ProviderSelectionService.spec.ts +23 -21
  63. package/src/cluster/ClusterRuleMatcher.spec.ts +2 -1
  64. package/src/cluster/cluster.service.spec.ts +7 -7
  65. package/src/cluster/filter/ClusterFilterService.spec.ts +15 -14
  66. package/src/cluster/filter/LabelFilter.spec.tsx +3 -3
  67. package/src/cluster/filter/MultiselectModel.spec.ts +2 -2
  68. package/src/cluster/filter/labelFilterUtils.spec.ts +3 -7
  69. package/src/config/settings.ts +1 -3
  70. package/src/core.module.ts +1 -1
  71. package/src/filterModel/dependentFilter/DependentFilterService.spec.ts +1 -1
  72. package/src/function/filter/FunctionFilterService.spec.ts +5 -3
  73. package/src/function/function.read.service.spec.ts +4 -3
  74. package/src/header/customBanner/CustomBanner.spec.tsx +3 -4
  75. package/src/healthCounts/HealthCounts.spec.tsx +2 -2
  76. package/src/history/recentHistory.service.spec.ts +2 -1
  77. package/src/insight/InsightMenu.spec.tsx +9 -6
  78. package/src/instance/instance.write.service.spec.ts +8 -7
  79. package/src/instance/instanceType.service.ts +12 -2
  80. package/src/instance/instanceTypeService.spec.ts +2 -1
  81. package/src/loadBalancer/LoadBalancersTag.spec.tsx +8 -6
  82. package/src/loadBalancer/filter/LoadBalancerFilterService.spec.ts +2 -2
  83. package/src/managed/Environments.less +4 -4
  84. package/src/managed/Environments.tsx +1 -1
  85. package/src/managed/RelativeTimestamp.tsx +8 -6
  86. package/src/managed/artifactActions/ArtifactActions.tsx +77 -0
  87. package/src/managed/constraints/AllowedTimes.spec.ts +2 -1
  88. package/src/managed/constraints/registry.tsx +27 -1
  89. package/src/managed/environmentBaseElements/BaseEnvironment.less +3 -3
  90. package/src/managed/environmentBaseElements/EnvironmentItem.tsx +11 -4
  91. package/src/managed/graphql/graphql-sdk.ts +218 -29
  92. package/src/managed/graphql/schema.graphql +14 -1
  93. package/src/managed/overview/EnvironmentOverview.tsx +12 -15
  94. package/src/managed/overview/EnvironmentsOverview.less +6 -5
  95. package/src/managed/overview/PreviewEnvironments.tsx +0 -3
  96. package/src/managed/overview/Resource.less +1 -1
  97. package/src/managed/overview/Resource.tsx +62 -47
  98. package/src/managed/overview/artifact/Artifact.less +27 -52
  99. package/src/managed/overview/artifact/Artifact.tsx +86 -22
  100. package/src/managed/overview/artifact/ArtifactActionModal.less +19 -0
  101. package/src/managed/overview/artifact/ArtifactActionModal.tsx +150 -68
  102. package/src/managed/overview/artifact/ArtifactCollapsibleSection.tsx +32 -0
  103. package/src/managed/overview/artifact/ArtifactVersionTasks.tsx +2 -0
  104. package/src/managed/overview/artifact/{PendingVersion.tsx → ArtifactVersions.tsx} +35 -25
  105. package/src/managed/overview/artifact/Constraints.tsx +61 -21
  106. package/src/managed/overview/artifact/CurrentVersion.tsx +42 -27
  107. package/src/managed/overview/artifact/VersionTitle.tsx +18 -0
  108. package/src/managed/overview/artifact/hooks.ts +71 -34
  109. package/src/managed/overview/artifact/useCreateRollbackActions.hook.ts +75 -0
  110. package/src/managed/overview/artifact/utils.spec.ts +1 -1
  111. package/src/managed/overview/artifact/utils.ts +47 -80
  112. package/src/managed/overview/baseStyles.less +124 -88
  113. package/src/managed/overview/queries.graphql +54 -13
  114. package/src/managed/overview/useIsUpdatingResources.hook.ts +9 -0
  115. package/src/managed/resources/ResourceTitle.tsx +12 -5
  116. package/src/managed/utils/ActionModal.tsx +4 -1
  117. package/src/managed/utils/defaults.ts +3 -0
  118. package/src/managed/utils/useNotifyOnError.hook.ts +1 -1
  119. package/src/managed/versionMetadata/MetadataComponents.tsx +102 -70
  120. package/src/managed/versionMetadata/VersionMetadata.less +17 -18
  121. package/src/managed/versionMetadata/VersionMetadata.tsx +23 -31
  122. package/src/managed/versionsHistory/VersionContent.tsx +20 -13
  123. package/src/managed/versionsHistory/VersionHeading.tsx +2 -1
  124. package/src/managed/versionsHistory/VersionsHistory.less +11 -3
  125. package/src/manifest/PodNameProvider.spec.ts +1 -1
  126. package/src/navigation/customParamTypes.spec.ts +1 -1
  127. package/src/pagerDuty/pagerDuty.read.service.spec.ts +4 -2
  128. package/src/pagerDuty/pagerDutyTag.component.spec.ts +7 -3
  129. package/src/pipeline/config/PipelineRegistry.spec.ts +38 -37
  130. package/src/pipeline/config/actions/templateJson/ShowPipelineTemplateJsonModal.spec.tsx +3 -3
  131. package/src/pipeline/config/pipelineConfigurer.controller.spec.ts +3 -3
  132. package/src/pipeline/config/services/PipelineConfigService.spec.ts +4 -3
  133. package/src/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.spec.tsx +51 -8
  134. package/src/pipeline/config/stages/bakeManifest/helm/BakeHelmConfigForm.tsx +36 -6
  135. package/src/pipeline/config/stages/findArtifactFromExecution/findArtifactFromExecution.controller.spec.ts +2 -1
  136. package/src/pipeline/config/stages/manualJudgment/manualJudgment.service.spec.ts +6 -4
  137. package/src/pipeline/config/stages/travis/travisExecutionDetails.controller.spec.ts +5 -2
  138. package/src/pipeline/config/stages/travis/travisStage.controller.spec.ts +3 -2
  139. package/src/pipeline/config/stages/unmatchedStageTypeStage/unmatchedStageTypeStage.controller.spec.ts +2 -1
  140. package/src/pipeline/config/stages/wait/SkipWait.tsx +3 -1
  141. package/src/pipeline/config/stages/wercker/werckerExecutionDetails.controller.spec.ts +5 -2
  142. package/src/pipeline/config/stages/wercker/werckerStage.controller.spec.ts +3 -2
  143. package/src/pipeline/config/templates/Variable.spec.tsx +6 -5
  144. package/src/pipeline/config/templates/configurePipelineTemplateModal.controller.spec.ts +7 -8
  145. package/src/pipeline/config/templates/v2/configurePipelineTemplateModalV2.controller.spec.ts +7 -8
  146. package/src/pipeline/config/templates/v2/pipelineTemplateV2.service.spec.ts +1 -1
  147. package/src/pipeline/config/triggers/TriggersPageContent.spec.tsx +4 -4
  148. package/src/pipeline/config/triggers/TriggersPageContent.tsx +1 -2
  149. package/src/pipeline/config/triggers/artifacts/docker/defaultDocker.artifact.spec.ts +1 -2
  150. package/src/pipeline/config/validation/pipelineConfig.validator.spec.ts +14 -15
  151. package/src/pipeline/create/CreatePipelineModal.spec.tsx +9 -7
  152. package/src/pipeline/details/executionDetailsSection.service.spec.ts +3 -2
  153. package/src/pipeline/executions/Executions.spec.tsx +9 -6
  154. package/src/pipeline/executions/executionAction/ExecutionAction.spec.tsx +1 -1
  155. package/src/pipeline/executions/executionGroup/ExecutionGroup.tsx +2 -1
  156. package/src/pipeline/filter/executionFilter.service.spec.ts +1 -1
  157. package/src/pipeline/pipeline.dataSource.spec.ts +8 -7
  158. package/src/pipeline/service/ExecutionsTransformer.spec.ts +2 -2
  159. package/src/pipeline/service/execution.service.spec.ts +7 -5
  160. package/src/pipeline/status/Artifact.spec.tsx +7 -6
  161. package/src/pipeline/status/ArtifactList.spec.tsx +7 -6
  162. package/src/pipeline/status/ExecutionParameters.spec.tsx +5 -4
  163. package/src/pipeline/status/ResolvedArtifactList.spec.tsx +7 -6
  164. package/src/plugins/deck.plugin.spec.ts +4 -2
  165. package/src/plugins/plugin.registry.spec.ts +6 -4
  166. package/src/presentation/forms/SpinFormik.spec.tsx +3 -2
  167. package/src/presentation/forms/fields/FormikFormField.spec.tsx +3 -3
  168. package/src/presentation/forms/hooks/useSaveRestoreMutuallyExclusiveFields.hook.spec.tsx +4 -3
  169. package/src/presentation/forms/inputs/ChecklistInput.spec.tsx +1 -1
  170. package/src/presentation/forms/inputs/RadioButtonInput.spec.tsx +2 -1
  171. package/src/presentation/forms/inputs/SelectInput.spec.tsx +2 -1
  172. package/src/presentation/forms/inputs/hooks/useInternalValidator.hook.spec.tsx +4 -3
  173. package/src/presentation/forms/validation/FormValidator.spec.ts +2 -2
  174. package/src/presentation/forms/validation/useValidationData.spec.tsx +4 -3
  175. package/src/presentation/hooks/useContainerClassNames.hook.spec.tsx +2 -1
  176. package/src/presentation/hooks/useData.hook.spec.tsx +3 -2
  177. package/src/presentation/hooks/useDebouncedValue.hook.spec.tsx +1 -1
  178. package/src/presentation/hooks/useDeepObjectDiff.hook.spec.tsx +2 -1
  179. package/src/presentation/hooks/useEventListener.hook.spec.tsx +2 -1
  180. package/src/presentation/hooks/useForceUpdate.hook.spec.tsx +2 -1
  181. package/src/presentation/hooks/useInterval.hook.spec.tsx +2 -1
  182. package/src/presentation/hooks/useIsMountedRef.hook.spec.tsx +1 -1
  183. package/src/presentation/hooks/useLatestCallback.hook.spec.tsx +2 -1
  184. package/src/presentation/hooks/useLatestPromise.hook.spec.tsx +9 -3
  185. package/src/presentation/hooks/useMountStatusRef.hook.spec.tsx +3 -1
  186. package/src/presentation/hooks/usePollingData.hook.spec.tsx +3 -2
  187. package/src/presentation/hooks/usePrevious.hook.spec.tsx +2 -1
  188. package/src/presentation/navigation/pageNavigator.component.spec.ts +6 -6
  189. package/src/presentation/spel/SpelInput.spec.tsx +9 -4
  190. package/src/presentation/spel/SpelService.spec.ts +1 -1
  191. package/src/scheduler/SchedulerFactory.spec.ts +2 -1
  192. package/src/search/infrastructure/infrastructureSearch.service.ts +3 -2
  193. package/src/search/widgets/Filter.spec.tsx +5 -3
  194. package/src/search/widgets/Filters.spec.tsx +5 -3
  195. package/src/search/widgets/Search.spec.tsx +4 -2
  196. package/src/securityGroup/index.ts +2 -1
  197. package/src/securityGroup/securityGroupReader.service.spec.ts +8 -10
  198. package/src/serverGroup/configure/common/deployInitializer.component.spec.ts +7 -3
  199. package/src/serverGroup/configure/common/v2instanceArchetypeSelector.component.ts +1 -1
  200. package/src/serverGroup/details/capacity/CapacityDetailsSection.spec.tsx +1 -1
  201. package/src/serverGroup/details/scalingActivities/ScalingActivitiesModal.spec.ts +2 -1
  202. package/src/serverGroup/details/serverGroupWarningMessage.service.spec.ts +4 -4
  203. package/src/serverGroup/serverGroupWriter.service.spec.ts +10 -8
  204. package/src/slack/SlackReader.spec.ts +2 -1
  205. package/src/subnet/subnet.read.service.spec.ts +4 -3
  206. package/src/task/monitor/taskMonitor.spec.ts +6 -5
  207. package/src/task/task.dataSource.spec.ts +5 -4
  208. package/src/task/task.write.service.spec.ts +3 -1
  209. package/src/utils/clipboard/CopyToClipboard.spec.tsx +2 -1
  210. package/src/utils/json/json.utility.service.spec.ts +2 -1
  211. package/src/utils/timeFormatters.spec.ts +3 -2
  212. package/src/utils/workerPool.spec.ts +2 -1
  213. package/src/widgets/ApplicationsPickerInput.spec.tsx +3 -2
  214. package/src/widgets/spelText/SpelAutocompleteService.spec.ts +4 -3
  215. package/src/widgets/tags/Tag.spec.tsx +4 -2
  216. package/src/widgets/tags/TagList.spec.tsx +5 -3
  217. package/src/yamlEditor/yamlEditorUtils.spec.ts +1 -1
  218. package/dist/managed/overview/artifact/PendingVersion.d.ts +0 -7
@@ -1,37 +1,42 @@
1
1
  import { isEmpty } from 'lodash';
2
2
  import React from 'react';
3
3
 
4
+ import { ArtifactCollapsibleSection } from './ArtifactCollapsibleSection';
4
5
  import { Constraints } from './Constraints';
5
- import { GitLink } from './GitLink';
6
+ import { VersionTitle } from './VersionTitle';
7
+ import { ArtifactActions } from '../../artifactActions/ArtifactActions';
6
8
  import type { QueryArtifact, QueryArtifactVersion } from '../types';
7
- import { useCreateVersionActions } from './utils';
9
+ import { useCreateVersionRollbackActions } from './useCreateRollbackActions.hook';
10
+ import { extractVersionRollbackDetails, isVersionVetoed } from './utils';
8
11
  import { useLogEvent } from '../../utils/logging';
9
12
  import type { VersionMessageData } from '../../versionMetadata/MetadataComponents';
10
13
  import { toPinnedMetadata } from '../../versionMetadata/MetadataComponents';
11
- import { getBaseMetadata, VersionMetadata } from '../../versionMetadata/VersionMetadata';
14
+ import { getBaseMetadata, getVersionCompareLinks, VersionMetadata } from '../../versionMetadata/VersionMetadata';
12
15
 
13
16
  export interface IPendingVersionsProps {
14
17
  artifact: QueryArtifact;
15
- pendingVersions?: QueryArtifactVersion[];
18
+ title: string;
19
+ versions?: QueryArtifactVersion[];
20
+ isDeploying?: boolean;
16
21
  }
17
22
 
18
- const NUM_VERSIONS_WHEN_COLLAPSED = 2;
23
+ const NUM_VERSIONS_WHEN_COLLAPSED = 1;
19
24
 
20
- export const PendingVersions = ({ artifact, pendingVersions }: IPendingVersionsProps) => {
21
- const numVersions = pendingVersions?.length || 0;
25
+ export const ArtifactVersions = ({ artifact, versions, title, isDeploying }: IPendingVersionsProps) => {
26
+ const numVersions = versions?.length || 0;
22
27
  const [isExpanded, setIsExpanded] = React.useState(false);
23
28
  const logEvent = useLogEvent('ArtifactPendingVersion');
24
29
 
25
- if (!pendingVersions || !numVersions) return null;
30
+ if (!versions || !numVersions) return null;
26
31
 
27
- const versionsToShow = isExpanded ? pendingVersions : pendingVersions.slice(0, NUM_VERSIONS_WHEN_COLLAPSED);
28
- const numDeploying = pendingVersions.filter((version) => version.status === 'DEPLOYING').length;
32
+ const versionsToShow = isExpanded ? versions : versions.slice(0, NUM_VERSIONS_WHEN_COLLAPSED);
29
33
  const { pinnedVersion } = artifact;
30
34
  return (
31
- <section className="artifact-pending-versions">
32
- <div className="artifact-versions-title">
33
- {numVersions} Pending Versions {numDeploying > 0 ? `(${numDeploying} deploying)` : ''}
34
- </div>
35
+ <ArtifactCollapsibleSection
36
+ outerDivClassName="artifact-versions artifact-section"
37
+ heading={title}
38
+ isUpdating={isDeploying}
39
+ >
35
40
  <div className="artifact-pending-versions-list">
36
41
  {versionsToShow.map((version, index) => (
37
42
  <PendingVersion
@@ -58,7 +63,7 @@ export const PendingVersions = ({ artifact, pendingVersions }: IPendingVersionsP
58
63
  </div>
59
64
  ) : undefined}
60
65
  </div>
61
- </section>
66
+ </ArtifactCollapsibleSection>
62
67
  );
63
68
  };
64
69
 
@@ -71,26 +76,31 @@ interface IPendingVersionProps {
71
76
  }
72
77
 
73
78
  const PendingVersion = ({ data, reference, environment, pinned, index }: IPendingVersionProps) => {
74
- const { buildNumber, version, gitMetadata, constraints, status } = data;
75
- const actions = useCreateVersionActions({
79
+ const { version, gitMetadata, constraints, isCurrent } = data;
80
+ const actions = useCreateVersionRollbackActions({
76
81
  environment,
77
82
  reference,
78
- buildNumber,
79
83
  version,
80
- status,
81
- commitMessage: gitMetadata?.commitInfo?.message,
84
+ isVetoed: isVersionVetoed(data),
82
85
  isPinned: Boolean(pinned),
83
- compareLinks: {
84
- current: gitMetadata?.comparisonLinks?.toCurrentVersion,
85
- },
86
+ isCurrent,
87
+
88
+ selectedVersion: extractVersionRollbackDetails(data),
86
89
  });
87
90
 
88
91
  return (
89
92
  <div className="artifact-pending-version">
90
93
  <div className="artifact-pending-version-commit">
91
- {gitMetadata ? <GitLink gitMetadata={gitMetadata} /> : `Build ${buildNumber}`}
94
+ <VersionTitle gitMetadata={gitMetadata} buildNumber={data?.buildNumber} version={data.version} />
92
95
  </div>
93
- <VersionMetadata {...getBaseMetadata(data)} pinned={pinned} createdAt={data.createdAt} actions={actions} />
96
+ <VersionMetadata {...getBaseMetadata(data)} pinned={pinned} />
97
+ <ArtifactActions
98
+ buildNumber={data?.buildNumber}
99
+ version={data.version}
100
+ actions={actions}
101
+ compareLinks={getVersionCompareLinks(data)}
102
+ className="sp-margin-s-yaxis"
103
+ />
94
104
  {constraints && !isEmpty(constraints) && (
95
105
  <Constraints
96
106
  key={index} // This is needed on refresh if a new version was added
@@ -5,7 +5,12 @@ import React from 'react';
5
5
  import { RelativeTimestamp } from '../../RelativeTimestamp';
6
6
  import { VersionOperationIcon } from './VersionOperation';
7
7
  import { constraintsManager } from '../../constraints/registry';
8
- import { FetchVersionDocument, useUpdateConstraintMutation } from '../../graphql/graphql-sdk';
8
+ import type { FetchVersionQueryVariables } from '../../graphql/graphql-sdk';
9
+ import {
10
+ FetchVersionDocument,
11
+ useRestartConstraintEvaluationMutation,
12
+ useUpdateConstraintMutation,
13
+ } from '../../graphql/graphql-sdk';
9
14
  import { CollapsibleSection, useApplicationContextSafe } from '../../../presentation';
10
15
  import type { ArtifactVersionProps, QueryConstraint } from '../types';
11
16
  import { getConstraintsStatusSummary } from './utils';
@@ -26,44 +31,77 @@ const ConstraintContent = ({ constraint, versionProps }: IConstraintContentProps
26
31
  const application = useApplicationContextSafe();
27
32
  const logEvent = useLogEvent('ArtifactConstraints', 'UpdateStatus');
28
33
 
29
- const [updateConstraint, { loading, error }] = useUpdateConstraintMutation({
30
- refetchQueries: [
31
- { query: FetchVersionDocument, variables: { appName: application?.name, versions: [versionProps.version] } },
32
- ],
34
+ const refetchVariables: FetchVersionQueryVariables = { appName: application.name, versions: [versionProps.version] };
35
+ const refetchQueries = [{ query: FetchVersionDocument, variables: refetchVariables }];
36
+
37
+ const showRestartButton = constraintsManager.isRestartVisible(constraint);
38
+
39
+ const baseRequestProps = {
40
+ application: application.name,
41
+ environment: versionProps.environment,
42
+ version: versionProps.version,
43
+ reference: versionProps.reference,
44
+ type: constraint.type,
45
+ };
46
+
47
+ const [
48
+ updateConstraint,
49
+ { loading: isUpdatingConstraint, error: updateConstraintError },
50
+ ] = useUpdateConstraintMutation({ refetchQueries });
51
+
52
+ const [
53
+ restartConstraint,
54
+ { loading: isRestartingConstraint, error: restartConstraintError },
55
+ ] = useRestartConstraintEvaluationMutation({
56
+ variables: { payload: baseRequestProps },
57
+ refetchQueries,
33
58
  });
34
59
 
35
- useNotifyOnError({ key: 'updateConstraintError', content: `Failed to update constraint`, error });
60
+ useNotifyOnError({
61
+ key: 'updateConstraintError',
62
+ content: `Failed to update constraint`,
63
+ error: updateConstraintError,
64
+ });
65
+
66
+ useNotifyOnError({
67
+ key: 'restartConstraintError',
68
+ content: `Failed to restart constraint`,
69
+ error: restartConstraintError,
70
+ });
36
71
 
37
72
  return (
38
73
  <dl className="constraint-content">
39
74
  {description && <dd>{description}</dd>}
40
- {!isEmpty(actions) && (
75
+ {(!isEmpty(actions) || showRestartButton) && (
41
76
  <dd className={classnames(description ? 'sp-margin-s-top' : undefined, 'horizontal middle')}>
42
77
  {actions?.map(({ title, pass }) => (
43
78
  <button
44
79
  className={classnames('btn md-btn constraint-action-button', pass ? 'md-btn-success' : 'md-btn-danger')}
45
80
  key={title}
46
- disabled={loading}
81
+ disabled={isUpdatingConstraint}
47
82
  onClick={() => {
48
83
  logEvent({ data: { newStatus: pass } });
49
84
  updateConstraint({
50
- variables: {
51
- payload: {
52
- application: application.name,
53
- environment: versionProps.environment,
54
- version: versionProps.version,
55
- type: constraint.type,
56
- reference: versionProps.reference,
57
- status: pass ? 'FORCE_PASS' : 'FAIL',
58
- },
59
- },
85
+ variables: { payload: { ...baseRequestProps, status: pass ? 'FORCE_PASS' : 'FAIL' } },
60
86
  });
61
87
  }}
62
88
  >
63
89
  {title}
64
90
  </button>
65
91
  ))}
66
- {loading && <Spinner mode="circular" size="nano" color="var(--color-accent)" />}
92
+ {showRestartButton && (
93
+ <button
94
+ className="btn md-btn constraint-action-button md-btn-accent"
95
+ disabled={isUpdatingConstraint}
96
+ onClick={() => {
97
+ restartConstraint();
98
+ }}
99
+ >
100
+ {constraintsManager.getRestartDisplayName(constraint)}
101
+ </button>
102
+ )}
103
+ {isUpdatingConstraint ||
104
+ (isRestartingConstraint && <Spinner mode="circular" size="nano" color="var(--color-accent)" />)}
67
105
  </dd>
68
106
  )}
69
107
  </dl>
@@ -102,7 +140,9 @@ const Constraint = ({ constraint, versionProps }: IConstraintProps) => {
102
140
  </div>
103
141
  )}
104
142
  >
105
- {hasContent ? <ConstraintContent constraint={constraint} versionProps={versionProps} /> : undefined}
143
+ {hasContent || constraintsManager.isRestartVisible(constraint) ? (
144
+ <ConstraintContent constraint={constraint} versionProps={versionProps} />
145
+ ) : undefined}
106
146
  </CollapsibleSection>
107
147
  </div>
108
148
  );
@@ -126,7 +166,7 @@ export const Constraints = ({
126
166
  <CollapsibleSection
127
167
  heading={({ chevron }) => (
128
168
  <div className="horizontal">
129
- Constraints: {summary.text} {chevron}
169
+ <span className="uppercase">Constraints</span>: {summary.text} {chevron}
130
170
  </div>
131
171
  )}
132
172
  outerDivClassName=""
@@ -3,52 +3,63 @@ import React from 'react';
3
3
  import type { ITaskArtifactVersionProps } from './ArtifactVersionTasks';
4
4
  import { ArtifactVersionTasks } from './ArtifactVersionTasks';
5
5
  import { Constraints } from './Constraints';
6
- import { GitLink } from './GitLink';
7
- import type { QueryArtifactVersion } from '../types';
8
- import { useCreateVersionActions } from './utils';
9
- import type { VersionMessageData } from '../../versionMetadata/MetadataComponents';
10
- import { getBaseMetadata, VersionMetadata } from '../../versionMetadata/VersionMetadata';
6
+ import { VersionTitle } from './VersionTitle';
7
+ import { ArtifactActions } from '../../artifactActions/ArtifactActions';
8
+ import type { QueryArtifact, QueryArtifactVersion } from '../types';
9
+ import { useCreateVersionRollbackActions } from './useCreateRollbackActions.hook';
10
+ import { extractVersionRollbackDetails, isVersionVetoed } from './utils';
11
+ import { toPinnedMetadata } from '../../versionMetadata/MetadataComponents';
12
+ import { getBaseMetadata, getVersionCompareLinks, VersionMetadata } from '../../versionMetadata/VersionMetadata';
11
13
 
12
- interface ICurrentVersionProps {
13
- data: QueryArtifactVersion;
14
+ interface ICurrentVersionProps<T = QueryArtifactVersion> {
15
+ data: T;
14
16
  environment: string;
15
17
  reference: string;
16
18
  numNewerVersions?: number;
17
- pinned?: VersionMessageData;
19
+ pinnedVersion: QueryArtifact['pinnedVersion'];
20
+ isPreview?: boolean;
18
21
  }
19
22
 
20
- export const CurrentVersion = ({ data, environment, reference, numNewerVersions, pinned }: ICurrentVersionProps) => {
21
- const { gitMetadata, constraints, verifications, postDeploy } = data;
22
- const actions = useCreateVersionActions({
23
+ export const CurrentVersionInternal = ({
24
+ data,
25
+ environment,
26
+ reference,
27
+ numNewerVersions,
28
+ pinnedVersion,
29
+ isPreview,
30
+ }: ICurrentVersionProps) => {
31
+ const { gitMetadata, constraints, verifications, postDeploy, isCurrent } = data;
32
+ const pinnedMetadata = pinnedVersion?.version === data.version ? toPinnedMetadata(pinnedVersion) : undefined;
33
+ const actions = useCreateVersionRollbackActions({
23
34
  environment,
24
35
  reference,
25
36
  version: data.version,
26
- buildNumber: data.buildNumber,
27
- status: data.status,
28
- commitMessage: gitMetadata?.commitInfo?.message,
29
- isPinned: Boolean(pinned),
30
- compareLinks: {
31
- previous: gitMetadata?.comparisonLinks?.toPreviousVersion,
32
- },
37
+ isVetoed: isVersionVetoed(data),
38
+ isPinned: Boolean(pinnedVersion),
39
+ isCurrent,
40
+ selectedVersion: extractVersionRollbackDetails(data),
33
41
  });
34
42
 
35
43
  const versionProps: ITaskArtifactVersionProps = {
36
44
  environment,
37
45
  reference,
38
46
  version: data.version,
39
- isCurrent: data.isCurrent,
47
+ isCurrent,
40
48
  };
41
49
 
42
50
  return (
43
51
  <div className="artifact-current-version">
44
- {gitMetadata ? <GitLink gitMetadata={gitMetadata} /> : <div>Build {data?.version}</div>}
45
- <VersionMetadata
46
- {...getBaseMetadata(data)}
47
- createdAt={data.createdAt}
48
- buildsBehind={numNewerVersions}
49
- actions={actions}
50
- pinned={pinned}
51
- />
52
+ <VersionTitle gitMetadata={gitMetadata} buildNumber={data?.buildNumber} version={data.version} />
53
+ <VersionMetadata {...getBaseMetadata(data)} buildsBehind={numNewerVersions} pinned={pinnedMetadata} />
54
+ {!isPreview && (
55
+ <ArtifactActions
56
+ buildNumber={data?.buildNumber}
57
+ version={data.version}
58
+ actions={actions}
59
+ compareLinks={getVersionCompareLinks(data)}
60
+ className="sp-margin-s-yaxis"
61
+ />
62
+ )}
52
63
  {constraints && (
53
64
  <Constraints constraints={constraints} versionProps={{ environment, reference, version: data.version }} />
54
65
  )}
@@ -57,3 +68,7 @@ export const CurrentVersion = ({ data, environment, reference, numNewerVersions,
57
68
  </div>
58
69
  );
59
70
  };
71
+
72
+ export const CurrentVersion = ({ data, ...otherProps }: ICurrentVersionProps<QueryArtifactVersion | undefined>) => {
73
+ return data ? <CurrentVersionInternal data={data} {...otherProps} /> : <div>No version is deployed</div>;
74
+ };
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+
3
+ import { GitLink } from './GitLink';
4
+ import type { QueryArtifactVersion } from '../types';
5
+
6
+ interface IVersionTitleProps {
7
+ gitMetadata?: QueryArtifactVersion['gitMetadata'];
8
+ version: string;
9
+ buildNumber?: string;
10
+ }
11
+
12
+ export const VersionTitle = ({ gitMetadata, buildNumber }: IVersionTitleProps) => {
13
+ return (
14
+ <div className="VersionTitle">
15
+ {gitMetadata ? <GitLink gitMetadata={gitMetadata} /> : <div>Build {buildNumber}</div>}
16
+ </div>
17
+ );
18
+ };
@@ -1,3 +1,4 @@
1
+ import type { IVersionActionsProps } from './ArtifactActionModal';
1
2
  import { MarkAsBadActionModal, MarkAsGoodActionModal, PinActionModal, UnpinActionModal } from './ArtifactActionModal';
2
3
  import {
3
4
  FetchPinnedVersionsDocument,
@@ -8,55 +9,77 @@ import {
8
9
  useUnpinVersionMutation,
9
10
  } from '../../graphql/graphql-sdk';
10
11
  import { showModal } from '../../../presentation';
12
+ import type { ICurrentVersion, IVersionRelativeAgeToCurrent } from './utils';
11
13
  import { MODAL_MAX_WIDTH } from '../../utils/defaults';
12
14
 
13
- interface ActionBasePayload {
14
- application: string;
15
- environment: string;
16
- reference: string;
17
- version: string;
18
- }
19
-
20
- export const useUnpinVersion = ({ version, ...payload }: ActionBasePayload, modalTitle: string) => {
15
+ export const useUnpinVersion = (payload: IVersionActionsProps) => {
16
+ const {
17
+ application,
18
+ environment,
19
+ reference,
20
+ selectedVersion: { buildNumber, commitMessage },
21
+ } = payload;
21
22
  const [onUnpin] = useUnpinVersionMutation({
22
- variables: { payload: payload },
23
- refetchQueries: [{ query: FetchPinnedVersionsDocument, variables: { appName: payload.application } }],
23
+ variables: { payload: { application, environment, reference } },
24
+ refetchQueries: [{ query: FetchPinnedVersionsDocument, variables: { appName: application } }],
24
25
  });
25
26
 
26
27
  return () => {
27
28
  showModal(
28
29
  UnpinActionModal,
29
30
  {
30
- application: payload.application,
31
- environment: payload.environment,
32
- title: modalTitle,
31
+ title: [`Unpin #${buildNumber}`, commitMessage].filter(Boolean).join(' - '),
33
32
  actionName: 'Unpin',
34
33
  onAction: async () => {
35
34
  await onUnpin();
36
35
  },
37
36
  withComment: false,
37
+ actionProps: payload,
38
38
  },
39
39
  { maxWidth: MODAL_MAX_WIDTH },
40
40
  );
41
41
  };
42
42
  };
43
43
 
44
- export const usePinVersion = (payload: ActionBasePayload, modalTitle: string) => {
44
+ const pinAction: { [key in IVersionRelativeAgeToCurrent]: string } = {
45
+ CURRENT: 'Pin',
46
+ NEWER: 'Roll forward',
47
+ OLDER: 'Roll back',
48
+ };
49
+
50
+ export const usePinVersion = (
51
+ payload: IVersionActionsProps,
52
+ currentVersion: ICurrentVersion | undefined,
53
+ ageRelativeToCurrent: IVersionRelativeAgeToCurrent,
54
+ ) => {
55
+ const {
56
+ application,
57
+ environment,
58
+ version,
59
+ reference,
60
+ selectedVersion: { buildNumber },
61
+ } = payload;
45
62
  const [onPin] = usePinVersionMutation({
46
63
  refetchQueries: [{ query: FetchPinnedVersionsDocument, variables: { appName: payload.application } }],
47
64
  });
48
65
 
66
+ const titleOptions: { [key in IVersionRelativeAgeToCurrent]: string } = {
67
+ CURRENT: `Pin #${buildNumber}`,
68
+ NEWER: `Roll forward to #${buildNumber} and pin to ${environment.toUpperCase()}`,
69
+ OLDER: `Roll back to #${buildNumber} and pin to ${environment.toUpperCase()}`,
70
+ };
71
+
49
72
  return () => {
50
73
  showModal(
51
74
  PinActionModal,
52
75
  {
53
- application: payload.application,
54
- title: modalTitle,
55
- actionName: 'Pin',
76
+ title: titleOptions[ageRelativeToCurrent],
77
+ actionName: pinAction[ageRelativeToCurrent],
56
78
  onAction: async (comment) => {
57
79
  if (!comment) throw new Error('Comment is required');
58
- await onPin({ variables: { payload: { ...payload, comment } } });
80
+ await onPin({ variables: { payload: { application, environment, reference, version, comment } } });
59
81
  },
82
+ actionProps: { ...payload, ageRelativeToCurrent, currentVersion },
60
83
  },
61
84
 
62
85
  { maxWidth: MODAL_MAX_WIDTH },
@@ -64,24 +87,33 @@ export const usePinVersion = (payload: ActionBasePayload, modalTitle: string) =>
64
87
  };
65
88
  };
66
89
 
67
- export const useMarkVersionAsBad = (payload: ActionBasePayload, modalTitle: string) => {
90
+ export const useMarkVersionAsBad = (payload: IVersionActionsProps) => {
91
+ const {
92
+ application,
93
+ environment,
94
+ reference,
95
+ version,
96
+ isCurrent,
97
+ selectedVersion: { buildNumber },
98
+ } = payload;
68
99
  const [onMarkAsBad] = useMarkVersionAsBadMutation({
69
- refetchQueries: [
70
- { query: FetchVersionDocument, variables: { appName: payload.application, versions: [payload.version] } },
71
- ],
100
+ refetchQueries: [{ query: FetchVersionDocument, variables: { appName: payload.application, versions: [version] } }],
72
101
  });
73
102
 
74
103
  return () => {
75
104
  showModal(
76
105
  MarkAsBadActionModal,
77
106
  {
78
- application: payload.application,
79
- title: modalTitle,
80
- actionName: 'Mark as Bad',
107
+ title:
108
+ (isCurrent ? `Roll back ${environment.toUpperCase()} to previous version and reject ` : 'Reject') +
109
+ ` #${buildNumber}`,
110
+ actionName: 'Rollback',
81
111
  onAction: async (comment) => {
82
112
  if (!comment) throw new Error('Comment is required');
83
- await onMarkAsBad({ variables: { payload: { ...payload, comment } } });
113
+ await onMarkAsBad({ variables: { payload: { application, environment, reference, version, comment } } });
84
114
  },
115
+ actionProps: payload,
116
+ isCurrent,
85
117
  },
86
118
 
87
119
  { maxWidth: MODAL_MAX_WIDTH },
@@ -89,24 +121,29 @@ export const useMarkVersionAsBad = (payload: ActionBasePayload, modalTitle: stri
89
121
  };
90
122
  };
91
123
 
92
- export const useMarkVersionAsGood = (payload: ActionBasePayload, modalTitle: string) => {
124
+ export const useMarkVersionAsGood = (payload: IVersionActionsProps) => {
125
+ const {
126
+ application,
127
+ environment,
128
+ reference,
129
+ version,
130
+ selectedVersion: { buildNumber, commitMessage },
131
+ } = payload;
93
132
  const [onMarkAsBad] = useMarkVersionAsGoodMutation({
94
- refetchQueries: [
95
- { query: FetchVersionDocument, variables: { appName: payload.application, versions: [payload.version] } },
96
- ],
133
+ refetchQueries: [{ query: FetchVersionDocument, variables: { appName: payload.application, versions: [version] } }],
97
134
  });
98
135
 
99
136
  return () => {
100
137
  showModal(
101
138
  MarkAsGoodActionModal,
102
139
  {
103
- application: payload.application,
104
- title: modalTitle,
105
- actionName: 'Mark as Good',
140
+ title: [`Allow deploying #${buildNumber}`, commitMessage].filter(Boolean).join(' - '),
141
+ actionName: 'Allow',
106
142
  onAction: async () => {
107
- await onMarkAsBad({ variables: { payload: { ...payload } } });
143
+ await onMarkAsBad({ variables: { payload: { application, environment, reference, version } } });
108
144
  },
109
145
  withComment: false,
146
+ actionProps: payload,
110
147
  },
111
148
 
112
149
  { maxWidth: MODAL_MAX_WIDTH },
@@ -0,0 +1,75 @@
1
+ import type { IVersionActionsProps } from './ArtifactActionModal';
2
+ import type { VersionAction } from '../../artifactActions/ArtifactActions';
3
+ import { useFetchCurrentVersionQuery } from '../../graphql/graphql-sdk';
4
+ import { useMarkVersionAsBad, useMarkVersionAsGood, usePinVersion, useUnpinVersion } from './hooks';
5
+ import { useApplicationContextSafe } from '../../../presentation';
6
+ import type { IVersionRelativeAgeToCurrent } from './utils';
7
+ import { getRelativeAgeToCurrent } from './utils';
8
+
9
+ const useGetCurrentVersion = (environment: string, reference: string) => {
10
+ const application = useApplicationContextSafe();
11
+ const { data: currentVersionData } = useFetchCurrentVersionQuery({ variables: { appName: application.name } });
12
+ const currentVersion = currentVersionData?.application?.environments
13
+ .find((e) => e.name === environment)
14
+ ?.state.artifacts?.find((artifact) => artifact.reference === reference)?.versions?.[0];
15
+ return currentVersion;
16
+ };
17
+
18
+ const rollbackText: { [key in IVersionRelativeAgeToCurrent]: string } = {
19
+ CURRENT: 'Pin version...',
20
+ NEWER: 'Roll forward to...',
21
+ OLDER: 'Roll back to...',
22
+ };
23
+
24
+ export const useCreateVersionRollbackActions = (
25
+ props: Omit<IVersionActionsProps, 'application'>,
26
+ ): VersionAction[] | undefined => {
27
+ const application = useApplicationContextSafe();
28
+
29
+ const { environment, reference, isPinned, isVetoed, isCurrent, selectedVersion } = props;
30
+
31
+ const currentVersion = useGetCurrentVersion(environment, reference);
32
+ const relativeAgeToCurrent = getRelativeAgeToCurrent({
33
+ isCurrent,
34
+ createdAt: selectedVersion.createdAt,
35
+ currentVersion,
36
+ });
37
+
38
+ const basePayload: IVersionActionsProps = { application: application.name, ...props };
39
+
40
+ const onUnpin = useUnpinVersion(basePayload);
41
+
42
+ const onPin = usePinVersion(basePayload, currentVersion, relativeAgeToCurrent);
43
+
44
+ const onMarkAsBad = useMarkVersionAsBad(basePayload);
45
+
46
+ const onMarkAsGood = useMarkVersionAsGood(basePayload);
47
+
48
+ const actions: VersionAction[] = [
49
+ isPinned
50
+ ? {
51
+ content: 'Unpin version...',
52
+ onClick: onUnpin,
53
+ }
54
+ : {
55
+ content: rollbackText[relativeAgeToCurrent],
56
+ onClick: onPin,
57
+ },
58
+ ];
59
+
60
+ if (isVetoed) {
61
+ actions.push({
62
+ content: 'Allow deploying...',
63
+ onClick: onMarkAsGood,
64
+ });
65
+ } else {
66
+ if (!isCurrent) {
67
+ actions.push({
68
+ content: isCurrent ? 'Rollback...' : 'Reject...',
69
+ onClick: onMarkAsBad,
70
+ });
71
+ }
72
+ }
73
+
74
+ return actions;
75
+ };
@@ -1,4 +1,4 @@
1
- import { QueryConstraint } from '../types';
1
+ import type { QueryConstraint } from '../types';
2
2
  import { getConstraintsStatusSummary } from './utils';
3
3
 
4
4
  describe('Constraints status summary', () => {