@patternfly/react-core#Modal JavaScript Examples

The following examples show how to use @patternfly/react-core#Modal. 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: delete-modal.js    From ibutsu-server with MIT License 6 votes vote down vote up
render () {
    return (
      <Modal
        variant={ModalVariant.small}
        title={this.props.title}
        isOpen={this.props.isOpen}
        onClose={this.onClose}
        actions={[
          <Button key="delete" variant="danger" onClick={this.onDelete}>Delete</Button>,
          <Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
        ]}
      >
      <Text>{this.props.body}</Text>
      </Modal>
    );
  }
Example #2
Source File: new-dashboard-modal.js    From ibutsu-server with MIT License 6 votes vote down vote up
render () {
    return (
      <Modal
        variant={ModalVariant.small}
        title="New Dashboard"
        isOpen={this.props.isOpen}
        onClose={this.onClose}
        actions={[
          <Button key="save" variant="primary" onClick={this.onSave}>Save</Button>,
          <Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
        ]}
      >
        <Form>
          <FormGroup label="Title" fieldId="dashboard-title" helperTextInvalid="A dashboard title is required" helperTextInvalidIcon={<ExclamationCircleIcon />} validated={this.state.isTitleValid} isRequired>

            <TextInput type="text" id="dashboard-title" name="dashboard-title" value={this.state.title} onChange={this.onTitleChange} validated={this.state.isTitleValid} isRequired />
          </FormGroup>
          <FormGroup label="Description" fieldId="dashboard-description">
            <TextInput type="text" id="dashboard-description" name="dashboard-description" value={this.state.description} onChange={this.onDescriptionChange} />
          </FormGroup>
        </Form>
      </Modal>
    );
  }
Example #3
Source File: index.js    From sed-frontend with Apache License 2.0 5 votes vote down vote up
ConnectLog = () => {
  const [activeTabKey, setActiveTabKey] = useState(0);
  const dispatch = useDispatch();
  const { push, location } = useHistory();
  useEffect(() => {
    dispatch(clearNotifications());
    const searchParams = new URLSearchParams(location.search);
    const activeTab = tabMapper.findIndex(
      (item) => item === searchParams.get('active_tab')
    );
    if (activeTab !== -1) {
      setActiveTabKey(activeTab);
    } else {
      push({
        pathname: location.pathname,
        search: new URLSearchParams({
          active_tab: tabMapper[0],
        }).toString(),
      });
    }
  }, []);
  return (
    <Modal
      title="Red Hat connect log"
      variant="medium"
      isOpen={true}
      onClose={() => push(paths.connector)}
    >
      <Tabs
        activeKey={activeTabKey}
        onSelect={(_e, tabKey) => {
          push({
            pathname: location.pathname,
            search: new URLSearchParams({
              active_tab: tabMapper[tabKey],
            }).toString(),
          });
          setActiveTabKey(tabKey);
        }}
      >
        <Tab eventKey={0} title={<TabTitleText>Runs</TabTitleText>}>
          <LogsTable />
        </Tab>
        <Tab eventKey={1} title={<TabTitleText>Systems</TabTitleText>}>
          <SystemsTable />
        </Tab>
      </Tabs>
    </Modal>
  );
}
Example #4
Source File: add-token-modal.js    From ibutsu-server with MIT License 5 votes vote down vote up
render () {
    return (
      <Modal
        variant={ModalVariant.small}
        title="Add Token"
        isOpen={this.props.isOpen}
        onClose={this.onClose}
        actions={[
          <Button key="save" variant="primary" onClick={this.onSave}>Save</Button>,
          <Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
        ]}
      >
        <Form>
          <FormGroup
            label="Name"
            fieldId="token-name"
            helperTextInvalid="A token name is required"
            helperTextInvalidIcon={<ExclamationCircleIcon />}
            validated={this.state.isNameValid ? ValidatedOptions.default : ValidatedOptions.error}
            isRequired
          >
            <TextInput
              type="text"
              id="token-name"
              name="token-name"
              value={this.state.name}
              onChange={this.onNameChange}
              validated={this.state.isNameValid ? ValidatedOptions.default : ValidatedOptions.error}
              isRequired
            />
          </FormGroup>
          <FormGroup
            label="Expiry"
            fieldId="token-expiry-date"
            helperTextInvalid="A valid epiry date is required"
            helperTextInvalidIcon={<ExclamationCircleIcon />}
            validated={this.state.isExpiryValid ? ValidatedOptions.default : ValidatedOptions.error}
            isRequired
          >
            <DatePicker
              onChange={this.onExpiryDateChange}
              value={this.state.expiryDate}
              inputProps={{
                id: "token-expiry-date",
                validated: this.state.isExpiryValid ? ValidatedOptions.default : ValidatedOptions.error
              }}
            />
          </FormGroup>
        </Form>
      </Modal>
    );
  }
Example #5
Source File: RunTaskModal.js    From tasks-frontend with Apache License 2.0 5 votes vote down vote up
RunTaskModal = ({ error, task, isOpen, setModalOpened }) => {
  const [selectedIds, setSelectedIds] = useState([]);
  const dispatch = useDispatch();

  useEffect(() => {
    setSelectedIds([]);
  }, [task]);

  useEffect(() => {
    dispatch({
      type: 'SELECT_ENTITY',
      payload: {
        selected: selectedIds,
      },
    });
  }, [selectedIds]);

  const selectIds = (_event, _isSelected, _index, entity) => {
    let newSelectedIds = [...selectedIds];

    !newSelectedIds.includes(entity.id)
      ? newSelectedIds.push(entity.id)
      : newSelectedIds.splice(newSelectedIds.indexOf(entity.id), 1);

    setSelectedIds(newSelectedIds);
  };

  return (
    <Modal
      aria-label="run-task-modal"
      title={task.title || 'Error'}
      isOpen={isOpen}
      onClose={() => setModalOpened(false)}
      width={'70%'}
    >
      {error ? (
        <EmptyStateDisplay
          icon={ExclamationCircleIcon}
          color="#c9190b"
          title={'This task cannot be displayed'}
          text={TASK_ERROR}
          error={`Error ${error?.response?.status}: ${error?.message}`}
        />
      ) : (
        <React.Fragment>
          <Flex>
            <FlexItem>
              <b>Task description</b>
            </FlexItem>
          </Flex>
          <Flex style={{ paddingBottom: '8px' }}>
            <FlexItem>{task.description}</FlexItem>
          </Flex>
          <Flex>
            <FlexItem>
              <a
                href={`${TASKS_API_ROOT}${AVAILABLE_TASKS_ROOT}/${task.slug}/playbook`}
              >
                Download preview of playbook
              </a>
            </FlexItem>
          </Flex>
          <br />
          <b>Systems to run tasks on</b>
          <SystemTable selectedIds={selectedIds} selectIds={selectIds} />
        </React.Fragment>
      )}
    </Modal>
  );
}
Example #6
Source File: EditActivationKeyModal.js    From sed-frontend with Apache License 2.0 5 votes vote down vote up
EditActivationKeyModal = (props) => {
  const { activationKeyName } = props;
  const queryClient = useQueryClient();
  const [updated, setUpdated] = React.useState(false);
  const [error, setError] = React.useState(false);
  const { handleModalToggle, isOpen } = props;
  const { mutate, isLoading } = useUpdateActivationKey();
  const {
    isLoading: isKeyLoading,
    error: keyError,
    data: activationKey,
  } = useActivationKey(activationKeyName);
  const submitForm = (name, role, serviceLevel, usage) => {
    mutate(
      { activationKeyName, role, serviceLevel, usage },
      {
        onSuccess: () => {
          setError(false);
          setUpdated(true);
          queryClient.invalidateQueries('activation_keys');
          queryClient.resetQueries(`activation_key_${activationKeyName}`);
        },
        onError: () => {
          setError(true);
          setUpdated(false);
        },
      }
    );
  };
  return (
    <Modal
      variant={ModalVariant.large}
      title="Edit activation key"
      description=""
      isOpen={isOpen}
      onClose={handleModalToggle}
    >
      {(isLoading || isKeyLoading) && !keyError ? (
        <Loading />
      ) : (
        <ActivationKeyForm
          activationKey={activationKey}
          handleModalToggle={handleModalToggle}
          submitForm={submitForm}
          isSuccess={updated}
          isError={error}
        />
      )}
    </Modal>
  );
}
Example #7
Source File: DeleteActivationKeyConfirmationModal.js    From sed-frontend with Apache License 2.0 5 votes vote down vote up
DeleteActivationKeyConfirmationModal = (props) => {
  const { isOpen, handleModalToggle, name } = props;
  const { addSuccessNotification, addErrorNotification } = useNotifications();
  const { mutate, isLoading } = useDeleteActivationKey();
  const queryClient = useQueryClient();

  const deleteActivationKey = (name) => {
    mutate(name, {
      onSuccess: (_data, name) => {
        queryClient.setQueryData('activation_keys', (oldData) =>
          oldData.filter((entry) => entry.name != name)
        );
        addSuccessNotification(`Activation Key ${name} deleted`);
        handleModalToggle();
      },
      onError: () => {
        addErrorNotification('Something went wrong. Please try again');
        handleModalToggle();
      },
    });
    mutate;
  };
  const actions = [
    <Button
      key="confirm"
      variant="danger"
      onClick={() => deleteActivationKey(name)}
      data-testid="delete-activation-key-confirmation-modal-confirm-button"
    >
      Delete
    </Button>,
    <Button key="cancel" variant="link" onClick={handleModalToggle}>
      Cancel
    </Button>,
  ];

  const title = (
    <>
      <TextContent>
        <Text component={TextVariants.h2}>
          <ExclamationTriangleIcon size="md" color="#F0AB00" /> Delete
          Activation Key?
        </Text>
      </TextContent>
    </>
  );
  const content = () => {
    if (isLoading) {
      return <Loading />;
    } else {
      return (
        <TextContent>
          <Text component={TextVariants.p}>
            <b>{name}</b> will no longer be available for use. This operation
            cannot be undone.
          </Text>
        </TextContent>
      );
    }
  };

  return (
    <Modal
      title={title}
      isOpen={isOpen}
      onClose={handleModalToggle}
      variant={ModalVariant.small}
      actions={actions}
    >
      {content()}
    </Modal>
  );
}
Example #8
Source File: CreateActivationKeyModal.js    From sed-frontend with Apache License 2.0 5 votes vote down vote up
CreateActivationKeyModal = (props) => {
  const queryClient = useQueryClient();
  const [created, setCreated] = React.useState(false);
  const [error, setError] = React.useState(false);
  const { handleModalToggle, isOpen } = props;
  const { mutate, isLoading } = useCreateActivationKey();
  const submitForm = (name, role, serviceLevel, usage) => {
    mutate(
      { name, role, serviceLevel, usage },
      {
        onSuccess: () => {
          setError(false);
          setCreated(true);
          queryClient.invalidateQueries('activation_keys');
        },
        onError: () => {
          setError(true);
          setCreated(false);
        },
      }
    );
  };
  return (
    <Modal
      variant={ModalVariant.large}
      title="Create new activation key"
      description=""
      isOpen={isOpen}
      onClose={handleModalToggle}
    >
      {isLoading ? (
        <Loading />
      ) : (
        <ActivationKeyForm
          handleModalToggle={handleModalToggle}
          submitForm={submitForm}
          isSuccess={created}
          isError={error}
        />
      )}
    </Modal>
  );
}
Example #9
Source File: index.js    From sed-frontend with Apache License 2.0 5 votes vote down vote up
ConfirmChangesModal = ({
  isOpen = false,
  handleCancel,
  handleConfirm,
  systemsCount,
  data,
}) => {
  return (
    <Modal
      variant="small"
      title="Confirm changes"
      isOpen={isOpen}
      onClose={handleCancel}
      actions={[
        <Button
          key="confirm"
          variant="primary"
          type="button"
          onClick={handleConfirm}
        >
          Confirm changes
        </Button>,
        <Button
          key="cancel"
          variant="link"
          type="button"
          onClick={handleCancel}
        >
          Cancel
        </Button>,
      ]}
    >
      <TextContent>
        <Text component="p">
          Your changes applies to{' '}
          <b>
            {systemsCount} connected {pluralize(systemsCount, 'system')}
          </b>
          . Selected settings will also be applied to <b>all future systems</b>{' '}
          that are connected through remote host configuration (rhc).
        </Text>
        <Text component="p" className="pf-u-mb-sm">
          Upon confirmation, an Ansible Playbook will be pushed to{' '}
          {systemsCount} {pluralize(systemsCount, 'system')} to apply changes.
        </Text>
      </TextContent>
      <Button
        variant="link"
        onClick={() => {
          (async () => {
            const playbook = await configApi.getPlaybookPreview({
              compliance_openscap: data.useOpenSCAP ? 'enabled' : 'disabled',
              insights: data.hasInsights ? 'enabled' : 'disabled',
              remediations: data.enableCloudConnector ? 'enabled' : 'disabled',
            });
            downloadFile(playbook);
          })();
        }}
        style={{ paddingLeft: 0 }}
      >
        View playbook
      </Button>
    </Modal>
  );
}
Example #10
Source File: user-list.js    From ibutsu-server with MIT License 5 votes vote down vote up
render() {
    document.title = 'Users - Administration | Ibutsu';
    const { columns, rows, textFilter } = this.state;
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    };
    const filters = [
      <TextInput type="text" id="filter" placeholder="Search for user..." value={textFilter || ''} onChange={this.onTextChanged} style={{height: "inherit"}} key="textFilter"/>
    ];
    return (
      <React.Fragment>
        <PageSection id="page" variant={PageSectionVariants.light}>
          <TextContent>
            <Text className="title" component="h1" ouiaId="users">Users</Text>
          </TextContent>
        </PageSection>
        <PageSection className="pf-u-pb-0">
          <Card>
            <CardBody className="pf-u-p-0">
              <FilterTable
                columns={columns}
                rows={rows}
                filters={filters}
                pagination={pagination}
                isEmpty={this.state.isEmpty}
                isError={this.state.isError}
                onSetPage={this.setPage}
                onSetPageSize={this.setPageSize}
              />
            </CardBody>
          </Card>
        </PageSection>
        <Modal
          title="Confirm Delete"
          variant="small"
          isOpen={this.state.isDeleteModalOpen}
          onClose={this.onDeleteModalClose}
          actions={[
            <Button key="delete" variant="danger" isLoading={this.state.isDeleting} isDisabled={this.state.isDeleting} onClick={this.onModalDeleteClick}>
              {this.state.isDeleting ? 'Deleting...' : 'Delete'}
            </Button>,
            <Button key="cancel" variant="secondary" isDisabled={this.state.isDeleting} onClick={this.onDeleteModalClose}>
              Cancel
            </Button>
          ]}
        >
          Are you sure you want to delete &ldquo;{this.state.selectedUser && this.state.selectedUser.name}&rdquo;? This cannot be undone!
        </Modal>
      </React.Fragment>
    );
  }
Example #11
Source File: ModalConfirm.js    From cockpit-wicked with GNU General Public License v2.0 5 votes vote down vote up
ModalConfirm = ({
    caption,
    title,
    isOpen = false,
    onConfirm,
    onConfirmDisable = false,
    onConfirmLabel = _("Confirm"),
    onCancel,
    onCancelLabel = _("Cancel"),
    variant = ModalVariant.small,
    children
}) => {
    if (!isOpen) return;

    return (
        <Modal
            aria-label={title}
            variant={variant}
            isOpen={isOpen}
            showClose={false}
            header={
                <>
                    <Text component={TextVariants.small} className='modal-form-caption'>
                        {caption}
                    </Text>
                    <Title headingLevel="h1">
                        {title}
                    </Title>
                </>
            }
            footer={
                <ActionGroup>
                    <Button key="confirm" variant="danger" onClick={onConfirm}>
                        {onConfirmLabel}
                    </Button>

                    <Button key="cancel" variant="link" onClick={onCancel}>
                        {onCancelLabel}
                    </Button>
                </ActionGroup>
            }
        >
            {children}
        </Modal>
    );
}
Example #12
Source File: Modal.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
RepoModal = ({
  isOpen,
  title,
  titleIconVariant,
  openModal, // should be closeModal, update here and other places that use it
  submitLabel,
  schema,
  initialValues,
  variant,
  reloadData,
  size,
  onSubmit,
  additionalMappers,
}) => {
  return (
    <Modal
      variant={size ?? 'small'}
      title={title}
      titleIconVariant={titleIconVariant ?? null}
      isOpen={isOpen}
      onClose={openModal}
    >
      <FormRenderer
        schema={schema}
        FormTemplate={(props) => (
          <FormTemplate
            {...props}
            submitLabel={submitLabel}
            disableSubmit={['invalid']}
            buttonsProps={{
              submit: { variant },
            }}
          />
        )}
        initialValues={initialValues}
        componentMapper={
          additionalMappers
            ? { ...additionalMappers, ...componentMapper }
            : componentMapper
        }
        onSubmit={async (values) => {
          await onSubmit(values);
          setTimeout(async () => await reloadData(), 500);
          openModal();
        }}
        onCancel={() => openModal()}
      />
    </Modal>
  );
}
Example #13
Source File: AuthModal.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
AuthModal = () => {
  return (
    <Modal
      style={{ padding: '15px' }}
      isOpen={true}
      variant="small"
      onClose={() => (window.location.href = 'https://console.redhat.com/')}
      aria-label="auth-modal"
      header={
        <h2 className="pf-u-pr-xl pf-u-pl-xl pf-u-font-size-2xl pf-u-text-align-center pf-u-font-weight-bold">
          Edge management requires a valid Smart Management subscription
        </h2>
      }
      footer={
        <ModalBoxFooter
          style={{
            display: 'flex',
            justifyContent: 'center',
            width: '100%',
            flexDirection: 'column',
            paddingTop: 0,
          }}
        >
          <Button
            key="get-started"
            component="a"
            className="pf-u-mb-md"
            variant="primary"
            target="_blank"
            href="https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux/try-it"
          >
            Get started
          </Button>
          <Button
            component="a"
            key="interactive-demo"
            className="pf-u-mb-md"
            variant="secondary"
            target="_blank"
            href="https://red.ht/edgemanagementlab"
          >
            Try the interactive demo
          </Button>
          <Button
            component="a"
            key="not-now"
            variant="link"
            href="https://console.redhat.com/"
          >
            Not now
          </Button>
        </ModalBoxFooter>
      }
      title="Edge management requires a valid subscription"
      width="640px"
    >
      <img
        style={{ margin: '0 auto', display: 'block' }}
        src={edgeIcon}
        width="200px"
        alt="edge icon"
      />
      <p className="pf-u-pr-xl pf-u-pl-xl pf-u-text-align-center">
        Securely manage and scale deployments at the edge with zero-touch
        provisioning, system health visibility, and quick security remediations
        and more with a Red Hat Smart Management subscription
      </p>
    </Modal>
  );
}
Example #14
Source File: AddSystemsToGroupModal.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
AddSystemsToGroupModal = ({
  groupId,
  closeModal,
  isOpen,
  reloadData,
  groupName,
}) => {
  const [response, fetchDevices] = useApi({
    api: getInventory,
    tableReload: true,
  });
  const { data, isLoading, hasError } = response;
  const [deviceIds, setDeviceIds] = useState([]);
  const dispatch = useDispatch();

  const handleAddDevicesToGroup = () => {
    const statusMessages = {
      onSuccess: {
        title: 'Success',
        description: `Device(s) have been added to ${groupName} successfully`,
      },
      onError: {
        title: 'Error',
        description: `An error occurred making the request`,
      },
    };

    apiWithToast(
      dispatch,
      () =>
        addDevicesToGroup(
          parseInt(groupId),
          deviceIds.map((device) => ({ ID: device.deviceID }))
        ),
      statusMessages
    );
    setTimeout(async () => await reloadData(), 500);
    closeModal();
  };

  return (
    <Modal
      id="add-systems-modal"
      title="Add systems"
      position="top"
      isOpen={isOpen}
      onClose={closeModal}
      variant="large"
      actions={[
        <Button
          isDisabled={deviceIds.length === 0}
          key="confirm"
          variant="primary"
          onClick={handleAddDevicesToGroup}
        >
          Add systems
        </Button>,
        <Button key="cancel" variant="link" onClick={closeModal}>
          Cancel
        </Button>,
      ]}
    >
      <DeviceTable
        selectedItems={setDeviceIds}
        skeletonRowQuantity={15}
        hasCheckbox={true}
        isLoading={isLoading}
        hasError={hasError}
        count={data?.count}
        data={data?.data?.devices || []}
        fetchDevices={fetchDevices}
      />
    </Modal>
  );
}
Example #15
Source File: ModalForm.js    From cockpit-wicked with GNU General Public License v2.0 5 votes vote down vote up
ModalForm = ({
    caption,
    title,
    isOpen = false,
    onSubmit,
    onSubmitDisable = false,
    onSubmitLabel = _("Apply"),
    onCancel,
    onCancelLabel = _("Cancel"),
    variant = ModalVariant.small,
    children
}) => {
    if (!isOpen) return;

    return (
        <Modal
            aria-label={title}
            variant={variant}
            isOpen={isOpen}
            showClose={false}
            header={
                <>
                    <Text component={TextVariants.small} className='modal-form-caption'>
                        {caption}
                    </Text>
                    <Title headingLevel="h1">
                        {title}
                    </Title>
                </>
            }
            footer={
                <ActionGroup>
                    <Button key="submit" onClick={onSubmit} isDisabled={onSubmitDisable}>
                        {onSubmitLabel}
                    </Button>

                    <Button key="cancel" variant="link" onClick={onCancel}>
                        {onCancelLabel}
                    </Button>
                </ActionGroup>
            }
        >

            <Form>
                {children}
            </Form>
        </Modal>
    );
}
Example #16
Source File: CancelRequestModal.js    From access-requests-frontend with Apache License 2.0 5 votes vote down vote up
CancelRequestModal = ({ requestId, onClose }) => {
  const [isLoading, setIsLoading] = React.useState(false);
  const dispatch = useDispatch();
  const onCancel = () => {
    setIsLoading(true);
    // https://ci.cloud.redhat.com/docs/api-docs/rbac#operations-CrossAccountRequest-patchCrossAccountRequest
    apiInstance
      .patch(
        `${API_BASE}/cross-account-requests/${requestId}/`,
        { status: 'cancelled' },
        {
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
          },
        }
      )
      .then((res) => {
        if (res.errors && res.errors.length > 0) {
          throw Error(res.errors.map((e) => e.detail).join('\n'));
        }
        dispatch(
          addNotification({
            variant: 'success',
            title: 'Request cancelled successfully',
          })
        );
        setIsLoading(false);
        onClose(true);
      })
      .catch((err) => {
        dispatch(
          addNotification({
            variant: 'danger',
            title: 'There was an error cancelling your request',
            description: err.message,
          })
        );
        setIsLoading(false);
        onClose(true);
      });
  };
  return (
    <Modal
      title="Cancel request?"
      isOpen
      variant="small"
      onClose={() => onClose(false)}
      actions={[
        <Button key="confirm" variant="danger" onClick={onCancel}>
          Yes, cancel
        </Button>,
        <Button key="cancel" variant="link" onClick={() => onClose(false)}>
          No, keep
        </Button>,
      ]}
    >
      Request <b>{requestId}</b> will be withdrawn.
      {isLoading && <Spinner size="lg" />}
    </Modal>
  );
}
Example #17
Source File: WirelessForm.js    From cockpit-wicked with GNU General Public License v2.0 4 votes vote down vote up
WirelessForm = ({ isOpen, onClose, iface, connection }) => {
    const { wireless } = connection || {};
    const isEditing = !!connection;
    const [essid, setEssid] = useState(wireless?.essid);
    const [mode, setMode] = useState(wireless?.mode || wirelessModes.MANAGED);
    const [authMode, setAuthMode] = useState(wireless?.authMode || wirelessAuthModes.WEP_OPEN);
    const [password, setPassword] = useState(wireless?.password || "");
    const dispatch = useNetworkDispatch();

    const addOrUpdateConnection = () => {
        if (isEditing) {
            updateConnection(
                dispatch, connection,
                { wireless: { essid, mode, authMode, password } }
            );
        } else {
            addConnection(
                dispatch, { name: iface.name, type: interfaceType.WIRELESS, wireless: { essid, mode, authMode, password } }
            );
        }
        onClose();
    };

    return (
        <Modal
            variant={ModalVariant.small}
            title={isEditing ? _("Edit WiFi settings") : _("Add WiFi settings")}
            isOpen={isOpen}
            onClose={onClose}
            actions={[
                <Button key="confirm" variant="primary" onClick={addOrUpdateConnection}>
                    {isEditing ? _("Change") : _("Add")}
                </Button>,
                <Button key="cancel" variant="link" onClick={onClose}>
                    {_("Cancel")}
                </Button>
            ]}
        >
            <Form>
                <FormGroup
                    label={_("Mode")}
                    isRequired
                    fieldId="wireless-mode"
                >
                    <FormSelect value={mode} onChange={setMode} id="wireless-mode">
                        {modeOptions.map((option, index) => (
                            <FormSelectOption key={index} {...option} />
                        ))}
                    </FormSelect>
                </FormGroup>

                <FormGroup
                    label={_("ESSID")}
                    isRequired
                    fieldId="essid"
                >
                    <WirelessEssidSelect essid={essid} setEssid={setEssid} iface={iface} />
                </FormGroup>
                <FormGroup
                    label={_("Auth Mode")}
                    isRequired
                    fieldId="wireless-auth-mode"
                >
                    <FormSelect value={authMode} onChange={setAuthMode} id="wireless-auth-mode">
                        {authModeOptions.map((option, index) => (
                            <FormSelectOption key={index} {...option} />
                        ))}
                    </FormSelect>
                </FormGroup>
                { (authMode === "psk") &&
                    <FormGroup
                        label={_("Password")}
                        isRequired
                        fieldId="password"
                    >
                        <TextInput
                            isRequired
                            id="password"
                            value={password}
                            onChange={setPassword}
                            type='password'
                        />
                    </FormGroup>}
            </Form>
        </Modal>
    );
}
Example #18
Source File: project-list.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    document.title = 'Projects - Administration | Ibutsu';
    const { columns, rows, textFilter } = this.state;
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    };
    const filters = [
      <TextInput type="text" id="filter" placeholder="Search for project..." value={textFilter || ''} onChange={this.onTextChanged} style={{height: "inherit"}} key="textFilter"/>
    ];
    return (
      <React.Fragment>
        <PageSection id="page" variant={PageSectionVariants.light}>
          <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
            <Flex>
              <FlexItem spacer={{ default: 'spacerLg' }}>
                <TextContent>
                  <Text className="title" component="h1" ouiaId="admin-projects">Projects</Text>
                </TextContent>
              </FlexItem>
            </Flex>
            <Flex>
              <FlexItem>
                <Button
                  aria-label="Add project"
                  variant="secondary"
                  title="Add project"
                  ouiaId="admin-projects-add"
                  component={(props: any) => <Link {...props} to="/admin/projects/new" />}
                >
                  <PlusCircleIcon /> Add Project
                </Button>
              </FlexItem>
            </Flex>
          </Flex>
        </PageSection>
        <PageSection className="pf-u-pb-0">
          <Card>
            <CardBody className="pf-u-p-0">
              <FilterTable
                columns={columns}
                rows={rows}
                filters={filters}
                pagination={pagination}
                isEmpty={this.state.isEmpty}
                isError={this.state.isError}
                onSetPage={this.setPage}
                onSetPageSize={this.setPageSize}
              />
            </CardBody>
          </Card>
        </PageSection>
        <Modal
          title="Confirm Delete"
          variant="small"
          isOpen={this.state.isDeleteModalOpen}
          onClose={this.onDeleteModalClose}
          actions={[
            <Button
              key="delete"
              variant="danger"
              ouiaId="admin-projects-modal-delete"
              isLoading={this.state.isDeleting}
              isDisabled={this.state.isDeleting}
              onClick={this.onModalDeleteClick}
            >
              {this.state.isDeleting ? 'Deleting...' : 'Delete'}
            </Button>,
            <Button
              key="cancel"
              variant="secondary"
              ouiaId="admin-projects-modal-cancel"
              isDisabled={this.state.isDeleting}
              onClick={this.onDeleteModalClose}
            >
              Cancel
            </Button>
          ]}
        >
          Are you sure you want to delete &ldquo;{this.state.selectedProject && this.state.selectedProject.title}&rdquo;? This cannot be undone!
        </Modal>
      </React.Fragment>
    );
  }
Example #19
Source File: new-widget-wizard.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const { widgetTypes, selectedType, selectedTypeId, stepIdReached, isTitleValid, areParamsFilled } = this.state;
    const steps = [
      {
        id: 1,
        name: 'Select type',
        enableNext: selectedType,
        component: (
          <Form>
            <Title headingLevel="h1" size="xl">Select a widget type</Title>
            {widgetTypes.map(widgetType => {
              return (
                <div key={widgetType.id}>
                  <Radio id={widgetType.id} value={widgetType.id} label={widgetType.title} description={widgetType.description} isChecked={selectedTypeId === widgetType.id} onChange={this.onSelectType}/>
                </div>
              );
            })}
          </Form>
        )
      },
      {
        id: 2,
        name: 'Set info',
        canJumpTo: stepIdReached >= 2,
        enableNext: isTitleValid,
        component: (
          <Form isHorizontal>
            <Title headingLevel="h1" size="xl">Set widget information</Title>
            <FormGroup label="Title" fieldId="widget-title" helperText="A title for the widget" validated={this.isTitleValid} helperTextInvalid="Please enter a title for this widget" helperTextInvalidIcon={<ExclamationCircleIcon/>} isRequired>
              <TextInput type="text" id="widget-title" name="widget-title" value={this.state.title} onChange={this.onTitleChange} validated={this.state.isTitleValid} isRequired />
            </FormGroup>
            <FormGroup label="Weight" fieldId="widget-weight" helperText="How widgets are ordered on the dashboard">
              <TextInput type="number" id="widget-weight" name="widget-weight" value={this.state.weight} onChange={this.onWeightChange} />
            </FormGroup>
          </Form>
        )
      },
      {
        id: 3,
        name: 'Set parameters',
        canJumpTo: stepIdReached >= 3,
        enableNext: areParamsFilled,
        component: (
          <Form isHorizontal>
            <Title headingLevel="h1" size="xl">Set widget parameters</Title>
            {!!selectedType && selectedType.params.map(param => {
              return (
                <React.Fragment key={param.name}>
                {(param.type === 'string' || param.type === 'integer' || param.type === 'float') &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    helperText={<Linkify componentDecorator={linkifyDecorator}>{param.description}</Linkify>}
                    isRequired={param.required}>
                    <TextInput
                      value={this.state.params[param.name]}
                      type={(param.type === 'integer' || param.type === 'float') ? 'number' : 'text'}
                      id={param.name}
                      aria-describedby={`${param.name}-helper`}
                      name={param.name}
                      onChange={this.onParamChange}
                      isRequired={param.required}
                    />
                  </FormGroup>
                }
                {param.type === 'boolean' &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    isRequired={param.required}
                    hasNoPaddingTop>
                    <Checkbox
                      isChecked={this.state.params[param.name]}
                      onChange={this.onParamChange}
                      id={param.name}
                      name={param.name}
                      label={param.description} />
                  </FormGroup>
                }
                {param.type === 'list' &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    helperText={`${param.description}. Place items on separate lines.`}>
                    isRequired={param.required}
                    <TextArea
                      id={param.name}
                      name={param.name}
                      isRequired={param.required}
                      value={this.state.params[param.name]}
                      onChange={this.onParamChange}
                      resizeOrientation='vertical' />
                  </FormGroup>
                }
                </React.Fragment>
              );
            })}
          </Form>
        )
      },
      {
        id: 4,
        name: 'Review details',
        canJumpTo: stepIdReached >= 4,
        nextButtonText: 'Finish',
        component: (
          <Stack hasGutter>
            <StackItem>
              <Title headingLevel="h1" size="xl">Review details</Title>
            </StackItem>
            <StackItem>
              <Grid hasGutter>
                <GridItem span="2">
                  <Title headingLevel="h4">Title</Title>
                </GridItem>
                <GridItem span="10">
                  <TextContent><Text>{this.state.title}</Text></TextContent>
                </GridItem>
                <GridItem span="2">
                  <Title headingLevel="h4">Weight</Title>
                </GridItem>
                <GridItem span="10">
                  <TextContent><Text>{this.state.weight}</Text></TextContent>
                </GridItem>
                <GridItem span="2">
                  <Title headingLevel="h4">Parameters</Title>
                </GridItem>
                <GridItem span="10">
                  <Table
                    cells={["Name", "Value"]}
                    variant="compact"
                    borders="compactBorderless"
                    rows={Object.entries(this.state.params).map(param => { return [param[0], param[1].toString()]; })}
                    aria-label="Parameters">
                    <TableHeader />
                    <TableBody />
                  </Table>
                </GridItem>
              </Grid>
            </StackItem>
          </Stack>
        )
      }
    ];
    return (
      <Modal
        isOpen={this.props.isOpen}
        variant={ModalVariant.large}
        showClose={false}
        onClose={this.onClose}
        hasNoBodyWrapper
        aria-describedby="add-widget-description"
        aria-labelledby="add-widget-title"
      >
        <Wizard
          titleId="add-widget-title"
          descriptionId="add-widget-description"
          title="Add Widget"
          description="Add a widget to the current dashboard"
          steps={steps}
          onNext={this.onNext}
          onSave={this.onSave}
          onClose={this.onClose}
          height={400}
        />
      </Modal>
    );
  }
Example #20
Source File: requestCertificate.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 4 votes vote down vote up
RequestCertificateModal = ({ onClose, hostname, cas, addAlert, mode }) => {
    const [_userChangedNickname, setUserChangedNickname] = useState(false);
    const [ca, _setCa] = useState(cas[Object.keys(cas)[0]] ? cas[Object.keys(cas)[0]].nickname.v : undefined);
    const [storage, setStorage] = useState(mode === "request" ? "nssdb" : "file");
    const [nickname, _setNickname] = useState(makeNickName(hostname, ca));
    const [certFile, setCertFile] = useState("");
    const [keyFile, setKeyFile] = useState("");
    const [subjectName, setSubjectName] = useState("");
    const [dnsName, _setDnsName] = useState("");
    const [principalName, setPricipalName] = useState("");
    const [signingParameters, setSigningParameters] = useState("");
    const [errorName, setErrorName] = useState();
    const [errorMessage, setErrorMessage] = useState();

    const setCa = value => {
        if (!_userChangedNickname)
            _setNickname(makeNickName(hostname, value));

        _setCa(value);
    };

    const setNickname = value => {
        setUserChangedNickname(true);
        _setNickname(value);
    };

    const setDnsName = value => {
        value = value.replace(/\s/g, ',');
        while (value.includes(",,"))
            value = value.replace(",,", ',');
        _setDnsName(value);
    };

    const onRequest = () => {
        const casKeys = Object.keys(cas);
        let caPath;
        casKeys.forEach(key => {
            if (cas[key].nickname.v === ca)
                caPath = key;
        });

        const parameter = {
            "cert-storage": cockpit.variant("s", storage),
            "key-storage": cockpit.variant("s", storage),
            ca: cockpit.variant("s", caPath),
        };

        if (storage === "nssdb") {
            parameter["cert-database"] = cockpit.variant("s", NSSDB_PATH);
            parameter["cert-nickname"] = cockpit.variant("s", nickname);
            parameter["key-database"] = cockpit.variant("s", NSSDB_PATH);
            parameter["key-nickname"] = cockpit.variant("s", nickname);
        } else { // file
            parameter["cert-file"] = cockpit.variant("s", certFile);
            parameter["key-file"] = cockpit.variant("s", keyFile);
        }

        if (signingParameters) {
            let subjectNameParam;
            if (subjectName && !subjectName.includes("="))
                subjectNameParam = "CN=" + subjectName;
            let dnsNamesParam = dnsName.split(',');
            dnsNamesParam = dnsNamesParam.filter(Boolean); // Removes empty string entries

            if (subjectName)
                parameter["template-subject"] = cockpit.variant("s", subjectNameParam);
            if (principalName)
                parameter["template-principal"] = cockpit.variant("as", [principalName]);
            if (dnsName)
                parameter["template-hostname"] = cockpit.variant("as", dnsNamesParam);
        }

        addRequest(parameter)
                .then(onClose)
                .catch(error => {
                    setErrorName(error.name);
                    setErrorMessage(error.message);
                });
    };

    const body = (
        <Form isHorizontal>
            <CAsRow ca={ca} setCa={setCa} cas={Object.values(cas)} />

            <StorageRow storage={storage} setStorage={setStorage} />
            {storage === "nssdb" &&
                <NicknameRow nickname={nickname} setNickname={setNickname} />}

            {storage === "file" && <>
                <CertFileRow setCertFile={setCertFile} mode={mode} />
                <KeyFileRow setKeyFile={setKeyFile} mode={mode} />
            </>}

            <SetSigningParametersRow signingParameters={signingParameters} setSigningParameters={setSigningParameters} />
            {signingParameters && <>
                <SubjectNameRow subjectName={subjectName} setSubjectName={setSubjectName} />
                <DNSNameRow dnsName={dnsName} setDnsName={setDnsName} />
                <PrincipalNameRow principalName={principalName} setPricipalName={setPricipalName} />
            </>}
        </Form>
    );

    return (
        <Modal id="request-certificate-dialog" onClose={onClose}
               position="top" variant="medium"
               isOpen
               title={mode === "request" ? _("Request certificate") : _("Import certificate")}
               footer={<>
                   {errorName && <ModalError dialogError={errorName} dialogErrorDetail={errorMessage} />}
                   <Button variant="primary"
                       onClick={onRequest}>
                       {mode === "request" ? _("Request") : _("Import")}
                   </Button>
                   <Button variant="link" className="btn-cancel" onClick={onClose}>
                       {_("Cancel")}
                   </Button>
               </>}>
            {body}
        </Modal>
    );
}
Example #21
Source File: requestCertificate.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 4 votes vote down vote up
ResubmitCertificateModal = ({ onClose, cas, addAlert, cert, certPath, mode }) => {
    const [ca, setCa] = useState(getCAName(cas, cert));
    const [subjectName, setSubjectName] = useState(cert.subject && cert.subject.v);
    const [dnsName, _setDnsName] = useState(cert.hostname && cert.hostname.v.join(','));
    const [principalName, setPricipalName] = useState(cert.principal && cert.principal.v.join(','));
    const [errorName, setErrorName] = useState("");
    const [errorMessage, setErrorMessage] = useState("");

    const setDnsName = (value) => {
        let newValue = value.replace(/\s/g, ',');
        while (newValue.includes(",,"))
            newValue = value.replace(",,", ',');

        _setDnsName(newValue);
    };

    const onResubmit = () => {
        const casKeys = Object.keys(cas);
        let caPath;
        casKeys.forEach(key => {
            if (cas[key].nickname.v === ca)
                caPath = key;
        });

        let subjectNameParam = subjectName;
        if (subjectNameParam && !subjectNameParam.includes("="))
            subjectNameParam = "CN=" + subjectNameParam;
        let dnsNameParam;
        if (dnsName) {
            dnsNameParam = dnsName.split(',');
            dnsNameParam = dnsNameParam.filter(Boolean); // Removes empty string entries
        }

        const parameter = { ca: cockpit.variant("s", caPath) };
        parameter["template-subject"] = cockpit.variant("s", subjectNameParam || "");
        parameter["template-principal"] = cockpit.variant("as", [principalName || ""]);
        parameter["template-hostname"] = cockpit.variant("as", dnsNameParam || [""]);

        modifyRequest(certPath, parameter)
                .then(() => resubmitRequest(certPath))
                .then(onClose)
                .catch(error => {
                    setErrorName(error.name);
                    setErrorMessage(error.message);
                });
    };

    const body = (
        <Form isHorizontal>
            {cert["cert-storage"].v === "NSSDB" && <>
                <FormGroup label={_("Database path")} hasNoPaddingTop>
                    <span id="database-path-row">{ cert["cert-database"].v }</span>
                </FormGroup>
                <FormGroup label={_("Nickname")} hasNoPaddingTop>
                    <span id="nickname-row">{ cert["cert-nickname"].v }</span>
                </FormGroup>
            </>}

            {cert["cert-storage"].v === "FILE" && <>
                <FormGroup label={_("Certificate file")} hasNoPaddingTop>
                    <span id="cert-file-row">{ cert["cert-file"].v }</span>
                </FormGroup>
                <FormGroup label={_("Key file")} hasNoPaddingTop>
                    <span id="key-file-row">{ cert["key-file"].v }</span>
                </FormGroup>
            </>}

            <CAsRow ca={ca} setCa={setCa} cas={Object.values(cas)} />

            <SubjectNameRow subjectName={subjectName} setSubjectName={setSubjectName} />
            <DNSNameRow dnsName={dnsName} setDnsName={setDnsName} />
            <PrincipalNameRow principalName={principalName} setPricipalName={setPricipalName} />
        </Form>
    );

    return (
        <Modal id="resubmit-certificate-dialog"
               position="top" variant="medium"
               onClose={onClose}
               isOpen
               title={_("Resubmit Certificate")}
               footer={<>
                   {errorName && <ModalError dialogError={errorName} dialogErrorDetail={errorMessage} />}
                   <Button variant="primary" onClick={onResubmit}>
                       {_("Resubmit")}
                   </Button>
                   <Button variant="link" className="btn-cancel" onClick={onClose}>
                       {_("Cancel")}
                   </Button>
               </>}>
            {body}
        </Modal>
    );
}
Example #22
Source File: certificateActions.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 4 votes vote down vote up
RemoveModal = ({ onClose, certs, cert, certPath, addAlert, appOnValueChanged, idPrefix }) => {
    const [deleteFiles, setDeleteFiles] = useState(false);

    const onRemoveResponse = () => {
        delete certs[certPath];

        appOnValueChanged("certs, certs");
        onClose();
    };

    const onRemove = () => {
        if (deleteFiles) {
            cockpit.file(cert["key-file"].v, { superuser: "try" }).replace(null) // delete key file
                    .then(() => cockpit.file(cert["cert-file"].v, { superuser: "try" }).replace(null)) // delete cert file
                    .then(() => removeRequest(certPath))
                    // There is no dbus signal for cert removal, so we have to update UI manually
                    .then(() => onRemoveResponse())
                    .catch(error => {
                        addAlert(_("Error: ") + (error.name || error.problem), error.message);
                        onClose();
                    });
        } else {
            removeRequest(certPath)
                    // There is no dbus signal for cert removal, so we have to update UI manually
                    .then(() => onRemoveResponse())
                    .catch(error => {
                        addAlert(_("Error: ") + error.name, error.message);
                        onClose();
                    });
        }
    };

    const title = _("Remove certificate: ") + (cert["cert-storage"].v === "FILE" ? cert.nickname.v : cert["cert-nickname"].v);

    const fileCertBody = (
        <Form isHorizontal>
            <FormGroup label={_("Certificate file")} hasNoPaddingTop>
                <samp id={idPrefix + "cert-file"}>
                    {cert["cert-file"].v}
                </samp>
            </FormGroup>

            <FormGroup label={_("Key file")}>
                <samp id={idPrefix + "key-file"} hasNoPaddingTop>
                    {cert["key-file"].v}
                </samp>
            </FormGroup>
        </Form>
    );

    const nssdbCertBody = (
        <Form isHorizontal>
            <FormGroup label={_("NSSDB path")} hasNoPaddingTop>
                <samp id={idPrefix + "cert-database"}>
                    {cert["cert-database"].v}
                </samp>
            </FormGroup>

            <FormGroup label={_("Nickname")} hasNoPaddingTop>
                <samp id={idPrefix + "cert-nickname"}>
                    {cert["cert-nickname"].v}
                </samp>
            </FormGroup>
        </Form>
    );

    const body = (<>
        { cert["cert-storage"].v === "FILE" ? fileCertBody : nssdbCertBody }
        { cert["key-file"] && cert["cert-file"] && cert["key-file"].v && cert["cert-file"].v && (
            <Checkbox id={idPrefix + "-delete-files"}
                      className="checkbox-delete-files"
                      isChecked={deleteFiles}
                      label={_("Also delete certificate and key files")}
                      onChange={e => setDeleteFiles(!deleteFiles)} />
        )}
    </>);

    return (
        <Modal id={idPrefix + "-remove-dialog"}
               position="top" variant="medium"
               onClose={onClose}
               isOpen
               title={title}
               footer={<>
                   <Button variant="danger" onClick={onRemove}>
                       { deleteFiles ? _("Remove and delete") : _("Remove") }
                   </Button>
                   <Button variant="link" className="btn-cancel" onClick={onClose}>
                       {_("Cancel")}
                   </Button>
               </>}>
            {body}
        </Modal>
    );
}
Example #23
Source File: ViewHostAcks.js    From ocp-advisor-frontend with Apache License 2.0 4 votes vote down vote up
ViewHostAcks = ({
  handleModalToggle,
  isModalOpen,
  clusters,
  recId,
  afterFn,
}) => {
  const intl = useIntl();
  const dispatch = useDispatch();
  const addNotification = (data) => dispatch(notification(data));
  const { data, isFetching, isLoading, refetch } = clusters;
  const hostAcks = data?.disabled || [];
  const [rows, setRows] = useState([]);
  const [unclean, setUnclean] = useState(false);

  const columns = [
    {
      title: intl.formatMessage(messages.clusterName),

      transforms: [cellWidth(50)],
    },
    {
      title: intl.formatMessage(messages.justificationNote),

      transforms: [cellWidth(25)],
    },
    {
      title: intl.formatMessage(messages.dateDisabled),

      transforms: [cellWidth(15)],
    },
    '',
  ];

  const deleteAck = async (host) => {
    try {
      await enableRuleForCluster({ uuid: host.cluster_id, recId });
      refetch();
      setUnclean(true);
    } catch (error) {
      handleModalToggle(false);
      addNotification({
        variant: 'danger',
        dismissable: true,
        title: intl.formatMessage(messages.error),
        description: `${error}`,
      });
    }
  };

  useEffect(() => {
    const rows = hostAcks?.map((item) => ({
      cells: [
        item.cluster_name || item.cluster_id,
        item.justification || intl.formatMessage(messages.none),
        {
          title: (
            <DateFormat date={new Date(item.disabled_at)} type="onlyDate" />
          ),
        },
        {
          title: (
            <Button
              key={item.cluster_id}
              ouiaId="enable"
              isInline
              variant="link"
              onClick={() => deleteAck(item)}
            >
              <OutlinedBellIcon size="sm" />
              {` ${intl.formatMessage(messages.enable)}`}
            </Button>
          ),
        },
      ],
    }));

    if (!isLoading && hostAcks.length === 0) {
      afterFn();
      handleModalToggle(false);
    }
    setRows(rows);
  }, [hostAcks]);

  return (
    <Modal
      width={'75%'}
      title={intl.formatMessage(messages.hostAckModalTitle)}
      isOpen={isModalOpen}
      onClose={() => {
        unclean && afterFn();
        handleModalToggle(false);
      }}
    >
      {!isFetching ? (
        <Table aria-label="host-ack-table" rows={rows} cells={columns}>
          <TableHeader />
          <TableBody />
        </Table>
      ) : (
        <Table
          aria-label="host-ack-table"
          rows={[
            {
              cells: [{ props: { colSpan: 3 }, title: <List /> }],
            },
          ]}
          cells={columns}
        >
          <TableHeader />
          <TableBody />
        </Table>
      )}
    </Modal>
  );
}
Example #24
Source File: DisableRule.js    From ocp-advisor-frontend with Apache License 2.0 4 votes vote down vote up
DisableRule = ({
  isModalOpen,
  handleModalToggle,
  rule,
  afterFn,
  host,
  hosts,
}) => {
  const intl = useIntl();
  const [justification, setJustificaton] = useState('');
  const [singleHost, setSingleHost] = useState(!!host);
  const [multipleHosts, setMultipleHosts] = useState(hosts.length > 0);
  const [setAck] = useSetAckMutation();
  const dispatch = useDispatch();
  const notify = (data) => dispatch(addNotification(data));

  const bulkHostActions = async () => {
    // disable for a group of hosts (clusters)
    try {
      const requests = hosts.map((h) =>
        disableRuleForCluster({
          uuid: h.id,
          recId: rule.rule_id,
          justification,
        })
      );
      await Promise.all(requests);
      notify({
        variant: 'success',
        dismissable: true,
        timeout: true,
        title: intl.formatMessage(messages.recSuccessfullyDisabledForCluster),
      });
      afterFn && afterFn();
    } catch (error) {
      notify({
        variant: 'danger',
        dismissable: true,
        title: intl.formatMessage(messages.error),
        description: `${error}`,
      });
    }
  };

  const disableRule = async () => {
    try {
      if (singleHost) {
        // disable the rec for this single cluster
        await disableRuleForCluster({
          uuid: host,
          recId: rule.rule_id,
          justification,
        });
        notify({
          variant: 'success',
          timeout: true,
          dismissable: true,
          title: intl.formatMessage(messages.recSuccessfullyDisabledForCluster),
        });
      } else if (multipleHosts) {
        bulkHostActions();
      } else {
        // disable the whole rec
        await setAck({
          rule_id: rule.rule_id,
          justification,
        }).unwrap();
        notify({
          variant: 'success',
          timeout: true,
          dismissable: true,
          title: intl.formatMessage(messages.recSuccessfullyDisabled),
        });
      }
      setJustificaton('');
      afterFn && afterFn();
    } catch (error) {
      notify({
        variant: 'danger',
        dismissable: true,
        title: intl.formatMessage(messages.error),
        description: `${error}`,
      });
    }

    handleModalToggle(false);
  };

  return (
    <Modal
      variant="small"
      title={intl.formatMessage(messages.disableRule)}
      isOpen={isModalOpen}
      onClose={() => {
        handleModalToggle();
        setJustificaton('');
      }}
      actions={[
        <Button
          key="confirm"
          variant="primary"
          onClick={() => disableRule()}
          ouiaId="confirm"
        >
          {intl.formatMessage(messages.save)}
        </Button>,
        <Button
          key="cancel"
          variant="link"
          onClick={() => {
            handleModalToggle(false);
            setJustificaton('');
          }}
          ouiaId="cancel"
        >
          {intl.formatMessage(messages.cancel)}
        </Button>,
      ]}
      ouiaId="recommendation-disable"
    >
      {intl.formatMessage(messages.disableRuleBody)}
      <Form>
        <FormGroup fieldId="blank-form" />
        {(host || hosts.length > 0) && (
          <FormGroup fieldId="disable-rule-one-system">
            <Checkbox
              isChecked={singleHost || multipleHosts}
              onChange={() => {
                host
                  ? setSingleHost(!singleHost)
                  : setMultipleHosts(!multipleHosts);
              }}
              label={
                host
                  ? intl.formatMessage(messages.disableRuleSingleCluster)
                  : intl.formatMessage(messages.disableRuleForClusters)
              }
              id="disable-rule-one-system"
              name="disable-rule-one-system"
              ouiaId="disable-recommendation-one-cluster"
            />
          </FormGroup>
        )}
        <FormGroup
          label={intl.formatMessage(messages.justificationNote)}
          fieldId="disable-rule-justification"
        >
          <TextInput
            type="text"
            id="disable-rule-justification"
            aria-describedby="disable-rule-justification"
            value={justification}
            onChange={(text) => setJustificaton(text)}
            onKeyDown={(e) =>
              e.key === 'Enter' && (e.preventDefault(), disableRule())
            }
          />
        </FormGroup>
      </Form>
    </Modal>
  );
}
Example #25
Source File: UpdateImageModal.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
UpdateImageModal = ({ updateCveModal, setUpdateCveModal, setReload }) => {
  const dispatch = useDispatch();

  const { getRegistry } = useContext(RegistryContext);
  const { data } = useSelector(
    ({ imageDetailReducer }) => ({
      data: imageDetailReducer?.data || null,
    }),
    shallowEqual
  );

  useEffect(() => {
    const registered = getRegistry().register({
      imageDetailReducer,
    });
    updateCveModal?.imageId &&
      loadImageDetail(dispatch, updateCveModal?.imageId);
    return () => registered();
  }, [dispatch]);

  const handleUpdateModal = () => {
    const payload = {
      Id: data?.image?.ID,
      description: data?.image?.Description,
      name: data?.image?.Name,
      version: data?.image?.Version + 1,
      architecture: 'x86_64',
      credentials: data?.image?.Installer.SshKey,
      username: data?.image?.Installer.Username,
      imageType: data?.image?.OutputTypes,
      'selected-packages': data?.image?.Packages?.map((pack) => ({
        name: pack.Name,
      })),
      release: data?.image?.Distribution,
    };
    handleClose();
    setReload(true);
    createNewImage(dispatch, payload, (resp) => {
      dispatch({
        ...addNotification({
          variant: 'info',
          title: 'Update image',
          description: `${resp.value.Name} image was added to the queue.`,
        }),
        meta: {
          polling: {
            id: `FETCH_IMAGE_${resp.value.ID}_BUILD_STATUS`,
            fetcher: () => getEdgeImageStatus(resp.value.ID),
            condition: (resp) => {
              switch (resp.Status) {
                case 'BUILDING':
                  return [true, ''];
                case 'ERROR':
                  return [false, 'failure'];
                default:
                  return [false, 'success'];
              }
            },
            onEvent: {
              failure: [
                (dispatch) =>
                  dispatch(
                    addNotification({
                      variant: 'danger',
                      title: 'Image build failed',
                      description: `${resp.value.Name} image build is completed unsuccessfully`,
                    })
                  ),
              ],
              success: [
                (dispatch) =>
                  dispatch(
                    addNotification({
                      variant: 'success',
                      title: 'Image is ready',
                      description: `${resp.value.Name} image build is completed`,
                    })
                  ),
                (dispatch) => loadEdgeImageSets(dispatch),
              ],
            },
          },
        },
      });
      loadEdgeImageSets(dispatch);
      dispatch(
        addImageToPoll({ name: data?.image?.Name, id: data?.image?.ID })
      );
    });
  };

  const handleClose = () => {
    setUpdateCveModal((prevState) => ({ ...prevState, isOpen: false }));
  };

  return data ? (
    <Modal
      variant="medium"
      title={`Update image: ${data?.image?.Name}`}
      description="Review the information and click Create image to start the build process"
      isOpen={updateCveModal.isOpen}
      onClose={handleClose}
      //onSubmit={handleUpdateModal}
      actions={[
        <Button key="confirm" variant="primary" onClick={handleUpdateModal}>
          Create Image
        </Button>,
        <Button key="cancel" variant="link" onClick={handleClose}>
          Cancel
        </Button>,
      ]}
    >
      <TextContent>
        <TextListItem component={TextVariants.h3}>
          <Text component={'b'}>Details</Text>
        </TextListItem>
        <TextList component={TextListVariants.dl}>
          <TextListItem component={TextListItemVariants.dt}>Name</TextListItem>
          <TextListItem component={TextListItemVariants.dd}>
            {data?.image?.Name}
          </TextListItem>
          <TextListItem component={TextListItemVariants.dt}>
            Version
          </TextListItem>
          <TextListItem component={TextListItemVariants.dd}>
            {data?.image?.Version + 1}
          </TextListItem>
          <TextListItem component={TextListItemVariants.dt}>
            Description
          </TextListItem>
          <TextListItem component={TextListItemVariants.dd}>
            {data?.image?.Description}
          </TextListItem>
        </TextList>
        <TextListItem component={TextVariants.h3}>
          <Text component={'b'}>Output</Text>
        </TextListItem>
        <TextList component={TextListVariants.dl}>
          <TextListItem component={TextListItemVariants.dt}>
            Release
          </TextListItem>
          <TextListItem component={TextListItemVariants.dd}>
            {releaseMapper[data?.image?.Distribution]}
          </TextListItem>
          <TextListItem component={TextListItemVariants.dt}>
            Output type
          </TextListItem>
          <TextListItem component={TextListItemVariants.dd}>
            {imageTypeMapper[data?.image?.ImageType]}
          </TextListItem>
        </TextList>
        <TextListItem component={TextVariants.h3}>
          <Text component={'b'}>Packages</Text>
        </TextListItem>
        <TextList component={TextListVariants.dl}>
          <TextListItem component={TextListItemVariants.dt}>
            Updated
          </TextListItem>
          <TextListItem
            className="pf-u-pl-lg"
            component={TextListItemVariants.dd}
          >
            {updateCveModal?.cveCount}
          </TextListItem>
        </TextList>
      </TextContent>
    </Modal>
  ) : (
    <Backdrop>
      <Bullseye>
        <Spinner isSVG diameter="100px" />
      </Bullseye>
    </Backdrop>
  );
}
Example #26
Source File: EditRequestModal.js    From access-requests-frontend with Apache License 2.0 4 votes vote down vote up
EditRequestModal = ({ requestId, variant, onClose }) => {
  const isEdit = variant === 'edit';
  const [isLoading, setIsLoading] = React.useState(true);
  const [error, setError] = React.useState();
  const [user, setUser] = React.useState();
  const [targetAccount, setTargetAccount] = React.useState();
  const [targetOrg, setTargetOrg] = React.useState();
  const [start, setStart] = React.useState();
  const [end, setEnd] = React.useState();
  const [roles, setRoles] = React.useState([]);
  const [warnClose, setWarnClose] = React.useState(false);
  const [step, setStep] = React.useState(1);
  const dispatch = useDispatch();
  const isDirty = Boolean(targetAccount || start || end || roles.length > 0);

  // We need to be logged in (and see the username) which is an async request.
  // If we're editing we also need to fetch the roles
  React.useEffect(() => {
    const userPromise = window.insights.chrome.auth.getUser();
    const detailsPromise = isEdit
      ? apiInstance.get(
          `${API_BASE}/cross-account-requests/${requestId}/?query_by=user_id`,
          {
            headers: { Accept: 'application/json' },
          }
        )
      : new Promise((res) => res(true));

    Promise.all([userPromise, detailsPromise])
      .then(([user, details]) => {
        if (user && user.identity && user.identity.user) {
          setUser(user.identity.user);
        } else {
          throw Error("Couldn't get current user. Make sure you're logged in");
        }
        if (isEdit) {
          if (details.errors) {
            throw Error(details.errors.map((e) => e.detail).join('\n'));
          }
          if (details && details.target_account) {
            setTargetAccount(details.target_account);
            setStart(details.start_date);
            setEnd(details.end_date);
            setRoles(details.roles.map((role) => role.display_name));
            setTargetOrg(details.target_org);
          } else {
            throw Error(`Could not fetch details for request ${requestId}`);
          }
        }
        setIsLoading(false);
      })
      .catch((err) => {
        dispatch(
          addNotification({
            variant: 'danger',
            title: 'Could not load access request',
            description: err.message,
          })
        );
      });
  }, []);

  const onSave = () => {
    setIsLoading(true);
    // https://cloud.redhat.com/docs/api-docs/rbac#operations-CrossAccountRequest-createCrossAccountRequests
    const body = {
      target_account: targetAccount,
      start_date: start,
      end_date: end,
      target_org: targetOrg,
      roles,
    };
    apiInstance[isEdit ? 'put' : 'post'](
      `${API_BASE}/cross-account-requests/${isEdit ? `/${requestId}/` : ''}`,
      body,
      {
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
        },
      }
    )
      .then((res) => {
        if (res.errors && res.errors.length > 0) {
          throw Error(res.errors[0].detail);
        }
        dispatch(
          addNotification({
            variant: 'success',
            title: `${isEdit ? 'Edited' : 'Created'} access request`,
            description: res.request_id,
          })
        );
        onClose(true);
      })
      .catch((err) => {
        const isInvalidAccount = /Account .* does not exist/.test(err.message);
        setError({
          title: isInvalidAccount
            ? invalidAccountTitle
            : `Could not ${variant} access request`,
          description: isInvalidAccount
            ? 'Please return to Step 1: Request details and input a new account number for your request.'
            : err.message,
        });
        setIsLoading(false);
      });
  };

  const step1Complete = [targetAccount, start, end].every(Boolean);
  const step2Complete = roles.length > 0;
  const steps = [
    {
      id: 1,
      name: 'Request details',
      component: (
        <RequestDetailsForm
          user={user}
          targetAccount={targetAccount}
          setTargetAccount={setTargetAccount}
          targetOrg={targetOrg}
          setTargetOrg={setTargetOrg}
          start={start}
          setStart={setStart}
          end={end}
          setEnd={setEnd}
          disableAccount={isEdit}
          disableOrgId={isEdit}
          isLoading={isLoading}
          error={error}
        />
      ),
      enableNext: step1Complete,
    },
    {
      id: 2,
      name: 'Select roles',
      component: <MUARolesTable roles={roles} setRoles={setRoles} />,
      enableNext: step2Complete,
      canJumpTo: step1Complete,
    },
    {
      id: 3,
      name: 'Review details',
      component: (
        <ReviewStep
          targetAccount={targetAccount}
          start={start}
          end={end}
          roles={roles}
          isLoading={isLoading}
          error={error}
          setError={setError}
          onClose={() => onClose(false)}
        />
      ),
      canJumpTo: step1Complete && step2Complete,
      enableNext: !isLoading,
      nextButtonText: 'Finish',
    },
  ];

  const titleId = `${variant}-request`;
  const descriptionId = `${variant} request`;
  return (
    <React.Fragment>
      <Modal
        variant="large"
        style={{ height: '900px' }}
        showClose={false}
        hasNoBodyWrapper
        isOpen={!warnClose}
        aria-describedby={descriptionId}
        aria-labelledby={titleId}
      >
        <Wizard
          titleId={titleId}
          descriptionId={descriptionId}
          title={capitalize(variant) + ' request'}
          steps={steps}
          onClose={() => (isDirty ? setWarnClose(true) : onClose(false))}
          onSave={onSave}
          startAtStep={step}
          onNext={({ id }) => {
            setError();
            setStep(id);
          }}
          onBack={({ id }) => {
            setError();
            setStep(id);
          }}
          onGoToStep={({ id }) => {
            setError();
            setStep(id);
          }}
        />
      </Modal>
      {warnClose && (
        <Modal
          title="Exit request creation?"
          variant="small"
          titleIconVariant="warning"
          isOpen
          onClose={() => setWarnClose(false)}
          actions={[
            <Button
              key="confirm"
              variant="primary"
              onClick={() => onClose(false)}
            >
              Exit
            </Button>,
            <Button
              key="cancel"
              variant="link"
              onClick={() => setWarnClose(false)}
            >
              Stay
            </Button>,
          ]}
        >
          All inputs will be discarded.
        </Modal>
      )}
    </React.Fragment>
  );
}