mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor(site): Group app and agent actions together (#7267)
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import Button from "@material-ui/core/Button"
|
||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
||||
import Link from "@material-ui/core/Link"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Tooltip from "@material-ui/core/Tooltip"
|
||||
import ErrorOutlineIcon from "@material-ui/icons/ErrorOutline"
|
||||
import { PrimaryAgentButton } from "components/Resources/AgentButton"
|
||||
import { FC } from "react"
|
||||
import { combineClasses } from "utils/combineClasses"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
@@ -83,16 +83,15 @@ export const AppLink: FC<AppLinkProps> = ({
|
||||
const isPrivateApp = app.sharing_level === "owner"
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
<PrimaryAgentButton
|
||||
startIcon={icon}
|
||||
endIcon={isPrivateApp ? undefined : <ShareIcon app={app} />}
|
||||
className={styles.button}
|
||||
disabled={!canClick}
|
||||
>
|
||||
<span className={combineClasses({ [styles.appName]: !isPrivateApp })}>
|
||||
{appDisplayName}
|
||||
</span>
|
||||
</Button>
|
||||
</PrimaryAgentButton>
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -132,24 +131,6 @@ const useStyles = makeStyles((theme) => ({
|
||||
textDecoration: "none !important",
|
||||
},
|
||||
|
||||
button: {
|
||||
whiteSpace: "nowrap",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
padding: theme.spacing(0, 3),
|
||||
height: 44,
|
||||
borderRadius: 6,
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: `${theme.palette.background.paper} !important`,
|
||||
},
|
||||
|
||||
"& .MuiButton-startIcon": {
|
||||
width: 16,
|
||||
height: 16,
|
||||
marginRight: theme.spacing(1.5),
|
||||
},
|
||||
},
|
||||
|
||||
unhealthyIcon: {
|
||||
color: theme.palette.warning.light,
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { Maybe } from "components/Conditionals/Maybe"
|
||||
import { useMachine } from "@xstate/react"
|
||||
import { portForwardMachine } from "xServices/portForward/portForwardXService"
|
||||
import { SecondaryAgentButton } from "components/Resources/AgentButton"
|
||||
|
||||
export interface PortForwardButtonProps {
|
||||
host: string
|
||||
@@ -147,17 +148,14 @@ export const PortForwardButton: React.FC<PortForwardButtonProps> = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={styles.button}
|
||||
size="small"
|
||||
<SecondaryAgentButton
|
||||
ref={anchorRef}
|
||||
onClick={() => {
|
||||
setIsOpen(true)
|
||||
}}
|
||||
>
|
||||
Port forward
|
||||
</Button>
|
||||
</SecondaryAgentButton>
|
||||
<Popover
|
||||
classes={{ paper: styles.popoverPaper }}
|
||||
id={id}
|
||||
@@ -208,12 +206,4 @@ const useStyles = makeStyles((theme) => ({
|
||||
form: {
|
||||
margin: theme.spacing(1.5, 0, 0),
|
||||
},
|
||||
|
||||
button: {
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
height: theme.spacing(4),
|
||||
minHeight: theme.spacing(4),
|
||||
borderRadius: 4,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Button, { ButtonProps } from "@material-ui/core/Button"
|
||||
import { FC } from "react"
|
||||
import { combineClasses } from "utils/combineClasses"
|
||||
|
||||
export const PrimaryAgentButton: FC<ButtonProps> = ({
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={combineClasses([styles.primaryButton, className])}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const SecondaryAgentButton: FC<ButtonProps> = ({
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="outlined"
|
||||
className={combineClasses([styles.secondaryButton, className])}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
primaryButton: {
|
||||
whiteSpace: "nowrap",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
height: 36,
|
||||
minHeight: 36,
|
||||
borderRadius: 4,
|
||||
fontWeight: 500,
|
||||
fontSize: 14,
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: `${theme.palette.background.paper} !important`,
|
||||
},
|
||||
|
||||
"& .MuiButton-startIcon": {
|
||||
width: 12,
|
||||
height: 12,
|
||||
marginRight: theme.spacing(1.5),
|
||||
|
||||
"& svg": {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
secondaryButton: {
|
||||
fontSize: 14,
|
||||
fontWeight: 500,
|
||||
height: 36,
|
||||
minHeight: 36,
|
||||
borderRadius: 4,
|
||||
},
|
||||
}))
|
||||
@@ -181,7 +181,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
padding: theme.spacing(2.5, 4),
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
background: theme.palette.background.paper,
|
||||
overflowX: "auto",
|
||||
scrollPadding: theme.spacing(0, 4),
|
||||
},
|
||||
|
||||
metadata: {
|
||||
fontSize: 12,
|
||||
lineHeight: "normal",
|
||||
@@ -189,6 +192,11 @@ const useStyles = makeStyles((theme) => ({
|
||||
flexDirection: "column",
|
||||
gap: theme.spacing(0.5),
|
||||
overflow: "visible",
|
||||
|
||||
// Because of scrolling
|
||||
"&:last-child": {
|
||||
paddingRight: theme.spacing(4),
|
||||
},
|
||||
},
|
||||
|
||||
metadataLabel: {
|
||||
|
||||
@@ -42,6 +42,7 @@ import { AgentLatency } from "./AgentLatency"
|
||||
import { AgentMetadata } from "./AgentMetadata"
|
||||
import { AgentVersion } from "./AgentVersion"
|
||||
import { AgentStatus } from "./AgentStatus"
|
||||
import Collapse from "@material-ui/core/Collapse"
|
||||
|
||||
export interface AgentRowProps {
|
||||
agent: WorkspaceAgent
|
||||
@@ -178,14 +179,9 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
styles[`agentRow-lifecycle-${agent.lifecycle_state}`],
|
||||
])}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={6}
|
||||
className={styles.agentInfo}
|
||||
>
|
||||
<div className={styles.agentInfo}>
|
||||
<div className={styles.agentNameAndStatus}>
|
||||
<Stack alignItems="center" direction="row" spacing={3}>
|
||||
<div className={styles.agentNameAndInfo}>
|
||||
<AgentStatus agent={agent} />
|
||||
<div className={styles.agentName}>{agent.name}</div>
|
||||
<Stack
|
||||
@@ -214,11 +210,33 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{agent.status === "connected" && (
|
||||
<div className={styles.agentDefaultActions}>
|
||||
<div className={styles.agentButtons}>
|
||||
{shouldDisplayApps && (
|
||||
<>
|
||||
{!hideVSCodeDesktopButton && (
|
||||
<VSCodeDesktopButton
|
||||
userName={workspace.owner_name}
|
||||
workspaceName={workspace.name}
|
||||
agentName={agent.name}
|
||||
folderPath={agent.expanded_directory}
|
||||
/>
|
||||
)}
|
||||
{agent.apps.map((app) => (
|
||||
<AppLink
|
||||
key={app.slug}
|
||||
appsHost={applicationsHost}
|
||||
app={app}
|
||||
agent={agent}
|
||||
workspace={workspace}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
<TerminalLink
|
||||
workspaceName={workspace.name}
|
||||
agentName={agent.name}
|
||||
@@ -244,7 +262,7 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
)}
|
||||
|
||||
{agent.status === "connecting" && (
|
||||
<div className={styles.agentDefaultActions}>
|
||||
<div className={styles.agentButtons}>
|
||||
<Skeleton
|
||||
width={80}
|
||||
height={32}
|
||||
@@ -259,56 +277,13 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
|
||||
<AgentMetadata storybookMetadata={storybookAgentMetadata} agent={agent} />
|
||||
|
||||
{shouldDisplayApps && (
|
||||
<div className={styles.apps}>
|
||||
{agent.status === "connected" && (
|
||||
<>
|
||||
{!hideVSCodeDesktopButton && (
|
||||
<VSCodeDesktopButton
|
||||
userName={workspace.owner_name}
|
||||
workspaceName={workspace.name}
|
||||
agentName={agent.name}
|
||||
folderPath={agent.expanded_directory}
|
||||
/>
|
||||
)}
|
||||
{agent.apps.map((app) => (
|
||||
<AppLink
|
||||
key={app.slug}
|
||||
appsHost={applicationsHost}
|
||||
app={app}
|
||||
agent={agent}
|
||||
workspace={workspace}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{agent.status === "connecting" && (
|
||||
<>
|
||||
<Skeleton
|
||||
width={80}
|
||||
height={36}
|
||||
variant="rect"
|
||||
className={styles.buttonSkeleton}
|
||||
/>
|
||||
<Skeleton
|
||||
width={110}
|
||||
height={36}
|
||||
variant="rect"
|
||||
className={styles.buttonSkeleton}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasStartupFeatures && (
|
||||
<div className={styles.logsPanel}>
|
||||
{showStartupLogs && (
|
||||
<Collapse in={showStartupLogs}>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }) => (
|
||||
<List
|
||||
@@ -331,7 +306,8 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
</List>
|
||||
)}
|
||||
</AutoSizer>
|
||||
)}
|
||||
</Collapse>
|
||||
|
||||
<div className={styles.logsPanelButtons}>
|
||||
{showStartupLogs ? (
|
||||
<button
|
||||
@@ -471,12 +447,38 @@ const useStyles = makeStyles((theme) => ({
|
||||
|
||||
agentInfo: {
|
||||
padding: theme.spacing(2, 4),
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(6),
|
||||
flexWrap: "wrap",
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
gap: theme.spacing(2),
|
||||
},
|
||||
},
|
||||
|
||||
agentDefaultActions: {
|
||||
agentNameAndInfo: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(3),
|
||||
flexWrap: "wrap",
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
gap: theme.spacing(1.5),
|
||||
},
|
||||
},
|
||||
|
||||
agentButtons: {
|
||||
display: "flex",
|
||||
gap: theme.spacing(1),
|
||||
marginLeft: "auto",
|
||||
justifyContent: "flex-end",
|
||||
flexWrap: "wrap",
|
||||
flex: 1,
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
marginLeft: 0,
|
||||
justifyContent: "flex-start",
|
||||
},
|
||||
},
|
||||
|
||||
agentDescription: {
|
||||
@@ -504,6 +506,10 @@ const useStyles = makeStyles((theme) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(4),
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
width: "100%",
|
||||
},
|
||||
},
|
||||
|
||||
agentName: {
|
||||
@@ -513,6 +519,12 @@ const useStyles = makeStyles((theme) => ({
|
||||
maxWidth: 260,
|
||||
fontWeight: 600,
|
||||
fontSize: theme.spacing(2),
|
||||
flexShrink: 0,
|
||||
width: "fit-content",
|
||||
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
overflow: "unset",
|
||||
},
|
||||
},
|
||||
|
||||
agentDataGroup: {
|
||||
@@ -532,14 +544,6 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
},
|
||||
|
||||
apps: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
gap: theme.spacing(1.5),
|
||||
padding: theme.spacing(4),
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
|
||||
logsPanel: {
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Button from "@material-ui/core/Button"
|
||||
import Popover from "@material-ui/core/Popover"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { SecondaryAgentButton } from "components/Resources/AgentButton"
|
||||
import { useRef, useState } from "react"
|
||||
import { CodeExample } from "../CodeExample/CodeExample"
|
||||
import { Stack } from "../Stack/Stack"
|
||||
@@ -34,17 +34,14 @@ export const SSHButton: React.FC<React.PropsWithChildren<SSHButtonProps>> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className={styles.button}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
<SecondaryAgentButton
|
||||
ref={anchorRef}
|
||||
onClick={() => {
|
||||
setIsOpen(true)
|
||||
}}
|
||||
>
|
||||
Connect SSH
|
||||
</Button>
|
||||
</SecondaryAgentButton>
|
||||
<Popover
|
||||
classes={{ paper: styles.popoverPaper }}
|
||||
id={id}
|
||||
@@ -126,12 +123,4 @@ const useStyles = makeStyles((theme) => ({
|
||||
textHelper: {
|
||||
fontWeight: 400,
|
||||
},
|
||||
|
||||
button: {
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
height: theme.spacing(4),
|
||||
minHeight: theme.spacing(4),
|
||||
borderRadius: 4,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import Button from "@material-ui/core/Button"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Link from "@material-ui/core/Link"
|
||||
import { SecondaryAgentButton } from "components/Resources/AgentButton"
|
||||
import { FC } from "react"
|
||||
import * as TypesGen from "../../api/typesGenerated"
|
||||
import { combineClasses } from "../../utils/combineClasses"
|
||||
import { generateRandomString } from "../../utils/random"
|
||||
|
||||
export const Language = {
|
||||
@@ -14,7 +13,6 @@ export interface TerminalLinkProps {
|
||||
agentName?: TypesGen.WorkspaceAgent["name"]
|
||||
userName?: TypesGen.User["username"]
|
||||
workspaceName: TypesGen.Workspace["name"]
|
||||
className?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,20 +26,15 @@ export const TerminalLink: FC<React.PropsWithChildren<TerminalLinkProps>> = ({
|
||||
agentName,
|
||||
userName = "me",
|
||||
workspaceName,
|
||||
className = "",
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
const href = `/@${userName}/${workspaceName}${
|
||||
agentName ? `.${agentName}` : ""
|
||||
}/terminal`
|
||||
|
||||
return (
|
||||
<Button
|
||||
<Link
|
||||
underline="none"
|
||||
href={href}
|
||||
component="a"
|
||||
size="small"
|
||||
variant="outlined"
|
||||
className={combineClasses([styles.button, className])}
|
||||
target="_blank"
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
@@ -52,17 +45,9 @@ export const TerminalLink: FC<React.PropsWithChildren<TerminalLinkProps>> = ({
|
||||
)
|
||||
}}
|
||||
>
|
||||
{Language.linkText}
|
||||
</Button>
|
||||
<SecondaryAgentButton size="small" variant="outlined">
|
||||
{Language.linkText}
|
||||
</SecondaryAgentButton>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
button: {
|
||||
fontSize: 12,
|
||||
fontWeight: 500,
|
||||
height: theme.spacing(4),
|
||||
minHeight: theme.spacing(4),
|
||||
borderRadius: 4,
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Button from "@material-ui/core/Button"
|
||||
import { getApiKey } from "api/api"
|
||||
import { VSCodeIcon } from "components/Icons/VSCodeIcon"
|
||||
import { FC, PropsWithChildren, useState } from "react"
|
||||
import { PrimaryAgentButton } from "components/Resources/AgentButton"
|
||||
|
||||
export interface VSCodeDesktopButtonProps {
|
||||
userName: string
|
||||
@@ -15,13 +14,11 @@ export const VSCodeDesktopButton: FC<
|
||||
PropsWithChildren<VSCodeDesktopButtonProps>
|
||||
> = ({ userName, workspaceName, agentName, folderPath }) => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Button
|
||||
<PrimaryAgentButton
|
||||
startIcon={<VSCodeIcon />}
|
||||
disabled={loading}
|
||||
className={styles.button}
|
||||
onClick={() => {
|
||||
setLoading(true)
|
||||
getApiKey()
|
||||
@@ -50,31 +47,6 @@ export const VSCodeDesktopButton: FC<
|
||||
}}
|
||||
>
|
||||
VS Code Desktop
|
||||
</Button>
|
||||
</PrimaryAgentButton>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
button: {
|
||||
whiteSpace: "nowrap",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
padding: theme.spacing(0, 3),
|
||||
height: 44,
|
||||
borderRadius: 6,
|
||||
|
||||
"&:hover": {
|
||||
backgroundColor: `${theme.palette.background.paper} !important`,
|
||||
},
|
||||
|
||||
"& .MuiButton-startIcon": {
|
||||
marginRight: theme.spacing(1.5),
|
||||
width: 16,
|
||||
height: 16,
|
||||
|
||||
"& svg": {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user