mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
@@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import { Footer } from "../Footer/Footer"
|
||||
import { Navbar } from "../Navbar/Navbar"
|
||||
import { Footer } from "../Page/Footer"
|
||||
import { RequireAuth } from "../Page/RequireAuth"
|
||||
import { RequireAuth } from "../RequireAuth/RequireAuth"
|
||||
|
||||
interface AuthAndFrameProps {
|
||||
children: JSX.Element
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import React from "react"
|
||||
import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
|
||||
import { CopyButton } from "../Button/CopyButton"
|
||||
import { CopyButton } from "../CopyButton/CopyButton"
|
||||
|
||||
export interface CodeExampleProps {
|
||||
code: string
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { FormikContextType } from "formik/dist/types"
|
||||
import { getFormHelpers, onChangeTrimmed } from "./utils"
|
||||
|
||||
interface TestType {
|
||||
untouchedGoodField: string
|
||||
untouchedBadField: string
|
||||
touchedGoodField: string
|
||||
touchedBadField: string
|
||||
}
|
||||
|
||||
const mockHandleChange = jest.fn()
|
||||
|
||||
const form = {
|
||||
errors: {
|
||||
untouchedGoodField: undefined,
|
||||
untouchedBadField: "oops!",
|
||||
touchedGoodField: undefined,
|
||||
touchedBadField: "oops!",
|
||||
},
|
||||
touched: {
|
||||
untouchedGoodField: false,
|
||||
untouchedBadField: false,
|
||||
touchedGoodField: true,
|
||||
touchedBadField: true,
|
||||
},
|
||||
handleChange: mockHandleChange,
|
||||
handleBlur: jest.fn(),
|
||||
getFieldProps: (name: string) => {
|
||||
return {
|
||||
name,
|
||||
onBlur: jest.fn(),
|
||||
onChange: jest.fn(),
|
||||
value: "",
|
||||
}
|
||||
},
|
||||
} as unknown as FormikContextType<TestType>
|
||||
|
||||
describe("form util functions", () => {
|
||||
describe("getFormHelpers", () => {
|
||||
const untouchedGoodResult = getFormHelpers<TestType>(form, "untouchedGoodField")
|
||||
const untouchedBadResult = getFormHelpers<TestType>(form, "untouchedBadField")
|
||||
const touchedGoodResult = getFormHelpers<TestType>(form, "touchedGoodField")
|
||||
const touchedBadResult = getFormHelpers<TestType>(form, "touchedBadField")
|
||||
it("populates the 'field props'", () => {
|
||||
expect(untouchedGoodResult.name).toEqual("untouchedGoodField")
|
||||
expect(untouchedGoodResult.onBlur).toBeDefined()
|
||||
expect(untouchedGoodResult.onChange).toBeDefined()
|
||||
expect(untouchedGoodResult.value).toBeDefined()
|
||||
})
|
||||
it("sets the id to the name", () => {
|
||||
expect(untouchedGoodResult.id).toEqual("untouchedGoodField")
|
||||
})
|
||||
it("sets error to true if touched and invalid", () => {
|
||||
expect(untouchedGoodResult.error).toBeFalsy
|
||||
expect(untouchedBadResult.error).toBeFalsy
|
||||
expect(touchedGoodResult.error).toBeFalsy
|
||||
expect(touchedBadResult.error).toBeTruthy
|
||||
})
|
||||
it("sets helperText to the error message if touched and invalid", () => {
|
||||
expect(untouchedGoodResult.helperText).toBeUndefined
|
||||
expect(untouchedBadResult.helperText).toBeUndefined
|
||||
expect(touchedGoodResult.helperText).toBeUndefined
|
||||
expect(touchedBadResult.helperText).toEqual("oops!")
|
||||
})
|
||||
})
|
||||
|
||||
describe("onChangeTrimmed", () => {
|
||||
it("calls handleChange with trimmed value", () => {
|
||||
const event = { target: { value: " hello " } } as React.ChangeEvent<HTMLInputElement>
|
||||
onChangeTrimmed<TestType>(form)(event)
|
||||
expect(mockHandleChange).toHaveBeenCalledWith({ target: { value: "hello" } })
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,36 +0,0 @@
|
||||
import { FormikContextType, getIn } from "formik"
|
||||
import { ChangeEvent, ChangeEventHandler, FocusEventHandler } from "react"
|
||||
|
||||
interface FormHelpers {
|
||||
name: string
|
||||
onBlur: FocusEventHandler
|
||||
onChange: ChangeEventHandler
|
||||
id: string
|
||||
value?: string | number
|
||||
error: boolean
|
||||
helperText?: string
|
||||
}
|
||||
|
||||
export const getFormHelpers = <T>(form: FormikContextType<T>, name: keyof T, error?: string): FormHelpers => {
|
||||
if (typeof name !== "string") {
|
||||
throw new Error(`name must be type of string, instead received '${typeof name}'`)
|
||||
}
|
||||
|
||||
// getIn is a util function from Formik that gets at any depth of nesting
|
||||
// and is necessary for the types to work
|
||||
const touched = getIn(form.touched, name)
|
||||
const errors = error ?? getIn(form.errors, name)
|
||||
return {
|
||||
...form.getFieldProps(name),
|
||||
id: name,
|
||||
error: touched && Boolean(errors),
|
||||
helperText: touched && errors,
|
||||
}
|
||||
}
|
||||
|
||||
export const onChangeTrimmed =
|
||||
<T>(form: FormikContextType<T>) =>
|
||||
(event: ChangeEvent<HTMLInputElement>): void => {
|
||||
event.target.value = event.target.value.trim()
|
||||
form.handleChange(event)
|
||||
}
|
||||
+4
-4
@@ -3,23 +3,23 @@ import MenuItem from "@material-ui/core/MenuItem"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { FormTextField, FormTextFieldProps } from "./FormTextField"
|
||||
import { FormTextField, FormTextFieldProps } from "../FormTextField/FormTextField"
|
||||
|
||||
export interface DropdownItem {
|
||||
export interface FormDropdownItem {
|
||||
value: string
|
||||
name: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface FormDropdownFieldProps<T> extends FormTextFieldProps<T> {
|
||||
items: DropdownItem[]
|
||||
items: FormDropdownItem[]
|
||||
}
|
||||
|
||||
export const FormDropdownField = <T,>({ items, ...props }: FormDropdownFieldProps<T>): React.ReactElement => {
|
||||
const styles = useStyles()
|
||||
return (
|
||||
<FormTextField select {...props}>
|
||||
{items.map((item: DropdownItem) => (
|
||||
{items.map((item: FormDropdownItem) => (
|
||||
<MenuItem key={item.value} value={item.value}>
|
||||
<Box alignItems="center" display="flex">
|
||||
<Box ml={1}>
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import TextField, { TextFieldProps } from "@material-ui/core/TextField"
|
||||
import { FormikContextType } from "formik"
|
||||
import React from "react"
|
||||
import { PasswordField } from "./PasswordField"
|
||||
import { PasswordField } from "../PasswordField/PasswordField"
|
||||
|
||||
/**
|
||||
* FormFieldProps are required props for creating form fields using a factory.
|
||||
+1
-1
@@ -2,9 +2,9 @@ import { makeStyles } from "@material-ui/core/styles"
|
||||
import React, { useCallback, useState } from "react"
|
||||
import { useCustomEvent } from "../../hooks/events"
|
||||
import { CustomEventListener } from "../../util/events"
|
||||
import { EnterpriseSnackbar } from "../EnterpriseSnackbar/EnterpriseSnackbar"
|
||||
import { ErrorIcon } from "../Icons/ErrorIcon"
|
||||
import { Typography } from "../Typography/Typography"
|
||||
import { EnterpriseSnackbar } from "./EnterpriseSnackbar"
|
||||
import {
|
||||
AdditionalMessage,
|
||||
isNotificationList,
|
||||
@@ -2,7 +2,7 @@ import Box from "@material-ui/core/Box"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { HeaderButton } from "./HeaderButton"
|
||||
import { HeaderButton } from "../HeaderButton/HeaderButton"
|
||||
|
||||
export interface HeaderAction {
|
||||
readonly text: string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useActor } from "@xstate/react"
|
||||
import React, { useContext } from "react"
|
||||
import { XServiceContext } from "../../xServices/StateContext"
|
||||
import { NavbarView } from "./NavbarView/NavbarView"
|
||||
import { NavbarView } from "../NavbarView/NavbarView"
|
||||
|
||||
export const Navbar: React.FC = () => {
|
||||
const xServices = useContext(XServiceContext)
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { screen } from "@testing-library/react"
|
||||
import React from "react"
|
||||
import { render } from "../../../testHelpers"
|
||||
import { MockUser } from "../../../testHelpers/entities"
|
||||
import { render } from "../../testHelpers"
|
||||
import { MockUser } from "../../testHelpers/entities"
|
||||
import { NavbarView } from "./NavbarView"
|
||||
|
||||
describe("NavbarView", () => {
|
||||
+4
-4
@@ -3,10 +3,10 @@ import ListItem from "@material-ui/core/ListItem"
|
||||
import { fade, makeStyles } from "@material-ui/core/styles"
|
||||
import React from "react"
|
||||
import { NavLink } from "react-router-dom"
|
||||
import { UserResponse } from "../../../api/types"
|
||||
import { navHeight } from "../../../theme/constants"
|
||||
import { AdminDropdown } from "../../AdminDropdown/AdminDropdown"
|
||||
import { Logo } from "../../Icons/Logo"
|
||||
import { UserResponse } from "../../api/types"
|
||||
import { navHeight } from "../../theme/constants"
|
||||
import { AdminDropdown } from "../AdminDropdown/AdminDropdown"
|
||||
import { Logo } from "../Icons/Logo"
|
||||
import { UserDropdown } from "../UserDropdown/UsersDropdown"
|
||||
|
||||
export interface NavbarViewProps {
|
||||
+2
-2
@@ -3,9 +3,9 @@ import TextField from "@material-ui/core/TextField"
|
||||
import { FormikContextType, FormikErrors, useFormik } from "formik"
|
||||
import React from "react"
|
||||
import * as Yup from "yup"
|
||||
import { getFormHelpers, onChangeTrimmed } from "../Form/utils"
|
||||
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
|
||||
import { LoadingButton } from "../LoadingButton/LoadingButton"
|
||||
import { Stack } from "../Stack/Stack"
|
||||
import { LoadingButton } from "./../Button/LoadingButton"
|
||||
|
||||
interface AccountFormValues {
|
||||
name: string
|
||||
@@ -2,7 +2,7 @@ import { makeStyles } from "@material-ui/core/styles"
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { SectionAction } from "./Action"
|
||||
import { SectionAction } from "../SectionAction/SectionAction"
|
||||
|
||||
type SectionLayout = "fixed" | "fluid"
|
||||
|
||||
|
||||
+3
-3
@@ -4,9 +4,9 @@ import TextField from "@material-ui/core/TextField"
|
||||
import { FormikContextType, useFormik } from "formik"
|
||||
import React from "react"
|
||||
import * as Yup from "yup"
|
||||
import { getFormHelpers, onChangeTrimmed } from "../Form/utils"
|
||||
import { LoadingButton } from "./../Button/LoadingButton"
|
||||
import { Welcome } from "./Welcome"
|
||||
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
|
||||
import { Welcome } from "../Welcome/Welcome"
|
||||
import { LoadingButton } from "./../LoadingButton/LoadingButton"
|
||||
|
||||
/**
|
||||
* BuiltInAuthFormValues describes a form using built-in (email/password)
|
||||
@@ -1,7 +1,7 @@
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator"
|
||||
import React from "react"
|
||||
import { TabSidebar, TabSidebarItem } from "./TabSidebar"
|
||||
import { TabSidebar, TabSidebarItem } from "../TabSidebar/TabSidebar"
|
||||
|
||||
export type AdminMenuItemCallback = (menuItem: string) => void
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import TableCell from "@material-ui/core/TableCell"
|
||||
import TableHead from "@material-ui/core/TableHead"
|
||||
import TableRow from "@material-ui/core/TableRow"
|
||||
import React from "react"
|
||||
import { TableHeaders } from "./TableHeaders"
|
||||
import { TableTitle } from "./TableTitle"
|
||||
import { TableHeaders } from "../TableHeaders/TableHeaders"
|
||||
import { TableTitle } from "../TableTitle/TableTitle"
|
||||
|
||||
export interface Column<T> {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { ComponentMeta, Story } from "@storybook/react"
|
||||
import React from "react"
|
||||
import { MockUser, MockUserAgent } from "../../../testHelpers"
|
||||
import { MockUser, MockUserAgent } from "../../testHelpers"
|
||||
import { UserCell, UserCellProps } from "./UserCell"
|
||||
|
||||
export default {
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react"
|
||||
import React from "react"
|
||||
import { MockUser, MockUserAgent, WrapperComponent } from "../../../testHelpers"
|
||||
import { MockUser, MockUserAgent, WrapperComponent } from "../../testHelpers"
|
||||
import { UserCell, UserCellProps } from "./UserCell"
|
||||
|
||||
namespace Helpers {
|
||||
+1
-1
@@ -3,7 +3,7 @@ import Link from "@material-ui/core/Link"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { UserAvatar, UserAvatarProps } from "../../User/UserAvatar"
|
||||
import { UserAvatar, UserAvatarProps } from "../UserAvatar/UserAvatar"
|
||||
|
||||
export interface UserCellProps {
|
||||
Avatar: UserAvatarProps
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { screen } from "@testing-library/react"
|
||||
import React from "react"
|
||||
import { render } from "../../../testHelpers"
|
||||
import { MockUser } from "../../../testHelpers/entities"
|
||||
import { render } from "../../testHelpers"
|
||||
import { MockUser } from "../../testHelpers/entities"
|
||||
import { Language, UserDropdown, UserDropdownProps } from "./UsersDropdown"
|
||||
|
||||
const renderAndClick = async (props: Partial<UserDropdownProps> = {}) => {
|
||||
+7
-7
@@ -7,13 +7,13 @@ import { fade, makeStyles } from "@material-ui/core/styles"
|
||||
import AccountIcon from "@material-ui/icons/AccountCircleOutlined"
|
||||
import React, { useState } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import { UserResponse } from "../../../api/types"
|
||||
import { BorderedMenu } from "../../BorderedMenu/BorderedMenu"
|
||||
import { CloseDropdown, OpenDropdown } from "../../DropdownArrows/DropdownArrows"
|
||||
import { DocsIcon } from "../../Icons/DocsIcon"
|
||||
import { LogoutIcon } from "../../Icons/LogoutIcon"
|
||||
import { UserAvatar } from "../../User/UserAvatar"
|
||||
import { UserProfileCard } from "../../User/UserProfileCard"
|
||||
import { UserResponse } from "../../api/types"
|
||||
import { BorderedMenu } from "../BorderedMenu/BorderedMenu"
|
||||
import { CloseDropdown, OpenDropdown } from "../DropdownArrows/DropdownArrows"
|
||||
import { DocsIcon } from "../Icons/DocsIcon"
|
||||
import { LogoutIcon } from "../Icons/LogoutIcon"
|
||||
import { UserAvatar } from "../UserAvatar/UserAvatar"
|
||||
import { UserProfileCard } from "../UserProfileCard/UserProfileCard"
|
||||
|
||||
export const Language = {
|
||||
accountLabel: "Account",
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { makeStyles } from "@material-ui/core/styles"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { UserResponse } from "../../api/types"
|
||||
import { UserAvatar } from "./UserAvatar"
|
||||
import { UserAvatar } from "../UserAvatar/UserAvatar"
|
||||
|
||||
interface UserProfileCardProps {
|
||||
user: UserResponse
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react"
|
||||
import { UserResponse } from "../../api/types"
|
||||
import { Column, Table } from "../../components/Table/Table"
|
||||
import { EmptyState } from "../EmptyState/EmptyState"
|
||||
import { UserCell } from "../Table/Cells/UserCell"
|
||||
import { Column, Table } from "../Table/Table"
|
||||
import { UserCell } from "../UserCell/UserCell"
|
||||
|
||||
const Language = {
|
||||
pageTitle: "Users",
|
||||
|
||||
@@ -6,9 +6,9 @@ import CloudCircleIcon from "@material-ui/icons/CloudCircle"
|
||||
import React from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import * as Types from "../../api/types"
|
||||
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
|
||||
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
|
||||
import * as Constants from "./constants"
|
||||
import { WorkspaceSchedule } from "./WorkspaceSchedule"
|
||||
import { WorkspaceSection } from "./WorkspaceSection"
|
||||
|
||||
export interface WorkspaceProps {
|
||||
organization: Types.Organization
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import Typography from "@material-ui/core/Typography"
|
||||
import cronstrue from "cronstrue"
|
||||
import React from "react"
|
||||
import { extractTimezone, stripTimezone } from "../../util/schedule"
|
||||
import { WorkspaceSection } from "./WorkspaceSection"
|
||||
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
|
||||
|
||||
const Language = {
|
||||
autoStartLabel: (schedule: string): string => {
|
||||
+1
-1
@@ -2,7 +2,7 @@ import Paper from "@material-ui/core/Paper"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import Typography from "@material-ui/core/Typography"
|
||||
import React from "react"
|
||||
import { CardPadding, CardRadius } from "./constants"
|
||||
import { CardPadding, CardRadius } from "../Workspace/constants"
|
||||
|
||||
export interface WorkspaceSectionProps {
|
||||
title: string
|
||||
Reference in New Issue
Block a user