mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add orphan support (#3849)
* feat: add resource orphanage * feat: deny custom state in build for regular users * Minor protoc improvements
This commit is contained in:
@@ -170,6 +170,7 @@ export interface CreateWorkspaceBuildRequest {
|
||||
readonly transition: WorkspaceTransition
|
||||
readonly dry_run?: boolean
|
||||
readonly state?: string
|
||||
readonly orphan?: boolean
|
||||
readonly parameter_values?: CreateParameterRequest[]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { makeStyles, Theme } from "@material-ui/core/styles"
|
||||
import { FC } from "react"
|
||||
import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
|
||||
import { combineClasses } from "../../util/combineClasses"
|
||||
@@ -9,6 +9,7 @@ export interface CodeExampleProps {
|
||||
className?: string
|
||||
buttonClassName?: string
|
||||
tooltipTitle?: string
|
||||
inline?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,8 +20,9 @@ export const CodeExample: FC<React.PropsWithChildren<CodeExampleProps>> = ({
|
||||
className,
|
||||
buttonClassName,
|
||||
tooltipTitle,
|
||||
inline,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
const styles = useStyles({ inline: inline })
|
||||
|
||||
return (
|
||||
<div className={combineClasses([styles.root, className])}>
|
||||
@@ -34,35 +36,41 @@ export const CodeExample: FC<React.PropsWithChildren<CodeExampleProps>> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
display: "flex",
|
||||
interface styleProps {
|
||||
inline?: boolean
|
||||
}
|
||||
|
||||
const useStyles = makeStyles<Theme, styleProps>((theme) => ({
|
||||
root: (props) => ({
|
||||
display: props.inline ? "inline-flex" : "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
background: "hsl(223, 27%, 3%)",
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
background: props.inline ? "rgb(0 0 0 / 30%)" : "hsl(223, 27%, 3%)",
|
||||
border: props.inline ? undefined : `1px solid ${theme.palette.divider}`,
|
||||
color: theme.palette.primary.contrastText,
|
||||
fontFamily: MONOSPACE_FONT_FAMILY,
|
||||
fontSize: 14,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
padding: theme.spacing(0.5),
|
||||
},
|
||||
code: {
|
||||
padding: props.inline ? "0px" : theme.spacing(0.5),
|
||||
}),
|
||||
code: (props) => ({
|
||||
padding: `
|
||||
${theme.spacing(0.5)}px
|
||||
${props.inline ? 0 : theme.spacing(0.5)}px
|
||||
${theme.spacing(0.75)}px
|
||||
${theme.spacing(0.5)}px
|
||||
${theme.spacing(2)}px
|
||||
${props.inline ? 0 : theme.spacing(0.5)}px
|
||||
${props.inline ? theme.spacing(1) : theme.spacing(2)}px
|
||||
`,
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
wordBreak: "break-all",
|
||||
},
|
||||
button: {
|
||||
}),
|
||||
button: (props) => ({
|
||||
border: 0,
|
||||
minWidth: 42,
|
||||
minHeight: 42,
|
||||
minWidth: props.inline ? 30 : 42,
|
||||
minHeight: props.inline ? 30 : 42,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
padding: props.inline ? theme.spacing(0.4) : undefined,
|
||||
background: "transparent",
|
||||
}),
|
||||
}))
|
||||
|
||||
@@ -86,7 +86,6 @@ export const CopyButton: React.FC<React.PropsWithChildren<CopyButtonProps>> = ({
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
copyButtonWrapper: {
|
||||
display: "flex",
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
copyButton: {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { ComponentMeta, Story } from "@storybook/react"
|
||||
import { MockWorkspaceBuild, MockWorkspaceBuildLogs } from "../../testHelpers/entities"
|
||||
import {
|
||||
MockFailedWorkspaceBuild,
|
||||
MockWorkspaceBuild,
|
||||
MockWorkspaceBuildLogs,
|
||||
} from "../../testHelpers/entities"
|
||||
import { WorkspaceBuildPageView, WorkspaceBuildPageViewProps } from "./WorkspaceBuildPageView"
|
||||
|
||||
export default {
|
||||
@@ -13,5 +17,10 @@ export const Example = Template.bind({})
|
||||
Example.args = {
|
||||
build: MockWorkspaceBuild,
|
||||
logs: MockWorkspaceBuildLogs,
|
||||
isWaitingForLogs: false,
|
||||
}
|
||||
|
||||
export const FailedDelete = Template.bind({})
|
||||
FailedDelete.args = {
|
||||
build: MockFailedWorkspaceBuild("delete"),
|
||||
logs: MockWorkspaceBuildLogs,
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { PageHeader, PageHeaderTitle } from "../../components/PageHeader/PageHea
|
||||
import { Stack } from "../../components/Stack/Stack"
|
||||
import { WorkspaceBuildLogs } from "../../components/WorkspaceBuildLogs/WorkspaceBuildLogs"
|
||||
import { WorkspaceBuildStats } from "../../components/WorkspaceBuildStats/WorkspaceBuildStats"
|
||||
import { WorkspaceBuildStateError } from "./WorkspaceBuildStateError"
|
||||
|
||||
const sortLogsByCreatedAt = (logs: ProvisionerJobLog[]) => {
|
||||
return [...logs].sort(
|
||||
@@ -26,6 +27,9 @@ export const WorkspaceBuildPageView: FC<WorkspaceBuildPageViewProps> = ({ logs,
|
||||
</PageHeader>
|
||||
|
||||
<Stack>
|
||||
{build && build.transition === "delete" && build.job.status === "failed" && (
|
||||
<WorkspaceBuildStateError build={build} />
|
||||
)}
|
||||
{build && <WorkspaceBuildStats build={build} />}
|
||||
{!logs && <Loader />}
|
||||
{logs && <WorkspaceBuildLogs logs={sortLogsByCreatedAt(logs)} />}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { WorkspaceBuild } from "api/typesGenerated"
|
||||
import { CodeExample } from "components/CodeExample/CodeExample"
|
||||
import { Stack } from "components/Stack/Stack"
|
||||
|
||||
const Language = {
|
||||
stateMessage: "The workspace may have failed to delete due to a Terraform state mismatch.",
|
||||
}
|
||||
|
||||
export interface WorkspaceBuildStateErrorProps {
|
||||
build: WorkspaceBuild
|
||||
}
|
||||
|
||||
export const WorkspaceBuildStateError: React.FC<WorkspaceBuildStateErrorProps> = ({ build }) => {
|
||||
const styles = useStyles()
|
||||
|
||||
const orphanCommand = `coder rm ${
|
||||
build.workspace_owner_name + "/" + build.workspace_name
|
||||
} --orphan`
|
||||
return (
|
||||
<Stack className={styles.root}>
|
||||
<Stack direction="row" alignItems="center" className={styles.messageBox}>
|
||||
<Stack direction="row" spacing={0}>
|
||||
<span className={styles.errorMessage}>
|
||||
{Language.stateMessage} A template admin may run{" "}
|
||||
<CodeExample inline code={orphanCommand} /> to delete the workspace skipping resource
|
||||
destruction.
|
||||
</span>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
background: theme.palette.warning.main,
|
||||
padding: `${theme.spacing(2)}px`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
gap: 0,
|
||||
},
|
||||
flex: {
|
||||
display: "flex",
|
||||
},
|
||||
messageBox: {
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
errorMessage: {
|
||||
marginRight: `${theme.spacing(1)}px`,
|
||||
},
|
||||
iconButton: {
|
||||
padding: 0,
|
||||
},
|
||||
}))
|
||||
@@ -132,6 +132,7 @@ export const MockFailedProvisionerJob: TypesGen.ProvisionerJob = {
|
||||
...MockProvisionerJob,
|
||||
status: "failed",
|
||||
}
|
||||
|
||||
export const MockCancelingProvisionerJob: TypesGen.ProvisionerJob = {
|
||||
...MockProvisionerJob,
|
||||
status: "canceling",
|
||||
@@ -212,6 +213,27 @@ export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = {
|
||||
reason: "initiator",
|
||||
}
|
||||
|
||||
export const MockFailedWorkspaceBuild = (
|
||||
transition: TypesGen.WorkspaceTransition = "start",
|
||||
): TypesGen.WorkspaceBuild => ({
|
||||
build_number: 1,
|
||||
created_at: "2022-05-17T17:39:01.382927298Z",
|
||||
id: "1",
|
||||
initiator_id: MockUser.id,
|
||||
initiator_name: MockUser.username,
|
||||
job: MockFailedProvisionerJob,
|
||||
name: "a-workspace-build",
|
||||
template_version_id: "",
|
||||
transition: transition,
|
||||
updated_at: "2022-05-17T17:39:01.382927298Z",
|
||||
workspace_name: "test-workspace",
|
||||
workspace_owner_id: MockUser.id,
|
||||
workspace_owner_name: MockUser.username,
|
||||
workspace_id: "759f1d46-3174-453d-aa60-980a9c1442f3",
|
||||
deadline: "2022-05-17T23:39:00.00Z",
|
||||
reason: "initiator",
|
||||
})
|
||||
|
||||
export const MockWorkspaceBuildStop: TypesGen.WorkspaceBuild = {
|
||||
...MockWorkspaceBuild,
|
||||
id: "2",
|
||||
|
||||
Reference in New Issue
Block a user