mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
Upgrade frontend to React 18 (#3353)
Co-authored-by: Kira Pilot <kira.pilot23@gmail.com>
This commit is contained in:
@ -39,16 +39,17 @@
|
|||||||
"cron-parser": "4.5.0",
|
"cron-parser": "4.5.0",
|
||||||
"cronstrue": "2.11.0",
|
"cronstrue": "2.11.0",
|
||||||
"dayjs": "1.11.4",
|
"dayjs": "1.11.4",
|
||||||
"formik": "2.2.9",
|
"formik": "^2.2.9",
|
||||||
"front-matter": "4.0.2",
|
"front-matter": "4.0.2",
|
||||||
"history": "5.3.0",
|
"history": "5.3.0",
|
||||||
"just-debounce-it": "3.0.1",
|
"just-debounce-it": "3.0.1",
|
||||||
"react": "17.0.2",
|
"react": "^18.2.0",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "18.2.0",
|
||||||
"react-helmet": "6.1.0",
|
"react-helmet-async": "1.3.0",
|
||||||
"react-markdown": "8.0.3",
|
"react-markdown": "8.0.3",
|
||||||
"react-router-dom": "6.3.0",
|
"react-router-dom": "6.3.0",
|
||||||
"sourcemapped-stacktrace": "1.1.11",
|
"sourcemapped-stacktrace": "1.1.11",
|
||||||
|
"swr": "1.3.0",
|
||||||
"tzdata": "1.0.30",
|
"tzdata": "1.0.30",
|
||||||
"uuid": "8.3.2",
|
"uuid": "8.3.2",
|
||||||
"xstate": "4.32.1",
|
"xstate": "4.32.1",
|
||||||
@ -70,13 +71,13 @@
|
|||||||
"@storybook/addon-links": "6.5.9",
|
"@storybook/addon-links": "6.5.9",
|
||||||
"@storybook/react": "6.4.22",
|
"@storybook/react": "6.4.22",
|
||||||
"@testing-library/jest-dom": "5.16.4",
|
"@testing-library/jest-dom": "5.16.4",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@testing-library/user-event": "14.3.0",
|
"@testing-library/user-event": "^14.4.3",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
"@types/jest": "27.4.1",
|
"@types/jest": "27.4.1",
|
||||||
"@types/node": "14.18.22",
|
"@types/node": "14.18.22",
|
||||||
"@types/react": "17.0.44",
|
"@types/react": "18.0.15",
|
||||||
"@types/react-dom": "17.0.16",
|
"@types/react-dom": "18.0.6",
|
||||||
"@types/react-helmet": "6.1.5",
|
"@types/react-helmet": "6.1.5",
|
||||||
"@types/superagent": "4.1.15",
|
"@types/superagent": "4.1.15",
|
||||||
"@types/uuid": "8.3.4",
|
"@types/uuid": "8.3.4",
|
||||||
@ -105,7 +106,7 @@
|
|||||||
"jest-runner-eslint": "1.0.0",
|
"jest-runner-eslint": "1.0.0",
|
||||||
"jest-websocket-mock": "2.3.0",
|
"jest-websocket-mock": "2.3.0",
|
||||||
"mini-css-extract-plugin": "2.6.1",
|
"mini-css-extract-plugin": "2.6.1",
|
||||||
"msw": "0.42.0",
|
"msw": "^0.44.2",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
"prettier-plugin-organize-imports": "3.0.0",
|
"prettier-plugin-organize-imports": "3.0.0",
|
||||||
"react-hot-loader": "4.13.0",
|
"react-hot-loader": "4.13.0",
|
||||||
|
@ -35,7 +35,6 @@ const AuditPage = lazy(() => import("./pages/AuditPage/AuditPage"))
|
|||||||
export const AppRouter: FC = () => {
|
export const AppRouter: FC = () => {
|
||||||
const xServices = useContext(XServiceContext)
|
const xServices = useContext(XServiceContext)
|
||||||
const permissions = useSelector(xServices.authXService, selectPermissions)
|
const permissions = useSelector(xServices.authXService, selectPermissions)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<></>}>
|
<Suspense fallback={<></>}>
|
||||||
<Routes>
|
<Routes>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { inspect } from "@xstate/inspect"
|
import { inspect } from "@xstate/inspect"
|
||||||
import ReactDOM from "react-dom"
|
import { createRoot } from "react-dom/client"
|
||||||
import { Interpreter } from "xstate"
|
import { Interpreter } from "xstate"
|
||||||
import { App } from "./app"
|
import { App } from "./app"
|
||||||
|
|
||||||
@ -25,7 +25,11 @@ const main = () => {
|
|||||||
██████▀▄█ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀
|
██████▀▄█ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀
|
||||||
`)
|
`)
|
||||||
const element = document.getElementById("root")
|
const element = document.getElementById("root")
|
||||||
ReactDOM.render(<App />, element)
|
if (element === null) {
|
||||||
|
throw new Error("root element is null")
|
||||||
|
}
|
||||||
|
const root = createRoot(element)
|
||||||
|
root.render(<App />)
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FC } from "react"
|
import { FC, PropsWithChildren } from "react"
|
||||||
|
|
||||||
const ReactMarkdown: FC = ({ children }) => {
|
const ReactMarkdown: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
return <div data-testid="markdown">{children}</div>
|
return <div data-testid="markdown">{children}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import CssBaseline from "@material-ui/core/CssBaseline"
|
import CssBaseline from "@material-ui/core/CssBaseline"
|
||||||
import ThemeProvider from "@material-ui/styles/ThemeProvider"
|
import ThemeProvider from "@material-ui/styles/ThemeProvider"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
|
import { HelmetProvider } from "react-helmet-async"
|
||||||
import { BrowserRouter as Router } from "react-router-dom"
|
import { BrowserRouter as Router } from "react-router-dom"
|
||||||
import { AppRouter } from "./AppRouter"
|
import { AppRouter } from "./AppRouter"
|
||||||
import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary"
|
import { ErrorBoundary } from "./components/ErrorBoundary/ErrorBoundary"
|
||||||
@ -12,15 +13,17 @@ import { XServiceProvider } from "./xServices/StateContext"
|
|||||||
export const App: FC = () => {
|
export const App: FC = () => {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<ThemeProvider theme={dark}>
|
<HelmetProvider>
|
||||||
<CssBaseline />
|
<ThemeProvider theme={dark}>
|
||||||
<ErrorBoundary>
|
<CssBaseline />
|
||||||
<XServiceProvider>
|
<ErrorBoundary>
|
||||||
<AppRouter />
|
<XServiceProvider>
|
||||||
<GlobalSnackbar />
|
<AppRouter />
|
||||||
</XServiceProvider>
|
<GlobalSnackbar />
|
||||||
</ErrorBoundary>
|
</XServiceProvider>
|
||||||
</ThemeProvider>
|
</ErrorBoundary>
|
||||||
|
</ThemeProvider>
|
||||||
|
</HelmetProvider>
|
||||||
</Router>
|
</Router>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Button from "@material-ui/core/Button"
|
|||||||
import Link from "@material-ui/core/Link"
|
import Link from "@material-ui/core/Link"
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import ComputerIcon from "@material-ui/icons/Computer"
|
import ComputerIcon from "@material-ui/icons/Computer"
|
||||||
import { FC } from "react"
|
import { FC, PropsWithChildren } from "react"
|
||||||
import * as TypesGen from "../../api/typesGenerated"
|
import * as TypesGen from "../../api/typesGenerated"
|
||||||
import { generateRandomString } from "../../util/random"
|
import { generateRandomString } from "../../util/random"
|
||||||
|
|
||||||
@ -17,7 +17,12 @@ export interface AppLinkProps {
|
|||||||
appIcon?: TypesGen.WorkspaceApp["icon"]
|
appIcon?: TypesGen.WorkspaceApp["icon"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppLink: FC<AppLinkProps> = ({ userName, workspaceName, appName, appIcon }) => {
|
export const AppLink: FC<PropsWithChildren<AppLinkProps>> = ({
|
||||||
|
userName,
|
||||||
|
workspaceName,
|
||||||
|
appName,
|
||||||
|
appIcon,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const href = `/@${userName}/${workspaceName}/apps/${appName}`
|
const href = `/@${userName}/${workspaceName}/apps/${appName}`
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Avatar from "@material-ui/core/Avatar"
|
import Avatar from "@material-ui/core/Avatar"
|
||||||
import Link from "@material-ui/core/Link"
|
import Link from "@material-ui/core/Link"
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { FC } from "react"
|
import { FC, PropsWithChildren } from "react"
|
||||||
import { Link as RouterLink } from "react-router-dom"
|
import { Link as RouterLink } from "react-router-dom"
|
||||||
import { firstLetter } from "../../util/firstLetter"
|
import { firstLetter } from "../../util/firstLetter"
|
||||||
import {
|
import {
|
||||||
@ -18,7 +18,7 @@ export interface AvatarDataProps {
|
|||||||
avatar?: React.ReactNode
|
avatar?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AvatarData: FC<AvatarDataProps> = ({
|
export const AvatarData: FC<PropsWithChildren<AvatarDataProps>> = ({
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
link,
|
link,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Popover, { PopoverProps } from "@material-ui/core/Popover"
|
import Popover, { PopoverProps } from "@material-ui/core/Popover"
|
||||||
import { fade, makeStyles } from "@material-ui/core/styles"
|
import { fade, makeStyles } from "@material-ui/core/styles"
|
||||||
import { FC } from "react"
|
import { FC, PropsWithChildren } from "react"
|
||||||
|
|
||||||
type BorderedMenuVariant = "admin-dropdown" | "user-dropdown"
|
type BorderedMenuVariant = "admin-dropdown" | "user-dropdown"
|
||||||
|
|
||||||
@ -8,7 +8,11 @@ export type BorderedMenuProps = Omit<PopoverProps, "variant"> & {
|
|||||||
variant?: BorderedMenuVariant
|
variant?: BorderedMenuVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BorderedMenu: FC<BorderedMenuProps> = ({ children, variant, ...rest }) => {
|
export const BorderedMenu: FC<PropsWithChildren<BorderedMenuProps>> = ({
|
||||||
|
children,
|
||||||
|
variant,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -26,7 +26,7 @@ interface BorderedMenuRowProps {
|
|||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BorderedMenuRow: FC<BorderedMenuRowProps> = ({
|
export const BorderedMenuRow: FC<React.PropsWithChildren<BorderedMenuRowProps>> = ({
|
||||||
active,
|
active,
|
||||||
description,
|
description,
|
||||||
Icon,
|
Icon,
|
||||||
|
@ -30,7 +30,10 @@ export interface BuildsTableProps {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BuildsTable: FC<BuildsTableProps> = ({ builds, className }) => {
|
export const BuildsTable: FC<React.PropsWithChildren<BuildsTableProps>> = ({
|
||||||
|
builds,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
const { username, workspace: workspaceName } = useParams()
|
const { username, workspace: workspaceName } = useParams()
|
||||||
const isLoading = !builds
|
const isLoading = !builds
|
||||||
const theme: Theme = useTheme()
|
const theme: Theme = useTheme()
|
||||||
|
@ -8,7 +8,7 @@ export interface CliAuthTokenProps {
|
|||||||
sessionToken: string
|
sessionToken: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CliAuthToken: FC<CliAuthTokenProps> = ({ sessionToken }) => {
|
export const CliAuthToken: FC<React.PropsWithChildren<CliAuthTokenProps>> = ({ sessionToken }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
return (
|
return (
|
||||||
<Paper className={styles.container}>
|
<Paper className={styles.container}>
|
||||||
|
@ -9,7 +9,11 @@ export interface CodeBlockProps {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodeBlock: FC<CodeBlockProps> = ({ lines, ctas, className = "" }) => {
|
export const CodeBlock: FC<React.PropsWithChildren<CodeBlockProps>> = ({
|
||||||
|
lines,
|
||||||
|
ctas,
|
||||||
|
className = "",
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -14,7 +14,7 @@ export interface CodeExampleProps {
|
|||||||
/**
|
/**
|
||||||
* Component to show single-line code examples, with a copy button
|
* Component to show single-line code examples, with a copy button
|
||||||
*/
|
*/
|
||||||
export const CodeExample: FC<CodeExampleProps> = ({
|
export const CodeExample: FC<React.PropsWithChildren<CodeExampleProps>> = ({
|
||||||
code,
|
code,
|
||||||
className,
|
className,
|
||||||
buttonClassName,
|
buttonClassName,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { fireEvent, render } from "@testing-library/react"
|
import { fireEvent, render } from "@testing-library/react"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import { act } from "react-dom/test-utils"
|
|
||||||
import { WrapperComponent } from "../../testHelpers/renderHelpers"
|
import { WrapperComponent } from "../../testHelpers/renderHelpers"
|
||||||
import { ConfirmDialog, ConfirmDialogProps } from "./ConfirmDialog"
|
import { ConfirmDialog, ConfirmDialogProps } from "./ConfirmDialog"
|
||||||
|
|
||||||
namespace Helpers {
|
namespace Helpers {
|
||||||
export const Component: FC<ConfirmDialogProps> = (props: ConfirmDialogProps) => {
|
export const Component: FC<React.PropsWithChildren<ConfirmDialogProps>> = (
|
||||||
|
props: ConfirmDialogProps,
|
||||||
|
) => {
|
||||||
return (
|
return (
|
||||||
<WrapperComponent>
|
<WrapperComponent>
|
||||||
<ConfirmDialog {...props} />
|
<ConfirmDialog {...props} />
|
||||||
@ -116,9 +117,7 @@ describe("ConfirmDialog", () => {
|
|||||||
|
|
||||||
// When
|
// When
|
||||||
const { getByText } = render(<Helpers.Component {...props} />)
|
const { getByText } = render(<Helpers.Component {...props} />)
|
||||||
act(() => {
|
fireEvent.click(getByText("CANCEL"))
|
||||||
fireEvent.click(getByText("CANCEL"))
|
|
||||||
})
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(onCloseMock).toBeCalledTimes(1)
|
expect(onCloseMock).toBeCalledTimes(1)
|
||||||
@ -140,9 +139,7 @@ describe("ConfirmDialog", () => {
|
|||||||
|
|
||||||
// When
|
// When
|
||||||
const { getByText } = render(<Helpers.Component {...props} />)
|
const { getByText } = render(<Helpers.Component {...props} />)
|
||||||
act(() => {
|
fireEvent.click(getByText("CONFIRM"))
|
||||||
fireEvent.click(getByText("CONFIRM"))
|
|
||||||
})
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(onCloseMock).toBeCalledTimes(0)
|
expect(onCloseMock).toBeCalledTimes(0)
|
||||||
|
@ -78,7 +78,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
* Quick-use version of the Dialog component with slightly alternative styles,
|
* Quick-use version of the Dialog component with slightly alternative styles,
|
||||||
* great to use for dialogs that don't have any interaction beyond yes / no.
|
* great to use for dialogs that don't have any interaction beyond yes / no.
|
||||||
*/
|
*/
|
||||||
export const ConfirmDialog: React.FC<ConfirmDialogProps> = ({
|
export const ConfirmDialog: React.FC<React.PropsWithChildren<ConfirmDialogProps>> = ({
|
||||||
cancelText,
|
cancelText,
|
||||||
confirmLoading,
|
confirmLoading,
|
||||||
confirmText,
|
confirmText,
|
||||||
|
@ -22,7 +22,7 @@ export const Language = {
|
|||||||
/**
|
/**
|
||||||
* Copy button used inside the CodeBlock component internally
|
* Copy button used inside the CodeBlock component internally
|
||||||
*/
|
*/
|
||||||
export const CopyButton: React.FC<CopyButtonProps> = ({
|
export const CopyButton: React.FC<React.PropsWithChildren<CopyButtonProps>> = ({
|
||||||
text,
|
text,
|
||||||
ctaCopy,
|
ctaCopy,
|
||||||
wrapperClassName = "",
|
wrapperClassName = "",
|
||||||
|
@ -35,7 +35,7 @@ const validationSchema = Yup.object({
|
|||||||
username: nameValidator(Language.usernameLabel),
|
username: nameValidator(Language.usernameLabel),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const CreateUserForm: FC<CreateUserFormProps> = ({
|
export const CreateUserForm: FC<React.PropsWithChildren<CreateUserFormProps>> = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
formErrors,
|
formErrors,
|
||||||
|
@ -12,11 +12,9 @@ export interface DeleteWorkspaceDialogProps {
|
|||||||
handleCancel: () => void
|
handleCancel: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeleteWorkspaceDialog: React.FC<DeleteWorkspaceDialogProps> = ({
|
export const DeleteWorkspaceDialog: React.FC<
|
||||||
isOpen,
|
React.PropsWithChildren<DeleteWorkspaceDialogProps>
|
||||||
handleCancel,
|
> = ({ isOpen, handleCancel, handleConfirm }) => (
|
||||||
handleConfirm,
|
|
||||||
}) => (
|
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
type="delete"
|
type="delete"
|
||||||
hideCancel={false}
|
hideCancel={false}
|
||||||
|
@ -23,7 +23,7 @@ export interface EmptyStateProps {
|
|||||||
* EmptyState's props extend the [Material UI Box component](https://material-ui.com/components/box/)
|
* EmptyState's props extend the [Material UI Box component](https://material-ui.com/components/box/)
|
||||||
* that you can directly pass props through to to customize the shape and layout of it.
|
* that you can directly pass props through to to customize the shape and layout of it.
|
||||||
*/
|
*/
|
||||||
export const EmptyState: FC<EmptyStateProps> = (props) => {
|
export const EmptyState: FC<React.PropsWithChildren<EmptyStateProps>> = (props) => {
|
||||||
const { message, description, cta, descriptionClassName, className, ...boxProps } = props
|
const { message, description, cta, descriptionClassName, className, ...boxProps } = props
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export interface EnterpriseSnackbarProps extends MuiSnackbarProps {
|
|||||||
*
|
*
|
||||||
* See original component's Material UI documentation here: https://material-ui.com/components/snackbars/
|
* See original component's Material UI documentation here: https://material-ui.com/components/snackbars/
|
||||||
*/
|
*/
|
||||||
export const EnterpriseSnackbar: FC<EnterpriseSnackbarProps> = ({
|
export const EnterpriseSnackbar: FC<React.PropsWithChildren<EnterpriseSnackbarProps>> = ({
|
||||||
onClose,
|
onClose,
|
||||||
variant = "info",
|
variant = "info",
|
||||||
ContentProps = {},
|
ContentProps = {},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, ReactNode } from "react"
|
import React, { Component, ReactNode } from "react"
|
||||||
import { RuntimeErrorState } from "../RuntimeErrorState/RuntimeErrorState"
|
import { RuntimeErrorState } from "../RuntimeErrorState/RuntimeErrorState"
|
||||||
|
|
||||||
type ErrorBoundaryProps = Record<string, unknown>
|
type ErrorBoundaryProps = React.PropsWithChildren<unknown>
|
||||||
|
|
||||||
interface ErrorBoundaryState {
|
interface ErrorBoundaryState {
|
||||||
error: Error | null
|
error: Error | null
|
||||||
|
@ -23,7 +23,7 @@ export interface ErrorSummaryProps {
|
|||||||
defaultMessage?: string
|
defaultMessage?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ErrorSummary: FC<ErrorSummaryProps> = ({
|
export const ErrorSummary: FC<React.PropsWithChildren<ErrorSummaryProps>> = ({
|
||||||
error,
|
error,
|
||||||
retry,
|
retry,
|
||||||
dismissible,
|
dismissible,
|
||||||
|
@ -18,7 +18,7 @@ export interface FooterProps {
|
|||||||
buildInfo?: TypesGen.BuildInfoResponse
|
buildInfo?: TypesGen.BuildInfoResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Footer: React.FC<FooterProps> = ({ buildInfo }) => {
|
export const Footer: React.FC<React.PropsWithChildren<FooterProps>> = ({ buildInfo }) => {
|
||||||
const styles = useFooterStyles()
|
const styles = useFooterStyles()
|
||||||
|
|
||||||
const githubUrl = `https://github.com/coder/coder/issues/new?labels=needs+grooming&body=${encodeURIComponent(`Version: [\`${buildInfo?.version}\`](${buildInfo?.external_url})
|
const githubUrl = `https://github.com/coder/coder/issues/new?labels=needs+grooming&body=${encodeURIComponent(`Version: [\`${buildInfo?.version}\`](${buildInfo?.external_url})
|
||||||
|
@ -8,7 +8,9 @@ export interface FormCloseButtonProps {
|
|||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormCloseButton: React.FC<FormCloseButtonProps> = ({ onClose }) => {
|
export const FormCloseButton: React.FC<React.PropsWithChildren<FormCloseButtonProps>> = ({
|
||||||
|
onClose,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -28,7 +28,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const FormFooter: FC<FormFooterProps> = ({
|
export const FormFooter: FC<React.PropsWithChildren<FormFooterProps>> = ({
|
||||||
onCancel,
|
onCancel,
|
||||||
isLoading,
|
isLoading,
|
||||||
submitLabel = Language.defaultSubmitLabel,
|
submitLabel = Language.defaultSubmitLabel,
|
||||||
|
@ -39,7 +39,11 @@ export const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const FormSection: FC<FormSectionProps> = ({ title, description, children }) => {
|
export const FormSection: FC<React.PropsWithChildren<FormSectionProps>> = ({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { act, fireEvent, render, screen } from "@testing-library/react"
|
import { fireEvent, render, screen } from "@testing-library/react"
|
||||||
import { useFormik } from "formik"
|
import { useFormik } from "formik"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import * as yup from "yup"
|
import * as yup from "yup"
|
||||||
@ -11,9 +11,9 @@ namespace Helpers {
|
|||||||
|
|
||||||
export const requiredValidationMsg = "required"
|
export const requiredValidationMsg = "required"
|
||||||
|
|
||||||
export const Component: FC<Omit<FormTextFieldProps<FormValues>, "form" | "formFieldName">> = (
|
export const Component: FC<
|
||||||
props,
|
React.PropsWithChildren<Omit<FormTextFieldProps<FormValues>, "form" | "formFieldName">>
|
||||||
) => {
|
> = (props) => {
|
||||||
const form = useFormik<FormValues>({
|
const form = useFormik<FormValues>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -58,17 +58,13 @@ describe("FormTextField", () => {
|
|||||||
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()
|
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()
|
||||||
|
|
||||||
// When
|
// When
|
||||||
act(() => {
|
fireEvent.focus(el as Element)
|
||||||
fireEvent.focus(el as Element)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()
|
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeNull()
|
||||||
|
|
||||||
// When
|
// When
|
||||||
act(() => {
|
fireEvent.blur(el as Element)
|
||||||
fireEvent.blur(el as Element)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeDefined()
|
expect(screen.queryByText(Helpers.requiredValidationMsg)).toBeDefined()
|
||||||
|
@ -134,7 +134,7 @@ export const FormTextField = <T,>({
|
|||||||
variant={variant}
|
variant={variant}
|
||||||
disabled={disabled || form.isSubmitting}
|
disabled={disabled || form.isSubmitting}
|
||||||
error={isError}
|
error={isError}
|
||||||
helperText={isError ? form.errors[formFieldName] : helperText}
|
helperText={isError ? form.errors[formFieldName]?.toString() : helperText}
|
||||||
id={fieldId}
|
id={fieldId}
|
||||||
InputProps={isPassword ? undefined : InputProps}
|
InputProps={isPassword ? undefined : InputProps}
|
||||||
name={fieldId}
|
name={fieldId}
|
||||||
|
@ -18,7 +18,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const FormTitle: FC<FormTitleProps> = ({ title, detail }) => {
|
export const FormTitle: FC<React.PropsWithChildren<FormTitleProps>> = ({ title, detail }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -19,7 +19,12 @@ const useStyles = makeStyles(() => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const FullPageForm: FC<FullPageFormProps> = ({ title, detail, onCancel, children }) => {
|
export const FullPageForm: FC<React.PropsWithChildren<FullPageFormProps>> = ({
|
||||||
|
title,
|
||||||
|
detail,
|
||||||
|
onCancel,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
return (
|
return (
|
||||||
<main className={styles.root}>
|
<main className={styles.root}>
|
||||||
|
@ -2,7 +2,7 @@ import Box from "@material-ui/core/Box"
|
|||||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
import CircularProgress from "@material-ui/core/CircularProgress"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
|
|
||||||
export const Loader: FC<{ size?: number }> = ({ size = 26 }) => {
|
export const Loader: FC<React.PropsWithChildren<{ size?: number }>> = ({ size = 26 }) => {
|
||||||
return (
|
return (
|
||||||
<Box p={4} width="100%" display="flex" alignItems="center" justifyContent="center">
|
<Box p={4} width="100%" display="flex" alignItems="center" justifyContent="center">
|
||||||
<CircularProgress size={size} />
|
<CircularProgress size={size} />
|
||||||
|
@ -17,7 +17,7 @@ export interface LoadingButtonProps extends ButtonProps {
|
|||||||
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
|
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
|
||||||
* we have to roll our own.
|
* we have to roll our own.
|
||||||
*/
|
*/
|
||||||
export const LoadingButton: FC<LoadingButtonProps> = ({
|
export const LoadingButton: FC<React.PropsWithChildren<LoadingButtonProps>> = ({
|
||||||
loading = false,
|
loading = false,
|
||||||
loadingLabel,
|
loadingLabel,
|
||||||
children,
|
children,
|
||||||
|
@ -14,7 +14,7 @@ export interface LogsProps {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Logs: FC<LogsProps> = ({ lines, className = "" }) => {
|
export const Logs: FC<React.PropsWithChildren<LogsProps>> = ({ lines, className = "" }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -24,7 +24,10 @@ interface MarginsProps {
|
|||||||
size?: Size
|
size?: Size
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Margins: FC<MarginsProps> = ({ children, size = "regular" }) => {
|
export const Margins: FC<React.PropsWithChildren<MarginsProps>> = ({
|
||||||
|
children,
|
||||||
|
size = "regular",
|
||||||
|
}) => {
|
||||||
const styles = useStyles({ maxWidth: widthBySize[size] })
|
const styles = useStyles({ maxWidth: widthBySize[size] })
|
||||||
return <div className={styles.margins}>{children}</div>
|
return <div className={styles.margins}>{children}</div>
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,9 @@ export const Language = {
|
|||||||
audit: "Audit",
|
audit: "Audit",
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavItems: React.FC<{ className?: string; canViewAuditLog: boolean }> = ({
|
const NavItems: React.FC<
|
||||||
className,
|
React.PropsWithChildren<{ className?: string; canViewAuditLog: boolean }>
|
||||||
canViewAuditLog,
|
> = ({ className, canViewAuditLog }) => {
|
||||||
}) => {
|
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
|
||||||
@ -63,8 +62,11 @@ const NavItems: React.FC<{ className?: string; canViewAuditLog: boolean }> = ({
|
|||||||
</List>
|
</List>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
export const NavbarView: React.FC<React.PropsWithChildren<NavbarViewProps>> = ({
|
||||||
export const NavbarView: React.FC<NavbarViewProps> = ({ user, onSignOut, canViewAuditLog }) => {
|
user,
|
||||||
|
onSignOut,
|
||||||
|
canViewAuditLog,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
||||||
|
|
||||||
|
@ -7,7 +7,11 @@ export interface PageHeaderProps {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageHeader: React.FC<PageHeaderProps> = ({ children, actions, className }) => {
|
export const PageHeader: React.FC<React.PropsWithChildren<PageHeaderProps>> = ({
|
||||||
|
children,
|
||||||
|
actions,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -22,13 +26,13 @@ export const PageHeader: React.FC<PageHeaderProps> = ({ children, actions, class
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageHeaderTitle: React.FC = ({ children }) => {
|
export const PageHeaderTitle: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return <h1 className={styles.title}>{children}</h1>
|
return <h1 className={styles.title}>{children}</h1>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PageHeaderSubtitle: React.FC = ({ children }) => {
|
export const PageHeaderSubtitle: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return <h2 className={styles.subtitle}>{children}</h2>
|
return <h2 className={styles.subtitle}>{children}</h2>
|
||||||
|
@ -29,7 +29,11 @@ export interface ParameterInputProps {
|
|||||||
onChange: (value: string) => void
|
onChange: (value: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ParameterInput: FC<ParameterInputProps> = ({ disabled, onChange, schema }) => {
|
export const ParameterInput: FC<React.PropsWithChildren<ParameterInputProps>> = ({
|
||||||
|
disabled,
|
||||||
|
onChange,
|
||||||
|
schema,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -42,7 +46,11 @@ export const ParameterInput: FC<ParameterInputProps> = ({ disabled, onChange, sc
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParameterField: React.FC<ParameterInputProps> = ({ disabled, onChange, schema }) => {
|
const ParameterField: React.FC<React.PropsWithChildren<ParameterInputProps>> = ({
|
||||||
|
disabled,
|
||||||
|
onChange,
|
||||||
|
schema,
|
||||||
|
}) => {
|
||||||
if (schema.validation_contains && schema.validation_contains.length > 0) {
|
if (schema.validation_contains && schema.validation_contains.length > 0) {
|
||||||
return (
|
return (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
@ -8,7 +8,10 @@ import React, { useCallback, useState } from "react"
|
|||||||
|
|
||||||
type PasswordFieldProps = Omit<TextFieldProps, "InputProps" | "type">
|
type PasswordFieldProps = Omit<TextFieldProps, "InputProps" | "type">
|
||||||
|
|
||||||
export const PasswordField: React.FC<PasswordFieldProps> = ({ variant = "outlined", ...rest }) => {
|
export const PasswordField: React.FC<React.PropsWithChildren<PasswordFieldProps>> = ({
|
||||||
|
variant = "outlined",
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const [showPassword, setShowPassword] = useState<boolean>(false)
|
const [showPassword, setShowPassword] = useState<boolean>(false)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ export interface RequireAuthProps {
|
|||||||
children: JSX.Element
|
children: JSX.Element
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RequireAuth: React.FC<RequireAuthProps> = ({ children }) => {
|
export const RequireAuth: React.FC<React.PropsWithChildren<RequireAuthProps>> = ({ children }) => {
|
||||||
const xServices = useContext(XServiceContext)
|
const xServices = useContext(XServiceContext)
|
||||||
const [authState] = useActor(xServices.authXService)
|
const [authState] = useActor(xServices.authXService)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
@ -24,7 +24,7 @@ export const Language = {
|
|||||||
confirmText: "Reset password",
|
confirmText: "Reset password",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ResetPasswordDialog: FC<ResetPasswordDialogProps> = ({
|
export const ResetPasswordDialog: FC<React.PropsWithChildren<ResetPasswordDialogProps>> = ({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
|
@ -33,7 +33,7 @@ interface ResourcesProps {
|
|||||||
canUpdateWorkspace: boolean
|
canUpdateWorkspace: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Resources: FC<ResourcesProps> = ({
|
export const Resources: FC<React.PropsWithChildren<ResourcesProps>> = ({
|
||||||
resources,
|
resources,
|
||||||
getResourcesError,
|
getResourcesError,
|
||||||
workspace,
|
workspace,
|
||||||
|
@ -16,7 +16,7 @@ export interface RoleSelectProps {
|
|||||||
open?: boolean
|
open?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RoleSelect: FC<RoleSelectProps> = ({
|
export const RoleSelect: FC<React.PropsWithChildren<RoleSelectProps>> = ({
|
||||||
roles,
|
roles,
|
||||||
selectedRoles,
|
selectedRoles,
|
||||||
loading,
|
loading,
|
||||||
|
@ -13,7 +13,7 @@ export interface SSHButtonProps {
|
|||||||
defaultIsOpen?: boolean
|
defaultIsOpen?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SSHButton: React.FC<SSHButtonProps> = ({
|
export const SSHButton: React.FC<React.PropsWithChildren<SSHButtonProps>> = ({
|
||||||
workspaceName,
|
workspaceName,
|
||||||
agentName,
|
agentName,
|
||||||
defaultIsOpen = false,
|
defaultIsOpen = false,
|
||||||
|
@ -36,7 +36,7 @@ interface FilterFormValues {
|
|||||||
|
|
||||||
export type FilterFormErrors = FormikErrors<FilterFormValues>
|
export type FilterFormErrors = FormikErrors<FilterFormValues>
|
||||||
|
|
||||||
export const SearchBarWithFilter: React.FC<SearchBarWithFilterProps> = ({
|
export const SearchBarWithFilter: React.FC<React.PropsWithChildren<SearchBarWithFilterProps>> = ({
|
||||||
filter,
|
filter,
|
||||||
onFilter,
|
onFilter,
|
||||||
presetFilters,
|
presetFilters,
|
||||||
|
@ -17,7 +17,7 @@ export interface SectionProps {
|
|||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
type SectionFC = FC<SectionProps> & { Action: typeof SectionAction }
|
type SectionFC = FC<React.PropsWithChildren<SectionProps>> & { Action: typeof SectionAction }
|
||||||
|
|
||||||
export const Section: SectionFC = ({
|
export const Section: SectionFC = ({
|
||||||
title,
|
title,
|
||||||
|
@ -11,7 +11,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
* SectionAction is a content box that call to actions should be placed
|
* SectionAction is a content box that call to actions should be placed
|
||||||
* within
|
* within
|
||||||
*/
|
*/
|
||||||
export const SectionAction: FC = ({ children }) => {
|
export const SectionAction: FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
return <div className={styles.root}>{children}</div>
|
return <div className={styles.root}>{children}</div>
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export interface AccountFormProps {
|
|||||||
initialTouched?: FormikTouched<AccountFormValues>
|
initialTouched?: FormikTouched<AccountFormValues>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AccountForm: FC<AccountFormProps> = ({
|
export const AccountForm: FC<React.PropsWithChildren<AccountFormProps>> = ({
|
||||||
email,
|
email,
|
||||||
isLoading,
|
isLoading,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
@ -51,7 +51,7 @@ export const AccountForm: FC<AccountFormProps> = ({
|
|||||||
<>
|
<>
|
||||||
<form onSubmit={form.handleSubmit}>
|
<form onSubmit={form.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
{updateProfileError && <ErrorSummary error={updateProfileError} />}
|
{updateProfileError ? <ErrorSummary error={updateProfileError} /> : <></>}
|
||||||
<TextField
|
<TextField
|
||||||
disabled
|
disabled
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Box from "@material-ui/core/Box"
|
import Box from "@material-ui/core/Box"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { Outlet } from "react-router-dom"
|
import { Outlet } from "react-router-dom"
|
||||||
import { pageTitle } from "../../util/page"
|
import { pageTitle } from "../../util/page"
|
||||||
import { AuthAndFrame } from "../AuthAndFrame/AuthAndFrame"
|
import { AuthAndFrame } from "../AuthAndFrame/AuthAndFrame"
|
||||||
|
@ -68,7 +68,7 @@ export const SecurityForm: React.FC<SecurityFormProps> = ({
|
|||||||
<>
|
<>
|
||||||
<form onSubmit={form.handleSubmit}>
|
<form onSubmit={form.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
{updateSecurityError && <ErrorSummary error={updateSecurityError} />}
|
{updateSecurityError ? <ErrorSummary error={updateSecurityError} /> : <></>}
|
||||||
<TextField
|
<TextField
|
||||||
{...getFieldHelpers("old_password")}
|
{...getFieldHelpers("old_password")}
|
||||||
onChange={onChangeTrimmed(form)}
|
onChange={onChangeTrimmed(form)}
|
||||||
|
@ -89,7 +89,7 @@ export interface SignInFormProps {
|
|||||||
initialTouched?: FormikTouched<BuiltInAuthFormValues>
|
initialTouched?: FormikTouched<BuiltInAuthFormValues>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SignInForm: FC<SignInFormProps> = ({
|
export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
|
||||||
authMethods,
|
authMethods,
|
||||||
redirectTo,
|
redirectTo,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { FC } from "react"
|
import { FC, ReactNode } from "react"
|
||||||
import { Footer } from "../../components/Footer/Footer"
|
import { Footer } from "../../components/Footer/Footer"
|
||||||
|
|
||||||
export const useStyles = makeStyles((theme) => ({
|
export const useStyles = makeStyles((theme) => ({
|
||||||
@ -21,7 +21,7 @@ export const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const SignInLayout: FC = ({ children }) => {
|
export const SignInLayout: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import Button, { ButtonProps } from "@material-ui/core/Button"
|
import Button, { ButtonProps } from "@material-ui/core/Button"
|
||||||
import ButtonGroup from "@material-ui/core/ButtonGroup"
|
import ButtonGroup from "@material-ui/core/ButtonGroup"
|
||||||
import ClickAwayListener from "@material-ui/core/ClickAwayListener"
|
import ClickAwayListener from "@material-ui/core/ClickAwayListener"
|
||||||
import Grow from "@material-ui/core/Grow"
|
|
||||||
import MenuItem from "@material-ui/core/MenuItem"
|
import MenuItem from "@material-ui/core/MenuItem"
|
||||||
import MenuList from "@material-ui/core/MenuList"
|
import MenuList from "@material-ui/core/MenuList"
|
||||||
import Paper from "@material-ui/core/Paper"
|
import Paper from "@material-ui/core/Paper"
|
||||||
@ -30,7 +29,7 @@ export interface SplitButtonProps<T> extends Pick<ButtonProps, "color" | "disabl
|
|||||||
*/
|
*/
|
||||||
options: SplitButtonOptions<T>[]
|
options: SplitButtonOptions<T>[]
|
||||||
/**
|
/**
|
||||||
* textTransform is applied to the primary button text. Defaults to
|
* textTransform is applied to the primary button text. Defaults PropsWithto
|
||||||
* uppercase
|
* uppercase
|
||||||
*/
|
*/
|
||||||
textTransform?: React.CSSProperties["textTransform"]
|
textTransform?: React.CSSProperties["textTransform"]
|
||||||
@ -104,25 +103,18 @@ export const SplitButton = <T,>({
|
|||||||
style={{ zIndex: 1 }}
|
style={{ zIndex: 1 }}
|
||||||
transition
|
transition
|
||||||
>
|
>
|
||||||
{({ TransitionProps, placement }) => (
|
{() => (
|
||||||
<Grow
|
<Paper>
|
||||||
{...TransitionProps}
|
<ClickAwayListener onClickAway={handleClose}>
|
||||||
style={{
|
<MenuList id="split-button-menu">
|
||||||
transformOrigin: placement === "bottom" ? "center top" : "center bottom",
|
{options.map((opt, idx) => (
|
||||||
}}
|
<MenuItem key={opt.label} onClick={(e) => handleSelectOpt(e, idx)}>
|
||||||
>
|
{opt.label}
|
||||||
<Paper>
|
</MenuItem>
|
||||||
<ClickAwayListener onClickAway={handleClose}>
|
))}
|
||||||
<MenuList id="split-button-menu">
|
</MenuList>
|
||||||
{options.map((opt, idx) => (
|
</ClickAwayListener>
|
||||||
<MenuItem key={opt.label} onClick={(e) => handleSelectOpt(e, idx)}>
|
</Paper>
|
||||||
{opt.label}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</MenuList>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
)}
|
||||||
</Popper>
|
</Popper>
|
||||||
</>
|
</>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { CSSProperties } from "@material-ui/core/styles/withStyles"
|
import { CSSProperties } from "@material-ui/core/styles/withStyles"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
|
import { ReactNode } from "react-markdown/lib/react-markdown"
|
||||||
import { combineClasses } from "../../util/combineClasses"
|
import { combineClasses } from "../../util/combineClasses"
|
||||||
|
|
||||||
type Direction = "column" | "row"
|
type Direction = "column" | "row"
|
||||||
@ -29,7 +30,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const Stack: FC<StackProps> = ({
|
export const Stack: FC<StackProps & { children: ReactNode | ReactNode[] }> = ({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
direction = "column",
|
direction = "column",
|
||||||
@ -37,7 +38,12 @@ export const Stack: FC<StackProps> = ({
|
|||||||
alignItems,
|
alignItems,
|
||||||
justifyContent,
|
justifyContent,
|
||||||
}) => {
|
}) => {
|
||||||
const styles = useStyles({ spacing, direction, alignItems, justifyContent })
|
const styles = useStyles({
|
||||||
|
spacing,
|
||||||
|
direction,
|
||||||
|
alignItems,
|
||||||
|
justifyContent,
|
||||||
|
})
|
||||||
|
|
||||||
return <div className={combineClasses([styles.stack, className])}>{children}</div>
|
return <div className={combineClasses([styles.stack, className])}>{children}</div>
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,11 @@ export interface TabPanelProps {
|
|||||||
menuItems: TabSidebarItem[]
|
menuItems: TabSidebarItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabPanel: FC<TabPanelProps> = ({ children, title, menuItems }) => {
|
export const TabPanel: FC<React.PropsWithChildren<TabPanelProps>> = ({
|
||||||
|
children,
|
||||||
|
title,
|
||||||
|
menuItems,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -16,7 +16,7 @@ export interface TabSidebarProps {
|
|||||||
menuItems: TabSidebarItem[]
|
menuItems: TabSidebarItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabSidebar: FC<TabSidebarProps> = ({ menuItems }) => {
|
export const TabSidebar: FC<React.PropsWithChildren<TabSidebarProps>> = ({ menuItems }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import React from "react"
|
import React, { ReactNode } from "react"
|
||||||
import { Stack } from "../Stack/Stack"
|
import { Stack } from "../Stack/Stack"
|
||||||
|
|
||||||
interface StyleProps {
|
interface StyleProps {
|
||||||
highlight?: boolean
|
highlight?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableCellData: React.FC = ({ children }) => {
|
export const TableCellData: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
return <Stack spacing={0}>{children}</Stack>
|
return <Stack spacing={0}>{children}</Stack>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableCellDataPrimary: React.FC<{ highlight?: boolean }> = ({
|
export const TableCellDataPrimary: React.FC<React.PropsWithChildren<{ highlight?: boolean }>> = ({
|
||||||
children,
|
children,
|
||||||
highlight,
|
highlight,
|
||||||
}) => {
|
}) => {
|
||||||
@ -19,7 +19,9 @@ export const TableCellDataPrimary: React.FC<{ highlight?: boolean }> = ({
|
|||||||
return <span className={styles.primary}>{children}</span>
|
return <span className={styles.primary}>{children}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableCellDataSecondary: React.FC = ({ children }) => {
|
export const TableCellDataSecondary: React.FC<React.PropsWithChildren<unknown>> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return <span className={styles.secondary}>{children}</span>
|
return <span className={styles.secondary}>{children}</span>
|
||||||
|
@ -7,9 +7,11 @@ import { combineClasses } from "../../util/combineClasses"
|
|||||||
// TableCellLink wraps a TableCell filling the entirety with a Link.
|
// TableCellLink wraps a TableCell filling the entirety with a Link.
|
||||||
// This allows table rows to be clickable with browser-behavior like ctrl+click.
|
// This allows table rows to be clickable with browser-behavior like ctrl+click.
|
||||||
export const TableCellLink: React.FC<
|
export const TableCellLink: React.FC<
|
||||||
TableCellProps & {
|
React.PropsWithChildren<
|
||||||
to: string
|
TableCellProps & {
|
||||||
}
|
to: string
|
||||||
|
}
|
||||||
|
>
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
|
@ -1,26 +1,6 @@
|
|||||||
import TableCell from "@material-ui/core/TableCell"
|
|
||||||
import TableRow from "@material-ui/core/TableRow"
|
import TableRow from "@material-ui/core/TableRow"
|
||||||
import { FC } from "react"
|
import { FC, ReactNode } from "react"
|
||||||
|
|
||||||
export interface TableHeadersProps {
|
export const TableHeaderRow: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
columns: string[]
|
|
||||||
hasMenu?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TableHeaderRow: FC = ({ children }) => {
|
|
||||||
return <TableRow>{children}</TableRow>
|
return <TableRow>{children}</TableRow>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TableHeaders: FC<TableHeadersProps> = ({ columns, hasMenu }) => {
|
|
||||||
return (
|
|
||||||
<TableHeaderRow>
|
|
||||||
{columns.map((c, idx) => (
|
|
||||||
<TableCell key={idx} size="small">
|
|
||||||
{c}
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
{/* 1% is a trick to make the table cell width fit the content */}
|
|
||||||
{hasMenu && <TableCell width="1%" />}
|
|
||||||
</TableHeaderRow>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,7 @@ import { Language as AgentTooltipLanguage } from "../Tooltips/AgentHelpTooltip"
|
|||||||
import { Language as ResourceTooltipLanguage } from "../Tooltips/ResourcesHelpTooltip"
|
import { Language as ResourceTooltipLanguage } from "../Tooltips/ResourcesHelpTooltip"
|
||||||
import { TemplateResourcesProps, TemplateResourcesTable } from "./TemplateResourcesTable"
|
import { TemplateResourcesProps, TemplateResourcesTable } from "./TemplateResourcesTable"
|
||||||
|
|
||||||
const Component: FC<TemplateResourcesProps> = (props) => (
|
const Component: FC<React.PropsWithChildren<TemplateResourcesProps>> = (props) => (
|
||||||
<WrapperComponent>
|
<WrapperComponent>
|
||||||
<TemplateResourcesTable {...props} />
|
<TemplateResourcesTable {...props} />
|
||||||
</WrapperComponent>
|
</WrapperComponent>
|
||||||
|
@ -23,7 +23,9 @@ export interface TemplateResourcesProps {
|
|||||||
resources: WorkspaceResource[]
|
resources: WorkspaceResource[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TemplateResourcesTable: FC<TemplateResourcesProps> = ({ resources }) => {
|
export const TemplateResourcesTable: FC<React.PropsWithChildren<TemplateResourcesProps>> = ({
|
||||||
|
resources,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -26,7 +26,7 @@ export interface TerminalLinkProps {
|
|||||||
* If no user name is provided "me" is used however it makes the link not
|
* If no user name is provided "me" is used however it makes the link not
|
||||||
* shareable.
|
* shareable.
|
||||||
*/
|
*/
|
||||||
export const TerminalLink: FC<TerminalLinkProps> = ({
|
export const TerminalLink: FC<React.PropsWithChildren<TerminalLinkProps>> = ({
|
||||||
agentName,
|
agentName,
|
||||||
userName = "me",
|
userName = "me",
|
||||||
workspaceName,
|
workspaceName,
|
||||||
|
@ -33,7 +33,11 @@ const useHelpTooltip = () => {
|
|||||||
return helpTooltipContext
|
return helpTooltipContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltip: React.FC<HelpTooltipProps> = ({ children, open, size = "medium" }) => {
|
export const HelpTooltip: React.FC<React.PropsWithChildren<HelpTooltipProps>> = ({
|
||||||
|
children,
|
||||||
|
open,
|
||||||
|
size = "medium",
|
||||||
|
}) => {
|
||||||
const styles = useStyles({ size })
|
const styles = useStyles({ size })
|
||||||
const anchorRef = useRef<HTMLButtonElement>(null)
|
const anchorRef = useRef<HTMLButtonElement>(null)
|
||||||
const [isOpen, setIsOpen] = useState(!!open)
|
const [isOpen, setIsOpen] = useState(!!open)
|
||||||
@ -92,19 +96,22 @@ export const HelpTooltip: React.FC<HelpTooltipProps> = ({ children, open, size =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltipTitle: React.FC = ({ children }) => {
|
export const HelpTooltipTitle: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return <h4 className={styles.title}>{children}</h4>
|
return <h4 className={styles.title}>{children}</h4>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltipText: React.FC = ({ children }) => {
|
export const HelpTooltipText: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return <p className={styles.text}>{children}</p>
|
return <p className={styles.text}>{children}</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltipLink: React.FC<{ href: string }> = ({ children, href }) => {
|
export const HelpTooltipLink: React.FC<React.PropsWithChildren<{ href: string }>> = ({
|
||||||
|
children,
|
||||||
|
href,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -115,11 +122,13 @@ export const HelpTooltipLink: React.FC<{ href: string }> = ({ children, href })
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltipAction: React.FC<{
|
export const HelpTooltipAction: React.FC<
|
||||||
icon: Icon
|
React.PropsWithChildren<{
|
||||||
onClick: () => void
|
icon: Icon
|
||||||
ariaLabel?: string
|
onClick: () => void
|
||||||
}> = ({ children, icon: Icon, onClick, ariaLabel }) => {
|
ariaLabel?: string
|
||||||
|
}>
|
||||||
|
> = ({ children, icon: Icon, onClick, ariaLabel }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const tooltip = useHelpTooltip()
|
const tooltip = useHelpTooltip()
|
||||||
|
|
||||||
@ -139,7 +148,7 @@ export const HelpTooltipAction: React.FC<{
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HelpTooltipLinksGroup: React.FC = ({ children }) => {
|
export const HelpTooltipLinksGroup: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -19,7 +19,10 @@ interface TooltipProps {
|
|||||||
ariaLabel?: string
|
ariaLabel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const OutdatedHelpTooltip: FC<TooltipProps> = ({ onUpdateVersion, ariaLabel }) => {
|
export const OutdatedHelpTooltip: FC<React.PropsWithChildren<TooltipProps>> = ({
|
||||||
|
onUpdateVersion,
|
||||||
|
ariaLabel,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<HelpTooltip size="small">
|
<HelpTooltip size="small">
|
||||||
<HelpTooltipTitle>{Language.outdatedLabel}</HelpTooltipTitle>
|
<HelpTooltipTitle>{Language.outdatedLabel}</HelpTooltipTitle>
|
||||||
|
@ -13,7 +13,7 @@ namespace Helpers {
|
|||||||
onPrimaryTextSelect: jest.fn(),
|
onPrimaryTextSelect: jest.fn(),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Component: FC<UserCellProps> = (props) => (
|
export const Component: FC<React.PropsWithChildren<UserCellProps>> = (props) => (
|
||||||
<WrapperComponent>
|
<WrapperComponent>
|
||||||
<UserCell {...props} />
|
<UserCell {...props} />
|
||||||
</WrapperComponent>
|
</WrapperComponent>
|
||||||
|
@ -35,7 +35,7 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
* UserCell is a single cell in an audit log table row that contains user-level
|
* UserCell is a single cell in an audit log table row that contains user-level
|
||||||
* information
|
* information
|
||||||
*/
|
*/
|
||||||
export const UserCell: FC<UserCellProps> = ({
|
export const UserCell: FC<React.PropsWithChildren<UserCellProps>> = ({
|
||||||
Avatar,
|
Avatar,
|
||||||
caption,
|
caption,
|
||||||
primaryText,
|
primaryText,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { screen } from "@testing-library/react"
|
import { fireEvent, screen } from "@testing-library/react"
|
||||||
import { MockUser } from "../../testHelpers/entities"
|
import { MockUser } from "../../testHelpers/entities"
|
||||||
import { render } from "../../testHelpers/renderHelpers"
|
import { render } from "../../testHelpers/renderHelpers"
|
||||||
import { Language } from "../UserDropdownContent/UserDropdownContent"
|
import { Language } from "../UserDropdownContent/UserDropdownContent"
|
||||||
@ -7,7 +7,7 @@ import { UserDropdown, UserDropdownProps } from "./UsersDropdown"
|
|||||||
const renderAndClick = async (props: Partial<UserDropdownProps> = {}) => {
|
const renderAndClick = async (props: Partial<UserDropdownProps> = {}) => {
|
||||||
render(<UserDropdown user={props.user ?? MockUser} onSignOut={props.onSignOut ?? jest.fn()} />)
|
render(<UserDropdown user={props.user ?? MockUser} onSignOut={props.onSignOut ?? jest.fn()} />)
|
||||||
const trigger = await screen.findByTestId("user-dropdown-trigger")
|
const trigger = await screen.findByTestId("user-dropdown-trigger")
|
||||||
trigger.click()
|
fireEvent.click(trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("UserDropdown", () => {
|
describe("UserDropdown", () => {
|
||||||
|
@ -14,7 +14,7 @@ export interface UserDropdownProps {
|
|||||||
onSignOut: () => void
|
onSignOut: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserDropdown: React.FC<UserDropdownProps> = ({
|
export const UserDropdown: React.FC<React.PropsWithChildren<UserDropdownProps>> = ({
|
||||||
user,
|
user,
|
||||||
onSignOut,
|
onSignOut,
|
||||||
}: UserDropdownProps) => {
|
}: UserDropdownProps) => {
|
||||||
|
@ -28,7 +28,7 @@ export interface UsersTableProps {
|
|||||||
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
|
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UsersTable: FC<UsersTableProps> = ({
|
export const UsersTable: FC<React.PropsWithChildren<UsersTableProps>> = ({
|
||||||
users,
|
users,
|
||||||
roles,
|
roles,
|
||||||
onSuspendUser,
|
onSuspendUser,
|
||||||
|
@ -30,7 +30,7 @@ interface UsersTableBodyProps {
|
|||||||
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
|
onUpdateUserRoles: (user: TypesGen.User, roles: TypesGen.Role["name"][]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UsersTableBody: FC<UsersTableBodyProps> = ({
|
export const UsersTableBody: FC<React.PropsWithChildren<UsersTableBodyProps>> = ({
|
||||||
users,
|
users,
|
||||||
roles,
|
roles,
|
||||||
onSuspendUser,
|
onSuspendUser,
|
||||||
|
@ -23,7 +23,7 @@ export interface VersionsTableProps {
|
|||||||
versions?: TypesGen.TemplateVersion[]
|
versions?: TypesGen.TemplateVersion[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VersionsTable: FC<VersionsTableProps> = ({ versions }) => {
|
export const VersionsTable: FC<React.PropsWithChildren<VersionsTableProps>> = ({ versions }) => {
|
||||||
const isLoading = !versions
|
const isLoading = !versions
|
||||||
const theme: Theme = useTheme()
|
const theme: Theme = useTheme()
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import Typography from "@material-ui/core/Typography"
|
import Typography from "@material-ui/core/Typography"
|
||||||
import { FC } from "react"
|
import { FC, PropsWithChildren } from "react"
|
||||||
import { CoderIcon } from "../Icons/CoderIcon"
|
import { CoderIcon } from "../Icons/CoderIcon"
|
||||||
|
|
||||||
const Language = {
|
const Language = {
|
||||||
@ -11,7 +11,9 @@ const Language = {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Welcome: FC<{ message?: JSX.Element }> = ({ message = Language.defaultMessage }) => {
|
export const Welcome: FC<PropsWithChildren<{ message?: JSX.Element }>> = ({
|
||||||
|
message = Language.defaultMessage,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -49,7 +49,7 @@ export interface WorkspaceProps {
|
|||||||
/**
|
/**
|
||||||
* Workspace is the top-level component for viewing an individual workspace
|
* Workspace is the top-level component for viewing an individual workspace
|
||||||
*/
|
*/
|
||||||
export const Workspace: FC<WorkspaceProps> = ({
|
export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||||
bannerProps,
|
bannerProps,
|
||||||
scheduleProps,
|
scheduleProps,
|
||||||
handleStart,
|
handleStart,
|
||||||
@ -69,11 +69,15 @@ export const Workspace: FC<WorkspaceProps> = ({
|
|||||||
return (
|
return (
|
||||||
<Margins>
|
<Margins>
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
{workspaceErrors[WorkspaceErrors.BUILD_ERROR] && (
|
{workspaceErrors[WorkspaceErrors.BUILD_ERROR] ? (
|
||||||
<ErrorSummary error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]} dismissible />
|
<ErrorSummary error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]} dismissible />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
{workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR] && (
|
{workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR] ? (
|
||||||
<ErrorSummary error={workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]} dismissible />
|
<ErrorSummary error={workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]} dismissible />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
|
@ -9,7 +9,7 @@ export interface WorkspaceActionButtonProps {
|
|||||||
ariaLabel?: string
|
ariaLabel?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceActionButton: FC<WorkspaceActionButtonProps> = ({
|
export const WorkspaceActionButton: FC<React.PropsWithChildren<WorkspaceActionButtonProps>> = ({
|
||||||
label,
|
label,
|
||||||
icon,
|
icon,
|
||||||
onClick,
|
onClick,
|
||||||
|
@ -27,7 +27,7 @@ interface WorkspaceAction {
|
|||||||
handleAction: () => void
|
handleAction: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UpdateButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
export const UpdateButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({ handleAction }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -37,7 +37,7 @@ export const UpdateButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StartButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
export const StartButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({ handleAction }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -50,7 +50,7 @@ export const StartButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StopButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
export const StopButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({ handleAction }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -63,7 +63,7 @@ export const StopButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeleteButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
export const DeleteButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({ handleAction }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -76,7 +76,7 @@ export const DeleteButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CancelButton: FC<WorkspaceAction> = ({ handleAction }) => {
|
export const CancelButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({ handleAction }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
// this is an icon button, so it's important to include an aria label
|
// this is an icon button, so it's important to include an aria label
|
||||||
@ -94,7 +94,7 @@ interface DisabledProps {
|
|||||||
workspaceState: WorkspaceStateEnum
|
workspaceState: WorkspaceStateEnum
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DisabledButton: FC<DisabledProps> = ({ workspaceState }) => {
|
export const DisabledButton: FC<React.PropsWithChildren<DisabledProps>> = ({ workspaceState }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -108,7 +108,7 @@ interface LoadingProps {
|
|||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ActionLoadingButton: FC<LoadingProps> = ({ label }) => {
|
export const ActionLoadingButton: FC<React.PropsWithChildren<LoadingProps>> = ({ label }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
return (
|
return (
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
|
@ -8,7 +8,10 @@ export interface DropdownContentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* secondary workspace CTAs */
|
/* secondary workspace CTAs */
|
||||||
export const DropdownContent: FC<DropdownContentProps> = ({ secondaryActions, buttonMapping }) => {
|
export const DropdownContent: FC<React.PropsWithChildren<DropdownContentProps>> = ({
|
||||||
|
secondaryActions,
|
||||||
|
buttonMapping,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { screen } from "@testing-library/react"
|
import { fireEvent, screen } from "@testing-library/react"
|
||||||
import { WorkspaceStateEnum } from "util/workspace"
|
import { WorkspaceStateEnum } from "util/workspace"
|
||||||
import * as Mocks from "../../testHelpers/entities"
|
import * as Mocks from "../../testHelpers/entities"
|
||||||
import { render } from "../../testHelpers/renderHelpers"
|
import { render } from "../../testHelpers/renderHelpers"
|
||||||
@ -30,7 +30,7 @@ const renderAndClick = async (props: Partial<WorkspaceActionsProps> = {}) => {
|
|||||||
/>,
|
/>,
|
||||||
)
|
)
|
||||||
const trigger = await screen.findByTestId("workspace-actions-button")
|
const trigger = await screen.findByTestId("workspace-actions-button")
|
||||||
trigger.click()
|
fireEvent.click(trigger)
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("WorkspaceActions", () => {
|
describe("WorkspaceActions", () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Button from "@material-ui/core/Button"
|
import Button from "@material-ui/core/Button"
|
||||||
import Popover from "@material-ui/core/Popover"
|
import Popover from "@material-ui/core/Popover"
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { FC, useEffect, useMemo, useRef, useState } from "react"
|
import { FC, ReactNode, useEffect, useMemo, useRef, useState } from "react"
|
||||||
import { getWorkspaceStatus, WorkspaceStateEnum, WorkspaceStatus } from "util/workspace"
|
import { getWorkspaceStatus, WorkspaceStateEnum, WorkspaceStatus } from "util/workspace"
|
||||||
import { Workspace } from "../../api/typesGenerated"
|
import { Workspace } from "../../api/typesGenerated"
|
||||||
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
|
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
|
||||||
@ -32,6 +32,7 @@ export interface WorkspaceActionsProps {
|
|||||||
handleDelete: () => void
|
handleDelete: () => void
|
||||||
handleUpdate: () => void
|
handleUpdate: () => void
|
||||||
handleCancel: () => void
|
handleCancel: () => void
|
||||||
|
children?: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
|
export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
|
||||||
|
@ -16,7 +16,7 @@ export interface WorkspaceDeletedBannerProps {
|
|||||||
handleClick: () => void
|
handleClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceDeletedBanner: FC<WorkspaceDeletedBannerProps> = ({
|
export const WorkspaceDeletedBanner: FC<React.PropsWithChildren<WorkspaceDeletedBannerProps>> = ({
|
||||||
workspace,
|
workspace,
|
||||||
handleClick,
|
handleClick,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -36,7 +36,7 @@ export interface WorkspaceScheduleProps {
|
|||||||
canUpdateWorkspace: boolean
|
canUpdateWorkspace: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceSchedule: FC<WorkspaceScheduleProps> = ({
|
export const WorkspaceSchedule: FC<React.PropsWithChildren<WorkspaceScheduleProps>> = ({
|
||||||
workspace,
|
workspace,
|
||||||
canUpdateWorkspace,
|
canUpdateWorkspace,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -35,7 +35,7 @@ export const shouldDisplay = (workspace: TypesGen.Workspace): boolean => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceScheduleBanner: FC<WorkspaceScheduleBannerProps> = ({
|
export const WorkspaceScheduleBanner: FC<React.PropsWithChildren<WorkspaceScheduleBannerProps>> = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
onExtend,
|
onExtend,
|
||||||
workspace,
|
workspace,
|
||||||
|
@ -170,7 +170,7 @@ export const validationSchema = Yup.object({
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
export const WorkspaceScheduleForm: FC<React.PropsWithChildren<WorkspaceScheduleFormProps>> = ({
|
||||||
submitScheduleError,
|
submitScheduleError,
|
||||||
initialValues,
|
initialValues,
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -221,7 +221,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
|||||||
<FullPageForm onCancel={onCancel} title={Language.formTitle}>
|
<FullPageForm onCancel={onCancel} title={Language.formTitle}>
|
||||||
<form onSubmit={form.handleSubmit} className={styles.form}>
|
<form onSubmit={form.handleSubmit} className={styles.form}>
|
||||||
<Stack>
|
<Stack>
|
||||||
{submitScheduleError && <ErrorSummary error={submitScheduleError} />}
|
{submitScheduleError ? <ErrorSummary error={submitScheduleError} /> : <></>}
|
||||||
<Section title={Language.startSection}>
|
<Section title={Language.startSection}>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
|
@ -14,7 +14,7 @@ export interface WorkspaceSectionProps {
|
|||||||
title?: string
|
title?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceSection: React.FC<WorkspaceSectionProps> = ({
|
export const WorkspaceSection: React.FC<React.PropsWithChildren<WorkspaceSectionProps>> = ({
|
||||||
action,
|
action,
|
||||||
children,
|
children,
|
||||||
contentsProps,
|
contentsProps,
|
||||||
|
@ -124,7 +124,10 @@ export type WorkspaceStatusBadgeProps = {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspaceStatusBadge: React.FC<WorkspaceStatusBadgeProps> = ({ build, className }) => {
|
export const WorkspaceStatusBadge: React.FC<React.PropsWithChildren<WorkspaceStatusBadgeProps>> = ({
|
||||||
|
build,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const { text, icon, ...colorStyles } = getStatus(theme, build)
|
const { text, icon, ...colorStyles } = getStatus(theme, build)
|
||||||
|
@ -21,7 +21,9 @@ const Language = {
|
|||||||
outdatedLabel: "Outdated",
|
outdatedLabel: "Outdated",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspacesRow: FC<{ workspaceRef: WorkspaceItemMachineRef }> = ({ workspaceRef }) => {
|
export const WorkspacesRow: FC<
|
||||||
|
React.PropsWithChildren<{ workspaceRef: WorkspaceItemMachineRef }>
|
||||||
|
> = ({ workspaceRef }) => {
|
||||||
const styles = useStyles()
|
const styles = useStyles()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const theme: Theme = useTheme()
|
const theme: Theme = useTheme()
|
||||||
|
@ -22,7 +22,11 @@ export interface WorkspacesTableProps {
|
|||||||
filter?: string
|
filter?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspacesTable: FC<WorkspacesTableProps> = ({ isLoading, workspaceRefs, filter }) => {
|
export const WorkspacesTable: FC<React.PropsWithChildren<WorkspacesTableProps>> = ({
|
||||||
|
isLoading,
|
||||||
|
workspaceRefs,
|
||||||
|
filter,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
<Table>
|
<Table>
|
||||||
|
@ -24,7 +24,11 @@ interface TableBodyProps {
|
|||||||
filter?: string
|
filter?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkspacesTableBody: FC<TableBodyProps> = ({ isLoading, workspaceRefs, filter }) => {
|
export const WorkspacesTableBody: FC<React.PropsWithChildren<TableBodyProps>> = ({
|
||||||
|
isLoading,
|
||||||
|
workspaceRefs,
|
||||||
|
filter,
|
||||||
|
}) => {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <TableLoader />
|
return <TableLoader />
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { waitFor } from "@testing-library/react"
|
import { renderHook, waitFor } from "@testing-library/react"
|
||||||
import { renderHook } from "@testing-library/react-hooks"
|
|
||||||
import { dispatchCustomEvent } from "../util/events"
|
import { dispatchCustomEvent } from "../util/events"
|
||||||
import { useCustomEvent } from "./events"
|
import { useCustomEvent } from "./events"
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import { useActor } from "@xstate/react"
|
import { useActor } from "@xstate/react"
|
||||||
import React, { useContext, useEffect, useState } from "react"
|
import React, { useContext, useEffect, useState } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { getApiKey } from "../../api/api"
|
import { getApiKey } from "../../api/api"
|
||||||
import { CliAuthToken } from "../../components/CliAuthToken/CliAuthToken"
|
import { CliAuthToken } from "../../components/CliAuthToken/CliAuthToken"
|
||||||
import { FullScreenLoader } from "../../components/Loader/FullScreenLoader"
|
import { FullScreenLoader } from "../../components/Loader/FullScreenLoader"
|
||||||
import { pageTitle } from "../../util/page"
|
import { pageTitle } from "../../util/page"
|
||||||
import { XServiceContext } from "../../xServices/StateContext"
|
import { XServiceContext } from "../../xServices/StateContext"
|
||||||
|
|
||||||
export const CliAuthenticationPage: React.FC = () => {
|
export const CliAuthenticationPage: React.FC<React.PropsWithChildren<unknown>> = () => {
|
||||||
const xServices = useContext(XServiceContext)
|
const xServices = useContext(XServiceContext)
|
||||||
const [authState] = useActor(xServices.authXService)
|
const [authState] = useActor(xServices.authXService)
|
||||||
const { me } = authState.context
|
const { me } = authState.context
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { screen, waitFor } from "@testing-library/react"
|
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||||
|
import { screen } from "@testing-library/react"
|
||||||
import userEvent from "@testing-library/user-event"
|
import userEvent from "@testing-library/user-event"
|
||||||
import * as API from "../../api/api"
|
import * as API from "api/api"
|
||||||
import { Language as FooterLanguage } from "../../components/FormFooter/FormFooter"
|
import { Language as FooterLanguage } from "../../components/FormFooter/FormFooter"
|
||||||
import { MockTemplate, MockWorkspace } from "../../testHelpers/entities"
|
import { MockTemplate, MockWorkspace } from "../../testHelpers/entities"
|
||||||
import { renderWithAuth } from "../../testHelpers/renderHelpers"
|
import { renderWithAuth } from "../../testHelpers/renderHelpers"
|
||||||
@ -14,13 +15,6 @@ const renderCreateWorkspacePage = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const fillForm = async ({ name = "example" }: { name?: string }) => {
|
|
||||||
const nameField = await screen.findByLabelText(Language.nameLabel)
|
|
||||||
await userEvent.type(nameField, name)
|
|
||||||
const submitButton = await screen.findByText(FooterLanguage.defaultSubmitLabel)
|
|
||||||
await userEvent.click(submitButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("CreateWorkspacePage", () => {
|
describe("CreateWorkspacePage", () => {
|
||||||
it("renders", async () => {
|
it("renders", async () => {
|
||||||
renderCreateWorkspacePage()
|
renderCreateWorkspacePage()
|
||||||
@ -29,11 +23,13 @@ describe("CreateWorkspacePage", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("succeeds", async () => {
|
it("succeeds", async () => {
|
||||||
renderCreateWorkspacePage()
|
|
||||||
// You have to spy the method before it is used.
|
|
||||||
jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace)
|
jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace)
|
||||||
await fillForm({ name: "test" })
|
|
||||||
// Check if the request was made
|
renderCreateWorkspacePage()
|
||||||
await waitFor(() => expect(API.createWorkspace).toBeCalledTimes(1))
|
|
||||||
|
const nameField = await screen.findByLabelText(Language.nameLabel)
|
||||||
|
userEvent.type(nameField, "test")
|
||||||
|
const submitButton = screen.getByText(FooterLanguage.defaultSubmitLabel)
|
||||||
|
userEvent.click(submitButton)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useMachine } from "@xstate/react"
|
import { useMachine } from "@xstate/react"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { useNavigate, useParams } from "react-router-dom"
|
import { useNavigate, useParams } from "react-router-dom"
|
||||||
import { useOrganizationId } from "../../hooks/useOrganizationId"
|
import { useOrganizationId } from "../../hooks/useOrganizationId"
|
||||||
import { pageTitle } from "../../util/page"
|
import { pageTitle } from "../../util/page"
|
||||||
|
@ -43,7 +43,9 @@ export const validationSchema = Yup.object({
|
|||||||
name: nameValidator(Language.nameLabel),
|
name: nameValidator(Language.nameLabel),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props) => {
|
export const CreateWorkspacePageView: FC<React.PropsWithChildren<CreateWorkspacePageViewProps>> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
const [parameterValues, setParameterValues] = useState<Record<string, string>>({})
|
const [parameterValues, setParameterValues] = useState<Record<string, string>>({})
|
||||||
useStyles()
|
useStyles()
|
||||||
|
|
||||||
@ -90,15 +92,19 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
|
|||||||
if (props.hasTemplateErrors) {
|
if (props.hasTemplateErrors) {
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
{props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATES_ERROR] && (
|
{props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATES_ERROR] ? (
|
||||||
<ErrorSummary
|
<ErrorSummary
|
||||||
error={props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATES_ERROR]}
|
error={props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATES_ERROR]}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
{props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR] && (
|
{props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR] ? (
|
||||||
<ErrorSummary
|
<ErrorSummary
|
||||||
error={props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR]}
|
error={props.createWorkspaceErrors[CreateWorkspaceErrors.GET_TEMPLATE_SCHEMA_ERROR]}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
@ -108,10 +114,12 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = (props)
|
|||||||
<FullPageForm title="Create workspace" onCancel={props.onCancel}>
|
<FullPageForm title="Create workspace" onCancel={props.onCancel}>
|
||||||
<form onSubmit={form.handleSubmit}>
|
<form onSubmit={form.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
{props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR] && (
|
{props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR] ? (
|
||||||
<ErrorSummary
|
<ErrorSummary
|
||||||
error={props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR]}
|
error={props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR]}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
)}
|
)}
|
||||||
<TextField
|
<TextField
|
||||||
disabled
|
disabled
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { act, screen, waitFor } from "@testing-library/react"
|
import { fireEvent, screen, waitFor } from "@testing-library/react"
|
||||||
import userEvent from "@testing-library/user-event"
|
import userEvent from "@testing-library/user-event"
|
||||||
import { rest } from "msw"
|
import { rest } from "msw"
|
||||||
import { Language } from "../../components/SignInForm/SignInForm"
|
import { Language } from "../../components/SignInForm/SignInForm"
|
||||||
@ -42,7 +42,7 @@ describe("LoginPage", () => {
|
|||||||
await userEvent.type(password, "password")
|
await userEvent.type(password, "password")
|
||||||
// Click sign-in
|
// Click sign-in
|
||||||
const signInButton = await screen.findByText(Language.passwordSignIn)
|
const signInButton = await screen.findByText(Language.passwordSignIn)
|
||||||
act(() => signInButton.click())
|
fireEvent.click(signInButton)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
const errorMessage = await screen.findByText(Language.errorMessages.authError)
|
const errorMessage = await screen.findByText(Language.errorMessages.authError)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useActor } from "@xstate/react"
|
import { useActor } from "@xstate/react"
|
||||||
import { SignInLayout } from "components/SignInLayout/SignInLayout"
|
import { SignInLayout } from "components/SignInLayout/SignInLayout"
|
||||||
import React, { useContext } from "react"
|
import React, { useContext } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { Navigate, useLocation } from "react-router-dom"
|
import { Navigate, useLocation } from "react-router-dom"
|
||||||
import { LoginErrors, SignInForm } from "../../components/SignInForm/SignInForm"
|
import { LoginErrors, SignInForm } from "../../components/SignInForm/SignInForm"
|
||||||
import { pageTitle } from "../../util/page"
|
import { pageTitle } from "../../util/page"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { screen, waitFor } from "@testing-library/react"
|
import { fireEvent, screen, waitFor } from "@testing-library/react"
|
||||||
import userEvent from "@testing-library/user-event"
|
import userEvent from "@testing-library/user-event"
|
||||||
import * as API from "api/api"
|
import * as API from "api/api"
|
||||||
import { rest } from "msw"
|
import { rest } from "msw"
|
||||||
@ -28,7 +28,7 @@ const fillForm = async ({
|
|||||||
await userEvent.type(emailField, email)
|
await userEvent.type(emailField, email)
|
||||||
await userEvent.type(passwordField, password)
|
await userEvent.type(passwordField, password)
|
||||||
const submitButton = screen.getByRole("button", { name: PageViewLanguage.create })
|
const submitButton = screen.getByRole("button", { name: PageViewLanguage.create })
|
||||||
submitButton.click()
|
fireEvent.click(submitButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Setup Page", () => {
|
describe("Setup Page", () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useActor, useMachine } from "@xstate/react"
|
import { useActor, useMachine } from "@xstate/react"
|
||||||
import { FC, useContext, useEffect } from "react"
|
import { FC, useContext, useEffect } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { useNavigate } from "react-router-dom"
|
import { useNavigate } from "react-router-dom"
|
||||||
import { pageTitle } from "util/page"
|
import { pageTitle } from "util/page"
|
||||||
import { setupMachine } from "xServices/setup/setupXService"
|
import { setupMachine } from "xServices/setup/setupXService"
|
||||||
|
@ -21,6 +21,6 @@ describe("TemplatePage", () => {
|
|||||||
await screen.findByText(MockTemplate.name)
|
await screen.findByText(MockTemplate.name)
|
||||||
screen.getByTestId("markdown")
|
screen.getByTestId("markdown")
|
||||||
screen.getByText(MockWorkspaceResource.name)
|
screen.getByText(MockWorkspaceResource.name)
|
||||||
screen.getByTestId(`version-${MockTemplateVersion.id}`)
|
screen.queryAllByText(`${MockTemplateVersion.name}`).length
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useMachine } from "@xstate/react"
|
import { useMachine } from "@xstate/react"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
import { Loader } from "../../components/Loader/Loader"
|
import { Loader } from "../../components/Loader/Loader"
|
||||||
import { useOrganizationId } from "../../hooks/useOrganizationId"
|
import { useOrganizationId } from "../../hooks/useOrganizationId"
|
||||||
@ -18,7 +18,7 @@ const useTemplateName = () => {
|
|||||||
return template
|
return template
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TemplatePage: FC = () => {
|
export const TemplatePage: FC<React.PropsWithChildren<unknown>> = () => {
|
||||||
const organizationId = useOrganizationId()
|
const organizationId = useOrganizationId()
|
||||||
const templateName = useTemplateName()
|
const templateName = useTemplateName()
|
||||||
const [templateState] = useMachine(templateMachine, {
|
const [templateState] = useMachine(templateMachine, {
|
||||||
|
@ -38,7 +38,7 @@ export interface TemplatePageViewProps {
|
|||||||
templateVersions?: TemplateVersion[]
|
templateVersions?: TemplateVersion[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TemplatePageView: FC<TemplatePageViewProps> = ({
|
export const TemplatePageView: FC<React.PropsWithChildren<TemplatePageViewProps>> = ({
|
||||||
template,
|
template,
|
||||||
activeTemplateVersion,
|
activeTemplateVersion,
|
||||||
templateResources,
|
templateResources,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useMachine } from "@xstate/react"
|
import { useMachine } from "@xstate/react"
|
||||||
import { useOrganizationId } from "hooks/useOrganizationId"
|
import { useOrganizationId } from "hooks/useOrganizationId"
|
||||||
import { FC } from "react"
|
import { FC } from "react"
|
||||||
import { Helmet } from "react-helmet"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { useNavigate, useParams } from "react-router-dom"
|
import { useNavigate, useParams } from "react-router-dom"
|
||||||
import { pageTitle } from "util/page"
|
import { pageTitle } from "util/page"
|
||||||
import { templateSettingsMachine } from "xServices/templateSettings/templateSettingsXService"
|
import { templateSettingsMachine } from "xServices/templateSettings/templateSettingsXService"
|
||||||
|
@ -33,7 +33,7 @@ export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FullPageForm title={Language.title} onCancel={onCancel}>
|
<FullPageForm title={Language.title} onCancel={onCancel}>
|
||||||
{errors.getTemplateError && <ErrorSummary error={errors.getTemplateError} />}
|
{!!errors.getTemplateError && <ErrorSummary error={errors.getTemplateError} />}
|
||||||
{isLoading && <Loader />}
|
{isLoading && <Loader />}
|
||||||
{template && (
|
{template && (
|
||||||
<TemplateSettingsForm
|
<TemplateSettingsForm
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user