@mui/lab#LoadingButton TypeScript Examples

The following examples show how to use @mui/lab#LoadingButton. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Home.tsx    From mui-toolpad with MIT License 6 votes vote down vote up
function CreateAppDialog({ onClose, ...props }: CreateAppDialogProps) {
  const [name, setName] = React.useState('');
  const createAppMutation = client.useMutation('createApp');

  return (
    <Dialog {...props} onClose={onClose}>
      <DialogForm
        onSubmit={async (event) => {
          event.preventDefault();

          const app = await createAppMutation.mutateAsync([name]);
          window.location.href = `/_toolpad/app/${app.id}/editor`;
        }}
      >
        <DialogTitle>Create a new MUI Toolpad App</DialogTitle>
        <DialogContent>
          <TextField
            sx={{ my: 1 }}
            autoFocus
            fullWidth
            label="name"
            value={name}
            onChange={(event) => setName(event.target.value)}
          />
        </DialogContent>
        <DialogActions>
          <Button color="inherit" variant="text" onClick={onClose}>
            Cancel
          </Button>
          <LoadingButton type="submit" loading={createAppMutation.isLoading} disabled={!name}>
            Create
          </LoadingButton>
        </DialogActions>
      </DialogForm>
    </Dialog>
  );
}
Example #2
Source File: Home.tsx    From mui-toolpad with MIT License 6 votes vote down vote up
function AppDeleteDialog({ app, onClose }: AppDeleteDialogProps) {
  const latestApp = useLatest(app);
  const deleteAppMutation = client.useMutation('deleteApp');

  const handleDeleteClick = React.useCallback(async () => {
    if (app) {
      await deleteAppMutation.mutateAsync([app.id]);
    }
    await client.refetchQueries('getApps');
    onClose();
  }, [app, deleteAppMutation, onClose]);

  return (
    <Dialog open={!!app} onClose={onClose}>
      <DialogForm>
        <DialogTitle>Confirm delete</DialogTitle>
        <DialogContent>
          Are you sure you want to delete application &quot;{latestApp?.name}&quot;
        </DialogContent>
        <DialogActions>
          <Button color="inherit" variant="text" onClick={onClose}>
            Cancel
          </Button>
          <LoadingButton
            type="submit"
            loading={deleteAppMutation.isLoading}
            onClick={handleDeleteClick}
            color="error"
          >
            Delete
          </LoadingButton>
        </DialogActions>
      </DialogForm>
    </Dialog>
  );
}
Example #3
Source File: form-submit.tsx    From example with MIT License 6 votes vote down vote up
export function FormSubmit({ form, icon, label, state, disabled }: IFormSubmitProps) {
	const { formState: { errors, isSubmitting, isValidating } } = form

	const isValid = size(errors) === 0

	let color
	let iconEl
	if (!isValid) {
		color = "warning"
		iconEl = <Icon icon={faExclamationTriangle}/>
	} else {
		switch (state) {
			case "error":
				color = "error"
				iconEl = <Icon icon={faExclamationTriangle}/>
				break
			case "success":
				color = "success"
				iconEl = <Icon icon={faCheckDouble}/>
				break
			case "normal":
			default:
				color = "primary"
				iconEl = <Icon icon={icon ?? faCheck}/>
		}
	}

	return <LoadingButton
		type="submit"
		loading={isSubmitting || isValidating}
		loadingPosition="start"
		startIcon={iconEl}
		color={color as any}
		variant="contained"
		disabled={disabled}
	>
		{label}
	</LoadingButton>
}
Example #4
Source File: PersonSelectDialog.tsx    From frontend with MIT License 5 votes vote down vote up
function PersonSelectDialog({ onConfirm: confirmCallback, onClose: closeCallback, error }: Props) {
  const [person, setPerson] = useState<PersonResponse | null>(null)
  const { t } = useTranslation()
  const { open, confirmHandler, closeHandler, openHandler, loading } = useConfirm({
    onConfirm: async () => {
      confirmCallback ? confirmCallback(person) : null
    },
    onClose: async () => {
      closeCallback ? closeCallback(person) : null
    },
  })
  return (
    <>
      <FormFieldButton
        onClick={openHandler}
        placeholder={t('person:selectDialog.notSelected')}
        value={person ? `${person.firstName} ${person.lastName} (${person.id})` : undefined}
        button={{ label: t('person:selectDialog.select') }}
        error={error ? translateError(error, t) : undefined}
      />
      <Dialog fullWidth open={open} onClose={closeHandler}>
        <DialogTitle>{t('person:selectDialog.personSelect')}</DialogTitle>
        <DialogContent>
          <Box sx={{ marginTop: theme.spacing(2) }}>
            <PersonAutocomplete
              onSelect={(person) => {
                setPerson(person)
              }}
              showId
              autocompleteProps={{ defaultValue: person }}
            />
          </Box>

          <Box sx={{ marginTop: theme.spacing(2) }}>
            {person ? <PersonInfo person={person} /> : t('person:selectDialog.notSelected')}
          </Box>
        </DialogContent>
        <DialogActions>
          <CloseModalButton onClose={closeHandler} />
          <LoadingButton onClick={confirmHandler} loading={loading}>
            {t('person:selectDialog.confirm')}
          </LoadingButton>
        </DialogActions>
      </Dialog>
    </>
  )
}
Example #5
Source File: index.tsx    From Search-Next with GNU General Public License v3.0 5 votes vote down vote up
VersionInfoButton = () => {
  const [data, setData] = useState<Latest>({} as Latest);
  const [loading, setLoading] = useState(false);

  const getLatest = () => {
    setLoading(true);
    latest()
      .then((res) => {
        setLoading(false);
        if (res.data) {
          setData(res.data);
        }
      })
      .catch((err) => {
        setLoading(false);
      });
  };

  useEffect(() => {
    Object.keys(data).length &&
      confirm({
        title: '当前版本信息',
        type: false,
        content: <VersionModalContent data={data} />,
        showFooter: false,
      });
  }, [data]);

  return (
    <LoadingButton
      loading={loading}
      onClick={(e) => {
        e.stopPropagation();
        getLatest();
      }}
    >
      当前版本信息
    </LoadingButton>
  );
}
Example #6
Source File: ConfirmDialog.tsx    From console with GNU Affero General Public License v3.0 4 votes vote down vote up
ConfirmDialog = ({
  isOpen = false,
  onClose,
  onCancel,
  onConfirm,
  classes = {},
  title = "",
  isLoading,
  confirmationContent,
  cancelText = "Cancel",
  confirmText = "Confirm",
  confirmButtonProps = {},
  cancelButtonProps = {},
  titleIcon = null,
}: ConfirmDialogProps) => {
  return (
    <Dialog
      open={isOpen}
      onClose={(event, reason) => {
        if (reason !== "backdropClick") {
          onClose(); // close on Esc but not on click outside
        }
      }}
      className={classes.root}
      sx={{
        "& .MuiPaper-root": {
          padding: "1rem 2rem 2rem 1rem",
        },
      }}
    >
      <DialogTitle className={classes.title}>
        <div className={classes.titleText}>
          {titleIcon} {title}
        </div>
        <div className={classes.closeContainer}>
          <IconButton
            aria-label="close"
            className={classes.closeButton}
            onClick={onClose}
            disableRipple
            size="small"
          >
            <CloseIcon />
          </IconButton>
        </div>
      </DialogTitle>

      <DialogContent className={classes.content}>
        {confirmationContent}
      </DialogContent>
      <DialogActions className={classes.actions}>
        <Button
          className={classes.cancelButton}
          onClick={onCancel || onClose}
          disabled={isLoading}
          type="button"
          {...cancelButtonProps}
          variant="outlined"
          color="primary"
          id={"confirm-cancel"}
        >
          {cancelText}
        </Button>

        <LoadingButton
          className={classes.confirmButton}
          type="button"
          onClick={onConfirm}
          loading={isLoading}
          disabled={isLoading}
          variant="outlined"
          color="secondary"
          loadingPosition="start"
          startIcon={<React.Fragment />}
          autoFocus
          id={"confirm-ok"}
          {...confirmButtonProps}
        >
          {confirmText}
        </LoadingButton>
      </DialogActions>
    </Dialog>
  );
}
Example #7
Source File: QueryEditor.tsx    From mui-toolpad with MIT License 4 votes vote down vote up
function QueryNodeEditorDialog<Q, P>({
  open,
  node,
  onClose,
  onRemove,
  onSave,
}: QueryNodeEditorProps<Q, P>) {
  const { appId } = usePageEditorState();

  const [input, setInput] = React.useState(node);
  React.useEffect(() => setInput(node), [node]);

  const connectionId = input.attributes.connectionId.value;
  const dataSourceId = input.attributes.dataSource?.value;
  const dataSource = (dataSourceId && dataSources[dataSourceId]) || null;

  const handleConnectionChange = React.useCallback((newConnectionId) => {
    setInput((existing) =>
      update(existing, {
        attributes: update(existing.attributes, {
          connectionId: appDom.createConst(newConnectionId),
        }),
      }),
    );
  }, []);

  const handleQueryChange = React.useCallback((newQuery: Q) => {
    setInput((existing) =>
      update(existing, {
        attributes: update(existing.attributes, {
          query: appDom.createConst(newQuery),
        }),
      }),
    );
  }, []);

  const handleTransformFnChange = React.useCallback((newValue: string) => {
    setInput((existing) =>
      update(existing, {
        attributes: update(existing.attributes, {
          transform: appDom.createConst(newValue),
        }),
      }),
    );
  }, []);

  const handleTransformEnabledChange = React.useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      setInput((existing) =>
        update(existing, {
          attributes: update(existing.attributes, {
            transformEnabled: appDom.createConst(event.target.checked),
          }),
        }),
      );
    },
    [],
  );

  const handleRefetchOnWindowFocusChange = React.useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      setInput((existing) =>
        update(existing, {
          attributes: update(existing.attributes, {
            refetchOnWindowFocus: appDom.createConst(event.target.checked),
          }),
        }),
      );
    },
    [],
  );

  const handleRefetchOnReconnectChange = React.useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      setInput((existing) =>
        update(existing, {
          attributes: update(existing.attributes, {
            refetchOnReconnect: appDom.createConst(event.target.checked),
          }),
        }),
      );
    },
    [],
  );

  const handleRefetchIntervalChange = React.useCallback(
    (event: React.ChangeEvent<HTMLInputElement>) => {
      const interval = Number(event.target.value);

      setInput((existing) =>
        update(existing, {
          attributes:
            Number.isNaN(interval) || interval <= 0
              ? omit(existing.attributes, 'refetchInterval')
              : update(existing.attributes, {
                  refetchInterval: appDom.createConst(interval * 1000),
                }),
        }),
      );
    },
    [],
  );

  const [params, setParams] = React.useState<[string, BindableAttrValue<any>][]>(
    Object.entries(input.params || {}),
  );
  React.useEffect(() => setParams(Object.entries(input.params || {})), [input.params]);

  const { pageState } = usePageEditorState();
  const liveParams: [string, LiveBinding][] = React.useMemo(() => {
    return params.map(([name, bindable]) => [name, evaluateBindable(bindable, pageState)]);
  }, [params, pageState]);

  const handleParamsChange = React.useCallback((newParams: [string, BindableAttrValue<any>][]) => {
    setParams(newParams);
    const paramsObj: BindableAttrValues<any> = Object.fromEntries(newParams);
    setInput((existing) =>
      update(existing, {
        params: paramsObj,
      }),
    );
  }, []);

  const handleSave = React.useCallback(() => {
    onSave(input);
  }, [onSave, input]);

  const handleRemove = React.useCallback(() => {
    onRemove(node);
    onClose();
  }, [onRemove, node, onClose]);

  const paramsObject: Record<string, any> = React.useMemo(() => {
    const liveParamValues: [string, any][] = liveParams.map(([name, result]) => [
      name,
      result?.value,
    ]);
    return Object.fromEntries(liveParamValues);
  }, [liveParams]);

  const [previewQuery, setPreviewQuery] = React.useState<appDom.QueryNode<Q, P> | null>(null);
  const [previewParams, setPreviewParams] = React.useState(paramsObject);
  const queryPreview = client.useQuery(
    'execQuery',
    previewQuery ? [appId, previewQuery, previewParams] : null,
    { retry: false },
  );

  const handleUpdatePreview = React.useCallback(() => {
    setPreviewQuery(input);
    setPreviewParams(paramsObject);
  }, [input, paramsObject]);

  const isInputSaved = node === input;

  const handleClose = React.useCallback(() => {
    const ok = isInputSaved
      ? true
      : // eslint-disable-next-line no-alert
        window.confirm(
          'Are you sure you want to close the editor. All unsaved progress will be lost.',
        );

    if (ok) {
      onClose();
    }
  }, [onClose, isInputSaved]);

  if (!dataSourceId || !dataSource) {
    throw new Error(`DataSource "${dataSourceId}" not found`);
  }

  return (
    <Dialog fullWidth maxWidth="lg" open={open} onClose={handleClose} scroll="body">
      <DialogTitle>Edit Query ({node.id})</DialogTitle>
      <DialogContent>
        <Stack spacing={1} py={1} gap={2}>
          <Stack direction="row" gap={2}>
            <NodeNameEditor node={node} />
            <ConnectionSelect
              dataSource={dataSourceId}
              value={input.attributes.connectionId.value || null}
              onChange={handleConnectionChange}
            />
          </Stack>

          <Divider />
          <Typography>Parameters</Typography>
          <ParametersEditor
            value={params}
            onChange={handleParamsChange}
            globalScope={pageState}
            liveValue={liveParams}
          />
          <Divider />
          <Typography>Build query:</Typography>
          <dataSource.QueryEditor
            appId={appId}
            connectionId={connectionId}
            value={input.attributes.query.value}
            onChange={handleQueryChange}
            globalScope={{ query: paramsObject }}
          />
          <Divider />
          <Typography>Options:</Typography>
          <Grid container direction="row" spacing={1}>
            <Grid item xs={4}>
              <Stack direction="column">
                <FormControlLabel
                  control={
                    <Checkbox
                      checked={input.attributes.refetchOnWindowFocus?.value ?? true}
                      onChange={handleRefetchOnWindowFocusChange}
                    />
                  }
                  label="Refetch on window focus"
                />
                <FormControlLabel
                  control={
                    <Checkbox
                      checked={input.attributes.refetchOnReconnect?.value ?? true}
                      onChange={handleRefetchOnReconnectChange}
                    />
                  }
                  label="Refetch on network reconnect"
                />
                <TextField
                  InputProps={{
                    startAdornment: <InputAdornment position="start">s</InputAdornment>,
                  }}
                  sx={{ maxWidth: 300 }}
                  type="number"
                  label="Refetch interval"
                  value={refetchIntervalInSeconds(input.attributes.refetchInterval?.value) ?? ''}
                  onChange={handleRefetchIntervalChange}
                />
              </Stack>
            </Grid>
            <Grid item xs={6}>
              <Stack>
                <FormControlLabel
                  label="Transform API response"
                  control={
                    <Checkbox
                      checked={input.attributes.transformEnabled?.value ?? false}
                      onChange={handleTransformEnabledChange}
                      inputProps={{ 'aria-label': 'controlled' }}
                    />
                  }
                />

                <JsExpressionEditor
                  globalScope={{}}
                  value={input.attributes.transform?.value ?? '(data) => {\n  return data;\n}'}
                  onChange={handleTransformFnChange}
                  disabled={!input.attributes.transformEnabled?.value}
                />
              </Stack>
            </Grid>
          </Grid>
          <Divider />
          <Toolbar disableGutters>
            preview
            <LoadingButton
              sx={{ ml: 2 }}
              disabled={previewParams === paramsObject && previewQuery === input}
              loading={queryPreview.isLoading}
              loadingPosition="start"
              onClick={handleUpdatePreview}
              startIcon={<PlayArrowIcon />}
            >
              Run
            </LoadingButton>
          </Toolbar>
          {queryPreview.error ? <ErrorAlert error={queryPreview.error} /> : null}
          {queryPreview.isSuccess ? <JsonView src={queryPreview.data} /> : null}
        </Stack>
      </DialogContent>
      <DialogActions>
        <Button color="inherit" variant="text" onClick={handleClose}>
          Cancel
        </Button>
        <Button onClick={handleRemove}>Remove</Button>
        <Button disabled={isInputSaved} onClick={handleSave}>
          Save
        </Button>
      </DialogActions>
    </Dialog>
  );
}
Example #8
Source File: FormikStepper.tsx    From frontend with MIT License 4 votes vote down vote up
export function FormikStepper({ children, ...props }: GenericFormProps<OneTimeDonation>) {
  const childrenArray = React.Children.toArray(children) as React.ReactElement<FormikStepProps>[]
  const { step, setStep } = useContext(StepsContext)
  const router = useRouter()
  useEffect(() => {
    router.query.success === 'false' || router.query.success === 'true' ? setStep(3) : null
  }, [router.query.success])
  const currentChild = childrenArray[step]

  const { data: currentPerson } = useCurrentPerson()
  function isLastStep() {
    return step === childrenArray.length - 2
  }

  function isFirstStep() {
    return step === 0
  }

  function isLogged() {
    if (currentPerson === undefined) {
      return false
    }
    if (currentPerson?.status && currentPerson.status !== 'unauthenticated') {
      return false
    }
    return true
  }
  const { t } = useTranslation('one-time-donation')

  return (
    <Formik
      {...props}
      validationSchema={currentChild.props.validationSchema}
      onSubmit={async (values, helpers) => {
        if (isLastStep()) {
          await props.onSubmit(values, helpers)
        } else if (isFirstStep() && isLogged()) {
          if (values.payment === 'bank') {
            router.push({
              pathname: router.route,
              query: {
                slug: router.query.slug,
                success: true,
              },
            })
          } else {
            setStep((s) => s + 2)
          }
        } else {
          setStep((s) => s + 1)
          helpers.setTouched({})
        }
      }}
      validateOnMount
      validateOnBlur>
      {({ isSubmitting, handleSubmit, isValid }) => (
        <Form
          onSubmit={handleSubmit}
          style={{
            maxWidth: '662px',
            marginLeft: 'auto',
            marginRight: 'auto',
          }}
          autoComplete="off">
          <StyledStepper>
            <Stepper alternativeLabel activeStep={step}>
              {childrenArray.map((child, index) => (
                <Step key={index}>
                  <StepLabel classes={{ alternativeLabel: classes.stepIcon }}>
                    {child.props.label}
                  </StepLabel>
                </Step>
              ))}
            </Stepper>
          </StyledStepper>
          <Box marginY={8}>{currentChild}</Box>
          {/* Controls of the form */}
          {step === 3 ? null : (
            <Grid container rowSpacing={2} columnSpacing={2}>
              <Grid item xs={12} md={6}>
                <Button
                  fullWidth
                  type="button"
                  variant="text"
                  disabled={step === 0 || isSubmitting}
                  color="error"
                  size="large"
                  onClick={() => {
                    if (step === 2 && isLogged()) {
                      setStep((s) => s - 2)
                      return
                    }
                    setStep((s) => s - 1)
                  }}>
                  {t('btns.back')}
                </Button>
              </Grid>
              <Grid item xs={12} md={6}>
                <LoadingButton
                  disabled={!isValid}
                  fullWidth
                  type="submit"
                  variant="contained"
                  loading={isSubmitting}
                  color="info"
                  size="large">
                  {isSubmitting ? 'Потвърждение' : isLastStep() ? t('btns.end') : t('btns.next')}
                </LoadingButton>
              </Grid>
            </Grid>
          )}
        </Form>
      )}
    </Formik>
  )
}
Example #9
Source File: AppEditorShell.tsx    From mui-toolpad with MIT License 2 votes vote down vote up
function CreateReleaseDialog({ appId, open, onClose }: CreateReleaseDialogProps) {
  const navigate = useNavigate();

  const lastRelease = client.useQuery('findLastRelease', [appId]);

  const { handleSubmit, register, formState, reset } = useForm({
    defaultValues: {
      description: '',
    },
  });

  const createReleaseMutation = client.useMutation('createRelease');
  const doSubmit = handleSubmit(async (releaseParams) => {
    const newRelease = await createReleaseMutation.mutateAsync([appId, releaseParams]);
    reset();
    navigate(`/app/${appId}/releases/${newRelease.version}`);
  });

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogForm autoComplete="off" onSubmit={doSubmit}>
        <DialogTitle>Create new release</DialogTitle>
        <DialogContent>
          {lastRelease.isSuccess ? (
            <Stack spacing={1}>
              <Typography>
                You are about to create a snapshot of your application under a unique url. You will
                be able to verify whether everything is working correctly before deploying this
                release to production.
              </Typography>
              <Typography>
                The new version to be created is &quot;
                {lastRelease.data ? lastRelease.data.version + 1 : 1}&quot;.
              </Typography>
              <Typography>
                Please summarize the changes you have made to the application since the last
                release:
              </Typography>
              <TextField
                label="description"
                autoFocus
                fullWidth
                multiline
                rows={5}
                {...register('description')}
                error={Boolean(formState.errors.description)}
                helperText={formState.errors.description?.message}
              />
            </Stack>
          ) : null}

          {createReleaseMutation.isError ? (
            <Alert severity="error">{(createReleaseMutation.error as Error).message}</Alert>
          ) : null}
        </DialogContent>
        <DialogActions>
          <Button color="inherit" variant="text" onClick={onClose}>
            Cancel
          </Button>
          <LoadingButton
            disabled={!lastRelease.isSuccess}
            loading={createReleaseMutation.isLoading}
            type="submit"
          >
            Create
          </LoadingButton>
        </DialogActions>
      </DialogForm>
    </Dialog>
  );
}
Example #10
Source File: connect-options.tsx    From example with MIT License 2 votes vote down vote up
export function ConnectOptions() {
	const { environment, setEnvironment } = useContext(EnvironmentContext)
	const connection = useContext(ConnectorContext)
	const { connector, state } = connection

	const options$ = useMemo(() => connector ? from(connector.getOptions()) : from([]), [connector])
	const envSelectHandler = useCallback((e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
		setEnvironment?.(e.target.value as RaribleSdkEnvironment)
	}, [setEnvironment])

	if (!connector) {
		return null
	}

	const style = {
		justifyContent: "start",
		pl: "3rem",
		"& .MuiButton-startIcon": {
			position: "absolute",
			left: "1.25rem"
		}
	}

	return <Box sx={{
		maxWidth: 300
	}}>
		<Rx value$={options$}>
			{options => (
				<Stack spacing={1}>
					<TextField
						select
						size="small"
						label="Environment"
						disabled={state?.status === "connected"}
						value={environment}
						onChange={envSelectHandler}
					>
						{ENVIRONMENTS.map((option) => (
							<MenuItem key={option.value} value={option.value}>
								{option.label}
							</MenuItem>
						))}
					</TextField>
					{
						options.map(o => {
							const walletInfo = getWalletInfo(o.option)
							return <LoadingButton
								key={o.option}
								onClick={() => connector.connect(o)}
								loading={state.status === "connecting" && state.providerId === o.provider.getId()}
								loadingPosition="start"
								startIcon={<Icon icon={faChevronRight}/>}
								sx={style}
								variant="outlined"
								disabled={state?.status === "connected"}
								fullWidth
							>
								{walletInfo.label}
							</LoadingButton>
						})
					}
					<Button
						onClick={(state as StateConnected<any>).disconnect}
						startIcon={<Icon icon={faLinkSlash}/>}
						color="error"
						sx={style}
						variant="outlined"
						disabled={state?.status !== "connected"}
						fullWidth
					>
						Disconnect
					</Button>
				</Stack>
			)}
		</Rx>
	</Box>
}