feat: Redesign workspaces page (#1450)

* feat: Improve navbar to be more compact

The navbar was unnecessarily large before, which made
the UI feel a bit bloaty from my perspective.

* Attempt to remove overrides

* Update theme

* Add text field

* Update theme to dark!

* Fix import ordering

* Fix page location

* Fix requested changes

* Add storybook for workspaces page view

* Add empty view

* Add tests for empty view

* Remove templates page

* Fix local port

* Remove templates from nav

* Fix e2e test

* Remove time.ts

* Remove dep

* Add background color to margins

* Merge status checking from workspace page

* Fix requested changes

* Fix workspace status tests
This commit is contained in:
Kyle Carberry
2022-05-16 16:52:54 -05:00
committed by GitHub
parent e925818526
commit 22ec366535
53 changed files with 626 additions and 1743 deletions

View File

@ -1,20 +1,17 @@
import CssBaseline from "@material-ui/core/CssBaseline"
import ThemeProvider from "@material-ui/styles/ThemeProvider"
import { withThemes } from "@react-theming/storybook-addon"
import { createMemoryHistory } from "history"
import { addDecorator } from "node_modules/@storybook/react"
import { unstable_HistoryRouter as HistoryRouter } from "react-router-dom"
import { dark, light } from "../src/theme"
import { dark } from "../src/theme"
import "../src/theme/globalFonts"
const providerFn = ({ children, theme }) => (
<ThemeProvider theme={theme}>
addDecorator((story) => (
<ThemeProvider theme={dark}>
<CssBaseline />
{children}
{story()}
</ThemeProvider>
)
addDecorator(withThemes(null, [light, dark], { providerFn }))
))
const history = createMemoryHistory()

View File

@ -1,8 +1,8 @@
import { Page } from "@playwright/test"
import { BasePom } from "./BasePom"
export class TemplatesPage extends BasePom {
export class WorkspacesPage extends BasePom {
constructor(baseURL: string | undefined, page: Page) {
super(baseURL, "/templates", page)
super(baseURL, "/workspaces", page)
}
}

View File

@ -1,2 +1,2 @@
export * from "./SignInPage"
export * from "./TemplatesPage"
export * from "./WorkspacesPage"

View File

@ -1,17 +1,17 @@
import { test } from "@playwright/test"
import { email, password } from "../constants"
import { SignInPage, TemplatesPage } from "../pom"
import { SignInPage, WorkspacesPage } from "../pom"
import { waitForClientSideNavigation } from "./../util"
test("Login takes user to /templates", async ({ baseURL, page }) => {
test("Login takes user to /workspaces", async ({ baseURL, page }) => {
await page.goto(baseURL + "/", { waitUntil: "networkidle" })
// Log-in with the default credentials we set up in the development server
const signInPage = new SignInPage(baseURL, page)
await signInPage.submitBuiltInAuthentication(email, password)
const templatesPage = new TemplatesPage(baseURL, page)
await waitForClientSideNavigation(page, { to: templatesPage.url })
const workspacesPage = new WorkspacesPage(baseURL, page)
await waitForClientSideNavigation(page, { to: workspacesPage.url })
await page.waitForSelector("text=Templates")
await page.waitForSelector("text=Workspaces")
})

View File

@ -25,7 +25,7 @@
"typegen": "xstate typegen 'src/**/*.ts'"
},
"dependencies": {
"@fontsource/fira-code": "4.5.9",
"@fontsource/ibm-plex-mono": "4.5.9",
"@fontsource/inter": "4.5.7",
"@material-ui/core": "4.9.4",
"@material-ui/icons": "4.5.1",
@ -35,6 +35,7 @@
"@xstate/react": "3.0.0",
"axios": "0.26.1",
"cronstrue": "2.4.0",
"dayjs": "^1.11.2",
"formik": "2.2.9",
"history": "5.3.0",
"react": "17.0.2",
@ -53,7 +54,6 @@
"devDependencies": {
"@playwright/test": "1.21.1",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
"@react-theming/storybook-addon": "1.1.5",
"@storybook/addon-actions": "6.4.22",
"@storybook/addon-essentials": "6.4.22",
"@storybook/addon-links": "6.4.22",

View File

@ -12,15 +12,13 @@ import { OrgsPage } from "./pages/OrgsPage/OrgsPage"
import { SettingsPage } from "./pages/SettingsPage/SettingsPage"
import { AccountPage } from "./pages/SettingsPages/AccountPage/AccountPage"
import { SSHKeysPage } from "./pages/SettingsPages/SSHKeysPage/SSHKeysPage"
import { CreateWorkspacePage } from "./pages/TemplatesPages/OrganizationPage/TemplatePage/CreateWorkspacePage"
import { TemplatePage } from "./pages/TemplatesPages/OrganizationPage/TemplatePage/TemplatePage"
import { TemplatesPage } from "./pages/TemplatesPages/TemplatesPage"
import { CreateUserPage } from "./pages/UsersPage/CreateUserPage/CreateUserPage"
import { UsersPage } from "./pages/UsersPage/UsersPage"
import { WorkspacePage } from "./pages/WorkspacePage/WorkspacePage"
import { WorkspaceSettingsPage } from "./pages/WorkspaceSettingsPage/WorkspaceSettingsPage"
const TerminalPage = React.lazy(() => import("./pages/TerminalPage/TerminalPage"))
const WorkspacesPage = React.lazy(() => import("./pages/WorkspacesPage/WorkspacesPage"))
export const AppRouter: React.FC = () => (
<React.Suspense fallback={<></>}>
@ -46,36 +44,15 @@ export const AppRouter: React.FC = () => (
}
/>
<Route path="templates">
<Route path="workspaces">
<Route
index
element={
<AuthAndFrame>
<TemplatesPage />
<WorkspacesPage />
</AuthAndFrame>
}
/>
<Route path=":organization/:template">
<Route
index
element={
<AuthAndFrame>
<TemplatePage />
</AuthAndFrame>
}
/>
<Route
path="create"
element={
<RequireAuth>
<CreateWorkspacePage />
</RequireAuth>
}
/>
</Route>
</Route>
<Route path="workspaces">
<Route path=":workspace">
<Route
index

View File

@ -115,6 +115,11 @@ export const getWorkspace = async (workspaceId: string): Promise<TypesGen.Worksp
return response.data
}
export const getWorkspaces = async (userID = "me"): Promise<TypesGen.Workspace[]> => {
const response = await axios.get<TypesGen.Workspace[]>(`/api/v2/users/${userID}/workspaces`)
return response.data
}
export const getWorkspaceByOwnerAndName = async (
organizationID: string,
username = "me",

View File

@ -5,7 +5,7 @@ import { BrowserRouter as Router } from "react-router-dom"
import { SWRConfig } from "swr"
import { AppRouter } from "./AppRouter"
import { GlobalSnackbar } from "./components/GlobalSnackbar/GlobalSnackbar"
import { light } from "./theme"
import { dark } from "./theme"
import "./theme/globalFonts"
import { XServiceProvider } from "./xServices/StateContext"
@ -31,7 +31,7 @@ export const App: React.FC = () => {
}}
>
<XServiceProvider>
<ThemeProvider theme={light}>
<ThemeProvider theme={dark}>
<CssBaseline />
<AppRouter />
<GlobalSnackbar />

View File

@ -51,7 +51,7 @@ export const AdminDropdown: React.FC = () => {
<>
<div className={styles.link}>
<ListItem selected={Boolean(anchorEl)} button onClick={onOpenAdminMenu}>
<ListItemText className="no-brace" color="primary" primary={Language.menuTitle} />
<ListItemText className="no-brace" primary={Language.menuTitle} />
{anchorEl ? <CloseDropdown /> : <OpenDropdown />}
</ListItem>
</div>

View File

@ -26,7 +26,7 @@ const useStyles = makeStyles((theme) => ({
root: {
minHeight: 156,
background: theme.palette.background.default,
color: theme.palette.codeBlock.contrastText,
color: theme.palette.text.primary,
fontFamily: MONOSPACE_FONT_FAMILY,
fontSize: 13,
wordBreak: "break-all",

View File

@ -28,7 +28,7 @@ const useStyles = makeStyles((theme) => ({
justifyContent: "space-between",
alignItems: "center",
background: theme.palette.background.default,
color: theme.palette.codeBlock.contrastText,
color: theme.palette.primary.contrastText,
fontFamily: MONOSPACE_FONT_FAMILY,
fontSize: 13,
padding: theme.spacing(2),

View File

@ -1,16 +1,15 @@
import ThemeProvider from "@material-ui/styles/ThemeProvider"
import { fireEvent, render } from "@testing-library/react"
import React from "react"
import { act } from "react-dom/test-utils"
import { light } from "../../theme"
import { WrapperComponent } from "../../testHelpers/renderHelpers"
import { ConfirmDialog, ConfirmDialogProps } from "./ConfirmDialog"
namespace Helpers {
export const Component: React.FC<ConfirmDialogProps> = (props: ConfirmDialogProps) => {
return (
<ThemeProvider theme={light}>
<WrapperComponent>
<ConfirmDialog {...props} />
</ThemeProvider>
</WrapperComponent>
)
}
}

View File

@ -48,14 +48,11 @@ interface StyleProps {
const useStyles = makeStyles((theme) => ({
dialogWrapper: (props: StyleProps) => ({
"& .MuiPaper-root": {
background:
props.type === "info"
? theme.palette.confirmDialog.info.background
: theme.palette.confirmDialog.error.background,
background: props.type === "info" ? theme.palette.primary.main : theme.palette.error.dark,
},
}),
dialogContent: (props: StyleProps) => ({
color: props.type === "info" ? theme.palette.confirmDialog.info.text : theme.palette.confirmDialog.error.text,
color: props.type === "info" ? theme.palette.primary.contrastText : theme.palette.error.contrastText,
padding: theme.spacing(6),
textAlign: "center",
}),
@ -65,15 +62,15 @@ const useStyles = makeStyles((theme) => ({
description: (props: StyleProps) => ({
color:
props.type === "info"
? fade(theme.palette.confirmDialog.info.text, 0.75)
: fade(theme.palette.confirmDialog.error.text, 0.75),
? fade(theme.palette.primary.contrastText, 0.75)
: fade(theme.palette.error.contrastText, 0.75),
lineHeight: "160%",
"& strong": {
color:
props.type === "info"
? fade(theme.palette.confirmDialog.info.text, 0.95)
: fade(theme.palette.confirmDialog.error.text, 0.95),
? fade(theme.palette.primary.contrastText, 0.95)
: fade(theme.palette.error.contrastText, 0.95),
},
}),
}))

View File

@ -52,13 +52,13 @@ const useStyles = makeStyles((theme) => ({
},
copyButton: {
borderRadius: 7,
background: theme.palette.codeBlock.button.main,
color: theme.palette.codeBlock.button.contrastText,
background: theme.palette.background.default,
color: theme.palette.primary.contrastText,
padding: theme.spacing(0.85),
minWidth: 32,
"&:hover": {
background: theme.palette.codeBlock.button.hover,
background: theme.palette.background.paper,
},
},
fileCopyIcon: {

View File

@ -161,7 +161,7 @@ const useButtonStyles = makeStyles((theme) => ({
},
},
confirmDialogCancelButton: (props: StyleProps) => {
const color = props.type === "info" ? theme.palette.confirmDialog.info.text : theme.palette.confirmDialog.error.text
const color = props.type === "info" ? theme.palette.primary.contrastText : theme.palette.error.contrastText
return {
background: fade(color, 0.15),
color,

View File

@ -68,7 +68,7 @@ const useStyles = makeStyles((theme) => ({
display: "flex",
alignItems: "center",
height: 126,
background: theme.palette.hero.main,
background: theme.palette.background.default,
boxShadow: theme.shadows[3],
},
topInner: {

View File

@ -1,5 +1,5 @@
import Button from "@material-ui/core/Button"
import { lighten, makeStyles } from "@material-ui/core/styles"
import { makeStyles } from "@material-ui/core/styles"
import React from "react"
export interface HeaderButtonProps {
@ -28,10 +28,8 @@ export const HeaderButton: React.FC<HeaderButtonProps> = (props) => {
)
}
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles(() => ({
pageButton: {
whiteSpace: "nowrap",
backgroundColor: lighten(theme.palette.hero.main, 0.1),
color: "#B5BFD2",
},
}))

View File

@ -9,7 +9,7 @@ export default {
const Template: Story = (args) => (
<Margins {...args}>
<div style={{ width: "100%", background: "lightgrey" }}>Here is some content that will not get too wide!</div>
<div style={{ width: "100%", background: "black" }}>Here is some content that will not get too wide!</div>
</Margins>
)

View File

@ -8,14 +8,11 @@ const useStyles = makeStyles(() => ({
maxWidth,
padding: `0 ${sidePadding}`,
flex: 1,
width: "100%",
},
}))
export const Margins: React.FC = ({ children }) => {
const styles = useStyles()
return (
<div>
<div className={styles.margins}>{children}</div>
</div>
)
return <div className={styles.margins}>{children}</div>
}

View File

@ -21,13 +21,13 @@ export const NavbarView: React.FC<NavbarViewProps> = ({ user, onSignOut, display
<nav className={styles.root}>
<List className={styles.fixed}>
<ListItem className={styles.item}>
<NavLink className={styles.logo} to="/">
<NavLink className={styles.logo} to="/workspaces">
<Logo fill="white" opacity={1} width={125} />
</NavLink>
</ListItem>
<ListItem button className={styles.item}>
<NavLink className={styles.link} to="/templates">
Templates
<NavLink className={styles.link} to="/workspaces">
Workspaces
</NavLink>
</ListItem>
</List>
@ -47,13 +47,13 @@ const useStyles = makeStyles((theme) => ({
justifyContent: "center",
alignItems: "center",
height: navHeight,
background: theme.palette.navbar.main,
background: theme.palette.background.paper,
marginTop: 0,
transition: "margin 150ms ease",
"@media (display-mode: standalone)": {
borderTop: `1px solid ${theme.palette.divider}`,
},
borderBottom: `1px solid #383838`,
borderBottom: `1px solid ${theme.palette.divider}`,
},
fixed: {
flex: 0,
@ -68,9 +68,9 @@ const useStyles = makeStyles((theme) => ({
display: "flex",
height: navHeight,
paddingLeft: theme.spacing(4),
paddingRight: theme.spacing(2),
paddingRight: theme.spacing(4),
"& svg": {
width: 125,
width: 109,
},
},
title: {
@ -98,18 +98,17 @@ const useStyles = makeStyles((theme) => ({
"&.active": {
position: "relative",
color: theme.palette.primary.contrastText,
fontWeight: "bold",
"&::before": {
content: `"{"`,
left: 10,
content: `" "`,
bottom: 0,
left: theme.spacing(3),
background: "#C16800",
right: theme.spacing(3),
height: 2,
position: "absolute",
},
"&::after": {
content: `"}"`,
position: "absolute",
right: 10,
},
},
},
}))

View File

@ -72,7 +72,7 @@ export const AccountForm: React.FC<AccountFormProps> = ({
{error && <FormHelperText error>{error}</FormHelperText>}
<div>
<LoadingButton color="primary" loading={isLoading} type="submit" variant="contained">
<LoadingButton loading={isLoading} type="submit" variant="contained">
{isLoading ? "" : Language.updateSettings}
</LoadingButton>
</div>

View File

@ -113,7 +113,7 @@ export const SignInForm: React.FC<SignInFormProps> = ({
{authErrorMessage && <FormHelperText error>{Language.authErrorMessage}</FormHelperText>}
{methodsErrorMessage && <FormHelperText error>{Language.methodsErrorMessage}</FormHelperText>}
<div className={styles.submitBtn}>
<LoadingButton color="primary" loading={isLoading} fullWidth type="submit" variant="contained">
<LoadingButton loading={isLoading} fullWidth type="submit" variant="contained">
{isLoading ? "" : Language.passwordSignIn}
</LoadingButton>
</div>
@ -121,7 +121,7 @@ export const SignInForm: React.FC<SignInFormProps> = ({
{authMethods?.github && (
<div className={styles.submitBtn}>
<Link href={`/api/v2/users/oauth2/github/callback?redirect=${encodeURIComponent(redirectTo)}`}>
<Button color="primary" disabled={isLoading} fullWidth type="submit" variant="contained">
<Button disabled={isLoading} fullWidth type="submit" variant="contained">
{Language.githubSignIn}
</Button>
</Link>

View File

@ -1,29 +0,0 @@
import { ComponentMeta, Story } from "@storybook/react"
import React from "react"
import { MockOrganization, MockTemplate } from "../../testHelpers/entities"
import { TemplatesTable, TemplatesTableProps } from "./TemplatesTable"
export default {
title: "components/TemplatesTable",
component: TemplatesTable,
} as ComponentMeta<typeof TemplatesTable>
const Template: Story<TemplatesTableProps> = (args) => <TemplatesTable {...args} />
export const Example = Template.bind({})
Example.args = {
templates: [MockTemplate],
organizations: [MockOrganization],
}
export const Empty = Template.bind({})
Empty.args = {
templates: [],
organizations: [],
}
export const Loading = Template.bind({})
Loading.args = {
templates: undefined,
organizations: [],
}

View File

@ -1,81 +0,0 @@
import Box from "@material-ui/core/Box"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
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 { Link } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { CodeExample } from "../../components/CodeExample/CodeExample"
import { EmptyState } from "../../components/EmptyState/EmptyState"
import { TableHeaderRow } from "../../components/TableHeaders/TableHeaders"
import { TableLoader } from "../../components/TableLoader/TableLoader"
import { TableTitle } from "../../components/TableTitle/TableTitle"
export const Language = {
title: "Templates",
tableTitle: "All templates",
nameLabel: "Name",
emptyMessage: "No templates have been created yet",
emptyDescription: "Run the following command to get started:",
totalLabel: "total",
}
export interface TemplatesTableProps {
templates?: TypesGen.Template[]
organizations?: TypesGen.Organization[]
}
export const TemplatesTable: React.FC<TemplatesTableProps> = ({ templates, organizations }) => {
const isLoading = !templates || !organizations
// Create a dictionary of organization ID -> organization Name
// Needed to properly construct links to dive into a template
const orgDictionary =
organizations &&
organizations.reduce((acc: Record<string, string>, curr: TypesGen.Organization) => {
return {
...acc,
[curr.id]: curr.name,
}
}, {})
return (
<Table>
<TableHead>
<TableTitle title={Language.tableTitle} />
<TableHeaderRow>
<TableCell size="small">{Language.nameLabel}</TableCell>
</TableHeaderRow>
</TableHead>
<TableBody>
{isLoading && <TableLoader />}
{templates &&
organizations &&
orgDictionary &&
templates.map((t) => (
<TableRow key={t.id}>
<TableCell>
<Link to={`/templates/${orgDictionary[t.organization_id]}/${t.name}`}>{t.name}</Link>
</TableCell>
</TableRow>
))}
{templates && templates.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<Box p={4}>
<EmptyState
message={Language.emptyMessage}
description={Language.emptyDescription}
cta={<CodeExample code="coder templates init" />}
/>
</Box>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)
}

View File

@ -1,5 +1,7 @@
import Avatar from "@material-ui/core/Avatar"
import { makeStyles } from "@material-ui/core/styles"
import React from "react"
import { combineClasses } from "../../util/combineClasses"
import { firstLetter } from "../../util/firstLetter"
export interface UserAvatarProps {
@ -8,5 +10,17 @@ export interface UserAvatarProps {
}
export const UserAvatar: React.FC<UserAvatarProps> = ({ username, className }) => {
return <Avatar className={className}>{firstLetter(username)}</Avatar>
const styles = useStyles()
return (
<Avatar variant="square" className={combineClasses([styles.avatar, className])}>
{firstLetter(username)}
</Avatar>
)
}
const useStyles = makeStyles((theme) => ({
avatar: {
borderRadius: 2,
border: `1px solid ${theme.palette.divider}`,
},
}))

View File

@ -1,7 +1,7 @@
import { action } from "@storybook/addon-actions"
import { Story } from "@storybook/react"
import React from "react"
import { MockOrganization, MockOutdatedWorkspace, MockTemplate, MockWorkspace } from "../../testHelpers/renderHelpers"
import { MockOutdatedWorkspace, MockWorkspace } from "../../testHelpers/renderHelpers"
import { Workspace, WorkspaceProps } from "./Workspace"
export default {
@ -14,8 +14,6 @@ const Template: Story<WorkspaceProps> = (args) => <Workspace {...args} />
export const Started = Template.bind({})
Started.args = {
organization: MockOrganization,
template: MockTemplate,
workspace: MockWorkspace,
handleStart: action("start"),
handleStop: action("stop"),

View File

@ -2,7 +2,7 @@ import { makeStyles } from "@material-ui/core/styles"
import Typography from "@material-ui/core/Typography"
import React from "react"
import * as TypesGen from "../../api/typesGenerated"
import { WorkspaceStatus } from "../../pages/WorkspacePage/WorkspacePage"
import { WorkspaceStatus } from "../../util/workspace"
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
import { WorkspaceStatusBar } from "../WorkspaceStatusBar/WorkspaceStatusBar"
@ -22,8 +22,6 @@ export interface WorkspaceProps {
* Workspace is the top-level component for viewing an individual workspace
*/
export const Workspace: React.FC<WorkspaceProps> = ({
organization,
template,
workspace,
handleStart,
handleStop,
@ -37,8 +35,6 @@ export const Workspace: React.FC<WorkspaceProps> = ({
<div className={styles.root}>
<div className={styles.vertical}>
<WorkspaceStatusBar
organization={organization}
template={template}
workspace={workspace}
handleStart={handleStart}
handleStop={handleStop}

View File

@ -5,9 +5,9 @@ import Typography from "@material-ui/core/Typography"
import React from "react"
import { Link } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { WorkspaceStatus } from "../../pages/WorkspacePage/WorkspacePage"
import { TitleIconSize } from "../../theme/constants"
import { combineClasses } from "../../util/combineClasses"
import { WorkspaceStatus } from "../../util/workspace"
import { Stack } from "../Stack/Stack"
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
@ -21,6 +21,8 @@ export const Language = {
stopped: "Stopped",
starting: "Building",
stopping: "Stopping",
canceled: "Canceled",
queued: "Queued",
error: "Build Failed",
loading: "Loading Status",
deleting: "Deleting",
@ -46,14 +48,12 @@ export interface WorkspaceStatusBarProps {
* so check whether workspace job status has reached completion (whether successful or not).
*/
const canAcceptJobs = (workspaceStatus: WorkspaceStatus) =>
["started", "stopped", "deleted", "error"].includes(workspaceStatus)
["started", "stopped", "deleted", "error", "canceled"].includes(workspaceStatus)
/**
* Component for the header at the top of the workspace page
*/
export const WorkspaceStatusBar: React.FC<WorkspaceStatusBarProps> = ({
organization,
template,
workspace,
handleStart,
handleStop,
@ -63,7 +63,6 @@ export const WorkspaceStatusBar: React.FC<WorkspaceStatusBarProps> = ({
}) => {
const styles = useStyles()
const templateLink = `/templates/${organization?.name}/${template?.name}`
const settingsLink = "edit"
return (
@ -75,15 +74,6 @@ export const WorkspaceStatusBar: React.FC<WorkspaceStatusBarProps> = ({
{Language.settings}
</Link>
</div>
{organization && template && (
<Typography variant="body2" color="textSecondary">
Back to{" "}
<Link className={styles.link} to={templateLink}>
{template.name}
</Link>
</Typography>
)}
</div>
<div className={styles.horizontal}>

View File

@ -1,38 +0,0 @@
import { ComponentMeta, Story } from "@storybook/react"
import React from "react"
import { MockTemplate, MockWorkspace } from "../../testHelpers/entities"
import { WorkspacesTable, WorkspacesTableProps } from "./WorkspacesTable"
export default {
title: "components/WorkspacesTable",
component: WorkspacesTable,
} as ComponentMeta<typeof WorkspacesTable>
const Template: Story<WorkspacesTableProps> = (args) => <WorkspacesTable {...args} />
export const Example = Template.bind({})
Example.args = {
templateInfo: MockTemplate,
workspaces: [MockWorkspace],
onCreateWorkspace: () => {
console.info("Create workspace")
},
}
export const Empty = Template.bind({})
Empty.args = {
templateInfo: MockTemplate,
workspaces: [],
onCreateWorkspace: () => {
console.info("Create workspace")
},
}
export const Loading = Template.bind({})
Loading.args = {
templateInfo: MockTemplate,
workspaces: undefined,
onCreateWorkspace: () => {
console.info("Create workspace")
},
}

View File

@ -1,72 +0,0 @@
import Box from "@material-ui/core/Box"
import Button from "@material-ui/core/Button"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
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 { Link } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { EmptyState } from "../EmptyState/EmptyState"
import { TableHeaderRow } from "../TableHeaders/TableHeaders"
import { TableLoader } from "../TableLoader/TableLoader"
import { TableTitle } from "../TableTitle/TableTitle"
export const Language = {
title: "Workspaces",
nameLabel: "Name",
emptyMessage: "No workspaces have been created yet",
emptyDescription: "Create a workspace to get started",
ctaAction: "Create workspace",
}
export interface WorkspacesTableProps {
templateInfo?: TypesGen.Template
workspaces?: TypesGen.Workspace[]
onCreateWorkspace: () => void
}
export const WorkspacesTable: React.FC<WorkspacesTableProps> = ({ templateInfo, workspaces, onCreateWorkspace }) => {
const isLoading = !templateInfo || !workspaces
return (
<Table>
<TableHead>
<TableTitle title={Language.title} />
<TableHeaderRow>
<TableCell size="small">{Language.nameLabel}</TableCell>
</TableHeaderRow>
</TableHead>
<TableBody>
{isLoading && <TableLoader />}
{workspaces &&
workspaces.map((w) => (
<TableRow key={w.id}>
<TableCell>
<Link to={`/workspaces/${w.id}`}>{w.name}</Link>
</TableCell>
</TableRow>
))}
{workspaces && workspaces.length === 0 && (
<TableRow>
<TableCell colSpan={999}>
<Box p={4}>
<EmptyState
message={Language.emptyMessage}
description={Language.emptyDescription}
cta={
<Button variant="contained" color="primary" onClick={onCreateWorkspace}>
{Language.ctaAction}
</Button>
}
/>
</Box>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
)
}

View File

@ -1,72 +0,0 @@
import { makeStyles } from "@material-ui/core/styles"
import { useSelector } from "@xstate/react"
import React, { useCallback, useContext } from "react"
import { useNavigate, useParams } from "react-router-dom"
import useSWR from "swr"
import * as API from "../../../../api/api"
import * as TypesGen from "../../../../api/typesGenerated"
import { ErrorSummary } from "../../../../components/ErrorSummary/ErrorSummary"
import { FullScreenLoader } from "../../../../components/Loader/FullScreenLoader"
import { CreateWorkspaceForm } from "../../../../forms/CreateWorkspaceForm"
import { unsafeSWRArgument } from "../../../../util"
import { selectOrgId } from "../../../../xServices/auth/authSelectors"
import { XServiceContext } from "../../../../xServices/StateContext"
export const CreateWorkspacePage: React.FC = () => {
const { organization: organizationName, template: templateName } = useParams()
const navigate = useNavigate()
const styles = useStyles()
const xServices = useContext(XServiceContext)
const myOrgId = useSelector(xServices.authXService, selectOrgId)
const { data: organizationInfo, error: organizationError } = useSWR<TypesGen.Organization, Error>(
() => `/api/v2/users/me/organizations/${organizationName}`,
)
const { data: template, error: templateError } = useSWR<TypesGen.Template, Error>(() => {
return `/api/v2/organizations/${unsafeSWRArgument(organizationInfo).id}/templates/${templateName}`
})
const onCancel = useCallback(async () => {
navigate(`/templates/${organizationName}/${templateName}`)
}, [navigate, organizationName, templateName])
const onSubmit = async (organizationId: string, req: TypesGen.CreateWorkspaceRequest) => {
const workspace = await API.Workspace.create(organizationId, req)
navigate(`/workspaces/${workspace.id}`)
return workspace
}
if (organizationError) {
return <ErrorSummary error={organizationError} />
}
if (templateError) {
return <ErrorSummary error={templateError} />
}
if (!template) {
return <FullScreenLoader />
}
if (!myOrgId) {
return <ErrorSummary error={Error("no organization id")} />
}
return (
<div className={styles.root}>
<CreateWorkspaceForm onCancel={onCancel} onSubmit={onSubmit} template={template} organizationId={myOrgId} />
</div>
)
}
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
alignItems: "center",
height: "100vh",
backgroundColor: theme.palette.background.paper,
},
}))

View File

@ -1,70 +0,0 @@
import React from "react"
import { useNavigate, useParams } from "react-router-dom"
import useSWR from "swr"
import * as TypesGen from "../../../../api/typesGenerated"
import { ErrorSummary } from "../../../../components/ErrorSummary/ErrorSummary"
import { Header } from "../../../../components/Header/Header"
import { Margins } from "../../../../components/Margins/Margins"
import { Stack } from "../../../../components/Stack/Stack"
import { WorkspacesTable } from "../../../../components/WorkspacesTable/WorkspacesTable"
import { unsafeSWRArgument } from "../../../../util"
import { firstOrItem } from "../../../../util/array"
export const Language = {
subtitle: "workspaces",
}
export const TemplatePage: React.FC = () => {
const navigate = useNavigate()
const { template: templateName, organization: organizationName } = useParams()
const { data: organizationInfo, error: organizationError } = useSWR<TypesGen.Organization, Error>(
() => `/api/v2/users/me/organizations/${organizationName}`,
)
const { data: templateInfo, error: templateError } = useSWR<TypesGen.Template, Error>(
() => `/api/v2/organizations/${unsafeSWRArgument(organizationInfo).id}/templates/${templateName}`,
)
// This just grabs all workspaces... and then later filters them to match the
// current template.
const { data: workspaces, error: workspacesError } = useSWR<TypesGen.Workspace[], Error>(
() => `/api/v2/organizations/${unsafeSWRArgument(organizationInfo).id}/workspaces`,
)
const hasError = organizationError || templateError || workspacesError
const createWorkspace = () => {
navigate(`/templates/${organizationName}/${templateName}/create`)
}
const perTemplateWorkspaces =
workspaces && templateInfo
? workspaces.filter((workspace) => {
return workspace.template_id === templateInfo.id
})
: undefined
return (
<Stack spacing={4}>
<Header
title={firstOrItem(templateName, "")}
description={firstOrItem(organizationName, "")}
subTitle={perTemplateWorkspaces ? `${perTemplateWorkspaces.length} ${Language.subtitle}` : ""}
action={{
text: "Create Workspace",
onClick: createWorkspace,
}}
/>
<Margins>
{organizationError && <ErrorSummary error={organizationError} />}
{templateError && <ErrorSummary error={templateError} />}
{workspacesError && <ErrorSummary error={workspacesError} />}
{!hasError && (
<WorkspacesTable templateInfo={templateInfo} workspaces={workspaces} onCreateWorkspace={createWorkspace} />
)}
</Margins>
</Stack>
)
}

View File

@ -1,37 +0,0 @@
import React from "react"
import useSWR from "swr"
import * as TypesGen from "../../api/typesGenerated"
import { ErrorSummary } from "../../components/ErrorSummary/ErrorSummary"
import { Header } from "../../components/Header/Header"
import { Margins } from "../../components/Margins/Margins"
import { Stack } from "../../components/Stack/Stack"
import { TemplatesTable } from "../../components/TemplatesTable/TemplatesTable"
export const Language = {
title: "Templates",
tableTitle: "All templates",
nameLabel: "Name",
emptyMessage: "No templates have been created yet",
emptyDescription: "Run the following command to get started:",
totalLabel: "total",
}
export const TemplatesPage: React.FC = () => {
const { data: orgs, error: orgsError } = useSWR<TypesGen.Organization[], Error>("/api/v2/users/me/organizations")
const { data: templates, error } = useSWR<TypesGen.Template[] | undefined, Error>(
orgs ? `/api/v2/organizations/${orgs[0].id}/templates` : undefined,
)
const subTitle = templates ? `${templates.length} ${Language.totalLabel}` : undefined
const hasError = orgsError || error
return (
<Stack spacing={4}>
<Header title={Language.title} subTitle={subTitle} />
<Margins>
{error && <ErrorSummary error={error} />}
{orgsError && <ErrorSummary error={orgsError} />}
{!hasError && <TemplatesTable organizations={orgs} templates={templates} />}
</Margins>
</Stack>
)
}

View File

@ -56,9 +56,7 @@ describe("Workspace Page", () => {
it("shows a workspace", async () => {
renderWithAuth(<WorkspacePage />, { route: `/workspaces/${MockWorkspace.id}`, path: "/workspaces/:workspace" })
const workspaceName = await screen.findByText(MockWorkspace.name)
const templateName = await screen.findByText(MockTemplate.name)
expect(workspaceName).toBeDefined()
expect(templateName).toBeDefined()
})
it("shows the status of the workspace", async () => {
renderWithAuth(<WorkspacePage />, { route: `/workspaces/${MockWorkspace.id}`, path: "/workspaces/:workspace" })

View File

@ -7,19 +7,8 @@ import { Margins } from "../../components/Margins/Margins"
import { Stack } from "../../components/Stack/Stack"
import { Workspace } from "../../components/Workspace/Workspace"
import { firstOrItem } from "../../util/array"
import { getWorkspaceStatus } from "../../util/workspace"
import { XServiceContext } from "../../xServices/StateContext"
import { selectWorkspaceStatus } from "../../xServices/workspace/workspaceSelectors"
export type WorkspaceStatus =
| "started"
| "starting"
| "stopped"
| "stopping"
| "error"
| "loading"
| "deleting"
| "deleted"
| "canceling"
export const WorkspacePage: React.FC = () => {
const { workspace: workspaceQueryParam } = useParams()
@ -27,9 +16,10 @@ export const WorkspacePage: React.FC = () => {
const xServices = useContext(XServiceContext)
const [workspaceState, workspaceSend] = useActor(xServices.workspaceXService)
const { workspace, template, organization, getWorkspaceError, getTemplateError, getOrganizationError } =
workspaceState.context
const workspaceStatus = useSelector(xServices.workspaceXService, selectWorkspaceStatus)
const { workspace, getWorkspaceError, getTemplateError, getOrganizationError } = workspaceState.context
const workspaceStatus = useSelector(xServices.workspaceXService, (state) => {
return getWorkspaceStatus(state.context.workspace?.latest_build)
})
/**
* Get workspace, template, and organization on mount and whenever workspaceId changes.
@ -48,8 +38,6 @@ export const WorkspacePage: React.FC = () => {
<Margins>
<Stack spacing={4}>
<Workspace
organization={organization}
template={template}
workspace={workspace}
handleStart={() => workspaceSend("START")}
handleStop={() => workspaceSend("STOP")}

View File

@ -0,0 +1,37 @@
import { screen } from "@testing-library/react"
import { rest } from "msw"
import React from "react"
import { MockWorkspace } from "../../testHelpers/entities"
import { history, render } from "../../testHelpers/renderHelpers"
import { server } from "../../testHelpers/server"
import WorkspacesPage from "./WorkspacesPage"
import { Language } from "./WorkspacesPageView"
describe("WorkspacesPage", () => {
beforeEach(() => {
history.replace("/workspaces")
})
it("renders an empty workspaces page", async () => {
// Given
server.use(
rest.get("/api/v2/users/me/workspaces", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json([]))
}),
)
// When
render(<WorkspacesPage />)
// Then
await screen.findByText(Language.emptyView)
})
it("renders a filled workspaces page", async () => {
// When
render(<WorkspacesPage />)
// Then
await screen.findByText(MockWorkspace.name)
})
})

View File

@ -0,0 +1,20 @@
import { useMachine } from "@xstate/react"
import React from "react"
import { workspacesMachine } from "../../xServices/workspaces/workspacesXService"
import { WorkspacesPageView } from "./WorkspacesPageView"
const WorkspacesPage: React.FC = () => {
const [workspacesState] = useMachine(workspacesMachine)
return (
<>
<WorkspacesPageView
loading={workspacesState.hasTag("loading")}
workspaces={workspacesState.context.workspaces}
error={workspacesState.context.getWorkspacesError}
/>
</>
)
}
export default WorkspacesPage

View File

@ -0,0 +1,50 @@
import { ComponentMeta, Story } from "@storybook/react"
import React from "react"
import { ProvisionerJobStatus, Workspace } from "../../api/typesGenerated"
import { MockWorkspace } from "../../testHelpers/entities"
import { WorkspacesPageView, WorkspacesPageViewProps } from "./WorkspacesPageView"
export default {
title: "pages/WorkspacesPageView",
component: WorkspacesPageView,
} as ComponentMeta<typeof WorkspacesPageView>
const Template: Story<WorkspacesPageViewProps> = (args) => <WorkspacesPageView {...args} />
const createWorkspaceWithStatus = (status: ProvisionerJobStatus, transition = "start"): Workspace => {
return {
...MockWorkspace,
latest_build: {
...MockWorkspace.latest_build,
transition,
job: {
...MockWorkspace.latest_build.job,
status: status,
},
},
}
}
// This is type restricted to prevent future statuses from slipping
// through the cracks unchecked!
const workspaces: { [key in ProvisionerJobStatus]: Workspace } = {
canceled: createWorkspaceWithStatus("canceled"),
canceling: createWorkspaceWithStatus("canceling"),
failed: createWorkspaceWithStatus("failed"),
pending: createWorkspaceWithStatus("pending"),
running: createWorkspaceWithStatus("running"),
succeeded: createWorkspaceWithStatus("succeeded"),
}
export const AllStates = Template.bind({})
AllStates.args = {
workspaces: [
...Object.values(workspaces),
createWorkspaceWithStatus("running", "stop"),
createWorkspaceWithStatus("succeeded", "stop"),
createWorkspaceWithStatus("running", "delete"),
],
}
export const Empty = Template.bind({})
Empty.args = {}

View File

@ -0,0 +1,234 @@
import Avatar from "@material-ui/core/Avatar"
import Button from "@material-ui/core/Button"
import Link from "@material-ui/core/Link"
import { makeStyles, Theme } from "@material-ui/core/styles"
import Table from "@material-ui/core/Table"
import TableBody from "@material-ui/core/TableBody"
import TableCell from "@material-ui/core/TableCell"
import TableHead from "@material-ui/core/TableHead"
import TableRow from "@material-ui/core/TableRow"
import AddCircleOutline from "@material-ui/icons/AddCircleOutline"
import useTheme from "@material-ui/styles/useTheme"
import dayjs from "dayjs"
import relativeTime from "dayjs/plugin/relativeTime"
import React from "react"
import { Link as RouterLink } from "react-router-dom"
import * as TypesGen from "../../api/typesGenerated"
import { WorkspaceBuild } from "../../api/typesGenerated"
import { Margins } from "../../components/Margins/Margins"
import { Stack } from "../../components/Stack/Stack"
import { firstLetter } from "../../util/firstLetter"
import { getWorkspaceStatus } from "../../util/workspace"
dayjs.extend(relativeTime)
export const Language = {
createButton: "Create Workspace",
emptyView: "so you can check out your repositories, edit your source code, and build and test your software.",
}
export interface WorkspacesPageViewProps {
loading?: boolean
workspaces?: TypesGen.Workspace[]
error?: unknown
}
export const WorkspacesPageView: React.FC<WorkspacesPageViewProps> = (props) => {
const styles = useStyles()
const theme: Theme = useTheme()
return (
<Stack spacing={4}>
<Margins>
<div className={styles.actions}>
<Button startIcon={<AddCircleOutline />}>{Language.createButton}</Button>
</div>
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Template</TableCell>
<TableCell>Version</TableCell>
<TableCell>Last Built</TableCell>
<TableCell>Status</TableCell>
</TableRow>
</TableHead>
<TableBody>
{!props.loading && !props.workspaces?.length && (
<TableRow>
<TableCell colSpan={999}>
<div className={styles.welcome}>
<span>
<Link component={RouterLink} to="/workspaces/new">
Create a workspace
</Link>
&nbsp;{Language.emptyView}
</span>
</div>
</TableCell>
</TableRow>
)}
{props.workspaces?.map((workspace) => {
const status = getStatus(theme, workspace.latest_build)
return (
<TableRow key={workspace.id} className={styles.workspaceRow}>
<TableCell>
<div className={styles.workspaceName}>
<Avatar variant="square" className={styles.workspaceAvatar}>
{firstLetter(workspace.name)}
</Avatar>
<Link component={RouterLink} to={`/workspaces/${workspace.id}`} className={styles.workspaceLink}>
<b>{workspace.name}</b>
<span>{workspace.owner_name}</span>
</Link>
</div>
</TableCell>
<TableCell>{workspace.template_name}</TableCell>
<TableCell>
{workspace.outdated ? (
<span style={{ color: theme.palette.error.main }}>outdated</span>
) : (
<span style={{ color: theme.palette.text.secondary }}>up to date</span>
)}
</TableCell>
<TableCell>
<span style={{ color: theme.palette.text.secondary }}>
{dayjs().to(dayjs(workspace.latest_build.created_at))}
</span>
</TableCell>
<TableCell>
<span style={{ color: status.color }}>{status.status}</span>
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</Margins>
</Stack>
)
}
const getStatus = (
theme: Theme,
build: WorkspaceBuild,
): {
color: string
status: string
} => {
const status = getWorkspaceStatus(build)
switch (status) {
case undefined:
return {
color: theme.palette.text.secondary,
status: "Loading...",
}
case "started":
return {
color: theme.palette.success.main,
status: "⦿ Running",
}
case "starting":
return {
color: theme.palette.success.main,
status: "⦿ Starting",
}
case "stopping":
return {
color: theme.palette.text.secondary,
status: "◍ Stopping",
}
case "stopped":
return {
color: theme.palette.text.secondary,
status: "◍ Stopped",
}
case "deleting":
return {
color: theme.palette.text.secondary,
status: "⦸ Deleting",
}
case "deleted":
return {
color: theme.palette.text.secondary,
status: "⦸ Deleted",
}
case "canceling":
return {
color: theme.palette.warning.light,
status: "◍ Canceling",
}
case "canceled":
return {
color: theme.palette.text.secondary,
status: "◍ Canceled",
}
case "error":
return {
color: theme.palette.error.main,
status: "ⓧ Failed",
}
case "queued":
return {
color: theme.palette.text.secondary,
status: "◍ Queued",
}
}
throw new Error("unknown status " + status)
}
const useStyles = makeStyles((theme) => ({
actions: {
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
display: "flex",
height: theme.spacing(6),
"& button": {
marginLeft: "auto",
},
},
welcome: {
paddingTop: theme.spacing(12),
paddingBottom: theme.spacing(12),
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
"& span": {
maxWidth: 600,
textAlign: "center",
fontSize: theme.spacing(2),
lineHeight: `${theme.spacing(3)}px`,
},
},
workspaceRow: {
"& > td": {
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
},
},
workspaceAvatar: {
borderRadius: 2,
marginRight: theme.spacing(1),
width: 24,
height: 24,
fontSize: 16,
},
workspaceName: {
display: "flex",
alignItems: "center",
},
workspaceLink: {
display: "flex",
flexDirection: "column",
color: theme.palette.text.primary,
textDecoration: "none",
"&:hover": {
textDecoration: "underline",
},
"& span": {
fontSize: 12,
color: theme.palette.text.secondary,
},
},
}))

View File

@ -2,5 +2,5 @@ import React from "react"
import { Navigate } from "react-router-dom"
export const IndexPage: React.FC = () => {
return <Navigate to="/templates" replace />
return <Navigate to="/workspaces" replace />
}

View File

@ -112,7 +112,7 @@ export const MockWorkspaceAutostopEnabled: TypesGen.UpdateWorkspaceAutostartRequ
export const MockWorkspaceBuild: TypesGen.WorkspaceBuild = {
after_id: "",
before_id: "",
created_at: "",
created_at: new Date().toDateString(),
id: "test-workspace-build",
initiator_id: "",
job: MockProvisionerJob,

View File

@ -33,6 +33,9 @@ export const handlers = [
rest.post("/api/v2/users/me/workspaces", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json(M.MockWorkspace))
}),
rest.get("/api/v2/users/me/workspaces", async (req, res, ctx) => {
return res(ctx.status(200), ctx.json([M.MockWorkspace]))
}),
rest.get("/api/v2/users/me/organizations", (req, res, ctx) => {
return res(ctx.status(200), ctx.json([M.MockOrganization]))
}),

View File

@ -2,11 +2,11 @@ export const spacing = 8
export const borderRadius = 4
export const buttonBorderWidth = 2
export const MONOSPACE_FONT_FAMILY =
"'Fira Code', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace"
"'IBM Plex Mono', 'Lucida Console', 'Lucida Sans Typewriter', 'Liberation Mono', 'Monaco', 'Courier New', Courier, monospace"
export const BODY_FONT_FAMILY = `"Inter", sans-serif`
export const lightButtonShadow = "0 2px 2px rgba(0, 23, 121, 0.08)"
export const emptyBoxShadow = "none"
export const navHeight = 56
export const navHeight = 42
export const maxWidth = 1380
export const sidePadding = "50px"
export const TitleIconSize = 48

View File

@ -1,6 +1,6 @@
// Monospace fonts used for code, button styles, and banners
import "@fontsource/fira-code/400.css"
import "@fontsource/fira-code/600.css"
import "@fontsource/ibm-plex-mono/400.css"
import "@fontsource/ibm-plex-mono/600.css"
// Main body copy font
import "@fontsource/inter/300.css"
import "@fontsource/inter/400.css"

View File

@ -1 +1 @@
export { dark, light } from "./theme"
export { dark } from "./theme"

View File

@ -1,561 +1,84 @@
import { darken, fade } from "@material-ui/core/styles/colorManipulator"
import { Breakpoints } from "@material-ui/core/styles/createBreakpoints"
import {
BODY_FONT_FAMILY,
borderRadius,
buttonBorderWidth,
emptyBoxShadow,
lightButtonShadow,
spacing,
} from "./constants"
import { CustomPalette } from "./palettes"
import { typography } from "./typography"
import { PaletteOptions, SimplePaletteColorOptions } from "@material-ui/core/styles/createPalette"
import { MONOSPACE_FONT_FAMILY } from "./constants"
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const getOverrides = (palette: CustomPalette, breakpoints: Breakpoints) => {
const containedButtonShadow = palette.type === "dark" ? emptyBoxShadow : lightButtonShadow
export const getOverrides = (palette: PaletteOptions) => {
return {
MuiAvatar: {
root: {
width: 32,
height: 32,
fontSize: 24,
border: `1px solid ${palette.divider}`,
},
},
MuiTable: {
MuiButton: {
root: {
backgroundColor: palette.background.paper,
borderRadius: borderRadius * 2,
boxShadow: `0 0 0 1px ${palette.action.hover}`,
"&.is-inline": {
background: "none",
borderRadius: 0,
// Prevents a loading button from collapsing!
minHeight: 42,
fontWeight: "regular",
fontFamily: MONOSPACE_FONT_FAMILY,
fontSize: 16,
textTransform: "none",
letterSpacing: "none",
border: `1px solid ${palette.divider}`,
},
contained: {
boxShadow: "none",
color: palette.text?.primary,
backgroundColor: "#151515",
"&:hover": {
boxShadow: "none",
backgroundColor: "#000000",
},
},
},
MuiTableHead: {
root: {
"& .MuiTableCell-root": {
...typography.overline,
paddingTop: spacing,
paddingBottom: spacing,
color: palette.text.secondary,
backgroundColor: palette.background.default,
".MuiTable-root.is-inline &": {
background: "none",
},
},
"& .MuiTableRow-root:first-child .MuiTableCell-root:first-child": {
borderTopLeftRadius: borderRadius * 2,
".MuiTable-root.is-inline &": {
borderRadius: 0,
},
},
"& .MuiTableRow-root:first-child .MuiTableCell-root:last-child": {
borderTopRightRadius: borderRadius * 2,
".MuiTable-root.is-inline &": {
borderRadius: 0,
},
},
fontFamily: MONOSPACE_FONT_FAMILY,
textTransform: "uppercase",
},
},
MuiTableSortLabel: {
MuiTable: {
root: {
lineHeight: "20px",
"&$active": {
"&& $icon": {
color: palette.text.primary,
},
},
},
icon: {
"&.MuiSvgIcon-root": {
width: 18,
height: 18,
marginLeft: 2,
},
// Gives the appearance of a border!
borderRadius: 2,
border: `1px solid ${palette.divider}`,
},
},
MuiTableCell: {
head: {
color: palette.text?.secondary,
},
root: {
"&:first-child": {
paddingLeft: spacing * 4,
},
},
},
MuiTablePagination: {
input: {
height: "auto",
marginTop: 0,
border: `1px solid ${palette.action.disabled}`,
},
select: {
paddingTop: 6,
fontSize: 14,
},
selectIcon: {
right: -4,
},
},
MuiList: {
root: {
boxSizing: "border-box",
"& .MuiDivider-root": {
opacity: 0.5,
},
},
},
MuiListItem: {
root: {
minHeight: 24,
position: "relative",
"&.active": {
color: "white",
},
},
gutters: {
padding: spacing / 2,
paddingLeft: spacing * 2,
paddingRight: spacing * 2,
},
},
MuiListItemAvatar: {
root: {
minWidth: 46,
},
},
MuiListItemIcon: {
root: {
minWidth: 36,
color: palette.text.primary,
"& .MuiSvgIcon-root": {
width: 20,
height: 20,
},
},
},
MuiListSubheader: {
root: {
...typography.overline,
lineHeight: 2.5,
},
sticky: {
backgroundColor: palette.background.paper,
},
},
MuiMenu: {
paper: {
marginTop: spacing,
},
},
MuiMenuItem: {
root: {
minHeight: 48,
fontFamily: MONOSPACE_FONT_FAMILY,
fontSize: 16,
[breakpoints.up("sm")]: {
minHeight: 48,
background: palette.background?.paper,
borderBottom: `1px solid ${palette.divider}`,
padding: 8,
"&:first-child": {
paddingLeft: 32,
},
},
gutters: {
padding: spacing,
paddingLeft: spacing * 2,
paddingRight: spacing * 2,
},
},
MuiListItemText: {
primary: {
fontWeight: 500,
},
secondary: {
fontSize: 12,
},
},
MuiOutlinedInput: {
root: {
fontSize: 14,
"&$focused $notchedOutline": {
borderWidth: 1,
"&:last-child": {
paddingRight: 32,
},
},
notchedOutline: {
borderWidth: 1,
borderColor: palette.action.disabled,
},
},
MuiButton: {
root: {
minHeight: 40,
paddingLeft: 20,
paddingRight: 20,
fontWeight: 500,
"& .MuiSvgIcon-root": {
verticalAlign: "middle",
},
},
contained: {
backgroundColor: palette.hero.button,
color: palette.primary.contrastText,
boxShadow: containedButtonShadow,
"&:hover": {
backgroundColor: darken(palette.hero.button, 0.25),
},
"&$disabled": {
color: fade(palette.text.disabled, 0.5),
},
},
containedPrimary: {
boxShadow: containedButtonShadow,
},
containedSecondary: {
boxShadow: containedButtonShadow,
},
outlined: {
borderColor: palette.action.disabled,
borderWidth: buttonBorderWidth,
"&:hover": {
color: palette.primary.main,
borderColor: palette.primary.main,
borderWidth: buttonBorderWidth,
},
"&$disabled": {
color: fade(palette.text.disabled, 0.5),
},
},
outlinedPrimary: {
borderColor: palette.primary.main,
borderWidth: buttonBorderWidth,
"&:hover": {
borderWidth: buttonBorderWidth,
},
},
outlinedSecondary: {
borderColor: palette.secondary.main,
borderWidth: buttonBorderWidth,
"&:hover": {
color: palette.secondary.main,
borderWidth: buttonBorderWidth,
},
},
text: {
"&$disabled": {
color: fade(palette.text.disabled, 0.5),
},
},
sizeSmall: {
minHeight: 32,
paddingLeft: 10,
paddingRight: 10,
letterSpacing: 1.2,
fontSize: 13,
"&.MuiButton-outlined": {
borderWidth: 1,
},
},
sizeLarge: {
minHeight: 46,
paddingLeft: spacing * 3,
paddingRight: spacing * 3,
},
},
MuiButtonGroup: {
contained: {
boxShadow: containedButtonShadow,
},
},
MuiLink: {
root: {
fontWeight: 600,
},
},
MuiInputBase: {
root: {
minHeight: 40,
background: palette.background.paper,
marginTop: "12px",
borderRadius,
"&$disabled": {
background: palette.action.disabledBackground,
},
"&$focused .MuiSelect-icon": {
color: palette.primary.light,
},
},
input: {
fontSize: 16,
"&::placeholder": {
color: palette.text.secondary,
opacity: 1,
},
// See this thread https://stackoverflow.com/questions/69196525/how-to-change-the-color-of-the-calendar-icon-of-the-textfield-date-picker-in-ma
"&::-webkit-calendar-picker-indicator": {
filter:
palette.type === "dark"
? "invert(95%) sepia(0%) saturate(1082%) hue-rotate(173deg) brightness(84%) contrast(80%);"
: undefined,
},
borderRadius: 2,
},
},
MuiInputLabel: {
shrink: {
fontSize: 14,
marginTop: "2px",
left: "-12px",
transform: "translate(16px, -6px) scale(0.8)",
color: palette.text.primary,
},
outlined: {
letterSpacing: "0.2px",
lineHeight: "16px",
fontFamily: BODY_FONT_FAMILY,
"&$shrink": {
transform: "translate(14px, -13px)",
},
},
},
MuiChip: {
MuiOutlinedInput: {
root: {
fontSize: 16,
fontWeight: 500,
borderRadius: borderRadius,
backgroundColor: fade(palette.text.secondary, 0.1),
color: palette.text.secondary,
},
sizeSmall: {
height: 20,
},
labelSmall: {
fontSize: 12,
paddingLeft: 6,
paddingRight: 6,
},
colorPrimary: {
backgroundColor: fade(palette.primary.main, 0.1),
color: palette.primary.main,
},
colorSecondary: {
backgroundColor: fade(palette.secondary.main, 0.15),
color: palette.secondary.main,
"& input:-webkit-autofill": {
WebkitBoxShadow: `0 0 0 1000px ${palette.background?.paper} inset`,
},
},
},
MuiSelect: {
MuiLink: {
root: {
// Matches MuiInputBase-input height
lineHeight: "1.1875em",
overflow: "hidden",
},
select: {
"&:focus": {
borderRadius,
},
},
icon: {
"&.MuiSvgIcon-root": {
fontSize: 20,
margin: "3px 6px 0 0",
},
},
iconOutlined: {
right: 0,
},
iconOpen: {
transform: "none",
},
},
MuiDialog: {
paper: {
borderRadius: 11,
},
paperWidthSm: {
maxWidth: "530px",
},
},
MuiDialogTitle: {
root: {
color: palette.text.primary,
padding: `27px ${spacing * 6}px 0 ${spacing * 6}px`,
fontSize: 32,
fontWeight: 700,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
background: palette.background.paper,
},
},
MuiDialogContent: {
root: {
padding: `0 ${spacing * 6}px ${spacing * 6}px ${spacing * 6}px`,
},
},
MuiDialogContentText: {
root: {
color: palette.action.active,
},
},
MuiDialogActions: {
root: {
padding: 0,
},
spacing: {
"& > :not(:first-child)": {
marginLeft: 0,
},
},
},
MuiFormHelperText: {
root: {
fontSize: 12,
lineHeight: "16px",
},
contained: {
marginTop: 6,
marginLeft: spacing * 0.5,
},
},
MuiBackdrop: {
root: {
backgroundColor: fade("#242424", 0.6),
},
},
MuiInputAdornment: {
root: {
"& .MuiSvgIcon-root": {
color: palette.text.secondary,
},
},
positionStart: {
marginRight: 12,
marginLeft: 6,
},
},
MuiCheckbox: {
root: {
"& .MuiSvgIcon-root": {
width: 16,
height: 16,
margin: 1,
},
},
colorPrimary: {
"&.MuiCheckbox-root": {
color: palette.primary.main,
"&$disabled": {
color: palette.action.disabled,
},
},
},
colorSecondary: {
"&.MuiCheckbox-root": {
color: palette.secondary.main,
"&$disabled": {
color: palette.action.disabled,
},
},
},
},
MuiRadio: {
root: {
"& .MuiSvgIcon-root": {
width: 18,
height: 18,
},
},
colorPrimary: {
"&.MuiRadio-root": {
color: palette.primary.main,
"&$disabled": {
color: palette.action.disabled,
},
},
},
colorSecondary: {
"&.MuiRadio-root": {
color: palette.secondary.main,
"&$disabled": {
color: palette.action.disabled,
},
},
},
},
MuiTabs: {
root: {
minHeight: 40,
},
indicator: {
height: 3,
},
},
MuiTab: {
root: {
minHeight: 70,
marginRight: spacing * 5,
textTransform: "none",
fontWeight: 400,
fontSize: 16,
letterSpacing: 3,
"&:last-child": {
marginRight: 0,
},
"&.MuiButtonBase-root": {
minWidth: 0,
padding: 0,
},
"&.Mui-selected .MuiTab-wrapper": {
color: palette.primary.contrastText,
fontWeight: "bold",
},
},
wrapper: {},
textColorPrimary: {
color: palette.text.secondary,
},
textColorSecondary: {
color: palette.text.secondary,
},
},
MuiStepper: {
root: {
background: "none",
},
},
// Labs components aren't typed properly, so cast overrides
MuiAutocomplete: {
endAdornment: {
"& .MuiSvgIcon-root": {
fontSize: 20,
},
},
inputRoot: {
'&[class*="MuiOutlinedInput-root"]': {
"& $endAdornment": {
right: 6,
},
},
color: (palette.primary as SimplePaletteColorOptions).light,
},
},
}

View File

@ -1,173 +1,8 @@
import { Palette } from "@material-ui/core/styles/createPalette"
import { PaletteOptions } from "@material-ui/core/styles/createPalette"
/**
* Augment MUI Palette with Coder-specific design system
*/
declare module "@material-ui/core/styles/createPalette" {
interface Palette {
codeBlock: {
// Text color for codeblocks
contrastText: string
// Background color for codeblocks
main: string
button: {
// Background for buttons inside a codeblock
main: string
// Hover background color for buttons inside a codeblock
hover: string
// Text color for buttons inside a codeblock
contrastText: string
}
}
confirmDialog: {
error: {
background: string
text: string
}
info: {
background: string
text: string
}
}
navbar: {
main: string
}
// Styles for the 'hero' banner on several coder admin pages
hero: {
// Background color of the 'hero' banner
main: string
// Color for hero 'buttons'
button: string
}
}
interface PaletteOptions {
codeBlock: {
contrastText: string
main: string
button: {
main: string
hover: string
contrastText: string
}
}
confirmDialog: {
error: {
background: string
text: string
}
info: {
background: string
text: string
}
}
navbar: {
main: string
}
hero: {
main: string
button: string
}
}
}
/**
* CustomPalette implements a minimal subset of MUI Palette interface for our
* light and dark themes.
*/
export type CustomPalette = Pick<
Palette,
| "action"
| "background"
| "codeBlock"
| "confirmDialog"
| "divider"
| "error"
| "hero"
| "info"
| "navbar"
| "primary"
| "secondary"
| "text"
| "type"
>
/**
* Light theme color palette, the default
*
* This maps to our design system at:
* https://www.figma.com/file/VkXU4873QOsSprMQV02GgR/Design-System?node-id=3%3A2
*/
export const lightPalette: CustomPalette = {
type: "light",
background: {
default: "#F3F3F3",
paper: "#FFF",
},
codeBlock: {
main: "#F3F3F3",
contrastText: "rgba(0, 0, 0, 0.9)",
button: {
main: "#E6ECE6",
hover: "#DAEBDA",
contrastText: "#000",
},
},
confirmDialog: {
error: {
background: "#912F42",
text: "#FFF",
},
info: {
background: "#000",
text: "#FFF",
},
},
primary: {
main: "#519A54",
light: "#A2E0A5",
dark: "#3A783D",
contrastText: "#FFF",
},
info: {
main: "#000",
light: "#000",
dark: "#000",
contrastText: "#FFF",
},
navbar: {
main: "#242424",
},
secondary: {
main: "#F7CD6F",
light: "#FFE7A0",
dark: "#BF9331",
contrastText: "#FFF",
},
error: {
main: "#DD4764",
light: "#A14E5E",
dark: "#912F42",
contrastText: "#FFF",
},
hero: {
main: "#242424",
button: "#747474",
},
text: {
primary: "#000",
secondary: "#747474",
disabled: "#749367",
hint: "#749367",
},
action: {
active: "#242424",
hover: "rgba(0, 0, 0, 0.1)",
hoverOpacity: 0.08,
selected: "#D0EFD2",
disabled: "#DDE2EC",
disabledBackground: "#F3F3F3",
},
divider: "#DDE2EC",
}
/**
* Dark theme color palette
@ -175,52 +10,31 @@ export const lightPalette: CustomPalette = {
* This maps to our design system at:
* https://www.figma.com/file/VkXU4873QOsSprMQV02GgR/Design-System?node-id=219%3A40
*/
export const darkPalette: CustomPalette = {
export const darkPalette: PaletteOptions = {
type: "dark",
primary: lightPalette.primary,
secondary: lightPalette.secondary,
info: lightPalette.info,
error: lightPalette.error,
codeBlock: {
main: "rgb(24, 26, 27)",
contrastText: "rgba(255, 255, 255, 0.8)",
button: {
main: "rgba(255, 255, 255, 0.1)",
hover: "rgba(255, 255, 255, 0.25)",
contrastText: "#FFF",
},
primary: {
main: "#409BF4",
contrastText: "#f8f8f8",
light: "#79B8FF",
dark: "#1976D2",
},
confirmDialog: {
error: lightPalette.confirmDialog.error,
info: {
background: "rgba(255, 255, 255, 0.95)",
text: "rgb(31, 33, 35)",
},
},
hero: {
main: "#141414",
button: "#333333",
},
navbar: {
main: "rgb(8, 9, 10)",
secondary: {
main: "#008510",
contrastText: "#f8f8f8",
},
background: {
default: "rgb(24, 26, 27)",
paper: "rgb(31, 33, 35)",
default: "#1F1F1F",
paper: "#292929",
},
text: {
primary: "rgba(255, 255, 255, 0.95)",
secondary: "#BDBDBD",
disabled: "#BDBDBD",
hint: "#BDBDBD",
primary: "#F8F8F8",
secondary: "#C1C1C1",
},
action: {
active: "#FFF",
hover: "rgba(255, 255, 255, 0.1)",
hoverOpacity: 0.1,
selected: "rgba(255, 255, 255, 0.2)",
disabled: "rgba(255, 255, 255, 0.1)",
disabledBackground: "rgba(255, 255, 255, 0.12)",
divider: "#383838",
warning: {
main: "#C16800",
},
success: {
main: "#6BBE00",
},
divider: "rgba(255, 255, 255, 0.12)",
}

View File

@ -4,34 +4,21 @@ import { ComponentsProps } from "@material-ui/core/styles/props"
* These are global overrides to MUI components and we may move away from using them in the future.
*/
export const props = {
MuiButtonBase: {
disableRipple: true,
},
MuiButton: {
variant: "contained",
},
MuiTextField: {
margin: "dense",
InputProps: {
labelWidth: 0,
},
variant: "outlined",
spellCheck: false,
},
MuiInputLabel: {
shrink: true,
},
MuiFormControl: {
variant: "outlined",
margin: "dense",
},
MuiInput: {
spellCheck: false,
autoCorrect: "off",
},
MuiOutlinedInput: {
notched: false,
},
MuiDialogTitle: {
disableTypography: true,
},
MuiMenu: {
anchorOrigin: {
vertical: "bottom",
@ -51,7 +38,4 @@ export const props = {
textColor: "primary",
indicatorColor: "primary",
},
MuiTab: {
disableTouchRipple: true,
},
} as ComponentsProps

View File

@ -1,15 +1,13 @@
import { createMuiTheme } from "@material-ui/core/styles"
import { PaletteOptions } from "@material-ui/core/styles/createPalette"
import { Overrides } from "@material-ui/core/styles/overrides"
import { borderRadius } from "./constants"
import { getOverrides } from "./overrides"
import { CustomPalette, darkPalette, lightPalette } from "./palettes"
import { darkPalette } from "./palettes"
import { props } from "./props"
import { typography } from "./typography"
const makeTheme = (palette: CustomPalette) => {
// Grab defaults to re-use in overrides
const { breakpoints } = createMuiTheme()
const makeTheme = (palette: PaletteOptions) => {
return createMuiTheme({
palette,
typography,
@ -17,9 +15,8 @@ const makeTheme = (palette: CustomPalette) => {
borderRadius,
},
props,
overrides: getOverrides(palette, breakpoints) as Overrides,
overrides: getOverrides(palette) as Overrides,
})
}
export const light = makeTheme(lightPalette)
export const dark = makeTheme(darkPalette)

View File

@ -1,7 +1,18 @@
import { State } from "xstate"
import { WorkspaceBuildTransition } from "../../api/types"
import { WorkspaceStatus } from "../../pages/WorkspacePage/WorkspacePage"
import { WorkspaceContext, WorkspaceEvent } from "./workspaceXService"
import { WorkspaceBuildTransition } from "../api/types"
import { WorkspaceBuild } from "../api/typesGenerated"
export type WorkspaceStatus =
| "queued"
| "started"
| "starting"
| "stopped"
| "stopping"
| "error"
| "loading"
| "deleting"
| "deleted"
| "canceled"
| "canceling"
const inProgressToStatus: Record<WorkspaceBuildTransition, WorkspaceStatus> = {
start: "starting",
@ -15,22 +26,23 @@ const succeededToStatus: Record<WorkspaceBuildTransition, WorkspaceStatus> = {
delete: "deleted",
}
export const selectWorkspaceStatus = (state: State<WorkspaceContext, WorkspaceEvent>): WorkspaceStatus => {
const transition = state.context.workspace?.latest_build.transition as WorkspaceBuildTransition
const jobStatus = state.context.workspace?.latest_build.job.status
// Converts a workspaces status to a human-readable form.
export const getWorkspaceStatus = (workspaceBuild?: WorkspaceBuild): WorkspaceStatus => {
const transition = workspaceBuild?.transition as WorkspaceBuildTransition
const jobStatus = workspaceBuild?.job.status
switch (jobStatus) {
case undefined:
return "loading"
case "succeeded":
return succeededToStatus[transition]
case "pending":
return inProgressToStatus[transition]
return "queued"
case "running":
return inProgressToStatus[transition]
case "canceling":
return "canceling"
case "canceled":
return "error"
return "canceled"
case "failed":
return "error"
}

View File

@ -0,0 +1,61 @@
import { assign, createMachine } from "xstate"
import * as API from "../../api/api"
import * as TypesGen from "../../api/typesGenerated"
interface WorkspaceContext {
workspaces?: TypesGen.Workspace[]
getWorkspacesError?: Error | unknown
}
type WorkspaceEvent = { type: "GET_WORKSPACE"; workspaceId: string }
export const workspacesMachine = createMachine(
{
tsTypes: {} as import("./workspacesXService.typegen").Typegen0,
schema: {
context: {} as WorkspaceContext,
events: {} as WorkspaceEvent,
services: {} as {
getWorkspaces: {
data: TypesGen.Workspace[]
}
},
},
id: "workspaceState",
initial: "gettingWorkspaces",
states: {
gettingWorkspaces: {
entry: "clearGetWorkspacesError",
invoke: {
src: "getWorkspaces",
id: "getWorkspaces",
onDone: {
target: "done",
actions: ["assignWorkspaces", "clearGetWorkspacesError"],
},
onError: {
target: "error",
actions: "assignGetWorkspacesError",
},
},
tags: "loading",
},
done: {},
error: {},
},
},
{
actions: {
assignWorkspaces: assign({
workspaces: (_, event) => event.data,
}),
assignGetWorkspacesError: assign({
getWorkspacesError: (_, event) => event.data,
}),
clearGetWorkspacesError: (context) => assign({ ...context, getWorkspacesError: undefined }),
},
services: {
getWorkspaces: () => API.getWorkspaces(),
},
},
)

View File

@ -63,6 +63,7 @@ const config: Configuration = {
"/api": {
target: "http://localhost:3000",
ws: true,
secure: false,
},
},
static: ["./static"],

View File

@ -1269,10 +1269,10 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
"@fontsource/fira-code@4.5.9":
"@fontsource/ibm-plex-mono@4.5.9":
version "4.5.9"
resolved "https://registry.yarnpkg.com/@fontsource/fira-code/-/fira-code-4.5.9.tgz#8ca3e6020f9d3c340a643c5c0a12b2ebf37dc7a6"
integrity sha512-moi9UVTOfQFXjiUAITy5W727dIP6c0K5TGPN+wTaFHn+/5flc/V0Uq9cKTs39yGrPUOneTbuAe8C8q7CzUP4Aw==
resolved "https://registry.yarnpkg.com/@fontsource/ibm-plex-mono/-/ibm-plex-mono-4.5.9.tgz#96968bebc4b1ea559818a9c52c87b3854a8145ba"
integrity sha512-goblhmAX48GELIUQnWBg6AKVZklcTUu6NwF8tRiIzlxTZuOspbzHrW/3sF3WOH6+mJVay9n6QLbbikOfxSRekQ==
"@fontsource/inter@4.5.7":
version "4.5.7"
@ -1298,11 +1298,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@icons/material@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@ -1801,64 +1796,6 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
"@reach/component-component@^0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@reach/component-component/-/component-component-0.1.3.tgz#5d156319572dc38995b246f81878bc2577c517e5"
integrity sha512-a1USH7L3bEfDdPN4iNZGvMEFuBfkdG+QNybeyDv8RloVFgZYRoM+KGXyy2KOfEnTUM8QWDRSROwaL3+ts5Angg==
"@reach/observe-rect@^1.0.3":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@reach/observe-rect/-/observe-rect-1.2.0.tgz#d7a6013b8aafcc64c778a0ccb83355a11204d3b2"
integrity sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==
"@reach/rect@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@reach/rect/-/rect-0.2.1.tgz#7343020174c90e2290b844d17c03fd9c78e6b601"
integrity sha512-aZ9RsNHDMQ3zETonikqu9/85iXxj+LPqZ9Gr9UAncj3AufYmGeWG3XG6b37B+7ORH+mkhVpLU2ZlIWxmOe9Cqg==
dependencies:
"@reach/component-component" "^0.1.3"
"@reach/observe-rect" "^1.0.3"
"@react-theming/flatten@^0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@react-theming/flatten/-/flatten-0.1.1.tgz#62dc8a11f77b3dc1c6f26937ad4044a4d3e13853"
integrity sha512-cieWCbO4xTgl8/LAUTEgiafEiFIcheARteyxXddnUHm/+7POCmRvSE/woHGXlVH7dFBlCbI4y/e5ikMzwBA3CA==
dependencies:
color "^3.1.2"
color-convert "^2.0.1"
color-parse "^1.3.8"
color-rgba "^2.1.1"
color-string "^1.5.3"
color-stringify "^1.2.1"
flat "^5.0.0"
is-color-stop "^1.1.0"
rgb-hex "^3.0.0"
"@react-theming/storybook-addon@1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@react-theming/storybook-addon/-/storybook-addon-1.1.5.tgz#cb00ce26139859b2e233619b4c29b2cc391767c9"
integrity sha512-m4LM4j/dDzwMdvdHvsdiM64Qb6pI7DdALHHMoCCe0u4OFlAxtHk67FlwMkEGfsoV3zZWHYhz8hP7rcSrPUMbVw==
dependencies:
"@react-theming/flatten" "^0.1.1"
"@react-theming/theme-name" "^1.0.3"
"@react-theming/theme-swatch" "^1.0.0"
"@storybook/addon-devkit" "^1.4.2"
"@usulpro/react-json-view" "^2.0.1"
react-color "^2.18.0"
"@react-theming/theme-name@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@react-theming/theme-name/-/theme-name-1.0.3.tgz#f722defe226dc349b32d7b8a699611ff6eeea008"
integrity sha512-5tYnKIG3wUJ3GTX50ldeU+nxLTEU8WXEGsHk8mWeG9XGC4VxKIp2gSqS6B/opCGmfuIFm459Dtru8PSuEXiJJg==
dependencies:
color-name-list "^4.7.1"
nearest-color "^0.4.4"
"@react-theming/theme-swatch@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@react-theming/theme-swatch/-/theme-swatch-1.0.0.tgz#ba3ffc8e69c65a220b9bf1da0c2d5134287037e8"
integrity sha512-tOzDTUbFB5uQLMVHJ4fXWYZ4i7JIKjyrS7SlHDoscRZqM69lmT+s9fSZoD1/InTdX0M7Jh8thXF0SzeoxnD1/Q==
"@sinonjs/commons@^1.7.0":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d"
@ -1934,18 +1871,6 @@
lodash "^4.17.21"
ts-dedent "^2.0.0"
"@storybook/addon-devkit@^1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@storybook/addon-devkit/-/addon-devkit-1.4.2.tgz#a230fef4554c604799def525541c61af06e8d22d"
integrity sha512-ggy34eCzmiKOwgV7xYNjlPClGpmtnYODPJv0vkCKiDyPeVLHocq2UZ7ZkOhQ5GO7TM7aLeeC1JBS00tZId9oLA==
dependencies:
"@reach/rect" "^0.2.1"
"@storybook/addons" "^6.1.18"
"@storybook/core-events" "^6.1.18"
"@storybook/theming" "^6.1.18"
deep-equal "^2.0.2"
prop-types "^15.6.2"
"@storybook/addon-docs@6.4.22":
version "6.4.22"
resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-6.4.22.tgz#19f22ede8ae31291069af7ab5abbc23fa269012b"
@ -2095,7 +2020,7 @@
prop-types "^15.7.2"
regenerator-runtime "^0.13.7"
"@storybook/addons@6.4.22", "@storybook/addons@^6.1.18":
"@storybook/addons@6.4.22":
version "6.4.22"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.4.22.tgz#e165407ca132c2182de2d466b7ff7c5644b6ad7b"
integrity sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==
@ -2388,7 +2313,7 @@
util-deprecate "^1.0.2"
webpack "4"
"@storybook/core-events@6.4.22", "@storybook/core-events@^6.1.18":
"@storybook/core-events@6.4.22":
version "6.4.22"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.4.22.tgz#c09b0571951affd4254028b8958a4d8652700989"
integrity sha512-5GYY5+1gd58Gxjqex27RVaX6qbfIQmJxcbzbNpXGNSqwqAuIIepcV1rdCVm6I4C3Yb7/AQ3cN5dVbf33QxRIwA==
@ -2668,7 +2593,7 @@
ts-dedent "^2.0.0"
util-deprecate "^1.0.2"
"@storybook/theming@6.4.22", "@storybook/theming@^6.1.18":
"@storybook/theming@6.4.22":
version "6.4.22"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.4.22.tgz#19097eec0366447ddd0d6917b0e0f81d0ec5e51e"
integrity sha512-NVMKH/jxSPtnMTO4VCN1k47uztq+u9fWv4GSnzq/eezxdGg9ceGL4/lCrNGoNajht9xbrsZ4QvsJ/V2sVGM8wA==
@ -3375,17 +3300,6 @@
"@typescript-eslint/types" "5.23.0"
eslint-visitor-keys "^3.0.0"
"@usulpro/react-json-view@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@usulpro/react-json-view/-/react-json-view-2.0.1.tgz#2240e9319a9c6258df3b69961572a995ddca35d1"
integrity sha512-X8Ik4JmZF2Cu7vZTJQwHIbDqNaJEUEGZmdAPxKe4Ed+Xa3dyVTAeA9ea/nTNCzKRTZBIxvJFXvibpglpJ136BA==
dependencies:
color-string "^1.5.3"
flux "^4.0.1"
react-base16-styling "^0.6.0"
react-lifecycles-compat "^3.0.4"
react-textarea-autosize "^6.1.0"
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -4092,11 +4006,6 @@ arrify@^2.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
asn1.js@^5.2.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
@ -4179,11 +4088,6 @@ autoprefixer@^9.8.6:
postcss "^7.0.32"
postcss-value-parser "^4.1.0"
available-typed-arrays@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
axe-core@^4.3.5:
version "4.4.0"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.0.tgz#f93be7f81017eb8bedeb1859cc8092cc918d2dc8"
@ -4394,11 +4298,6 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base16@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
base64-js@^1.0.2, base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -5101,7 +5000,7 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^1.9.0, color-convert@^1.9.3:
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@ -5115,69 +5014,21 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
color-name-list@^4.7.1:
version "4.15.0"
resolved "https://registry.yarnpkg.com/color-name-list/-/color-name-list-4.15.0.tgz#23a632bdb37fdad4c7f50303d0068c410fe3d601"
integrity sha512-4P3pFob8w6LNnku94oIacj8suCfhOLmY+25bmfoOwqFtuhLTD4Oux+/aUBdZLcvLK3fHrBe6XrzAU2IbwoWnQA==
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4:
color-name@^1.1.4, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-parse@^1.3.8, color-parse@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/color-parse/-/color-parse-1.4.2.tgz#78651f5d34df1a57f997643d86f7f87268ad4eb5"
integrity sha512-RI7s49/8yqDj3fECFZjUI1Yi0z/Gq1py43oNJivAIIDSyJiOZLfYCRQEgn8HEVAj++PcRe8AnL2XF0fRJ3BTnA==
dependencies:
color-name "^1.0.0"
color-rgba@^2.1.1:
version "2.4.0"
resolved "https://registry.yarnpkg.com/color-rgba/-/color-rgba-2.4.0.tgz#ae85819c530262c29fc2da129fc7c8f9efc57015"
integrity sha512-Nti4qbzr/z2LbUWySr7H9dk3Rl7gZt7ihHAxlgT4Ho90EXWkjtkL1avTleu9yeGuqrt/chxTB6GKK8nZZ6V0+Q==
dependencies:
color-parse "^1.4.2"
color-space "^2.0.0"
color-space@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/color-space/-/color-space-2.0.0.tgz#ae7813abcbe3dabda9e3e2266b0675f688b24977"
integrity sha512-Bu8P/usGNuVWushjxcuaGSkhT+L2KX0cvgMGMTF0KJ7lFeqonhsntT68d6Yu3uwZzCmbF7KTB9EV67AGcUXhJw==
color-string@^1.5.3, color-string@^1.6.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa"
integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color-stringify@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/color-stringify/-/color-stringify-1.2.1.tgz#289b5cf0dff64d147bf76b2317f93a573a3fe071"
integrity sha1-KJtc8N/2TRR792sjF/k6Vzo/4HE=
dependencies:
color-name "^1.0.0"
color-support@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
color@^3.1.2:
version "3.2.1"
resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
dependencies:
color-convert "^1.9.3"
color-string "^1.6.0"
colord@^2.9.1:
version "2.9.2"
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
@ -5490,13 +5341,6 @@ cronstrue@2.4.0:
resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-2.4.0.tgz#16c6d10a17b90c37a71c7e8fb3bb67d0243d70e5"
integrity sha512-KDJgE8XoT0Nupt1iljNGAQnxkfITwIYkL7mHrzH4a0AWyrj7Xk6GVCNPN3Avs7tU2yYoNuDculMKp9T3jysbPA==
cross-fetch@^3.0.4:
version "3.1.5"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
dependencies:
node-fetch "2.6.7"
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -5534,11 +5378,6 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=
css-declaration-sorter@^6.0.3:
version "6.1.4"
resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4"
@ -5749,6 +5588,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
dayjs@^1.11.2:
version "1.11.2"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -5792,27 +5636,6 @@ dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
deep-equal@^2.0.2:
version "2.0.5"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.5.tgz#55cd2fe326d83f9cbf7261ef0e060b3f724c5cb9"
integrity sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==
dependencies:
call-bind "^1.0.0"
es-get-iterator "^1.1.1"
get-intrinsic "^1.0.1"
is-arguments "^1.0.4"
is-date-object "^1.0.2"
is-regex "^1.1.1"
isarray "^2.0.5"
object-is "^1.1.4"
object-keys "^1.1.1"
object.assign "^4.1.2"
regexp.prototype.flags "^1.3.0"
side-channel "^1.0.3"
which-boxed-primitive "^1.0.1"
which-collection "^1.0.1"
which-typed-array "^1.1.2"
deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
@ -6251,7 +6074,7 @@ error-stack-parser@^2.0.6:
dependencies:
stackframe "^1.1.1"
es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1:
es-abstract@^1.19.0, es-abstract@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==
@ -6282,7 +6105,7 @@ es-array-method-boxes-properly@^1.0.0:
resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e"
integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==
es-get-iterator@^1.0.2, es-get-iterator@^1.1.1:
es-get-iterator@^1.0.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7"
integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==
@ -6883,31 +6706,6 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
fbemitter@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==
dependencies:
fbjs "^3.0.0"
fbjs-css-vars@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
fbjs@^3.0.0, fbjs@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.2.tgz#dfae08a85c66a58372993ce2caf30863f569ff94"
integrity sha512-qv+boqYndjElAJHNN3NoM8XuwQZ1j2m3kEvTgdle8IDjr6oUbkEpvABWtj/rQl3vq4ew7dnElBxL4YJAwTVqQQ==
dependencies:
cross-fetch "^3.0.4"
fbjs-css-vars "^1.0.0"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.30"
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
@ -7047,11 +6845,6 @@ flat-cache@^3.0.4:
flatted "^3.1.0"
rimraf "^3.0.2"
flat@^5.0.0:
version "5.0.2"
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
flatted@^3.1.0:
version "3.2.5"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
@ -7065,14 +6858,6 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
flux@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7"
integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==
dependencies:
fbemitter "^3.0.0"
fbjs "^3.0.1"
follow-redirects@^1.0.0:
version "1.14.8"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
@ -7088,11 +6873,6 @@ for-in@^1.0.2:
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
foreground-child@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53"
@ -7301,7 +7081,7 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
@ -7674,11 +7454,6 @@ headers-polyfill@^3.0.4:
resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-3.0.4.tgz#cd70c815a441dd882372fcd6eda212ce997c9b18"
integrity sha512-I1DOM1EdWYntdrnCvqQtcKwSSuiTzoqOExy4v1mdcFixFZABlWP4IPHdmoLtPda0abMHqDOY4H9svhQ10DFR4w==
hex-color-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
highlight.js@^10.1.1, highlight.js@~10.7.0:
version "10.7.3"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
@ -7729,16 +7504,6 @@ hpack.js@^2.1.6:
readable-stream "^2.0.1"
wbuf "^1.1.0"
hsl-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e"
integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=
hsla-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg=
html-encoding-sniffer@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
@ -8097,7 +7862,7 @@ is-alphanumerical@^1.0.0:
is-alphabetical "^1.0.0"
is-decimal "^1.0.0"
is-arguments@^1.0.4, is-arguments@^1.1.0:
is-arguments@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
@ -8110,11 +7875,6 @@ is-arrayish@^0.2.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
is-arrayish@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
@ -8166,18 +7926,6 @@ is-ci@^2.0.0:
dependencies:
ci-info "^2.0.0"
is-color-stop@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345"
integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=
dependencies:
css-color-names "^0.0.4"
hex-color-regex "^1.1.0"
hsl-regex "^1.0.0"
hsla-regex "^1.0.0"
rgb-regex "^1.0.1"
rgba-regex "^1.0.0"
is-core-module@^2.2.0, is-core-module@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
@ -8199,7 +7947,7 @@ is-data-descriptor@^1.0.0:
dependencies:
kind-of "^6.0.0"
is-date-object@^1.0.1, is-date-object@^1.0.2:
is-date-object@^1.0.1:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
@ -8303,7 +8051,7 @@ is-interactive@^1.0.0:
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
is-map@^2.0.1, is-map@^2.0.2:
is-map@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==
@ -8374,7 +8122,7 @@ is-potential-custom-element-name@^1.0.1:
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
is-regex@^1.1.1, is-regex@^1.1.2, is-regex@^1.1.4:
is-regex@^1.1.2, is-regex@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
@ -8382,7 +8130,7 @@ is-regex@^1.1.1, is-regex@^1.1.2, is-regex@^1.1.4:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-set@^2.0.1, is-set@^2.0.2:
is-set@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec"
integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==
@ -8416,17 +8164,6 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
dependencies:
has-symbols "^1.0.2"
is-typed-array@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79"
integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==
dependencies:
available-typed-arrays "^1.0.5"
call-bind "^1.0.2"
es-abstract "^1.18.5"
foreach "^2.0.5"
has-tostringtag "^1.0.0"
is-typedarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@ -8437,11 +8174,6 @@ is-unicode-supported@^0.1.0:
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
is-weakmap@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2"
integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==
is-weakref@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
@ -8449,14 +8181,6 @@ is-weakref@^1.0.1:
dependencies:
call-bind "^1.0.2"
is-weakset@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d"
integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==
dependencies:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
is-whitespace-character@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
@ -9466,26 +9190,16 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash-es@^4.17.15, lodash-es@^4.17.21:
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.curry@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.flow@^3.3.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
lodash.memoize@4.1.2, lodash.memoize@4.x, lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -9501,7 +9215,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.0.1, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -9609,11 +9323,6 @@ markdown-to-jsx@^7.1.3:
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.6.tgz#421487df2a66fe4231d94db653a34da033691e62"
integrity sha512-1wrIGZYwIG2gR3yfRmbr4FlQmhaAKoKTpRo4wur4fp9p0njU1Hi7vR8fj0AUKKIcPduiJmPprzmCB5B/GvlC7g==
material-colors@^1.2.1:
version "1.2.6"
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@ -10042,11 +9751,6 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
nearest-color@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/nearest-color/-/nearest-color-0.4.4.tgz#fb812072b511f4f09a0a316903332e09fa5d7f1d"
integrity sha512-orhcaIORC10tf41Ld2wwlcC+FaAavHG87JHWB3eHH5p7v2k9Tzym2XNEZzLAm5YJwGv6Q38WWc7SOb+Qfu/4NQ==
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
@ -10082,7 +9786,7 @@ node-dir@^0.1.10:
dependencies:
minimatch "^3.0.2"
node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7:
node-fetch@^2.6.1, node-fetch@^2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
@ -10206,7 +9910,7 @@ nwsapi@^2.2.0:
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
object-assign@^4.1.0, object-assign@^4.1.1:
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
@ -10225,14 +9929,6 @@ object-inspect@^1.11.0, object-inspect@^1.9.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
object-is@^1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@ -11246,13 +10942,6 @@ promise.prototype.finally@^3.1.0:
define-properties "^1.1.3"
es-abstract "^1.19.1"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
dependencies:
asap "~2.0.3"
prompts@^2.0.1, prompts@^2.4.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
@ -11261,7 +10950,7 @@ prompts@^2.0.1, prompts@^2.4.0:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
prop-types@^15.0.0, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -11366,11 +11055,6 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
pure-color@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
qs@6.9.7:
version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
@ -11446,29 +11130,6 @@ raw-loader@^4.0.2:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
react-base16-styling@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
dependencies:
base16 "^1.0.0"
lodash.curry "^4.0.1"
lodash.flow "^3.3.0"
pure-color "^1.2.0"
react-color@^2.18.0:
version "2.19.3"
resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d"
integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==
dependencies:
"@icons/material" "^0.2.4"
lodash "^4.17.15"
lodash-es "^4.17.15"
material-colors "^1.2.1"
prop-types "^15.5.10"
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
react-colorful@^5.1.2:
version "5.5.1"
resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784"
@ -11645,13 +11306,6 @@ react-syntax-highlighter@^13.5.3:
prismjs "^1.21.0"
refractor "^3.1.0"
react-textarea-autosize@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5"
integrity sha512-F6bI1dgib6fSvG8so1HuArPUv+iVEfPliuLWusLF+gAKz0FbB4jLrWUrTAeq1afnPT2c9toEZYUdz/y1uKMy4A==
dependencies:
prop-types "^15.6.0"
react-textarea-autosize@^8.3.0:
version "8.3.3"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8"
@ -11679,13 +11333,6 @@ react@17.0.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"
reactcss@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
dependencies:
lodash "^4.0.1"
read-pkg-up@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
@ -11799,7 +11446,7 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.3.1:
regexp.prototype.flags@^1.3.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307"
integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==
@ -12033,21 +11680,6 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rgb-hex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-3.0.0.tgz#eab0168cc1279563b18a14605315389142e2e487"
integrity sha512-8h7ZcwxCBDKvchSWbWngJuSCqJGQ6nDuLLg+QcRyQDbX9jMWt+PpPeXAhSla0GOooEomk3lCprUpGkMdsLjKyg==
rgb-regex@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1"
integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE=
rgba-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -12332,7 +11964,7 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
setimmediate@^1.0.4, setimmediate@^1.0.5:
setimmediate@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
@ -12391,7 +12023,7 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
side-channel@^1.0.3, side-channel@^1.0.4:
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
@ -12405,13 +12037,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af"
integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
dependencies:
is-arrayish "^0.3.1"
sirv@^1.0.7:
version "1.0.19"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49"
@ -13139,11 +12764,6 @@ tiny-warning@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tinycolor2@^1.4.1:
version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -13408,11 +13028,6 @@ typescript@4.6.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9"
integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==
ua-parser-js@^0.7.30:
version "0.7.31"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
uglify-js@^3.1.4:
version "3.15.1"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.1.tgz#9403dc6fa5695a6172a91bc983ea39f0f7c9086d"
@ -14085,7 +13700,7 @@ whatwg-url@^8.0.0, whatwg-url@^8.5.0:
tr46 "^2.1.0"
webidl-conversions "^6.1.0"
which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2:
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
@ -14096,28 +13711,6 @@ which-boxed-primitive@^1.0.1, which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"
which-collection@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906"
integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==
dependencies:
is-map "^2.0.1"
is-set "^2.0.1"
is-weakmap "^2.0.1"
is-weakset "^2.0.1"
which-typed-array@^1.1.2:
version "1.1.7"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793"
integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==
dependencies:
available-typed-arrays "^1.0.5"
call-bind "^1.0.2"
es-abstract "^1.18.5"
foreach "^2.0.5"
has-tostringtag "^1.0.0"
is-typed-array "^1.1.7"
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"