11import { makeStyles } from "@mui/styles"
22import { useMachine } from "@xstate/react"
3- import { UpdateCheckResponse } from "api/typesGenerated"
43import { DeploymentBanner } from "components/DeploymentBanner/DeploymentBanner"
54import { LicenseBanner } from "components/LicenseBanner/LicenseBanner"
65import { Loader } from "components/Loader/Loader"
7- import { Margins } from "components/Margins/Margins"
86import { ServiceBanner } from "components/ServiceBanner/ServiceBanner"
9- import { UpdateCheckBanner } from "components/UpdateCheckBanner/UpdateCheckBanner"
107import { usePermissions } from "hooks/usePermissions"
118import { FC , Suspense } from "react"
129import { Outlet } from "react-router-dom"
1310import { dashboardContentBottomPadding } from "theme/constants"
1411import { updateCheckMachine } from "xServices/updateCheck/updateCheckXService"
1512import { Navbar } from "../Navbar/Navbar"
13+ import Snackbar from "@mui/material/Snackbar"
14+ import Link from "@mui/material/Link"
15+ import Box from "@mui/material/Box"
16+ import InfoOutlined from "@mui/icons-material/InfoOutlined"
17+ import Button from "@mui/material/Button"
1618
1719export const DashboardLayout :FC = ( ) => {
1820const styles = useStyles ( )
@@ -22,8 +24,7 @@ export const DashboardLayout: FC = () => {
2224 permissions,
2325} ,
2426} )
25- const { error :updateCheckError , updateCheck} = updateCheckState . context
26-
27+ const { updateCheck} = updateCheckState . context
2728const canViewDeployment = Boolean ( permissions . viewDeploymentValues )
2829
2930return (
@@ -34,48 +35,80 @@ export const DashboardLayout: FC = () => {
3435< div className = { styles . site } >
3536< Navbar />
3637
37- { updateCheckState . matches ( "show" ) && (
38- < div className = { styles . updateCheckBanner } >
39- < Margins >
40- < UpdateCheckBanner
41- // We can trust when it is show, the update check is filled
42- // unfortunately, XState does not has typed state - context yet
43- updateCheck = { updateCheck as UpdateCheckResponse }
44- error = { updateCheckError }
45- onDismiss = { ( ) => updateCheckSend ( "DISMISS" ) }
46- />
47- </ Margins >
48- </ div >
49- ) }
50-
5138< div className = { styles . siteContent } >
5239< Suspense fallback = { < Loader /> } >
5340< Outlet />
5441</ Suspense >
5542</ div >
5643
5744< DeploymentBanner />
45+
46+ < Snackbar
47+ data-testid = "update-check-snackbar"
48+ open = { updateCheckState . matches ( "show" ) }
49+ anchorOrigin = { {
50+ vertical :"bottom" ,
51+ horizontal :"right" ,
52+ } }
53+ ContentProps = { {
54+ sx :( theme ) => ( {
55+ background :theme . palette . background . paper ,
56+ color :theme . palette . text . primary ,
57+ maxWidth :theme . spacing ( 55 ) ,
58+ flexDirection :"row" ,
59+ borderColor :theme . palette . info . light ,
60+
61+ "& .MuiSnackbarContent-message" :{
62+ flex :1 ,
63+ } ,
64+
65+ "& .MuiSnackbarContent-action" :{
66+ marginRight :0 ,
67+ } ,
68+ } ) ,
69+ } }
70+ message = {
71+ < Box display = "flex" gap = { 2 } >
72+ < InfoOutlined
73+ sx = { ( theme ) => ( {
74+ fontSize :16 ,
75+ height :20 , // 20 is the height of the text line so we can align them
76+ color :theme . palette . info . light ,
77+ } ) }
78+ />
79+ < Box >
80+ Coder{ updateCheck ?. version } is now available. View the{ " " }
81+ < Link href = { updateCheck ?. url } > release notes</ Link > and{ " " }
82+ < Link href = "https://coder.com/docs/coder-oss/latest/admin/upgrade" >
83+ upgrade instructions
84+ </ Link > { " " }
85+ for more information.
86+ </ Box >
87+ </ Box >
88+ }
89+ action = {
90+ < Button
91+ variant = "text"
92+ size = "small"
93+ onClick = { ( ) => updateCheckSend ( "DISMISS" ) }
94+ >
95+ Dismiss
96+ </ Button >
97+ }
98+ />
5899</ div >
59100</ >
60101)
61102}
62103
63- const useStyles = makeStyles ( ( theme ) => ( {
104+ const useStyles = makeStyles ( {
64105site :{
65106display :"flex" ,
66107minHeight :"100vh" ,
67108flexDirection :"column" ,
68109} ,
69- updateCheckBanner :{
70- // Add spacing at the top and remove some from the bottom. Removal
71- // is necessary to avoid a visual jerk when the banner is dismissed.
72- // It also give a more pleasant distance to the site content when
73- // the banner is visible.
74- marginTop :theme . spacing ( 2 ) ,
75- marginBottom :theme . spacing ( - 2 ) ,
76- } ,
77110siteContent :{
78111flex :1 ,
79112paddingBottom :dashboardContentBottomPadding , // Add bottom space since we don't use a footer
80113} ,
81- } ) )
114+ } )