2022-10-18 13:44:58 +00:00
|
|
|
|
import Tooltip from "@material-ui/core/Tooltip"
|
|
|
|
|
import { makeStyles } from "@material-ui/core/styles"
|
|
|
|
|
import { combineClasses } from "util/combineClasses"
|
2022-11-16 10:53:02 +00:00
|
|
|
|
import { WorkspaceAgent } from "api/typesGenerated"
|
2022-10-18 13:44:58 +00:00
|
|
|
|
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
|
|
|
|
|
import { useTranslation } from "react-i18next"
|
2022-11-09 20:40:34 +00:00
|
|
|
|
import WarningRounded from "@material-ui/icons/WarningRounded"
|
|
|
|
|
import {
|
|
|
|
|
HelpPopover,
|
|
|
|
|
HelpTooltipText,
|
|
|
|
|
HelpTooltipTitle,
|
|
|
|
|
} from "components/Tooltips/HelpTooltip"
|
|
|
|
|
import { useRef, useState } from "react"
|
|
|
|
|
import Link from "@material-ui/core/Link"
|
2022-10-18 13:44:58 +00:00
|
|
|
|
|
2023-01-24 17:48:03 +00:00
|
|
|
|
// If we think in the agent status and lifecycle into a single enum/state I’d
|
|
|
|
|
// say we would have: connecting, timeout, disconnected, connected:created,
|
|
|
|
|
// connected:starting, connected:start_timeout, connected:start_error,
|
|
|
|
|
// connected:ready
|
|
|
|
|
|
|
|
|
|
const ReadyLifeCycle: React.FC = () => {
|
2022-10-18 13:44:58 +00:00
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const { t } = useTranslation("workspacePage")
|
|
|
|
|
|
|
|
|
|
return (
|
2022-11-09 20:40:34 +00:00
|
|
|
|
<div
|
|
|
|
|
role="status"
|
2023-01-24 17:48:03 +00:00
|
|
|
|
aria-label={t("agentStatus.connected.ready")}
|
2022-11-09 20:40:34 +00:00
|
|
|
|
className={combineClasses([styles.status, styles.connected])}
|
|
|
|
|
/>
|
2022-10-18 13:44:58 +00:00
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 17:48:03 +00:00
|
|
|
|
const StartingLifecycle: React.FC = () => {
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const { t } = useTranslation("workspacePage")
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Tooltip title={t("agentStatus.connected.starting")}>
|
|
|
|
|
<div
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("agentStatus.connected.starting")}
|
|
|
|
|
className={combineClasses([styles.status, styles.connecting])}
|
|
|
|
|
/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const StartTimeoutLifecycle: React.FC<{
|
|
|
|
|
agent: WorkspaceAgent
|
|
|
|
|
}> = ({ agent }) => {
|
|
|
|
|
const { t } = useTranslation("agent")
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const anchorRef = useRef<SVGSVGElement>(null)
|
|
|
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
|
|
|
const id = isOpen ? "timeout-popover" : undefined
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<WarningRounded
|
|
|
|
|
ref={anchorRef}
|
|
|
|
|
onMouseEnter={() => setIsOpen(true)}
|
|
|
|
|
onMouseLeave={() => setIsOpen(false)}
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("status.startTimeout")}
|
|
|
|
|
className={styles.timeoutWarning}
|
|
|
|
|
/>
|
|
|
|
|
<HelpPopover
|
|
|
|
|
id={id}
|
|
|
|
|
open={isOpen}
|
|
|
|
|
anchorEl={anchorRef.current}
|
|
|
|
|
onOpen={() => setIsOpen(true)}
|
|
|
|
|
onClose={() => setIsOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
<HelpTooltipTitle>{t("startTimeoutTooltip.title")}</HelpTooltipTitle>
|
|
|
|
|
<HelpTooltipText>
|
|
|
|
|
{t("startTimeoutTooltip.message")}{" "}
|
|
|
|
|
<Link
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noreferrer"
|
|
|
|
|
href={agent.troubleshooting_url}
|
|
|
|
|
>
|
|
|
|
|
{t("startTimeoutTooltip.link")}
|
|
|
|
|
</Link>
|
|
|
|
|
.
|
|
|
|
|
</HelpTooltipText>
|
|
|
|
|
</HelpPopover>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const StartErrorLifecycle: React.FC<{
|
|
|
|
|
agent: WorkspaceAgent
|
|
|
|
|
}> = ({ agent }) => {
|
|
|
|
|
const { t } = useTranslation("agent")
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const anchorRef = useRef<SVGSVGElement>(null)
|
|
|
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
|
|
|
const id = isOpen ? "timeout-popover" : undefined
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<WarningRounded
|
|
|
|
|
ref={anchorRef}
|
|
|
|
|
onMouseEnter={() => setIsOpen(true)}
|
|
|
|
|
onMouseLeave={() => setIsOpen(false)}
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("status.error")}
|
|
|
|
|
className={styles.errorWarning}
|
|
|
|
|
/>
|
|
|
|
|
<HelpPopover
|
|
|
|
|
id={id}
|
|
|
|
|
open={isOpen}
|
|
|
|
|
anchorEl={anchorRef.current}
|
|
|
|
|
onOpen={() => setIsOpen(true)}
|
|
|
|
|
onClose={() => setIsOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
<HelpTooltipTitle>{t("startErrorTooltip.title")}</HelpTooltipTitle>
|
|
|
|
|
<HelpTooltipText>
|
|
|
|
|
{t("startErrorTooltip.message")}{" "}
|
|
|
|
|
<Link
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noreferrer"
|
|
|
|
|
href={agent.troubleshooting_url}
|
|
|
|
|
>
|
|
|
|
|
{t("startErrorTooltip.link")}
|
|
|
|
|
</Link>
|
|
|
|
|
.
|
|
|
|
|
</HelpTooltipText>
|
|
|
|
|
</HelpPopover>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ConnectedStatus: React.FC<{
|
|
|
|
|
agent: WorkspaceAgent
|
|
|
|
|
}> = ({ agent }) => {
|
2023-01-25 13:23:31 +00:00
|
|
|
|
// NOTE(mafredri): Keep this behind feature flag for the time-being,
|
2023-01-27 20:07:47 +00:00
|
|
|
|
// if login_before_ready is false, the user has updated to
|
|
|
|
|
// terraform-provider-coder v0.6.10 and opted in to the functionality.
|
2023-01-25 13:23:31 +00:00
|
|
|
|
//
|
|
|
|
|
// Remove check once documentation is in place and we do a breaking
|
|
|
|
|
// release indicating startup script behavior has changed.
|
|
|
|
|
// https://github.com/coder/coder/issues/5749
|
2023-01-27 20:07:47 +00:00
|
|
|
|
if (agent.login_before_ready) {
|
|
|
|
|
return <ReadyLifeCycle />
|
2023-01-25 13:23:31 +00:00
|
|
|
|
}
|
2023-01-27 20:07:47 +00:00
|
|
|
|
return (
|
|
|
|
|
<ChooseOne>
|
|
|
|
|
<Cond condition={agent.lifecycle_state === "ready"}>
|
|
|
|
|
<ReadyLifeCycle />
|
|
|
|
|
</Cond>
|
|
|
|
|
<Cond condition={agent.lifecycle_state === "start_timeout"}>
|
|
|
|
|
<StartTimeoutLifecycle agent={agent} />
|
|
|
|
|
</Cond>
|
|
|
|
|
<Cond condition={agent.lifecycle_state === "start_error"}>
|
|
|
|
|
<StartErrorLifecycle agent={agent} />
|
|
|
|
|
</Cond>
|
|
|
|
|
<Cond>
|
|
|
|
|
<StartingLifecycle />
|
|
|
|
|
</Cond>
|
|
|
|
|
</ChooseOne>
|
|
|
|
|
)
|
2023-01-24 17:48:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-18 13:44:58 +00:00
|
|
|
|
const DisconnectedStatus: React.FC = () => {
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const { t } = useTranslation("workspacePage")
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Tooltip title={t("agentStatus.disconnected")}>
|
|
|
|
|
<div
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("agentStatus.disconnected")}
|
|
|
|
|
className={combineClasses([styles.status, styles.disconnected])}
|
|
|
|
|
/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ConnectingStatus: React.FC = () => {
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const { t } = useTranslation("workspacePage")
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Tooltip title={t("agentStatus.connecting")}>
|
|
|
|
|
<div
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("agentStatus.connecting")}
|
|
|
|
|
className={combineClasses([styles.status, styles.connecting])}
|
|
|
|
|
/>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 20:40:34 +00:00
|
|
|
|
const TimeoutStatus: React.FC<{
|
|
|
|
|
agent: WorkspaceAgent
|
2022-11-16 10:53:02 +00:00
|
|
|
|
}> = ({ agent }) => {
|
2022-11-09 20:40:34 +00:00
|
|
|
|
const { t } = useTranslation("agent")
|
|
|
|
|
const styles = useStyles()
|
|
|
|
|
const anchorRef = useRef<SVGSVGElement>(null)
|
|
|
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
|
|
|
const id = isOpen ? "timeout-popover" : undefined
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<WarningRounded
|
|
|
|
|
ref={anchorRef}
|
|
|
|
|
onMouseEnter={() => setIsOpen(true)}
|
|
|
|
|
onMouseLeave={() => setIsOpen(false)}
|
|
|
|
|
role="status"
|
|
|
|
|
aria-label={t("status.timeout")}
|
|
|
|
|
className={styles.timeoutWarning}
|
|
|
|
|
/>
|
|
|
|
|
<HelpPopover
|
|
|
|
|
id={id}
|
|
|
|
|
open={isOpen}
|
|
|
|
|
anchorEl={anchorRef.current}
|
|
|
|
|
onOpen={() => setIsOpen(true)}
|
|
|
|
|
onClose={() => setIsOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
<HelpTooltipTitle>{t("timeoutTooltip.title")}</HelpTooltipTitle>
|
|
|
|
|
<HelpTooltipText>
|
|
|
|
|
{t("timeoutTooltip.message")}{" "}
|
2022-11-16 10:53:02 +00:00
|
|
|
|
<Link
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noreferrer"
|
|
|
|
|
href={agent.troubleshooting_url}
|
|
|
|
|
>
|
2022-11-09 20:40:34 +00:00
|
|
|
|
{t("timeoutTooltip.link")}
|
|
|
|
|
</Link>
|
|
|
|
|
.
|
|
|
|
|
</HelpTooltipText>
|
|
|
|
|
</HelpPopover>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const AgentStatus: React.FC<{
|
|
|
|
|
agent: WorkspaceAgent
|
2022-11-16 10:53:02 +00:00
|
|
|
|
}> = ({ agent }) => {
|
2022-10-18 13:44:58 +00:00
|
|
|
|
return (
|
|
|
|
|
<ChooseOne>
|
|
|
|
|
<Cond condition={agent.status === "connected"}>
|
2023-01-24 17:48:03 +00:00
|
|
|
|
<ConnectedStatus agent={agent} />
|
2022-10-18 13:44:58 +00:00
|
|
|
|
</Cond>
|
|
|
|
|
<Cond condition={agent.status === "disconnected"}>
|
|
|
|
|
<DisconnectedStatus />
|
|
|
|
|
</Cond>
|
2022-11-09 20:40:34 +00:00
|
|
|
|
<Cond condition={agent.status === "timeout"}>
|
2022-11-16 10:53:02 +00:00
|
|
|
|
<TimeoutStatus agent={agent} />
|
2022-11-09 20:40:34 +00:00
|
|
|
|
</Cond>
|
2022-10-18 13:44:58 +00:00
|
|
|
|
<Cond>
|
|
|
|
|
<ConnectingStatus />
|
|
|
|
|
</Cond>
|
|
|
|
|
</ChooseOne>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
|
|
|
status: {
|
|
|
|
|
width: theme.spacing(1),
|
|
|
|
|
height: theme.spacing(1),
|
|
|
|
|
borderRadius: "100%",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
connected: {
|
|
|
|
|
backgroundColor: theme.palette.success.light,
|
2022-10-25 19:41:38 +00:00
|
|
|
|
boxShadow: `0 0 12px 0 ${theme.palette.success.light}`,
|
2022-10-18 13:44:58 +00:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
disconnected: {
|
|
|
|
|
backgroundColor: theme.palette.text.secondary,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
"@keyframes pulse": {
|
|
|
|
|
"0%": {
|
2022-10-31 20:35:05 +00:00
|
|
|
|
opacity: 1,
|
2022-10-18 13:44:58 +00:00
|
|
|
|
},
|
|
|
|
|
"50%": {
|
2022-10-31 20:35:05 +00:00
|
|
|
|
opacity: 0.4,
|
2022-10-18 13:44:58 +00:00
|
|
|
|
},
|
|
|
|
|
"100%": {
|
2022-10-31 20:35:05 +00:00
|
|
|
|
opacity: 1,
|
2022-10-18 13:44:58 +00:00
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
connecting: {
|
|
|
|
|
backgroundColor: theme.palette.info.light,
|
2022-10-31 20:35:05 +00:00
|
|
|
|
animation: "$pulse 1.5s 0.5s ease-in-out forwards infinite",
|
2022-10-18 13:44:58 +00:00
|
|
|
|
},
|
2022-11-09 20:40:34 +00:00
|
|
|
|
|
|
|
|
|
timeoutWarning: {
|
|
|
|
|
color: theme.palette.warning.light,
|
|
|
|
|
width: theme.spacing(2.5),
|
|
|
|
|
height: theme.spacing(2.5),
|
|
|
|
|
position: "relative",
|
|
|
|
|
top: theme.spacing(1),
|
|
|
|
|
},
|
2023-01-24 17:48:03 +00:00
|
|
|
|
|
|
|
|
|
errorWarning: {
|
|
|
|
|
color: theme.palette.error.main,
|
|
|
|
|
width: theme.spacing(2.5),
|
|
|
|
|
height: theme.spacing(2.5),
|
|
|
|
|
position: "relative",
|
|
|
|
|
top: theme.spacing(1),
|
|
|
|
|
},
|
2022-10-18 13:44:58 +00:00
|
|
|
|
}))
|