Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix(site): Fix loading buttons#7549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
BrunoQuaresma merged 1 commit intomainfrombq/improve-loading-buttons
May 17, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,12 +19,10 @@ const Template: Story<LoadingButtonProps> = (args) => (

export const Loading = Template.bind({})
Loading.args = {
variant: "contained",
loading: true,
}

export const NotLoading = Template.bind({})
NotLoading.args = {
variant: "contained",
loading: false,
}
76 changes: 13 additions & 63 deletionssite/src/components/LoadingButton/LoadingButton.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,21 @@
import Button, { ButtonProps } from "@mui/material/Button"
import CircularProgress from "@mui/material/CircularProgress"
import { makeStyles } from "@mui/styles"
import { Theme } from "@mui/material/styles"
import { FC } from "react"
import MuiLoadingButton, {
LoadingButtonProps as MuiLoadingButtonProps,
} from "@mui/lab/LoadingButton"

export interface LoadingButtonProps extends ButtonProps {
/** Whether or not to disable the button and show a spinner */
loading?: boolean
/** An optional label to display with the loading spinner */
loadingLabel?: string
}
export type LoadingButtonProps = MuiLoadingButtonProps

/**
* LoadingButton is a small wrapper around Material-UI's button to show a loading spinner
*
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
* we have to roll our own.
*/
export const LoadingButton: FC<React.PropsWithChildren<LoadingButtonProps>> = ({
loading = false,
loadingLabel,
export const LoadingButton: FC<LoadingButtonProps> = ({
children,
...rest
loadingIndicator,
...buttonProps
}) => {
const styles = useStyles({ hasLoadingLabel: Boolean(loadingLabel) })
const hidden = loading ? { opacity: 0 } : undefined

return (
<Button {...rest} disabled={rest.disabled || loading}>
<span style={hidden}>{children}</span>
{loading && (
<div className={styles.loader}>
<CircularProgress size={16} className={styles.spinner} />
</div>
)}
{Boolean(loadingLabel) && loadingLabel}
</Button>
<MuiLoadingButton variant="outlined" color="neutral" {...buttonProps}>
{/* known issue: https://github.com/mui/material-ui/issues/27853 */}
<span>
{buttonProps.loading && loadingIndicator ? loadingIndicator : children}
</span>
</MuiLoadingButton>
)
}

interface StyleProps {
hasLoadingLabel?: boolean
}

const useStyles = makeStyles<Theme, StyleProps>((theme) => ({
loader: {
position: (props) => {
if (!props.hasLoadingLabel) {
return "absolute"
}
},
transform: (props) => {
if (!props.hasLoadingLabel) {
return "translate(-50%, -50%)"
}
},
marginRight: (props) => {
if (props.hasLoadingLabel) {
return "10px"
}
},
top: "50%",
left: "50%",
height: 22, // centering loading icon
width: 16,
},
spinner: {
color: theme.palette.text.disabled,
},
}))
98 changes: 56 additions & 42 deletionssite/src/components/WorkspaceActions/Buttons.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,76 +5,85 @@ import CropSquareIcon from "@mui/icons-material/CropSquare"
import PlayCircleOutlineIcon from "@mui/icons-material/PlayCircleOutline"
import ReplayIcon from "@mui/icons-material/Replay"
import { LoadingButton } from "components/LoadingButton/LoadingButton"
import { FC, PropsWithChildren } from "react"
import{ useTranslation }from "react-i18next"
import { FC } from "react"
importBlockOutlinedfrom "@mui/icons-material/BlockOutlined"

interface WorkspaceAction {
loading?: boolean
handleAction: () => void
}

export const UpdateButton: FC<PropsWithChildren<WorkspaceAction>> = ({
export const UpdateButton: FC<WorkspaceAction> = ({
handleAction,
loading,
}) => {
const { t } = useTranslation("workspacePage")

return (
<Button
<LoadingButton
loading={loading}
loadingIndicator="Updating..."
loadingPosition="start"
size="small"
data-testid="workspace-update-button"
startIcon={<CloudQueueIcon />}
onClick={handleAction}
>
{t("actionButton.update")}
</Button>
Update
</LoadingButton>
)
}

export const StartButton: FC<PropsWithChildren<WorkspaceAction>> = ({
handleAction,
}) => {
const { t } = useTranslation("workspacePage")

export const StartButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
return (
<Button startIcon={<PlayCircleOutlineIcon />} onClick={handleAction}>
{t("actionButton.start")}
</Button>
<LoadingButton
size="small"
loading={loading}
loadingIndicator="Starting..."
loadingPosition="start"
startIcon={<PlayCircleOutlineIcon />}
onClick={handleAction}
>
Start
</LoadingButton>
)
}

export const StopButton: FC<PropsWithChildren<WorkspaceAction>> = ({
handleAction,
}) => {
const { t } = useTranslation("workspacePage")

export const StopButton: FC<WorkspaceAction> = ({ handleAction, loading }) => {
return (
<Button size="small" startIcon={<CropSquareIcon />} onClick={handleAction}>
{t("actionButton.stop")}
</Button>
<LoadingButton
size="small"
loading={loading}
loadingIndicator="Stopping..."
loadingPosition="start"
startIcon={<CropSquareIcon />}
onClick={handleAction}
>
Stop
</LoadingButton>
)
}

export const RestartButton: FC<PropsWithChildren<WorkspaceAction>> = ({
export const RestartButton: FC<WorkspaceAction> = ({
handleAction,
loading,
}) => {
const { t } = useTranslation("workspacePage")

return (
<Button
<LoadingButton
loading={loading}
loadingIndicator="Restarting..."
loadingPosition="start"
size="small"
startIcon={<ReplayIcon />}
onClick={handleAction}
data-testid="workspace-restart-button"
>
{t("actionButton.restart")}
</Button>
Restart
</LoadingButton>
)
}

export const CancelButton: FC<PropsWithChildren<WorkspaceAction>> = ({
handleAction,
}) => {
export const CancelButton: FC<WorkspaceAction> = ({ handleAction }) => {
return (
<Button startIcon={<BlockIcon />} onClick={handleAction}>
<Buttonsize="small"startIcon={<BlockIcon />} onClick={handleAction}>
Cancel
</Button>
)
Expand All@@ -84,11 +93,9 @@ interface DisabledProps {
label: string
}

export const DisabledButton: FC<PropsWithChildren<DisabledProps>> = ({
label,
}) => {
export const DisabledButton: FC<DisabledProps> = ({ label }) => {
return (
<Button size="small" disabled>
<Button size="small"startIcon={<BlockOutlined />}disabled>
{label}
</Button>
)
Expand All@@ -98,8 +105,15 @@ interface LoadingProps {
label: string
}

export const ActionLoadingButton: FC<PropsWithChildren<LoadingProps>> = ({
label,
}) => {
return <LoadingButton loading size="small" loadingLabel={label} />
export const ActionLoadingButton: FC<LoadingProps> = ({ label }) => {
return (
<LoadingButton
loading
size="small"
loadingPosition="start"
loadingIndicator={label}
// This icon can be anything
startIcon={<ReplayIcon />}
/>
)
}
62 changes: 11 additions & 51 deletionssite/src/components/WorkspaceActions/WorkspaceActions.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,6 @@ import Menu from "@mui/material/Menu"
import { makeStyles } from "@mui/styles"
import MoreVertOutlined from "@mui/icons-material/MoreVertOutlined"
import { FC, ReactNode, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import { WorkspaceStatus } from "api/typesGenerated"
import {
ActionLoadingButton,
Expand DownExpand Up@@ -57,7 +56,6 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
canChangeVersions,
}) => {
const styles = useStyles()
const { t } = useTranslation("workspacePage")
const {
canCancel,
canAcceptJobs,
Expand All@@ -69,64 +67,26 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({

// A mapping of button type to the corresponding React component
const buttonMapping: ButtonMapping = {
[ButtonTypesEnum.update]: (
<UpdateButton handleAction={handleUpdate} key={ButtonTypesEnum.update} />
),
[ButtonTypesEnum.update]: <UpdateButton handleAction={handleUpdate} />,
[ButtonTypesEnum.updating]: (
<ActionLoadingButton
label={t("actionButton.updating")}
key={ButtonTypesEnum.updating}
/>
),
[ButtonTypesEnum.start]: (
<StartButton handleAction={handleStart} key={ButtonTypesEnum.start} />
<UpdateButton loading handleAction={handleUpdate} />
),
[ButtonTypesEnum.start]: <StartButton handleAction={handleStart} />,
[ButtonTypesEnum.starting]: (
<ActionLoadingButton
label={t("actionButton.starting")}
key={ButtonTypesEnum.starting}
/>
),
[ButtonTypesEnum.stop]: (
<StopButton handleAction={handleStop} key={ButtonTypesEnum.stop} />
<StartButton loading handleAction={handleStart} />
),
[ButtonTypesEnum.stop]: <StopButton handleAction={handleStop} />,
[ButtonTypesEnum.stopping]: (
<ActionLoadingButton
label={t("actionButton.stopping")}
key={ButtonTypesEnum.stopping}
/>
<StopButton loading handleAction={handleStop} />
),
[ButtonTypesEnum.restart]: <RestartButton handleAction={handleRestart} />,
[ButtonTypesEnum.restarting]: (
<ActionLoadingButton
label="Restarting"
key={ButtonTypesEnum.restarting}
/>
),
[ButtonTypesEnum.deleting]: (
<ActionLoadingButton
label={t("actionButton.deleting")}
key={ButtonTypesEnum.deleting}
/>
),
[ButtonTypesEnum.canceling]: (
<DisabledButton
label={t("disabledButton.canceling")}
key={ButtonTypesEnum.canceling}
/>
),
[ButtonTypesEnum.deleted]: (
<DisabledButton
label={t("disabledButton.deleted")}
key={ButtonTypesEnum.deleted}
/>
),
[ButtonTypesEnum.pending]: (
<ActionLoadingButton
label={t("disabledButton.pending")}
key={ButtonTypesEnum.pending}
/>
<RestartButton loading handleAction={handleRestart} />
),
[ButtonTypesEnum.deleting]: <ActionLoadingButton label="Deleting" />,
[ButtonTypesEnum.canceling]: <DisabledButton label="Canceling..." />,
[ButtonTypesEnum.deleted]: <DisabledButton label="Deleted" />,
[ButtonTypesEnum.pending]: <ActionLoadingButton label="Pending..." />,
}

// Returns a function that will execute the action and close the menu
Expand Down
14 changes: 14 additions & 0 deletionssite/src/theme/theme.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -133,12 +133,26 @@ dark = createTheme(dark, {
sizeSmall: {
borderRadius: 6,
height: BUTTON_SM_HEIGHT,

"& .MuiCircularProgress-root": {
width: "14px !important",
height: "14px !important",
},
},
sizeLarge: {
height: BUTTON_LG_HEIGHT,
},
outlinedNeutral: {
borderColor: colors.gray[12],

"&.Mui-disabled": {
borderColor: colors.gray[13],
color: colors.gray[11],

"& > .MuiLoadingButton-loadingIndicator": {
color: colors.gray[11],
},
},
},
containedNeutral: {
borderColor: colors.gray[12],
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp