mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: cleanup inline prop type definitions (#11317)
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import { type FC } from "react";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
import { LicenseBannerView } from "./LicenseBannerView";
|
||||
|
||||
export const LicenseBanner: React.FC = () => {
|
||||
export const LicenseBanner: FC = () => {
|
||||
const { entitlements } = useDashboard();
|
||||
const { errors, warnings } = entitlements;
|
||||
|
||||
if (errors.length > 0 || warnings.length > 0) {
|
||||
return <LicenseBannerView errors={errors} warnings={warnings} />;
|
||||
} else {
|
||||
if (errors.length === 0 && warnings.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <LicenseBannerView errors={errors} warnings={warnings} />;
|
||||
};
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import { type FC } from "react";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
import { ServiceBannerView } from "./ServiceBannerView";
|
||||
|
||||
export const ServiceBanner: React.FC = () => {
|
||||
export const ServiceBanner: FC = () => {
|
||||
const { appearance } = useDashboard();
|
||||
const { message, background_color, enabled } =
|
||||
appearance.config.service_banner;
|
||||
|
||||
if (!enabled) {
|
||||
if (!enabled || message === undefined || background_color === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (message !== undefined && background_color !== undefined) {
|
||||
return (
|
||||
<ServiceBannerView
|
||||
message={message}
|
||||
backgroundColor={background_color}
|
||||
isPreview={appearance.isPreview}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ServiceBannerView
|
||||
message={message}
|
||||
backgroundColor={background_color}
|
||||
isPreview={appearance.isPreview}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import Button from "@mui/material/Button";
|
||||
import LaunchOutlined from "@mui/icons-material/LaunchOutlined";
|
||||
import type { FC } from "react";
|
||||
import type { FC, ReactNode } from "react";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
||||
export const Header: FC<{
|
||||
title: string | JSX.Element;
|
||||
description?: string | JSX.Element;
|
||||
interface HeaderProps {
|
||||
title: ReactNode;
|
||||
description?: ReactNode;
|
||||
secondary?: boolean;
|
||||
docsHref?: string;
|
||||
}> = ({ title, description, docsHref, secondary }) => {
|
||||
}
|
||||
|
||||
export const Header: FC<HeaderProps> = ({
|
||||
title,
|
||||
description,
|
||||
docsHref,
|
||||
secondary,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import MuiDialog, { DialogProps as MuiDialogProps } from "@mui/material/Dialog";
|
||||
import { type ReactNode } from "react";
|
||||
import { type FC, type ReactNode } from "react";
|
||||
import { ConfirmDialogType } from "./types";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import LoadingButton, { LoadingButtonProps } from "@mui/lab/LoadingButton";
|
||||
@@ -30,7 +30,7 @@ const typeToColor = (type: ConfirmDialogType): LoadingButtonProps["color"] => {
|
||||
/**
|
||||
* Quickly handles most modals actions, some combination of a cancel and confirm button
|
||||
*/
|
||||
export const DialogActionButtons: React.FC<DialogActionButtonsProps> = ({
|
||||
export const DialogActionButtons: FC<DialogActionButtonsProps> = ({
|
||||
cancelText = "Cancel",
|
||||
confirmText = "Confirm",
|
||||
confirmLoading = false,
|
||||
@@ -159,13 +159,7 @@ const styles = {
|
||||
export type DialogProps = MuiDialogProps;
|
||||
|
||||
/**
|
||||
* Wrapper around Material UI's Dialog component. Conveniently exports all of
|
||||
* Dialog's components in one import, so for example `<DialogContent />` becomes
|
||||
* `<Dialog.Content />` etc. Also contains some custom Dialog components listed below.
|
||||
*
|
||||
* See original component's Material UI documentation here: https://material-ui.com/components/dialogs/
|
||||
* Re-export of MUI's Dialog component, for convenience.
|
||||
* @link See original documentation here: https://mui.com/material-ui/react-dialog/
|
||||
*/
|
||||
export const Dialog: React.FC<DialogProps> = (props) => {
|
||||
// Wrapped so we can add custom attributes below
|
||||
return <MuiDialog {...props} />;
|
||||
};
|
||||
export { MuiDialog as Dialog };
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import { WorkspaceAgent } from "api/typesGenerated";
|
||||
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
|
||||
import WarningRounded from "@mui/icons-material/WarningRounded";
|
||||
import Link from "@mui/material/Link";
|
||||
import { type FC } from "react";
|
||||
import type { WorkspaceAgent } from "api/typesGenerated";
|
||||
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
|
||||
import {
|
||||
HelpTooltip,
|
||||
HelpTooltipContent,
|
||||
HelpTooltipText,
|
||||
HelpTooltipTitle,
|
||||
} from "components/HelpTooltip/HelpTooltip";
|
||||
import Link from "@mui/material/Link";
|
||||
import { PopoverTrigger } from "components/Popover/Popover";
|
||||
|
||||
// If we think in the agent status and lifecycle into a single enum/state I’d
|
||||
@@ -18,7 +19,7 @@ import { PopoverTrigger } from "components/Popover/Popover";
|
||||
// connected:ready, connected:shutting_down, connected:shutdown_timeout,
|
||||
// connected:shutdown_error, connected:off.
|
||||
|
||||
const ReadyLifecycle = () => {
|
||||
const ReadyLifecycle: FC = () => {
|
||||
return (
|
||||
<div
|
||||
role="status"
|
||||
@@ -29,7 +30,7 @@ const ReadyLifecycle = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const StartingLifecycle: React.FC = () => {
|
||||
const StartingLifecycle: FC = () => {
|
||||
return (
|
||||
<Tooltip title="Starting...">
|
||||
<div
|
||||
@@ -41,9 +42,11 @@ const StartingLifecycle: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const StartTimeoutLifecycle: React.FC<{
|
||||
interface AgentStatusProps {
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
}
|
||||
|
||||
const StartTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<HelpTooltip>
|
||||
<PopoverTrigger role="status" aria-label="Agent timeout">
|
||||
@@ -68,9 +71,7 @@ const StartTimeoutLifecycle: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const StartErrorLifecycle: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
const StartErrorLifecycle: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<HelpTooltip>
|
||||
<PopoverTrigger role="status" aria-label="Start error">
|
||||
@@ -94,7 +95,7 @@ const StartErrorLifecycle: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const ShuttingDownLifecycle: React.FC = () => {
|
||||
const ShuttingDownLifecycle: FC = () => {
|
||||
return (
|
||||
<Tooltip title="Stopping...">
|
||||
<div
|
||||
@@ -106,9 +107,7 @@ const ShuttingDownLifecycle: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ShutdownTimeoutLifecycle: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
const ShutdownTimeoutLifecycle: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<HelpTooltip>
|
||||
<PopoverTrigger role="status" aria-label="Stop timeout">
|
||||
@@ -132,9 +131,7 @@ const ShutdownTimeoutLifecycle: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const ShutdownErrorLifecycle: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
const ShutdownErrorLifecycle: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<HelpTooltip>
|
||||
<PopoverTrigger role="status" aria-label="Stop error">
|
||||
@@ -158,7 +155,7 @@ const ShutdownErrorLifecycle: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const OffLifecycle: React.FC = () => {
|
||||
const OffLifecycle: FC = () => {
|
||||
return (
|
||||
<Tooltip title="Stopped">
|
||||
<div
|
||||
@@ -170,9 +167,7 @@ const OffLifecycle: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ConnectedStatus: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
const ConnectedStatus: FC<AgentStatusProps> = ({ agent }) => {
|
||||
// This is to support legacy agents that do not support
|
||||
// reporting the lifecycle_state field.
|
||||
if (agent.scripts.length === 0) {
|
||||
@@ -208,7 +203,7 @@ const ConnectedStatus: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const DisconnectedStatus: React.FC = () => {
|
||||
const DisconnectedStatus: FC = () => {
|
||||
return (
|
||||
<Tooltip title="Disconnected">
|
||||
<div
|
||||
@@ -220,7 +215,7 @@ const DisconnectedStatus: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ConnectingStatus: React.FC = () => {
|
||||
const ConnectingStatus: FC = () => {
|
||||
return (
|
||||
<Tooltip title="Connecting...">
|
||||
<div
|
||||
@@ -232,9 +227,7 @@ const ConnectingStatus: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const TimeoutStatus: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
const TimeoutStatus: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<HelpTooltip>
|
||||
<PopoverTrigger role="status" aria-label="Timeout">
|
||||
@@ -258,9 +251,7 @@ const TimeoutStatus: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export const AgentStatus: React.FC<{
|
||||
agent: WorkspaceAgent;
|
||||
}> = ({ agent }) => {
|
||||
export const AgentStatus: FC<AgentStatusProps> = ({ agent }) => {
|
||||
return (
|
||||
<ChooseOne>
|
||||
<Cond condition={agent.status === "connected"}>
|
||||
|
||||
@@ -3,12 +3,19 @@ import type { WorkspaceAgent } from "api/typesGenerated";
|
||||
import { agentVersionStatus, getDisplayVersionStatus } from "utils/workspace";
|
||||
import { AgentOutdatedTooltip } from "./AgentOutdatedTooltip";
|
||||
|
||||
export const AgentVersion: FC<{
|
||||
interface AgentVersionProps {
|
||||
agent: WorkspaceAgent;
|
||||
serverVersion: string;
|
||||
serverAPIVersion: string;
|
||||
onUpdate: () => void;
|
||||
}> = ({ agent, serverVersion, serverAPIVersion, onUpdate }) => {
|
||||
}
|
||||
|
||||
export const AgentVersion: FC<AgentVersionProps> = ({
|
||||
agent,
|
||||
serverVersion,
|
||||
serverAPIVersion,
|
||||
onUpdate,
|
||||
}) => {
|
||||
const { status } = getDisplayVersionStatus(
|
||||
agent.version,
|
||||
serverVersion,
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { WorkspaceApp } from "api/typesGenerated";
|
||||
import { FC } from "react";
|
||||
import ComputerIcon from "@mui/icons-material/Computer";
|
||||
import { type FC } from "react";
|
||||
import type { WorkspaceApp } from "api/typesGenerated";
|
||||
|
||||
export const BaseIcon: FC<{ app: WorkspaceApp }> = ({ app }) => {
|
||||
interface BaseIconProps {
|
||||
app: WorkspaceApp;
|
||||
}
|
||||
|
||||
export const BaseIcon: FC<BaseIconProps> = ({ app }) => {
|
||||
return app.icon ? (
|
||||
<img
|
||||
alt={`${app.display_name} Icon`}
|
||||
src={app.icon}
|
||||
style={{
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
style={{ pointerEvents: "none" }}
|
||||
/>
|
||||
) : (
|
||||
<ComputerIcon />
|
||||
|
||||
@@ -3,7 +3,7 @@ import Tooltip from "@mui/material/Tooltip";
|
||||
import VisibilityOffOutlined from "@mui/icons-material/VisibilityOffOutlined";
|
||||
import VisibilityOutlined from "@mui/icons-material/VisibilityOutlined";
|
||||
import { type FC, useState } from "react";
|
||||
import { css } from "@emotion/react";
|
||||
import { css, type Interpolation, type Theme } from "@emotion/react";
|
||||
import { CopyableValue } from "components/CopyableValue/CopyableValue";
|
||||
|
||||
const Language = {
|
||||
@@ -11,7 +11,11 @@ const Language = {
|
||||
hideLabel: "Hide value",
|
||||
};
|
||||
|
||||
export const SensitiveValue: FC<{ value: string }> = ({ value }) => {
|
||||
interface SensitiveValueProps {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const SensitiveValue: FC<SensitiveValueProps> = ({ value }) => {
|
||||
const [shouldDisplay, setShouldDisplay] = useState(false);
|
||||
const displayValue = shouldDisplay ? value : "••••••••";
|
||||
const buttonLabel = shouldDisplay ? Language.hideLabel : Language.showLabel;
|
||||
@@ -29,28 +33,12 @@ export const SensitiveValue: FC<{ value: string }> = ({ value }) => {
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<CopyableValue
|
||||
value={value}
|
||||
css={{
|
||||
// 22px is the button width
|
||||
width: "calc(100% - 22px)",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
<CopyableValue value={value} css={styles.value}>
|
||||
{displayValue}
|
||||
</CopyableValue>
|
||||
<Tooltip title={buttonLabel}>
|
||||
<IconButton
|
||||
css={css`
|
||||
color: inherit;
|
||||
|
||||
& .MuiSvgIcon-root {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
`}
|
||||
css={styles.button}
|
||||
onClick={() => {
|
||||
setShouldDisplay((value) => !value);
|
||||
}}
|
||||
@@ -63,3 +51,22 @@ export const SensitiveValue: FC<{ value: string }> = ({ value }) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
value: {
|
||||
// 22px is the button width
|
||||
width: "calc(100% - 22px)",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
},
|
||||
|
||||
button: css`
|
||||
color: inherit;
|
||||
|
||||
& .MuiSvgIcon-root {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
`,
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
@@ -160,7 +160,7 @@ export const RichParameterInput: FC<RichParameterInputProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const RichParameterField: React.FC<RichParameterInputProps> = ({
|
||||
const RichParameterField: FC<RichParameterInputProps> = ({
|
||||
disabled,
|
||||
onChange,
|
||||
parameter,
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
import { type FC, type ReactNode } from "react";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC, type PropsWithChildren } from "react";
|
||||
|
||||
export const SignInLayout: FC<{ children: ReactNode }> = ({ children }) => {
|
||||
export const SignInLayout: FC<PropsWithChildren> = ({ children }) => {
|
||||
return (
|
||||
<div
|
||||
css={{
|
||||
flex: 1,
|
||||
height: "-webkit-fill-available",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
css={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
css={{
|
||||
maxWidth: 385,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
<div
|
||||
css={(theme) => ({
|
||||
fontSize: 12,
|
||||
color: theme.palette.text.secondary,
|
||||
marginTop: 24,
|
||||
})}
|
||||
>
|
||||
{`\u00a9 ${new Date().getFullYear()} Coder Technologies, Inc.`}
|
||||
<div css={styles.container}>
|
||||
<div css={styles.content}>
|
||||
<div css={styles.signIn}>{children}</div>
|
||||
<div css={styles.copyright}>
|
||||
{"\u00a9"} {new Date().getFullYear()} Coder Technologies, Inc.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
flex: 1,
|
||||
height: "-webkit-fill-available",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
content: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
signIn: {
|
||||
maxWidth: 385,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
},
|
||||
|
||||
copyright: (theme) => ({
|
||||
fontSize: 12,
|
||||
color: theme.palette.text.secondary,
|
||||
marginTop: 24,
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FC } from "react";
|
||||
import { type FC } from "react";
|
||||
import { TemplateAutostartRequirementDaysValue } from "utils/schedule";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
@@ -11,9 +11,7 @@ export interface TemplateScheduleAutostartProps {
|
||||
onChange: (newDaysOfWeek: TemplateAutostartRequirementDaysValue[]) => void;
|
||||
}
|
||||
|
||||
export const TemplateScheduleAutostart: FC<
|
||||
React.PropsWithChildren<TemplateScheduleAutostartProps>
|
||||
> = ({
|
||||
export const TemplateScheduleAutostart: FC<TemplateScheduleAutostartProps> = ({
|
||||
autostart_requirement_days_of_week,
|
||||
isSubmitting,
|
||||
allow_user_autostart,
|
||||
@@ -24,18 +22,14 @@ export const TemplateScheduleAutostart: FC<
|
||||
direction="column"
|
||||
width="100%"
|
||||
alignItems="center"
|
||||
css={{
|
||||
marginBottom: "20px",
|
||||
}}
|
||||
css={{ marginBottom: "20px" }}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
css={{
|
||||
width: "100%",
|
||||
}}
|
||||
spacing={0}
|
||||
alignItems="baseline"
|
||||
justifyContent="center"
|
||||
css={{ width: "100%" }}
|
||||
>
|
||||
{(
|
||||
[
|
||||
@@ -53,9 +47,7 @@ export const TemplateScheduleAutostart: FC<
|
||||
).map((day) => (
|
||||
<Button
|
||||
key={day.key}
|
||||
css={{
|
||||
borderRadius: "0px",
|
||||
}}
|
||||
css={{ borderRadius: 0 }}
|
||||
// TODO: Adding a background color would also help
|
||||
color={
|
||||
autostart_requirement_days_of_week.includes(day.value)
|
||||
@@ -80,7 +72,7 @@ export const TemplateScheduleAutostart: FC<
|
||||
))}
|
||||
</Stack>
|
||||
<FormHelperText>
|
||||
<AutostartRequirementDaysHelperText
|
||||
<AutostartHelperText
|
||||
allowed={allow_user_autostart}
|
||||
days={autostart_requirement_days_of_week}
|
||||
/>
|
||||
@@ -99,24 +91,26 @@ export const sortedDays = [
|
||||
"sunday",
|
||||
] as TemplateAutostartRequirementDaysValue[];
|
||||
|
||||
const AutostartRequirementDaysHelperText: FC<{
|
||||
interface AutostartHelperTextProps {
|
||||
allowed?: boolean;
|
||||
days: TemplateAutostartRequirementDaysValue[];
|
||||
}> = ({ allowed, days: unsortedDays }) => {
|
||||
}
|
||||
|
||||
const AutostartHelperText: FC<AutostartHelperTextProps> = ({
|
||||
allowed,
|
||||
days: unsortedDays,
|
||||
}) => {
|
||||
if (!allowed) {
|
||||
return <span>Workspaces are not allowed to auto start.</span>;
|
||||
}
|
||||
// Sort the days
|
||||
const days = unsortedDays.sort(
|
||||
(a, b) => sortedDays.indexOf(a) - sortedDays.indexOf(b),
|
||||
);
|
||||
|
||||
let daymsg = `Workspaces can autostart on ${days.join(", ")}.`;
|
||||
if (days.length === 7) {
|
||||
const days = new Set(unsortedDays);
|
||||
|
||||
if (days.size === 7) {
|
||||
// If every day is allowed, no more explaining is needed.
|
||||
return <span>Workspaces are allowed to auto start on any day.</span>;
|
||||
}
|
||||
if (days.length === 0) {
|
||||
if (days.size === 0) {
|
||||
return (
|
||||
<span>
|
||||
Workspaces will never auto start. This is effectively the same as
|
||||
@@ -124,13 +118,14 @@ const AutostartRequirementDaysHelperText: FC<{
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (
|
||||
days.length === 5 &&
|
||||
!days.includes("saturday") &&
|
||||
!days.includes("sunday")
|
||||
) {
|
||||
daymsg = "Workspaces will never auto start on the weekends.";
|
||||
|
||||
let daymsg = "Workspaces will never auto start on the weekends.";
|
||||
if (days.size !== 5 || days.has("saturday") || days.has("sunday")) {
|
||||
daymsg = `Workspaces can autostart on ${sortedDays
|
||||
.filter((day) => days.has(day))
|
||||
.join(", ")}.`;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>{daymsg} These days are relative to the user's timezone.</span>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { AuditLog } from "api/typesGenerated";
|
||||
import { FC, useMemo } from "react";
|
||||
import type { AuditLog } from "api/typesGenerated";
|
||||
import { type FC, useMemo } from "react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import Link from "@mui/material/Link";
|
||||
|
||||
export const BuildAuditDescription: FC<{ auditLog: AuditLog }> = ({
|
||||
interface BuildAuditDescriptionProps {
|
||||
auditLog: AuditLog;
|
||||
}
|
||||
|
||||
export const BuildAuditDescription: FC<BuildAuditDescriptionProps> = ({
|
||||
auditLog,
|
||||
}): JSX.Element => {
|
||||
}) => {
|
||||
const workspaceName = auditLog.additional_fields?.workspace_name?.trim();
|
||||
// workspaces can be started/stopped/deleted by a user, or kicked off automatically by Coder
|
||||
const user =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC } from "react";
|
||||
import type { AuditLog } from "api/typesGenerated";
|
||||
import type { AuditDiff } from "api/typesGenerated";
|
||||
import colors from "theme/tailwindColors";
|
||||
import { MONOSPACE_FONT_FAMILY } from "theme/constants";
|
||||
|
||||
@@ -21,7 +21,11 @@ const getDiffValue = (value: unknown): string => {
|
||||
return String(value);
|
||||
};
|
||||
|
||||
export const AuditLogDiff: FC<{ diff: AuditLog["diff"] }> = ({ diff }) => {
|
||||
interface AuditLogDiffProps {
|
||||
diff: AuditDiff;
|
||||
}
|
||||
|
||||
export const AuditLogDiff: FC<AuditLogDiffProps> = ({ diff }) => {
|
||||
const diffEntries = Object.entries(diff);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Pill, type PillType } from "components/Pill/Pill";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { TimelineEntry } from "components/Timeline/TimelineEntry";
|
||||
import { UserAvatar } from "components/UserAvatar/UserAvatar";
|
||||
import { useState } from "react";
|
||||
import { type FC, useState } from "react";
|
||||
import userAgentParser from "ua-parser-js";
|
||||
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
|
||||
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
|
||||
@@ -36,7 +36,7 @@ export interface AuditLogRowProps {
|
||||
defaultIsDiffOpen?: boolean;
|
||||
}
|
||||
|
||||
export const AuditLogRow: React.FC<AuditLogRowProps> = ({
|
||||
export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
auditLog,
|
||||
defaultIsDiffOpen = false,
|
||||
}) => {
|
||||
|
||||
@@ -11,9 +11,11 @@ const isBoolean = (variable: TemplateVersionVariable) => {
|
||||
return variable.type === "bool";
|
||||
};
|
||||
|
||||
const VariableLabel: FC<{ variable: TemplateVersionVariable }> = ({
|
||||
variable,
|
||||
}) => {
|
||||
interface VariableLabelProps {
|
||||
variable: TemplateVersionVariable;
|
||||
}
|
||||
|
||||
const VariableLabel: FC<VariableLabelProps> = ({ variable }) => {
|
||||
return (
|
||||
<label htmlFor={variable.name}>
|
||||
<span css={styles.labelName}>
|
||||
@@ -53,7 +55,7 @@ export const VariableInput: FC<VariableInputProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const VariableField: React.FC<VariableInputProps> = ({
|
||||
const VariableField: FC<VariableInputProps> = ({
|
||||
disabled,
|
||||
onChange,
|
||||
variable,
|
||||
|
||||
@@ -137,10 +137,15 @@ const ExternalAuthPageView: FC<ExternalAuthPageViewProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const GitDeviceAuth: FC<{
|
||||
interface GitDeviceAuthProps {
|
||||
externalAuthDevice?: ExternalAuthDevice;
|
||||
deviceExchangeError?: ApiErrorResponse;
|
||||
}> = ({ externalAuthDevice, deviceExchangeError }) => {
|
||||
}
|
||||
|
||||
const GitDeviceAuth: FC<GitDeviceAuthProps> = ({
|
||||
externalAuthDevice,
|
||||
deviceExchangeError,
|
||||
}) => {
|
||||
let status = (
|
||||
<p css={styles.status}>
|
||||
<CircularProgress size={16} color="secondary" data-chromatic="ignore" />
|
||||
|
||||
@@ -211,10 +211,12 @@ export const GroupPage: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const AddGroupMember: React.FC<{
|
||||
interface AddGroupMemberProps {
|
||||
isLoading: boolean;
|
||||
onSubmit: (user: User, reset: () => void) => void;
|
||||
}> = ({ isLoading, onSubmit }) => {
|
||||
}
|
||||
|
||||
const AddGroupMember: FC<AddGroupMemberProps> = ({ isLoading, onSubmit }) => {
|
||||
const [selectedUser, setSelectedUser] = useState<User | null>(null);
|
||||
|
||||
const resetValues = () => {
|
||||
@@ -254,12 +256,17 @@ const AddGroupMember: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
const GroupMemberRow = (props: {
|
||||
interface GroupMemberRowProps {
|
||||
member: User;
|
||||
group: Group;
|
||||
canUpdate: boolean;
|
||||
}
|
||||
|
||||
const GroupMemberRow: FC<GroupMemberRowProps> = ({
|
||||
member,
|
||||
group,
|
||||
canUpdate,
|
||||
}) => {
|
||||
const { member, group, canUpdate } = props;
|
||||
const queryClient = useQueryClient();
|
||||
const removeMemberMutation = useMutation(removeMember(queryClient));
|
||||
|
||||
|
||||
@@ -28,13 +28,21 @@ const validationSchema = Yup.object({
|
||||
quota_allowance: Yup.number().required().min(0).integer(),
|
||||
});
|
||||
|
||||
const UpdateGroupForm: FC<{
|
||||
interface UpdateGroupFormProps {
|
||||
group: Group;
|
||||
errors: unknown;
|
||||
onSubmit: (data: FormData) => void;
|
||||
onCancel: () => void;
|
||||
isLoading: boolean;
|
||||
}> = ({ group, errors, onSubmit, onCancel, isLoading }) => {
|
||||
}
|
||||
|
||||
const UpdateGroupForm: FC<UpdateGroupFormProps> = ({
|
||||
group,
|
||||
errors,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
isLoading,
|
||||
}) => {
|
||||
const form = useFormik<FormData>({
|
||||
initialValues: {
|
||||
name: group.name,
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import Checkbox from "@mui/material/Checkbox";
|
||||
import Link from "@mui/material/Link";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { SignInLayout } from "components/SignInLayout/SignInLayout";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import { type FormikContextType, useFormik } from "formik";
|
||||
import { type FC } from "react";
|
||||
import * as Yup from "yup";
|
||||
import type * as TypesGen from "api/typesGenerated";
|
||||
import {
|
||||
getFormHelpers,
|
||||
nameValidator,
|
||||
onChangeTrimmed,
|
||||
} from "utils/formUtils";
|
||||
import * as Yup from "yup";
|
||||
import type * as TypesGen from "api/typesGenerated";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import { docs } from "utils/docs";
|
||||
import { SignInLayout } from "components/SignInLayout/SignInLayout";
|
||||
import { FormFields, VerticalForm } from "components/Form/Form";
|
||||
import { CoderIcon } from "components/Icons/CoderIcon";
|
||||
import Link from "@mui/material/Link";
|
||||
import { docs } from "utils/docs";
|
||||
|
||||
export const Language = {
|
||||
emailLabel: "Email",
|
||||
@@ -41,7 +42,7 @@ export interface SetupPageViewProps {
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export const SetupPageView: React.FC<SetupPageViewProps> = ({
|
||||
export const SetupPageView: FC<SetupPageViewProps> = ({
|
||||
onSubmit,
|
||||
error,
|
||||
isLoading,
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
TemplateParametersSectionProps,
|
||||
} from "components/TemplateParameters/TemplateParameters";
|
||||
import { useClipboard } from "hooks/useClipboard";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { type FC, useEffect, useState } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { getInitialRichParameterValues } from "utils/richParameters";
|
||||
@@ -24,7 +24,7 @@ import { paramsUsedToCreateWorkspace } from "utils/workspace";
|
||||
|
||||
type ButtonValues = Record<string, string>;
|
||||
|
||||
const TemplateEmbedPage = () => {
|
||||
const TemplateEmbedPage: FC = () => {
|
||||
const { template } = useTemplateLayoutContext();
|
||||
const { data: templateParameters } = useQuery({
|
||||
queryKey: ["template", template.id, "embed"],
|
||||
@@ -46,10 +46,15 @@ const TemplateEmbedPage = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const TemplateEmbedPageView: FC<{
|
||||
interface TemplateEmbedPageViewProps {
|
||||
template: Template;
|
||||
templateParameters?: TemplateVersionParameter[];
|
||||
}> = ({ template, templateParameters }) => {
|
||||
}
|
||||
|
||||
export const TemplateEmbedPageView: FC<TemplateEmbedPageViewProps> = ({
|
||||
template,
|
||||
templateParameters,
|
||||
}) => {
|
||||
const [buttonValues, setButtonValues] = useState<ButtonValues | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { createContext, type FC, Suspense, useContext } from "react";
|
||||
import {
|
||||
createContext,
|
||||
type FC,
|
||||
type PropsWithChildren,
|
||||
Suspense,
|
||||
useContext,
|
||||
} from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { Outlet, useNavigate, useParams } from "react-router-dom";
|
||||
import type { AuthorizationRequest } from "api/typesGenerated";
|
||||
@@ -64,7 +70,7 @@ export const useTemplateLayoutContext = (): TemplateLayoutContextValue => {
|
||||
return context;
|
||||
};
|
||||
|
||||
export const TemplateLayout: FC<{ children?: JSX.Element }> = ({
|
||||
export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
children = <Outlet />,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
+13
-13
@@ -7,7 +7,9 @@ import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import PersonAdd from "@mui/icons-material/PersonAdd";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC, useState } from "react";
|
||||
import type {
|
||||
Group,
|
||||
TemplateACL,
|
||||
@@ -15,6 +17,16 @@ import type {
|
||||
TemplateRole,
|
||||
TemplateUser,
|
||||
} from "api/typesGenerated";
|
||||
import { getGroupSubtitle } from "utils/groups";
|
||||
import { GroupAvatar } from "components/GroupAvatar/GroupAvatar";
|
||||
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader";
|
||||
import {
|
||||
MoreMenu,
|
||||
MoreMenuContent,
|
||||
MoreMenuItem,
|
||||
MoreMenuTrigger,
|
||||
ThreeDotsButton,
|
||||
} from "components/MoreMenu/MoreMenu";
|
||||
import { AvatarData } from "components/AvatarData/AvatarData";
|
||||
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
|
||||
import { EmptyState } from "components/EmptyState/EmptyState";
|
||||
@@ -24,18 +36,6 @@ import {
|
||||
UserOrGroupAutocomplete,
|
||||
UserOrGroupAutocompleteValue,
|
||||
} from "./UserOrGroupAutocomplete";
|
||||
import { type FC, useState } from "react";
|
||||
import { GroupAvatar } from "components/GroupAvatar/GroupAvatar";
|
||||
import { getGroupSubtitle } from "utils/groups";
|
||||
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import {
|
||||
MoreMenu,
|
||||
MoreMenuContent,
|
||||
MoreMenuItem,
|
||||
MoreMenuTrigger,
|
||||
ThreeDotsButton,
|
||||
} from "components/MoreMenu/MoreMenu";
|
||||
|
||||
type AddTemplateUserOrGroupProps = {
|
||||
organizationId: string;
|
||||
@@ -49,7 +49,7 @@ type AddTemplateUserOrGroupProps = {
|
||||
) => void;
|
||||
};
|
||||
|
||||
const AddTemplateUserOrGroup: React.FC<AddTemplateUserOrGroupProps> = ({
|
||||
const AddTemplateUserOrGroup: FC<AddTemplateUserOrGroupProps> = ({
|
||||
isLoading,
|
||||
onSubmit,
|
||||
templateID,
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import { ChangeEvent, FC, useState } from "react";
|
||||
import { type ChangeEvent, type FC, useState } from "react";
|
||||
import { allowedExtensions, isAllowedFile } from "utils/templateVersion";
|
||||
import { FileTree, isFolder, validatePath } from "utils/filetree";
|
||||
import { type FileTree, isFolder, validatePath } from "utils/filetree";
|
||||
|
||||
export const CreateFileDialog: FC<{
|
||||
interface CreateFileDialogProps {
|
||||
onClose: () => void;
|
||||
checkExists: (path: string) => boolean;
|
||||
onConfirm: (path: string) => void;
|
||||
open: boolean;
|
||||
fileTree: FileTree;
|
||||
}> = ({ checkExists, onClose, onConfirm, open, fileTree }) => {
|
||||
}
|
||||
|
||||
export const CreateFileDialog: FC<CreateFileDialogProps> = ({
|
||||
checkExists,
|
||||
onClose,
|
||||
onConfirm,
|
||||
open,
|
||||
fileTree,
|
||||
}) => {
|
||||
const [pathValue, setPathValue] = useState("");
|
||||
const [error, setError] = useState<string>();
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -86,12 +94,19 @@ export const CreateFileDialog: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export const DeleteFileDialog: FC<{
|
||||
interface DeleteFileDialogProps {
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
open: boolean;
|
||||
filename: string;
|
||||
}> = ({ onClose, onConfirm, open, filename }) => {
|
||||
}
|
||||
|
||||
export const DeleteFileDialog: FC<DeleteFileDialogProps> = ({
|
||||
onClose,
|
||||
onConfirm,
|
||||
open,
|
||||
filename,
|
||||
}) => {
|
||||
return (
|
||||
<ConfirmDialog
|
||||
type="delete"
|
||||
@@ -109,14 +124,23 @@ export const DeleteFileDialog: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export const RenameFileDialog: FC<{
|
||||
interface RenameFileDialogProps {
|
||||
onClose: () => void;
|
||||
onConfirm: (filename: string) => void;
|
||||
checkExists: (path: string) => boolean;
|
||||
open: boolean;
|
||||
filename: string;
|
||||
fileTree: FileTree;
|
||||
}> = ({ checkExists, onClose, onConfirm, open, filename, fileTree }) => {
|
||||
}
|
||||
|
||||
export const RenameFileDialog: FC<RenameFileDialogProps> = ({
|
||||
checkExists,
|
||||
onClose,
|
||||
onConfirm,
|
||||
open,
|
||||
filename,
|
||||
fileTree,
|
||||
}) => {
|
||||
const [pathValue, setPathValue] = useState(filename);
|
||||
const [error, setError] = useState<string>();
|
||||
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
@@ -5,9 +5,13 @@ import ErrorIcon from "@mui/icons-material/ErrorOutline";
|
||||
import CheckIcon from "@mui/icons-material/CheckOutlined";
|
||||
import { Pill, type PillType } from "components/Pill/Pill";
|
||||
|
||||
export const TemplateVersionStatusBadge: FC<{
|
||||
interface TemplateVersionStatusBadgeProps {
|
||||
version: TemplateVersion;
|
||||
}> = ({ version }) => {
|
||||
}
|
||||
|
||||
export const TemplateVersionStatusBadge: FC<
|
||||
TemplateVersionStatusBadgeProps
|
||||
> = ({ version }) => {
|
||||
const { text, icon, type } = getStatus(version);
|
||||
return (
|
||||
<Pill icon={icon} type={type} title={`Build status is ${text}`}>
|
||||
|
||||
@@ -35,10 +35,15 @@ const findFeaturedExamples = (examples: TemplateExample[]) => {
|
||||
return featuredExamples;
|
||||
};
|
||||
|
||||
export const EmptyTemplates: FC<{
|
||||
interface EmptyTemplatesProps {
|
||||
canCreateTemplates: boolean;
|
||||
examples: TemplateExample[];
|
||||
}> = ({ canCreateTemplates, examples }) => {
|
||||
}
|
||||
|
||||
export const EmptyTemplates: FC<EmptyTemplatesProps> = ({
|
||||
canCreateTemplates,
|
||||
examples,
|
||||
}) => {
|
||||
const featuredExamples = findFeaturedExamples(examples);
|
||||
|
||||
if (canCreateTemplates) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type FC, type ReactNode, useState } from "react";
|
||||
import { type FC, type PropsWithChildren, useState } from "react";
|
||||
|
||||
import { type User } from "api/typesGenerated";
|
||||
import { roles } from "api/queries/roles";
|
||||
@@ -35,7 +35,7 @@ import { UsersPageView } from "./UsersPageView";
|
||||
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { usePaginatedQuery } from "hooks/usePaginatedQuery";
|
||||
|
||||
export const UsersPage: FC<{ children?: ReactNode }> = () => {
|
||||
export const UsersPage: FC<PropsWithChildren> = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import { type CSSObject, type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import type { WorkspaceBuild } from "api/typesGenerated";
|
||||
import { BuildAvatar } from "components/BuildAvatar/BuildAvatar";
|
||||
@@ -21,7 +22,7 @@ const transitionMessages = {
|
||||
delete: "deleted",
|
||||
};
|
||||
|
||||
export const BuildRow: React.FC<BuildRowProps> = ({ build }) => {
|
||||
export const BuildRow: FC<BuildRowProps> = ({ build }) => {
|
||||
const initiatedBy = getDisplayWorkspaceBuildInitiatedBy(build);
|
||||
const navigate = useNavigate();
|
||||
const clickableProps = useClickable<HTMLTableRowElement>(() =>
|
||||
|
||||
@@ -27,12 +27,19 @@ export type WorkspaceSettingsFormValues = {
|
||||
automatic_updates: AutomaticUpdates;
|
||||
};
|
||||
|
||||
export const WorkspaceSettingsForm: FC<{
|
||||
interface WorkspaceSettingsFormProps {
|
||||
workspace: Workspace;
|
||||
error: unknown;
|
||||
onCancel: () => void;
|
||||
onSubmit: (values: WorkspaceSettingsFormValues) => Promise<void>;
|
||||
}> = ({ onCancel, onSubmit, workspace, error }) => {
|
||||
}
|
||||
|
||||
export const WorkspaceSettingsForm: FC<WorkspaceSettingsFormProps> = ({
|
||||
onCancel,
|
||||
onSubmit,
|
||||
workspace,
|
||||
error,
|
||||
}) => {
|
||||
const formEnabled =
|
||||
!workspace.template_require_active_version || workspace.allow_renames;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user