-
Notifications
You must be signed in to change notification settings - Fork 900
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core/managed): Application pause/resume functionality (#8342)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Loading branch information
1 parent
638363d
commit 996145a
Showing
6 changed files
with
252 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
app/scripts/modules/core/src/managed/EnvironmentsHeader.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
.EnvironmentsHeader { | ||
background-color: var(--color-white); | ||
border-radius: 3px; | ||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12); | ||
margin: 0 3px 16px 3px; | ||
|
||
// dropdown-toggle class is from the bootstrap library and needed here to increase the specificity of our rule | ||
// to avoid bootstrap changing the background and text colors to default value. | ||
.dropdown-toggle.dropdown-toggle-btn, | ||
.dropdown-toggle.dropdown-toggle-btn:hover, | ||
.open > .dropdown-toggle.dropdown-toggle-btn, | ||
.open > .dropdown-toggle.dropdown-toggle-btn:hover, | ||
.open > .dropdown-toggle.dropdown-toggle-btn:focus { | ||
background-color: rgb(90, 95, 180); | ||
color: var(--color-white); | ||
} | ||
|
||
.dropdown-menu > li { | ||
cursor: pointer; | ||
|
||
&:hover { | ||
background-color: var(--color-alabaster); | ||
} | ||
|
||
a { | ||
padding: 8px 20px; | ||
} | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
app/scripts/modules/core/src/managed/EnvironmentsHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react'; | ||
import { Dropdown } from 'react-bootstrap'; | ||
|
||
import { Application } from '../application'; | ||
import { Illustration, IllustrationName } from '../presentation'; | ||
import { showToggleManagedResourceModal } from './ToggleManagedResourceForApplication'; | ||
|
||
import './EnvironmentsHeader.less'; | ||
|
||
interface IEnvironmentsHeaderProps { | ||
app: Application; | ||
resourceInfo: { managed: number; total: number }; | ||
} | ||
|
||
export const ToggleManagedResourceAction = ({ app }: { app: Application }) => ( | ||
<li> | ||
<a | ||
onClick={() => { | ||
showToggleManagedResourceModal({ application: app }); | ||
}} | ||
> | ||
{app.isManagementPaused ? 'Resume management' : 'Disable management'} | ||
</a> | ||
</li> | ||
); | ||
|
||
const environmentHeaderInfo: { | ||
[key: string]: { description: string | null; icon: IllustrationName; title: (info: string) => string }; | ||
} = { | ||
running: { | ||
description: null, | ||
icon: 'runManagement', | ||
title: (info: string) => `Spinnaker is continuously managing ${info} resources.`, | ||
}, | ||
paused: { | ||
description: 'Any actions made will take effect once management is resumed.', | ||
icon: 'disableManagement', | ||
title: () => 'Management is disabled for this application.', | ||
}, | ||
}; | ||
|
||
export const EnvironmentsHeader = ({ app, resourceInfo: { managed, total } }: IEnvironmentsHeaderProps) => { | ||
const { description, icon, title } = environmentHeaderInfo[app.isManagementPaused ? 'paused' : 'running']; | ||
|
||
return ( | ||
<div className="EnvironmentsHeader"> | ||
<div className="flex-container-h sp-padding-l"> | ||
<div style={{ minWidth: 145 }}> | ||
<Illustration name={icon} /> | ||
</div> | ||
<div className="flex-container-v sp-padding-xl-top sp-margin-m-left sp-margin-m-top"> | ||
<div className="heading-3 bold">{title(managed === total ? `${total}` : `${managed}/${total}`)}</div> | ||
{description && <div className="sp-margin-s-top">{description}</div>} | ||
<Dropdown id="application-actions" className="sp-margin-l-top"> | ||
<Dropdown.Toggle className="dropdown-toggle-btn">Application Actions</Dropdown.Toggle> | ||
<Dropdown.Menu className="dropdown-menu"> | ||
<ToggleManagedResourceAction app={app} /> | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
145 changes: 145 additions & 0 deletions
145
app/scripts/modules/core/src/managed/ToggleManagedResourceForApplication.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import React, { memo, useState } from 'react'; | ||
import ReactGA from 'react-ga'; | ||
|
||
import { Application } from '../application'; | ||
import { Button } from './Button'; | ||
import { | ||
Illustration, | ||
IllustrationName, | ||
IModalComponentProps, | ||
ModalBody, | ||
ModalFooter, | ||
ModalHeader, | ||
showModal, | ||
ValidationMessage, | ||
} from '../presentation'; | ||
import { ManagedWriter } from './ManagedWriter'; | ||
|
||
const logClick = (label: string, application: string) => | ||
ReactGA.event({ | ||
category: 'Environments - toggle application management modal', | ||
action: `${label} clicked`, | ||
label: application, | ||
}); | ||
|
||
export interface IToggleManagedResourceForApplicationModalProps extends IModalComponentProps { | ||
application: Application; | ||
} | ||
|
||
interface Error { | ||
data: { error: string; message: string }; | ||
} | ||
|
||
export const MDRunningStateDescription = () => ( | ||
<> | ||
<p> | ||
<span className="bold"> | ||
Careful! You’re about to stop Spinnaker from managing all resources in your application. | ||
</span> | ||
This feature should only be used if management is not working properly and manual intervention is required.{' '} | ||
<a href="https://www.spinnaker.io/guides/user/managed-delivery" target="_blank"> | ||
Check our documentation for more information | ||
</a> | ||
. | ||
</p> | ||
<p> | ||
Need to rollback?{' '} | ||
<a href="https://www.spinnaker.io/guides/user/managed-delivery/pinning/" target="_blank"> | ||
Try pinning a version instead | ||
</a> | ||
. | ||
</p> | ||
</> | ||
); | ||
|
||
export const MDPausedStateDescription = () => { | ||
return ( | ||
<p> | ||
You’re about to resume management for this application. The latest good version approved for deployment will be | ||
deployed to each environment, and any configuration changes made while disabled will take effect. | ||
</p> | ||
); | ||
}; | ||
|
||
const modalViewInfo = { | ||
paused: { | ||
actionToBeTaken: 'Resume', | ||
description: <MDPausedStateDescription />, | ||
icon: 'runManagement' as IllustrationName, | ||
}, | ||
running: { | ||
actionToBeTaken: 'Disable', | ||
description: <MDRunningStateDescription />, | ||
icon: 'disableManagement' as IllustrationName, | ||
}, | ||
}; | ||
|
||
export const showToggleManagedResourceModal = (props: IToggleManagedResourceForApplicationModalProps) => | ||
showModal(ToggleManagedResourceForApplicationModal, props, { maxWidth: 800 }); | ||
|
||
export const ToggleManagedResourceForApplicationModal = memo( | ||
({ application, closeModal, dismissModal }: IToggleManagedResourceForApplicationModalProps) => { | ||
const [isSubmitting, setSubmitting] = useState<boolean>(false); | ||
const [actionError, setActionError] = useState<{ error: string; message: string } | null>(null); | ||
const dataSource = application.getDataSource('environments'); | ||
|
||
const { actionToBeTaken, description, icon } = modalViewInfo[application.isManagementPaused ? 'paused' : 'running']; | ||
|
||
const handleActionInitiation = () => { | ||
setActionError(null); | ||
setSubmitting(true); | ||
logClick(`${actionToBeTaken} Management`, application.name); | ||
const call = application.isManagementPaused | ||
? ManagedWriter.resumeApplicationManagement(application.name) | ||
: ManagedWriter.pauseApplicationManagement(application.name); | ||
call | ||
.then(() => dataSource.refresh(true).catch(() => null)) | ||
.then(() => { | ||
closeModal(); | ||
}) | ||
.catch((error: Error) => { | ||
setActionError(error.data); | ||
setSubmitting(false); | ||
}); | ||
}; | ||
return ( | ||
<> | ||
<ModalHeader>{actionToBeTaken} management</ModalHeader> | ||
<ModalBody> | ||
<div className="flex-container-h sp-padding-xl-yaxis"> | ||
<div style={{ minWidth: 145 }}> | ||
<Illustration name={icon} /> | ||
</div> | ||
<div className="sp-padding-xl"> | ||
<div>{description}</div> | ||
{actionError && ( | ||
<div className="sp-margin-xl-top"> | ||
<ValidationMessage | ||
type="error" | ||
message={ | ||
<span className="flex-container-v"> | ||
<span className="text-bold">Something went wrong:</span> | ||
{actionError.error && <span className="text-semibold">{actionError.error}</span>} | ||
{actionError.message && <span>{actionError.message}</span>} | ||
</span> | ||
} | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</ModalBody> | ||
<ModalFooter | ||
primaryActions={ | ||
<div className="flex-container-h sp-group-margin-s-xaxis"> | ||
<Button onClick={dismissModal}>Cancel</Button> | ||
<Button appearance="primary" disabled={isSubmitting} onClick={handleActionInitiation}> | ||
{actionToBeTaken} | ||
</Button> | ||
</div> | ||
} | ||
/> | ||
</> | ||
); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
app/scripts/modules/core/src/presentation/illustrations/illustrationsByName.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,15 @@ | ||
import { ReactComponent as announcement } from './vectors/announcement.svg'; | ||
import { ReactComponent as disableManagement } from './vectors/disableManagement.svg'; | ||
import { ReactComponent as markArtifactVersionAsBad } from './vectors/markArtifactVersionAsBad.svg'; | ||
import { ReactComponent as pinArtifactVersion } from './vectors/pinArtifactVersion.svg'; | ||
import { ReactComponent as runManagement } from './vectors/runManagement.svg'; | ||
import { ReactComponent as unpinArtifactVersion } from './vectors/unpinArtifactVersion.svg'; | ||
|
||
export const illustrationsByName = { | ||
announcement, | ||
disableManagement, | ||
markArtifactVersionAsBad, | ||
pinArtifactVersion, | ||
runManagement, | ||
unpinArtifactVersion, | ||
} as const; |