@patternfly/react-core#Alert JavaScript Examples

The following examples show how to use @patternfly/react-core#Alert. 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: customPackage.js    From edge-frontend with Apache License 2.0 6 votes vote down vote up
showAlert = (type) => {
  return (
    <Alert
      className="pf-u-mt-lg"
      variant={type}
      isInline
      title={
        type === 'danger'
          ? 'No custom repositories linked. Clear custom packages or link a repository.'
          : 'Linked custom repositories were removed when these packages were added. Ensure the package list is still correct.'
      }
      style={{ '--pf-c-content--h4--MarginTop': 0 }}
    />
  );
}
Example #2
Source File: Notifications.js    From sed-frontend with Apache License 2.0 6 votes vote down vote up
Notifications = () => {
  const { notifications, removeNotification } = useNotifications();

  return (
    <AlertGroup isToast>
      {notifications.map((notification, i) => (
        <Alert
          isLiveRegion
          timeout={notification.timeout}
          title={notification.message}
          variant={notification.variant}
          key={notification.key}
          actionClose={
            <AlertActionCloseButton
              data-testid={`notification-close-btn-${i}`}
              title={notification.message}
              variantLabel={`${notification.variant} alert`}
              onClose={() => {
                removeNotification(notification.key);
                if (notification?.downloadHref) {
                  window.URL.revokeObjectURL(notification.downloadHref);
                }
              }}
            />
          }
        />
      ))}
    </AlertGroup>
  );
}
Example #3
Source File: ibutsu-page.js    From ibutsu-server with MIT License 6 votes vote down vote up
render() {
    document.title = this.props.title || 'Ibutsu';
    return (
      <React.Fragment>
        <AlertGroup isToast>
          {this.state.notifications.map((notification) => (
            <Alert key={notification.key} variant={notification.type} title={notification.title} actionLinks={notification.action} isLiveRegion>
              {notification.message}
            </Alert>
          ))}
        </AlertGroup>
        <Page header={<IbutsuHeader eventEmitter={this.props.eventEmitter} version={this.state.version} />} sidebar={<PageSidebar nav={this.props.navigation} theme="dark" />} isManagedSidebar={true} style={{position: "relative"}}>
          {this.props.children}
        </Page>
      </React.Fragment>
    );
  }
Example #4
Source File: project-edit.js    From ibutsu-server with MIT License 5 votes vote down vote up
render() {
    const { project, users, owner } = this.state;
    return (
      <React.Fragment>
        <PageSection variant={PageSectionVariants.light}>
          <Title headingLevel="h1" size='2xl' className="pf-c-title">
            Projects / {project && project.title}
          </Title>
        </PageSection>
        <PageSection>
          {!project && <Alert variant="info" title="Loading..." />}
          {project &&
          <Card>
            <CardBody>
              <Form>
                <FormGroup label="Title" isRequired fieldId="projectTitle" helperText="The project's friendly name">
                  <TextInput
                    isRequired
                    type="text"
                    id="projectTitle"
                    name="projectTitle"
                    aria-describedby="The project's friendly name"
                    value={project.title}
                    onChange={this.onProjectTitleChanged}
                  />
                </FormGroup>
                <FormGroup label="Name" isRequired fieldId="projectName" helperText="The project's machine name">
                  <TextInput
                    isRequired
                    type="text"
                    id="projectName"
                    name="projectName"
                    aria-describedby="The project's machine name"
                    value={project.name}
                    onChange={this.onProjectNameChanged}
                  />
                </FormGroup>
                <FormGroup fieldId="owner" label="Owner" helperText="The user who owns the project">
                   <Select
                     variant={SelectVariant.typeahead}
                     typeAheadAriaLabel="Select user"
                     onToggle={this.onOwnerToggle}
                     onSelect={this.onOwnerSelect}
                     onClear={this.onOwnerClear}
                     onTypeaheadInputChanged={this.onOwnerChanged}
                     selections={owner}
                     isOpen={this.state.isOwnerOpen}
                     aria-labelledby="owner"
                     placeholderText="Select user"
                   >
                     {users.map(user => (
                       <SelectOption key={user.id} value={userToOption(user)} description={user.email} />
                     ))}
                   </Select>
                </FormGroup>
                <ActionGroup>
                  <Button
                    variant="primary"
                    ouiaId="admin-project-edit-save"
                    onClick={this.onSubmitClick}
                  >
                    Submit
                  </Button>
                  <Button
                    variant="secondary"
                    ouiaId="admin-project-edit-cancel"
                    component={(props: any) => <Link {...props} to="/admin/projects" />}
                  >
                    Cancel
                  </Button>
                </ActionGroup>
              </Form>
            </CardBody>
          </Card>
          }
        </PageSection>
      </React.Fragment>
    );
  }
Example #5
Source File: InterfaceDetails.js    From cockpit-wicked with GNU General Public License v2.0 5 votes vote down vote up
renderError = (error) => {
    if (!error) return;

    return <Alert variant="warning" isInline title={error} />;
}
Example #6
Source File: forgot-password.js    From ibutsu-server with MIT License 5 votes vote down vote up
render() {
    const signUpForAccountMessage = (
      <LoginMainFooterBandItem>
        Need an account? <NavLink to="/sign-up">Sign up.</NavLink>
      </LoginMainFooterBandItem>
    );
    const forgotCredentials = (
      <LoginMainFooterBandItem>
        Already registered? <NavLink to="/login">Log in.</NavLink>
      </LoginMainFooterBandItem>
    );

    const backgroundImages = {
      lg: '/images/pfbg_1200.jpg',
      sm: '/images/pfbg_768.jpg',
      sm2x: '/images/[email protected]',
      xs: '/images/pfbg_576.jpg',
      xs2x: '/images/[email protected]'
    };

    return (
      <LoginPage
        footerListVariants="inline"
        brandImgSrc="/images/ibutsu-wordart-164.png"
        brandImgAlt="Ibutsu"
        backgroundImgSrc={backgroundImages}
        backgroundImgAlt="Background image"
        textContent="Ibutsu is an open source test result aggregation. Collect and display your test results, view artifacts, and monitor tests."
        loginTitle="Recover your account"
        loginSubtitle="Please type in your e-mail address and a reset link will be sent to it."
        signUpForAccountMessage={signUpForAccountMessage}
        forgotCredentials={forgotCredentials}
      >
        <Form>
          {this.state.showAlert &&
          <FormAlert>
            <Alert variant={this.state.alertType} title={this.state.alertText} aria-live="polite" isInline/>
          </FormAlert>
          }
          <FormGroup
            label="Email address"
            isRequired
            fieldId="email"
            validated={this.state.isValidEmail ? 'default' : 'error'}
            helperText="The e-mail address you signed up with"
          >
            <TextInput
              isRequired
              type="email"
              id="email"
              name="email"
              validated={this.state.isValidEmail ? 'default' : 'error'}
              aria-describedby="email-helper"
              value={this.state.emailValue}
              onChange={this.onEmailChange}
            />
          </FormGroup>
          <ActionGroup>
            <Button variant="primary" isBlock onClick={this.onRecoverAccountClick}>Recover account</Button>
          </ActionGroup>
        </Form>
      </LoginPage>
    );
  }
Example #7
Source File: app.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 5 votes vote down vote up
render() {
        const { certmongerService, startErrorMessage, cas, certs, toExpireCerts, expiredCerts } = this.state;

        if (expiredCerts > 0) {
            page_status.set_own({
                type: "error",
                title: cockpit.format(cockpit.ngettext("$0 certificate has expired",
                                                       "$0 certificates have expired",
                                                       expiredCerts), expiredCerts),
                details: []
            });
        } else if (toExpireCerts > 0) {
            page_status.set_own({
                type: "warning",
                title: cockpit.format(cockpit.ngettext("$0 certificate expires soon",
                                                       "$0 certificates expire soon",
                                                       toExpireCerts), toExpireCerts),
                details: []
            });
        }

        const certificatesBody = (
            <CertificateList cas={cas} certs={certs} addAlert={this.addAlert} appOnValueChanged={this.onValueChanged} />
        );

        const emptyStateBody = (
            <EmptyState service={ certmongerService }
                serviceName={ CERTMONGER_SERVICE_NAME }
                errorMessage={ startErrorMessage }
                updateService={ () => this.updateCertmongerService() } />
        );

        const body = () => {
            if (!certmongerService || !certmongerService.exists || !certmongerService.state || certmongerService.state !== "running")
                return emptyStateBody;

            return certificatesBody;
        };

        return (
            <Page>
                <PageSection variant={PageSectionVariants.light}>
                    { body() }
                    <AlertGroup isToast>
                        {this.state.alerts.map((danger, index) => (
                            <Alert isLiveRegion
                                variant={AlertVariant.danger}
                                title={danger.title}
                                actionClose={
                                    <AlertActionCloseButton variantLabel="danger alert"
                                      onClose={() => this.removeAlert(index)} />
                                }
                                key={index}>
                                {_("Error message: ") + danger.message}
                            </Alert>
                        ))}
                    </AlertGroup>
                </PageSection>
            </Page>
        );
    }
Example #8
Source File: Services.js    From sed-frontend with Apache License 2.0 4 votes vote down vote up
Services = ({
  defaults,
  setConfirmChangesOpen,
  onChange,
  isEditing,
  setIsEditing,
}) => {
  const initState = {
    enableCloudConnector: {
      value: defaults.enableCloudConnector,
      isDisabled: false,
    },
    useOpenSCAP: { value: defaults.useOpenSCAP, isDisabled: false },
  };
  const [formState, setFormState] = useState(initState);
  const [madeChanges, setMadeChanges] = useState(false);

  const { hasAccess, isLoading } = usePermissions(
    '',
    [
      'config-manager:activation_keys:*',
      'config-manager:state:read',
      'config-manager:state:write',
      'config-manager:state-changes:read',
      'inventory:*:read',
      'playbook-dispatcher:run:read',
    ],
    false,
    true
  );

  const cancelEditing = () => {
    setFormState(initState);
    setIsEditing(false);
  };

  useEffect(() => {
    setMadeChanges(
      formState.useOpenSCAP.value !== defaults.useOpenSCAP ||
        formState.enableCloudConnector.value != defaults.enableCloudConnector
    );
    onChange({
      useOpenSCAP: formState.useOpenSCAP.value,
      enableCloudConnector: formState.enableCloudConnector.value,
    });
  }, [formState]);

  const getStatusIcon = (row) => {
    if (formState[row.id].value) {
      return (
        <Flex style={{ color: 'var(--pf-global--success-color--200)' }}>
          <FlexItem spacer={{ default: 'spacerXs' }}>
            <CheckCircleIcon />
          </FlexItem>
          <FlexItem className="status">
            <b>Enabled</b>
          </FlexItem>
        </Flex>
      );
    }
    return (
      <Flex style={{ color: 'var(--pf-global--default-color--300)' }}>
        <FlexItem spacer={{ default: 'spacerXs' }}>
          <BanIcon />
        </FlexItem>
        <FlexItem className="status">
          <b>Disabled</b>
        </FlexItem>
      </Flex>
    );
  };

  return (
    <Stack hasGutter className="pf-u-p-md">
      <StackItem>
        <Toolbar id="toolbar-items">
          <ToolbarContent>
            {!isEditing && (
              <ToolbarItem>
                {!hasAccess ? (
                  <Tooltip
                    content={
                      <div>
                        To perform this action, you must be granted the
                        &quot;System Administrator&quot; role by your
                        Organization Administrator in your Setting&apos;s User
                        Access area.
                      </div>
                    }
                  >
                    {changeSettingsButton(isLoading, hasAccess, setIsEditing)}
                  </Tooltip>
                ) : (
                  changeSettingsButton(isLoading, hasAccess, setIsEditing)
                )}
              </ToolbarItem>
            )}
            {isEditing && (
              <>
                <ToolbarItem>
                  <Button
                    ouiaId="primary-save-button"
                    onClick={() => setConfirmChangesOpen(true)}
                    isDisabled={!madeChanges}
                  >
                    Save changes
                  </Button>
                </ToolbarItem>
                <ToolbarItem>
                  <Button
                    ouiaId="secondary-cancel-button"
                    onClick={() => cancelEditing()}
                    variant="secondary"
                  >
                    Cancel
                  </Button>
                </ToolbarItem>
                <ToolbarItem>
                  <Alert
                    variant="info"
                    isInline
                    isPlain
                    title="Changes will affect all systems connected with Red Hat connector"
                  />
                </ToolbarItem>
              </>
            )}
          </ToolbarContent>
        </Toolbar>
      </StackItem>
      <StackItem>
        <TableComposable aria-label="Settings table">
          <Thead>
            <Tr>
              <Th>Permission</Th>
              <Th>Status</Th>
            </Tr>
          </Thead>
          <Tbody>
            {permissions.map((row) => (
              <Tr key={row.name}>
                <Td
                  dataLabel="Permission"
                  width={80}
                  style={row.secondary && { paddingLeft: 70, fontSize: 14 }}
                >
                  <Stack>
                    <StackItem>
                      <Flex>
                        <FlexItem>
                          <b>{row.name}</b>
                        </FlexItem>
                        {row.additionalInfo && (
                          <FlexItem
                            style={{ color: 'var(--pf-global--Color--100)' }}
                          >
                            <i>{row.additionalInfo}</i>
                          </FlexItem>
                        )}
                      </Flex>
                    </StackItem>
                    <StackItem style={{ fontSize: 14 }}>
                      {row.description}
                    </StackItem>
                    {row.links && (
                      <StackItem className="stack-item">
                        <Flex>
                          {row.links.map((link) => (
                            <FlexItem key={link.name}>
                              <a
                                href={link.link}
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                {link.name}
                                <ExternalLinkAltIcon className="pf-u-ml-sm" />
                              </a>
                            </FlexItem>
                          ))}
                        </Flex>
                      </StackItem>
                    )}
                  </Stack>
                </Td>
                {!isEditing && <Td dataLabel="Status">{getStatusIcon(row)}</Td>}
                {isEditing && (
                  <Td dataLabel="Status">
                    <ToggleGroup aria-label="Default with single selectable">
                      <ToggleGroupItem
                        text="Enabled"
                        isSelected={formState[row.id].value}
                        onChange={() =>
                          setFormState({
                            ...formState,
                            [row.id]: { ...formState[row.id], value: true },
                          })
                        }
                        isDisabled={formState[row.id].isDisabled}
                      />
                      <ToggleGroupItem
                        text="Disabled"
                        isSelected={!formState[row.id].value}
                        onChange={() =>
                          setFormState({
                            ...formState,
                            [row.id]: { ...formState[row.id], value: false },
                          })
                        }
                        isDisabled={formState[row.id].isDisabled}
                      />
                    </ToggleGroup>
                  </Td>
                )}
              </Tr>
            ))}
          </Tbody>
        </TableComposable>
      </StackItem>
    </Stack>
  );
}
Example #9
Source File: login.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const socialMediaLoginContent = (
      <React.Fragment>
        {this.state.externalLogins.keycloak &&
        <LoginMainFooterLinksItem onClick={this.onKeycloakLogin} href="#" linkComponentProps={{ 'aria-label': `Login with ${this.getKeycloakName()}`, 'title': `Login with ${this.getKeycloakName()}` }}>
            {this.getKeycloakIcon()}
          </LoginMainFooterLinksItem>
        }
        {this.state.externalLogins.google &&
          <GoogleLogin
            clientId={this.state.externalLogins.google.client_id}
            scope={this.state.externalLogins.google.scope}
            redirectUri={this.state.externalLogins.google.redirect_uri}
            onSuccess={this.onGoogleLogin}
            onFailure={(response) => console.error(response)}
            render={renderProps => (
              <LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with Google', 'title': 'Login with Google' }}>
                <GoogleIcon size="lg" />
              </LoginMainFooterLinksItem>
            )}
          />
        }
        {this.state.externalLogins.github &&
          <OAuth2Login
            isCrossOrigin={true}
            authorizationUrl={this.state.externalLogins.github.authorization_url}
            responseType="code"
            clientId={this.state.externalLogins.github.client_id}
            redirectUri={this.state.externalLogins.github.redirect_uri}
            scope={this.state.externalLogins.github.scope}
            onSuccess={this.onOAuth2Success}
            onFailure={(response) => console.error(response)}
            render={renderProps => (
              <LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with GitHub', 'title': 'Login with GitHub' }}>
                <GithubIcon size="lg" />
              </LoginMainFooterLinksItem>
            )}
          />
        }
        {this.state.externalLogins.facebook &&
          <FacebookLogin
            appId={this.state.externalLogins.facebook.app_id}
            onSuccess={this.onFacebookLogin}
            onFail={(response) => console.error(response)}
            // useRedirect={true}
            dialogParams={{redirect_uri: this.state.externalLogins.facebook.redirect_uri, response_type: 'code'}}
            render={(renderProps) => (
              <LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with Facebook' }}>
                <FacebookIcon size="lg" />
              </LoginMainFooterLinksItem>
            )}
          />
        }
        {this.state.externalLogins.gitlab &&
            <OAuth2Login
              isCrossOrigin={true}
              authorizationUrl={this.state.externalLogins.gitlab.authorization_url}
              responseType="code"
              clientId={this.state.externalLogins.gitlab.client_id}
              redirectUri={this.state.externalLogins.gitlab.redirect_uri}
              scope={this.state.externalLogins.gitlab.scope}
              onSuccess={this.onOAuth2Success}
              onFailure={(response) => console.error(response)}
              render={renderProps => (
                <LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with GitLab', 'title': 'Login with GitLab' }}>
                  <GitlabIcon size="lg" />
                </LoginMainFooterLinksItem>
              )}
            />
        }
      </React.Fragment>
    );

    const signUpForAccountMessage = (
      <LoginMainFooterBandItem>
        Need an account? <NavLink to="/sign-up">Sign up.</NavLink>
      </LoginMainFooterBandItem>
    );
    const forgotCredentials = (
      <LoginMainFooterBandItem>
        <NavLink to="/forgot-password">Forgot username or password?</NavLink>
      </LoginMainFooterBandItem>
    );
    const loginWithUserDescription = 'Please use your e-mail address and password, or login via one of the icons below the Log In button.';
    const loginWithoutUserDescription = 'Log in via one of the icons below.';

    const backgroundImages = {
      lg: '/images/pfbg_1200.jpg',
      sm: '/images/pfbg_768.jpg',
      sm2x: '/images/[email protected]',
      xs: '/images/pfbg_576.jpg',
      xs2x: '/images/[email protected]'
    };

    return (
      <LoginPage
        footerListVariants="inline"
        brandImgSrc="/images/ibutsu-wordart-164.png"
        brandImgAlt="Ibutsu"
        backgroundImgSrc={backgroundImages}
        backgroundImgAlt="Background image"
        textContent="Ibutsu is an open source test result aggregation tool. Collect and display your test results, view artifacts, and monitor tests."
        loginTitle="Log in to your account"
        loginSubtitle={this.state.loginSupport.user ? loginWithUserDescription : loginWithoutUserDescription}
        socialMediaLoginContent={socialMediaLoginContent}
        signUpForAccountMessage={this.state.loginSupport.user ? signUpForAccountMessage : ''}
        forgotCredentials={this.state.loginSupport.user ? forgotCredentials : ''}
      >
        {this.state.loginSupport.user &&
        <Form>
          <FormAlert>
          {this.state.alert && this.state.alert.message &&
            <Alert
              variant={this.state.alert.status || 'info'}
              title={this.state.alert.message}
              aria-live="polite"
              isInline
            />
          }
          </FormAlert>
          <FormGroup
            label="Email address"
            isRequired
            fieldId="email"
            validated={this.state.isValidEmail ? 'default' : 'error'}
          >
            <TextInput
              isRequired
              type="email"
              id="email"
              name="email"
              validated={this.state.isValidEmail ? 'default' : 'error'}
              aria-describedby="email-helper"
              value={this.state.emailValue}
              onChange={this.onEmailChange}
              onKeyPress={this.onEnterKeyPress}
            />
          </FormGroup>
          <FormGroup
            label="Password"
            isRequired
            fieldId="password"
            validated={this.state.isValidPassword ? 'default' : 'error'}
          >
            <InputGroup>
              {!this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="password"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange}
                onKeyPress={this.onEnterKeyPress} />
              }
              {this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="text"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange}
                onKeyPress={this.onEnterKeyPress} />
              }
              <Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
                {!this.state.isPasswordVisible && <EyeIcon/>}
                {this.state.isPasswordVisible && <EyeSlashIcon/>}
              </Button>
            </InputGroup>
          </FormGroup>
          <ActionGroup>
            <Button
              variant="primary"
              isBlock
              isLoading={this.state.isLoggingIn}
              isDisabled={this.state.isLoggingIn}
              onClick={this.onLoginButtonClick}
            >
              {this.state.isLoggingIn ? 'Logging in...' : 'Log In'}
            </Button>
          </ActionGroup>
        </Form>
        }
      </LoginPage>
    );
  }
Example #10
Source File: Vulnerability.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
VulnerabilityTab = ({
  deviceData,
  setUpdateModal,
  imageId,
  setReload,
}) => {
  const { params } = useRouteMatch('/inventory/:deviceId');
  const { getRegistry } = useContext(RegistryContext);
  const [updateCveModal, setUpdateCveModal] = useState({
    isOpen: false,
    imageId: null,
    cveCount: 0,
  });
  const [CVEs, setCVEs] = useState(null);
  const [newImageStatus, setNewImageStatus] = useState(null);
  const [activeAlert, setActiveAlert] = useState('noAlert');

  useEffect(() => {
    setUpdateCveModal((prevState) => ({ ...prevState, imageId: imageId }));
  }, [imageId]);

  useEffect(() => {
    (async () => {
      if (!deviceData) {
        return;
      }
      const id = {
        id: deviceData?.ImageInfo?.Image?.ImageSetID,
      };
      const newImageData = await getImageSet(id);
      setNewImageStatus(newImageData?.Data?.images?.[0]?.image?.Status);
    })();
  }, [deviceData]);

  useEffect(() => {
    !CVEs?.isLoading &&
      !CVEs?.meta?.filter &&
      setUpdateCveModal((prevState) => ({
        ...prevState,
        cveCount: CVEs?.data?.length,
      }));

    setActiveAlert((prevState) =>
      getActiveAlert(CVEs, deviceData, newImageStatus, imageId, prevState)
    );
  }, [CVEs, deviceData, newImageStatus, imageId]);

  const handleUpdateImageButton = () => {
    setUpdateCveModal((preState) => ({
      ...preState,
      isOpen: true,
    }));
  };

  const handleUpdateDeviceButton = () => {
    setUpdateModal((preState) => ({
      ...preState,
      isOpen: true,
    }));
  };

  const alerts = {
    updateImage: (
      <Alert
        className="pf-u-mb-md"
        variant="info"
        isInline
        title="To remediate CVEs, update the image."
        actionLinks={
          <Button
            className="pf-u-mt-sm"
            isSmall
            onClick={handleUpdateImageButton}
          >
            Update Image
          </Button>
        }
      />
    ),
    imageBuilding: (
      <Alert
        className="pf-u-mb-md"
        customIcon={<InProgressIcon />}
        variant="info"
        isInline
        title="Image build in progress. Once completed, you'll need to update your device."
      />
    ),
    updateDevice: (
      <Alert
        className="pf-u-mb-md"
        variant="warning"
        isInline
        title=" Image build completed. Update device to the newest image version to remediate CVEs."
        actionLinks={
          <Button
            className="pf-u-mt-sm"
            isSmall
            onClick={handleUpdateDeviceButton}
          >
            Update Device
          </Button>
        }
      />
    ),
    systemUpdating: (
      <Alert
        className="pf-u-mb-md"
        customIcon={<InProgressIcon />}
        variant="info"
        isInline
        title="Device updating. No additional actions required."
      />
    ),
    noAlert: <></>,
  };

  return (
    <>
      <Main className="add-100vh">
        {alerts[activeAlert]}
        <AsyncComponent
          appName="vulnerability"
          module="./SystemDetail"
          getRegistry={getRegistry}
          customIntlProvider
          entity={{ id: params.deviceId }}
          canSelect={false}
          canEditPairStatus={false}
          canManageColumns={false}
          linkToCustomerPortal
          defaultColumns={[
            'synopsis',
            'public_date',
            'impact',
            'cvss_score',
            'advisory',
          ]}
          filters={[
            'filter',
            'security_rule',
            'known_exploit',
            'impact',
            'cvss_score',
            'advisory',
          ]}
          customAction={(cve) => {
            setCVEs(cve);
          }}
        />
      </Main>
      {updateCveModal.isOpen && (
        <UpdateImageModal
          updateCveModal={updateCveModal}
          setUpdateCveModal={setUpdateCveModal}
          setReload={setReload}
        />
      )}
    </>
  );
}
Example #11
Source File: user-edit.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const { user, projects, userProjects } = this.state;
    return (
      <React.Fragment>
        <PageSection variant={PageSectionVariants.light}>
          <Title headingLevel="h1" size='2xl' className="pf-c-title">
            Users / {user && user.name} {' '}
            {user && user.is_superadmin &&
              <Label className="super-admin-label" variant="outline" color="blue">Administrator</Label>
            }
          </Title>
        </PageSection>
        <PageSection>
          {!user && <Alert variant="info" title="Loading..." />}
          {user &&
          <Card>
            <CardBody>
              <Form>
                <FormGroup label="Name" isRequired fieldId="userName" helperText="The user's name">
                  <TextInput
                    isRequired
                    type="text"
                    id="userName"
                    name="userName"
                    aria-describedby="The user's name"
                    value={user.name}
                    onChange={this.onUserNameChanged}
                  />
                </FormGroup>
                <FormGroup label="E-mail" isRequired fieldId="userEmail" helperText="The user's e-mail address">
                  <TextInput
                    isRequired
                    type="email"
                    id="userEmail"
                    name="userEmail"
                    aria-describedby="The user's e-mail address"
                    value={user.email}
                    onChange={this.onUserEmailChanged}
                  />
                </FormGroup>
                <FormGroup fieldId="userStatus" label="User status">
                  <Checkbox
                    label="Is active"
                    id="userIsActive"
                    name="userIsActive"
                    aria-label="User is active"
                    isChecked={user.is_active}
                    onChange={this.onIsActiveToggle}
                  />
                  <Checkbox
                    label="Is administrator"
                    id="userIsAdmin"
                    name="userIsAdmin"
                    aria-label="User is administrator"
                    isChecked={user.is_superadmin}
                    onChange={this.onIsAdminToggle}
                  />
                </FormGroup>
                <FormGroup fieldId="userProjects" label="Projects" helperText="The projects to which a user has access">
                   <Select
                     variant={SelectVariant.typeaheadMulti}
                     typeAheadAriaLabel="Select one or more projects"
                     onToggle={this.onProjectsToggle}
                     onSelect={this.onProjectsSelect}
                     onClear={this.onProjectsClear}
                     selections={userProjects}
                     isOpen={this.state.isProjectsOpen}
                     aria-labelledby="userProjects"
                     placeholderText="Select one or more projects"
                   >
                     {projects.map(project => (
                       <SelectOption key={project.id} value={projectToOption(project)} description={project.name} />
                     ))}
                   </Select>
                </FormGroup>
                <ActionGroup>
                  <Button variant="primary" onClick={this.onSubmitClick}>Submit</Button>
                  <Button variant="secondary" onClick={this.props.history.goBack}>Cancel</Button>
                </ActionGroup>
              </Form>
            </CardBody>
          </Card>
          }
        </PageSection>
      </React.Fragment>
    );
  }
Example #12
Source File: user.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const { user, projects } = this.state;
    let projectInfo = [];
    // create the project rows
    if (projects && user) {
      projectInfo.push(projects.map((project) => (
            <DataListCell key={project.name} className="pf-u-p-sm">
              <span> {project.title} </span>
              {project.owner_id === user.id &&
                <Label className="project-owner-label" variant="filled" color="green" isCompact>Owner</Label>
              }
            </DataListCell>
      )))
    }
    return (
      <React.Fragment>
        <PageSection variant={PageSectionVariants.light}>
          <Title headingLevel="h1" size='2xl' className="pf-c-title">
            <React.Fragment>
              <span> Profile </span>
              {user && user.is_superadmin &&
                <Label className="super-admin-label" variant="filled" color="blue">Administrator</Label>
              }
            </React.Fragment>
          </Title>
        </PageSection>
        <PageSection>
          {!user && <Alert variant="danger" title="Error fetching user details" />}
          {user &&
          <DataList selectedDataListItemId={null} aria-label="User profile">
            <DataListItem aria-labelledby="Name">
              <DataListItemRow>
                {!this.state.isEditing &&
                  <DataListItemCells
                    dataListCells={[
                      <DataListCell key={1} width={2}><strong>Name:</strong></DataListCell>,
                      <DataListCell key={2} width={4}>{user.name} <Button variant="link" icon={<PencilAltIcon />} onClick={this.onEditButtonClicked} isInline isSmall ouiaId="edit-profile-button">Edit</Button></DataListCell>
                    ]}
                  />
                }
                {this.state.isEditing &&
                  <DataListItemCells
                    dataListCells={[
                      <DataListCell key={1} width={2}><strong>Name:</strong></DataListCell>,
                      <DataListCell key={2} width={4}>
                        <InputGroup>
                          <TextInput value={this.state.tempName} type="text" onChange={value => this.setState({tempName: value})} aria-label="User name" />
                          <Button variant="control" icon={<CheckIcon />} onClick={this.onSaveButtonClicked} ouiaId="edit-save-button">Save</Button>
                          <Button variant="control" icon={<TimesIcon />} onClick={this.onCancelButtonClicked} ouiaId="edit-cancel-button">Cancel</Button>
                        </InputGroup>
                      </DataListCell>
                    ]}
                  />
                }
              </DataListItemRow>
            </DataListItem>
            <DataListItem aria-labelledby="E-mail">
              <DataListItemRow>
                <DataListItemCells
                  dataListCells={[
                    <DataListCell key={1} width={2}><strong>E-mail:</strong></DataListCell>,
                    <DataListCell key={2} width={4}>{user.email}</DataListCell>
                  ]}
                />
              </DataListItemRow>
            </DataListItem>
            <DataListItem aria-labelledby="Projects">
              <DataListItemRow>
                <DataListItemCells
                  dataListCells={[
                    <DataListCell key={1} width={2}><strong>My Projects:</strong></DataListCell>,
                    <DataListCell key={2} width={4} style={{paddingTop: 0, paddingBottom: 0}}>
                      <DataList aria-lable="projects" style={{borderTop: "none"}}>
                        {projects &&
                          projectInfo
                        }
                      </DataList>
                    </DataListCell>
                  ]}
                />
              </DataListItemRow>
            </DataListItem>
          </DataList>
          }
        </PageSection>
      </React.Fragment>
    );
  }
Example #13
Source File: reset-password.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const loginMessage = (
      <LoginMainFooterBandItem>
        Already registered? <NavLink to="/login">Log in.</NavLink>
      </LoginMainFooterBandItem>
    );
    const forgotCredentials = (
      <LoginMainFooterBandItem>
        <NavLink to="/forgot-password">Forgot username or password?</NavLink>
      </LoginMainFooterBandItem>
    );

    const backgroundImages = {
      lg: '/images/pfbg_1200.jpg',
      sm: '/images/pfbg_768.jpg',
      sm2x: '/images/[email protected]',
      xs: '/images/pfbg_576.jpg',
      xs2x: '/images/[email protected]'
    };

    return (
      <LoginPage
        footerListVariants="inline"
        brandImgSrc="/images/ibutsu-wordart-164.png"
        brandImgAlt="Ibutsu"
        backgroundImgSrc={backgroundImages}
        backgroundImgAlt="Background image"
        textContent="Ibutsu is an open source test result aggregation. Collect and display your test results, view artifacts, and monitor tests."
        loginTitle="Reset your password"
        loginSubtitle="Please type in a secure password"
        signUpForAccountMessage={loginMessage}
        forgotCredentials={forgotCredentials}
      >
        <Form>
          {this.state.showAlert &&
          <FormAlert>
            <Alert variant={this.state.alertType} title={this.state.alertText} aria-live="polite" isInline/>
          </FormAlert>
          }
          <FormGroup
            label="Password"
            isRequired
            fieldId="password"
            validated={this.state.isValidPassword ? 'default' : 'error'}
          >
            <InputGroup>
              {!this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="password"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange} />
              }
              {this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="text"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange} />}
              <Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
                {!this.state.isPasswordVisible && <EyeIcon/>}
                {this.state.isPasswordVisible && <EyeSlashIcon/>}
              </Button>
            </InputGroup>
            <PasswordErrorBoundary>
              <Suspense fallback={""}>
                <PasswordStrengthBar password={this.state.passwordValue}/>
              </Suspense>
            </PasswordErrorBoundary>
          </FormGroup>
          <FormGroup
            label="Confirm password"
            isRequired
            fieldId="confirm-password"
            helperText={this.state.confirmPasswordHelpText}
            helperTextInvalid="Passwords do not match"
            validated={this.state.confirmPasswordValidation}
          >
            <InputGroup>
              {!this.state.isConfirmPasswordVisible && <TextInput isRequired type="password" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
              {this.state.isConfirmPasswordVisible && <TextInput isRequired type="text" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
              <Button variant="control" aria-label="Show password" onClick={this.onConfirmPasswordVisibleClick}>
                {!this.state.isConfirmPasswordVisible && <EyeIcon/>}
                {this.state.isConfirmPasswordVisible && <EyeSlashIcon/>}
              </Button>
            </InputGroup>
          </FormGroup>
          <ActionGroup>
            <Button variant="primary" isBlock onClick={this.onResetButtonClick}>Reset Password</Button>
          </ActionGroup>
        </Form>
      </LoginPage>
    );
  }
Example #14
Source File: sign-up.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const loginMessage = (
      <LoginMainFooterBandItem>
        Already registered? <NavLink to="/login">Log in.</NavLink>
      </LoginMainFooterBandItem>
    );
    const forgotCredentials = (
      <LoginMainFooterBandItem>
        <NavLink to="/forgot-password">Forgot username or password?</NavLink>
      </LoginMainFooterBandItem>
    );

    const backgroundImages = {
      lg: '/images/pfbg_1200.jpg',
      sm: '/images/pfbg_768.jpg',
      sm2x: '/images/[email protected]',
      xs: '/images/pfbg_576.jpg',
      xs2x: '/images/[email protected]'
    };

    return (
      <LoginPage
        footerListVariants="inline"
        brandImgSrc="/images/ibutsu-wordart-164.png"
        brandImgAlt="Ibutsu"
        backgroundImgSrc={backgroundImages}
        backgroundImgAlt="Background image"
        textContent="Ibutsu is an open source test result aggregation. Collect and display your test results, view artifacts, and monitor tests."
        loginTitle="Register a new account"
        loginSubtitle="Please type in your e-mail address and a secure password"
        signUpForAccountMessage={loginMessage}
        forgotCredentials={forgotCredentials}
      >
        <Form>
          {this.state.showAlert &&
          <FormAlert>
            <Alert variant={this.state.alertType} title={this.state.alertText} aria-live="polite" isInline/>
          </FormAlert>
          }
          <FormGroup
            label="Email address"
            isRequired
            fieldId="email"
            validated={this.state.isValidEmail ? 'default' : 'error'}
            helperText="The e-mail address you want to use to log in"
          >
            <TextInput
              isRequired
              type="email"
              id="email"
              name="email"
              validated={this.state.isValidEmail ? 'default' : 'error'}
              aria-describedby="email-helper"
              value={this.state.emailValue}
              onChange={this.onEmailChange}
            />
          </FormGroup>
          <FormGroup
            label="Password"
            isRequired
            fieldId="password"
            validated={this.state.isValidPassword ? 'default' : 'error'}
          >
            <InputGroup>
              {!this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="password"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange} />
              }
              {this.state.isPasswordVisible &&
              <TextInput
                isRequired
                type="text"
                id="password"
                name="password"
                validated={this.state.isValidPassword ? 'default' : 'error'}
                aria-describedby="password-helper"
                value={this.state.passwordValue}
                onChange={this.onPasswordChange} />}
              <Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
                {!this.state.isPasswordVisible && <EyeIcon/>}
                {this.state.isPasswordVisible && <EyeSlashIcon/>}
              </Button>
            </InputGroup>
            <PasswordErrorBoundary>
              <Suspense fallback={""}>
                <PasswordStrengthBar password={this.state.passwordValue}/>
              </Suspense>
            </PasswordErrorBoundary>
          </FormGroup>
          <FormGroup
            label="Confirm password"
            isRequired
            fieldId="confirm-password"
            helperText={this.state.confirmPasswordHelpText}
            helperTextInvalid="Passwords do not match"
            validated={this.state.confirmPasswordValidation}
          >
            <InputGroup>
              {!this.state.isConfirmPasswordVisible && <TextInput isRequired type="password" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
              {this.state.isConfirmPasswordVisible && <TextInput isRequired type="text" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
              <Button variant="control" aria-label="Show password" onClick={this.onConfirmPasswordVisibleClick}>
                {!this.state.isConfirmPasswordVisible && <EyeIcon/>}
                {this.state.isConfirmPasswordVisible && <EyeSlashIcon/>}
              </Button>
            </InputGroup>
          </FormGroup>
          <ActionGroup>
            <Button variant="primary" isBlock onClick={this.onRegisterButtonClick}>Register</Button>
          </ActionGroup>
        </Form>
      </LoginPage>
    );
  }
Example #15
Source File: DnsSettingsForm.js    From cockpit-wicked with GNU General Public License v2.0 4 votes vote down vote up
DnsSettingsForm = ({ isOpen, onClose, dns }) => {
    const dispatch = useNetworkDispatch();
    const [nameserver1, setNameserver1] = useState(dns.nameServers[0]);
    const [nameserver2, setNameserver2] = useState(dns.nameServers[1]);
    const [nameserver3, setNameserver3] = useState(dns.nameServers[2]);
    const [policy, setPolicy] = useState(dns.policy);
    const [searchListInput, setSearchListInput] = useState(dns.searchList.join(" "));
    const [errorMessages, setErrorMessages] = useState([]);

    const validate = () => {
        const errors = [];

        // Clean previous error messages
        setErrorMessages([]);

        if (searchList().some((d) => !isValidDomain(d))) {
            errors.push({
                key: 'invalid-searchlist',
                message: _("There are invalid domains in the search list.")
            });

            setSearchListInput(searchList().join(" "));
        }

        if (nameServers().some((s) => !isValidIP(s))) {
            errors.push({
                key: 'invalid-nameservers',
                message: _("There are invalid name servers.")
            });
        }

        setErrorMessages(errors);

        return (errors.length == 0);
    };

    const searchList = () => searchListInput.split(" ").filter(Boolean);

    const nameServers = () => [nameserver1, nameserver2, nameserver3].filter(Boolean);

    const configChanged = () => {
        return !deep_equal(dns, createDnsSettings({ policy, searchList: searchList(), nameServers: nameServers() }));
    };

    const handleSubmit = () => {
        if (!validate()) return false;

        if (configChanged()) {
            updateDnsSettings(dispatch, { nameServers: nameServers(), policy, searchList: searchList() });
        }

        onClose();
    };

    /**
     * Renders error messages in an Patternfly/Alert component, if any
     */
    const renderErrors = () => {
        if (errorMessages.length === 0) return null;

        return (
            <Alert
              isInline
              variant="danger"
              aria-live="polite"
              title={_("Data is not valid, please check it")}
            >
                {errorMessages.map(({ key, message }) => <p key={key}>{message}</p>)}
            </Alert>
        );
    };

    const handleError = (value) => console.log("Invalid value", value, "for nameserver 1");

    return (
        <ModalForm
            title={_("DNS Settings")}
            isOpen={isOpen}
            onCancel={onClose}
            onSubmit={handleSubmit}
        >
            {renderErrors()}
            <FormGroup
                label={_("Policy")}
                fieldId="dns_policy"
                helperText={_("Defines the DNS merge policy as documented in netconfig(8) manual page.")}
            >
                <TextInput
                    isRequired
                    id="dns_policy"
                    value={policy}
                    onChange={setPolicy}
                />
            </FormGroup>
            <FormGroup
                label={_("Search List")}
                isRequired
                fieldId="dns_search_list"
                helperText={_("Space separated list of DNS domain names used for host-name lookup")}
            >
                <TextInput
                    id="dns_search_list"
                    placeholder={_("example.com another.com")}
                    value={searchListInput}
                    onChange={setSearchListInput}
                />
            </FormGroup>
            <FormGroup
                label={_("Static Name Servers")}
                helperText={_("Name Server IP address used for host-name lookup.")}
            >
                <IPInput
                    id="dns_nameserver_one"
                    onChange={setNameserver1}
                    placeholder={_("Nameserver IP")}
                    defaultValue={nameserver1}
                    onError={handleError}
                />
            </FormGroup>

            <FormGroup>
                <IPInput
                    id="dns_nameserver_two"
                    placeholder={_("Name Server IP")}
                    defaultValue={nameserver2}
                    onChange={setNameserver2}
                    onError={handleError}
                />
            </FormGroup>
            <FormGroup>
                <IPInput
                    id="dns_nameserver_three"
                    placeholder={_("Name Server IP")}
                    defaultValue={nameserver3}
                    onChange={setNameserver3}
                    onError={handleError}
                />
            </FormGroup>
        </ModalForm>
    );
}
Example #16
Source File: IPSettingsForm.js    From cockpit-wicked with GNU General Public License v2.0 4 votes vote down vote up
IPSettingsForm = ({ connection, ipVersion = 'ipv4', isOpen, onClose }) => {
    const dispatch = useNetworkDispatch();
    const settings = connection[ipVersion];
    const [bootProto, setBootProto] = useState(settings.bootProto);
    const [addresses, setAddresses] = useState(settings.addresses);
    const [addressRequired, setAddressRequired] = useState(settings.bootProto === bootProtocol.STATIC);
    const [errorMessages, setErrorMessages] = useState([]);

    /**
     * Performs an update of the internal addresses state
     *
     * When the "Static" boot protocol is selected, it ensures that there is at least one {@link
     * module:/model~AddressConfig} in the collection, which helps displaying needed fields in the
     * UI.
     *
     * @param {Array<module:model~AddressConfig>} [nextAddresses] - Addresses to be used for the
     *   update. When not given, current addresses will be used.
     */
    const forceAddressesUpdate = useCallback((nextAddresses) => {
        nextAddresses ||= addresses;

        if (bootProto === bootProtocol.STATIC && nextAddresses.length === 0) {
            nextAddresses = [createAddressConfig()];
        }

        setAddresses(nextAddresses);
    }, [addresses, bootProto]);

    /**
     * Performs validations using given addresses
     *
     * @param {Array<module:model~AddressConfig>} sanitizedAddresses - a collection of sanitize
     *   addresses. See {@link sanitize}
     * @return {boolean} true when all validations success; false otherwise
     */
    const validate = (sanitizedAddresses) => {
        /**
         * TODO: improve validations
         * TODO: highlight addresses with errors?
         */
        let result = true;
        const errors = [];

        // Clean previous error messages
        setErrorMessages([]);

        if (bootProto === bootProtocol.STATIC && sanitizedAddresses.length === 0) {
            result = false;
            errors.push({
                key: 'static-address-required',
                message: format(
                    _('At least one address must be provided when using the "$bootProto" boot protocol'),
                    { bootProto: bootProtocol.label(bootProtocol.STATIC) }
                )
            });
        }

        if (findInvalidIP(sanitizedAddresses)) {
            result = false;
            errors.push({
                key: 'invalid-ips',
                message: _("There are invalid IPs")
            });
        }

        if (findRepeatedLabel(sanitizedAddresses)) {
            result = false;
            errors.push({
                key: 'repeated-labels',
                message: _("There are repeated labels")
            });
        }

        setErrorMessages(errors);

        return result;
    };

    /**
     * Handles the form submit, performing a connection update when proceed
     *
     * @see {@link validate}
     * @see {@link module/context/network~updateConnection}
     */
    const handleSubmit = () => {
        const sanitizedAddresses = sanitize(addresses);

        // Do not proceed if errors were found
        if (!validate(sanitizedAddresses)) {
            forceAddressesUpdate(sanitizedAddresses);
            return;
        }

        // If everything looks good, send requested changes and close
        updateConnection(
            dispatch,
            connection,
            { [ipVersion]: { bootProto, addresses: sanitizedAddresses } }
        );

        onClose();
    };

    /**
     * Updates the UI according to the bootProtocol selected
     *
     * Basically, setting the internal form state in order to ensure that the AddressDataList
     * component displays the fields for at least one {@link module/model~AddressConfig} item.
     */
    useEffect(() => {
        forceAddressesUpdate();
        setAddressRequired(bootProto === bootProtocol.STATIC);
    }, [forceAddressesUpdate, bootProto]);

    /**
     * Renders error messages in an Patternfly/Alert component, if any
     */
    const renderErrors = () => {
        if (errorMessages.length === 0) return null;

        return (
            <Alert
              isInline
              variant="danger"
              aria-live="polite"
              title={_("Data is not valid, please check it")}
            >
                {errorMessages.map(({ key, message }) => <p key={key}>{message}</p>)}
            </Alert>
        );
    };

    return (
        <ModalForm
            caption={connection.name}
            title={_(`${ipVersion.toUpperCase()} Settings`)}
            isOpen={isOpen}
            onSubmit={handleSubmit}
            onCancel={onClose}
            variant={ModalVariant.medium}
        >
            {renderErrors()}

            <FormGroup label={_("Boot Protocol")} isRequired>
                <BootProtoSelector value={bootProto} onChange={setBootProto} />
            </FormGroup>

            <FormGroup label={_("Addresses")}>
                <AddressesDataList
                    addresses={addresses}
                    updateAddresses={setAddresses}
                    allowEmpty={!addressRequired}
                />
            </FormGroup>
        </ModalForm>
    );
}
Example #17
Source File: ReviewStep.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
ReviewStep = () => {
  const { getState } = useFormApi();
  const isUpdate = getState().initialValues.isUpdate;
  const { getRegistry } = useContext(RegistryContext);
  const { isLoading, hasError } = useSelector(
    ({ createImageReducer }) => ({
      isLoading:
        createImageReducer?.isLoading !== undefined
          ? createImageReducer?.isLoading
          : false,
      hasError: createImageReducer?.hasError || false,
      error: createImageReducer?.error || null,
    }),
    shallowEqual
  );
  useEffect(() => {
    const registered = getRegistry().register({ createImageReducer });
    return () => registered();
  }, []);

  if (isLoading) {
    return (
      <Bullseye>
        <Spinner />
      </Bullseye>
    );
  }

  const details = [
    { name: 'Name', value: getState().values.name },
    { name: 'Version', value: String(getState().initialValues.version + 1) },
    { name: 'Description', value: getState().values.description },
  ];

  const output = () => {
    let outputs = [
      { name: 'Release', value: releaseMapper[getState().values.release] },
      {
        name: 'Output Type',
        value: imageTypeMapper['rhel-edge-commit'],
      },
    ];
    if (getState().values.imageType.includes('rhel-edge-installer')) {
      outputs.push({ name: '', value: imageTypeMapper['rhel-edge-installer'] });
    }
    return outputs;
  };

  const registration = [
    { name: 'Username', value: getState().values['username'] },
    { name: 'ssh-key', value: getState().values.credentials },
  ];

  const RHELPackageBefore = getState().initialValues['selected-packages'] || [];
  const RHELPackageAfter = getState().values['selected-packages'] || [];
  const customPackageBefore = getState().initialValues['custom-packages'] || [];
  const customPackageAfter = getState().values['custom-packages'] || [];

  const calcPkgDiff = (arr1, arr2) =>
    arr1.reduce(
      (acc, { name }) => acc + (!arr2.some((pkg) => pkg.name === name) ? 1 : 0),
      0
    );

  const packages = () => {
    const pkgs = [
      getState().values?.includesCustomRepos && {
        name: isUpdate ? 'Custom Updated' : 'Custom Added',
        value: String(calcPkgDiff(customPackageAfter, customPackageBefore)),
      },
      {
        name: isUpdate ? 'RHEL Updated' : 'RHEL Added',
        value: String(calcPkgDiff(RHELPackageAfter, RHELPackageBefore)),
      },
    ];
    return pkgs;
  };

  return (
    <Fragment>
      {hasError && (
        <Alert
          variant="danger"
          title="Failed sending the request: Edge API is not available"
        />
      )}
      <TextContent>
        <Text>
          Review the information and click{' '}
          <Text component={'b'}>Create image</Text> to start the build process.
        </Text>
        <ReviewSection
          title={'Details'}
          data={details}
          testid={'review-image-details'}
        />
        <ReviewSection
          title={'Output'}
          data={output()}
          testid={'review-image-output'}
        />
        {getState().values.imageType.includes('rhel-edge-installer') ? (
          <ReviewSection
            title={'Registration'}
            data={registration}
            testid={'review-image-registration'}
          />
        ) : null}
        <ReviewSection
          title={'Packages'}
          data={packages()}
          testid={'review-image-packages'}
        />
      </TextContent>
    </Fragment>
  );
}
Example #18
Source File: RouteForm.js    From cockpit-wicked with GNU General Public License v2.0 4 votes vote down vote up
RouteForm = ({ isOpen, onClose, route }) => {
    const isEditing = !!route;
    const [isDefault, setIsDefault] = useState(route?.isDefault || false);
    const [gateway, setGateway] = useState(route?.gateway || "");
    const [destination, setDestination] = useState(route?.destination || "");
    const [device, setDevice] = useState(route?.device || "");
    const [options, setOptions] = useState(route?.options || "");
    const [errors, setErrors] = useState([]);
    const { interfaces, routes } = useNetworkState();
    const [candidateInterfaces, setCandidateInterfaces] = useState([]);
    const dispatch = useNetworkDispatch();

    useEffect(() => {
        setCandidateInterfaces([{ name: "" }, ...Object.values(interfaces)]);
    }, [interfaces]);

    /**
     * Performs the form validations
     *
     * To be considered a valid form both, destination and gateway must be valid IPs values. There
     * is only an exception for destination, which can be "default" too.
     *
     * @return {boolean} true when route is valid; false otherwise
     */
    const validate = () => {
        const errors = [];

        if (!isDefault && !isValidIP(destination)) {
            errors.push({
                key: 'invalid-destination',
                message: _("Destination is not valid.")
            });
        }

        if (!isValidIP(gateway)) {
            errors.push({
                key: 'invalid-gateway',
                message: _("Gateway is not valid.")
            });
        }

        setErrors(errors);

        return errors.length === 0;
    };

    const addOrUpdateRoute = () => {
        if (!validate()) return;

        if (isEditing) {
            updateRoute(dispatch, routes, route.id, buildRouteData());
        } else {
            addRoute(dispatch, routes, buildRouteData());
        }

        onClose();
    };

    const buildRouteData = () => {
        return {
            isDefault,
            destination: isDefault ? "default" : destination,
            gateway,
            device,
            options
        };
    };

    const isIncomplete = () => {
        if (!isDefault && destination.length == 0) return true;
        if (gateway.length == 0) return true;

        return false;
    };

    /**
     * Renders error messages in an Patternfly/Alert component, if any
     */
    const renderErrors = () => {
        if (errors.length === 0) return null;

        return (
            <Alert
              isInline
              variant="danger"
              aria-live="polite"
              title={_("Route is not valid, please check it.")}
            >
                {errors.map(({ key, message }) => <p key={key}>{message}</p>)}
            </Alert>
        );
    };

    /**
     * Renders the destination input only when needed (i.e., route is not marked as a default)
     */
    const renderDestination = () => {
        if (isDefault) return null;

        return (
            <FormGroup
                isRequired
                label={_("Destination")}
                fieldId="destination"
                helperText={_("Destination")}
            >
                <TextInput
                    isRequired
                    id="destination"
                    value={destination}
                    onChange={setDestination}
                />
            </FormGroup>
        );
    };

    return (
        <ModalForm
            title={isEditing ? _("Edit Route") : _("Add Route")}
            isOpen={isOpen}
            onCancel={onClose}
            onSubmit={addOrUpdateRoute}
            onSubmitLabel={isEditing ? _("Change") : _("Add")}
            onSubmitDisable={isIncomplete()}
        >
            {renderErrors()}

            <FormGroup
                label={_("Default route")}
                fieldId="isDefault"
            >
                <Checkbox
                    id="isDefault"
                    isChecked={isDefault}
                    onChange={setIsDefault}
                />
            </FormGroup>

            {renderDestination()}

            <FormGroup
                isRequired
                label={_("Gateway")}
                fieldId="gateway"
            >
                <TextInput
                    isRequired
                    id="gateway"
                    value={gateway}
                    onChange={setGateway}
                />
            </FormGroup>

            <FormGroup
                label={_("Device")}
                fieldId="device"
            >
                <FormSelect value={device} onChange={setDevice} id="device">
                    {candidateInterfaces.map(({ name }, index) => (
                        <FormSelectOption key={index} value={name} label={name} />
                    ))}
                </FormSelect>
            </FormGroup>

            <FormGroup
                label={_("Options")}
                fieldId="options"
            >
                <TextInput
                    id="options"
                    value={options}
                    onChange={setOptions}
                />
            </FormGroup>
        </ModalForm>
    );
}