mirror of
https://github.com/coder/coder.git
synced 2025-07-18 14:17:22 +00:00
feat: Add resource icons (#3118)
This commit is contained in:
@ -15,14 +15,25 @@ export interface AvatarDataProps {
|
||||
subtitle: string
|
||||
highlightTitle?: boolean
|
||||
link?: string
|
||||
avatar?: React.ReactNode
|
||||
}
|
||||
|
||||
export const AvatarData: FC<AvatarDataProps> = ({ title, subtitle, link, highlightTitle }) => {
|
||||
export const AvatarData: FC<AvatarDataProps> = ({
|
||||
title,
|
||||
subtitle,
|
||||
link,
|
||||
highlightTitle,
|
||||
avatar,
|
||||
}) => {
|
||||
const styles = useStyles()
|
||||
|
||||
if (!avatar) {
|
||||
avatar = <Avatar>{firstLetter(title)}</Avatar>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<Avatar className={styles.avatar}>{firstLetter(title)}</Avatar>
|
||||
<div className={styles.avatarWrapper}>{avatar}</div>
|
||||
|
||||
{link ? (
|
||||
<Link to={link} underline="none" component={RouterLink}>
|
||||
@ -46,8 +57,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
avatar: {
|
||||
avatarWrapper: {
|
||||
marginRight: theme.spacing(1.5),
|
||||
background: "hsl(219, 8%, 52%)",
|
||||
},
|
||||
}))
|
||||
|
34
site/src/components/Resources/ResourceAvatar.stories.tsx
Normal file
34
site/src/components/Resources/ResourceAvatar.stories.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { Story } from "@storybook/react"
|
||||
import { ResourceAvatar, ResourceAvatarProps } from "./ResourceAvatar"
|
||||
|
||||
export default {
|
||||
title: "components/ResourceAvatar",
|
||||
component: ResourceAvatar,
|
||||
}
|
||||
|
||||
const Template: Story<ResourceAvatarProps> = (args) => <ResourceAvatar {...args} />
|
||||
|
||||
export const VolumeResource = Template.bind({})
|
||||
VolumeResource.args = {
|
||||
type: "docker_volume",
|
||||
}
|
||||
|
||||
export const ComputeResource = Template.bind({})
|
||||
ComputeResource.args = {
|
||||
type: "docker_container",
|
||||
}
|
||||
|
||||
export const ImageResource = Template.bind({})
|
||||
ImageResource.args = {
|
||||
type: "docker_image",
|
||||
}
|
||||
|
||||
export const NullResource = Template.bind({})
|
||||
NullResource.args = {
|
||||
type: "null_resource",
|
||||
}
|
||||
|
||||
export const UnkownResource = Template.bind({})
|
||||
UnkownResource.args = {
|
||||
type: "noexistentvalue",
|
||||
}
|
48
site/src/components/Resources/ResourceAvatar.tsx
Normal file
48
site/src/components/Resources/ResourceAvatar.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import Avatar from "@material-ui/core/Avatar"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import FolderIcon from "@material-ui/icons/FolderOutlined"
|
||||
import HelpIcon from "@material-ui/icons/HelpOutlined"
|
||||
import ImageIcon from "@material-ui/icons/ImageOutlined"
|
||||
import MemoryIcon from "@material-ui/icons/MemoryOutlined"
|
||||
import React from "react"
|
||||
|
||||
// For this special case, we need to apply a different style because how this
|
||||
// particular icon has been designed
|
||||
const AdjustedMemoryIcon: typeof MemoryIcon = ({ style, ...props }) => {
|
||||
return <MemoryIcon style={{ ...style, fontSize: 24 }} {...props} />
|
||||
}
|
||||
|
||||
const iconByResource: Record<string, typeof MemoryIcon> = {
|
||||
docker_volume: FolderIcon,
|
||||
docker_container: AdjustedMemoryIcon,
|
||||
docker_image: ImageIcon,
|
||||
kubernetes_persistent_volume_claim: FolderIcon,
|
||||
kubernetes_pod: AdjustedMemoryIcon,
|
||||
google_compute_disk: FolderIcon,
|
||||
google_compute_instance: AdjustedMemoryIcon,
|
||||
aws_instance: AdjustedMemoryIcon,
|
||||
kubernetes_deployment: AdjustedMemoryIcon,
|
||||
null_resource: HelpIcon,
|
||||
}
|
||||
|
||||
export type ResourceAvatarProps = { type: string }
|
||||
|
||||
export const ResourceAvatar: React.FC<ResourceAvatarProps> = ({ type }) => {
|
||||
// this resource can return undefined
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const IconComponent = iconByResource[type] ?? HelpIcon
|
||||
const styles = useStyles()
|
||||
|
||||
return (
|
||||
<Avatar className={styles.resourceAvatar}>
|
||||
<IconComponent style={{ fontSize: 20 }} />
|
||||
</Avatar>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
resourceAvatar: {
|
||||
color: theme.palette.info.contrastText,
|
||||
backgroundColor: theme.palette.info.main,
|
||||
},
|
||||
}))
|
@ -7,6 +7,7 @@ import TableRow from "@material-ui/core/TableRow"
|
||||
import useTheme from "@material-ui/styles/useTheme"
|
||||
import { FC } from "react"
|
||||
import { Workspace, WorkspaceResource } from "../../api/typesGenerated"
|
||||
import { AvatarData } from "../../components/AvatarData/AvatarData"
|
||||
import { getDisplayAgentStatus } from "../../util/workspace"
|
||||
import { AppLink } from "../AppLink/AppLink"
|
||||
import { SSHButton } from "../SSHButton/SSHButton"
|
||||
@ -15,6 +16,7 @@ import { TableHeaderRow } from "../TableHeaders/TableHeaders"
|
||||
import { TerminalLink } from "../TerminalLink/TerminalLink"
|
||||
import { AgentHelpTooltip } from "../Tooltips/AgentHelpTooltip"
|
||||
import { ResourcesHelpTooltip } from "../Tooltips/ResourcesHelpTooltip"
|
||||
import { ResourceAvatar } from "./ResourceAvatar"
|
||||
|
||||
const Language = {
|
||||
resources: "Resources",
|
||||
@ -68,6 +70,15 @@ export const Resources: FC<ResourcesProps> = ({
|
||||
/* We need to initialize the agents to display the resource */
|
||||
}
|
||||
const agents = resource.agents ?? [null]
|
||||
const resourceName = (
|
||||
<AvatarData
|
||||
avatar={<ResourceAvatar type={resource.type} />}
|
||||
title={resource.name}
|
||||
subtitle={resource.type}
|
||||
highlightTitle
|
||||
/>
|
||||
)
|
||||
|
||||
return agents.map((agent, agentIndex) => {
|
||||
{
|
||||
/* If there is no agent, just display the resource name */
|
||||
@ -75,10 +86,7 @@ export const Resources: FC<ResourcesProps> = ({
|
||||
if (!agent) {
|
||||
return (
|
||||
<TableRow key={`${resource.id}-${agentIndex}`}>
|
||||
<TableCell>
|
||||
{resource.name}
|
||||
<span className={styles.resourceType}>{resource.type}</span>
|
||||
</TableCell>
|
||||
<TableCell>{resourceName}</TableCell>
|
||||
<TableCell colSpan={3}></TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
@ -91,8 +99,7 @@ export const Resources: FC<ResourcesProps> = ({
|
||||
{/* The rowspan should be the same than the number of agents */}
|
||||
{agentIndex === 0 && (
|
||||
<TableCell className={styles.resourceNameCell} rowSpan={agents.length}>
|
||||
{resource.name}
|
||||
<span className={styles.resourceType}>{resource.type}</span>
|
||||
{resourceName}
|
||||
</TableCell>
|
||||
)}
|
||||
|
||||
@ -149,6 +156,11 @@ const useStyles = makeStyles((theme) => ({
|
||||
border: 0,
|
||||
},
|
||||
|
||||
resourceAvatar: {
|
||||
color: "#FFF",
|
||||
backgroundColor: "#3B73D8",
|
||||
},
|
||||
|
||||
resourceNameCell: {
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
|
@ -17,11 +17,13 @@ export const getOverrides = (palette: PaletteOptions) => {
|
||||
},
|
||||
MuiAvatar: {
|
||||
root: {
|
||||
borderColor: palette.divider,
|
||||
width: 36,
|
||||
height: 36,
|
||||
fontSize: 18,
|
||||
},
|
||||
colorDefault: {
|
||||
backgroundColor: "#a1adc9",
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
root: {
|
||||
|
@ -28,4 +28,7 @@ export const darkPalette: PaletteOptions = {
|
||||
success: {
|
||||
main: "hsl(142, 58%, 41%)",
|
||||
},
|
||||
info: {
|
||||
main: "hsl(219, 67%, 54%)",
|
||||
},
|
||||
}
|
||||
|
Reference in New Issue
Block a user