@patternfly/react-core#Title JavaScript Examples

The following examples show how to use @patternfly/react-core#Title. 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: index.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
ClustersList = () => {
  const intl = useIntl();
  insights.chrome.updateDocumentTitle(
    intl.formatMessage(messages.documentTitle, {
      subnav: intl.formatMessage(messages.clusters),
    })
  );

  return (
    <React.Fragment>
      <PageHeader className="ins-c-clusters-header">
        <Title headingLevel="h1" ouiaId="page-header">
          {`${intl.formatMessage(messages.insightsHeader)} ${intl
            .formatMessage(messages.clusters)
            .toLowerCase()}`}
        </Title>
      </PageHeader>
      <Main>
        <ClustersListTable />
      </Main>
    </React.Fragment>
  );
}
Example #2
Source File: tablestates.js    From ibutsu-server with MIT License 6 votes vote down vote up
render() {
    return (
      <Bullseye>
        <EmptyState>
          <EmptyStateIcon icon={ErrorCircleOIcon} />
          <Title headingLevel="h5" size="lg">Error occurred fetching results</Title>
          {!!this.props.onClearFilters &&
          <React.Fragment>
            <EmptyStateBody>
              An error occurred while fetching results. Try a different set of filters.
            </EmptyStateBody>
            <EmptyStateSecondaryActions>
              <Button variant="link" onClick={this.props.onClearFilters}>Clear all filters</Button>
            </EmptyStateSecondaryActions>
          </React.Fragment>
          }
        </EmptyState>
      </Bullseye>
    );
  }
Example #3
Source File: tablestates.js    From ibutsu-server with MIT License 6 votes vote down vote up
render() {
    return (
      <Bullseye>
        <EmptyState>
          <EmptyStateIcon icon={SearchIcon} />
          <Title headingLevel="h5" size="lg">No results found</Title>
          {!!this.props.onClearFilters &&
          <React.Fragment>
            <EmptyStateBody>
              No results match this filter criteria. Clear all filters to show results.
            </EmptyStateBody>
            <EmptyStateSecondaryActions>
              <Button variant="link" onClick={this.props.onClearFilters}>Clear all filters</Button>
            </EmptyStateSecondaryActions>
          </React.Fragment>
          }
        </EmptyState>
      </Bullseye>
    );
  }
Example #4
Source File: NoResultsTable.js    From tasks-frontend with Apache License 2.0 6 votes vote down vote up
NoResultsTable = ({ type }) => (
  <EmptyTable>
    <Bullseye>
      <EmptyState variant={EmptyStateVariant.full}>
        <Title headingLevel="h5" size="lg">
          {`No matching ${type} found`}
        </Title>
        <EmptyStateBody>
          To continue, edit your filter settings and search again.
        </EmptyStateBody>
      </EmptyState>
    </Bullseye>
  </EmptyTable>
)
Example #5
Source File: EmptyStateDisplay.js    From tasks-frontend with Apache License 2.0 6 votes vote down vote up
EmptyStateDisplay = ({
  button,
  color,
  error,
  icon,
  isSmall,
  text,
  title,
}) => {
  return (
    <EmptyState
      variant={isSmall ? EmptyStateVariant.small : EmptyStateVariant.large}
    >
      {icon ? (
        <EmptyStateIcon
          icon={icon}
          color={color ? color : null}
          className={isSmall ? 'small-empty-state-icon' : null}
        />
      ) : null}
      <br></br>
      <Title headingLevel={isSmall ? 'h5' : 'h1'} size={isSmall ? 'md' : 'lg'}>
        {title}
      </Title>
      <EmptyStateBody>
        {text
          ? text.map((line, index) => (
              <React.Fragment key={`line-${index}`}>
                {line}
                <br />
              </React.Fragment>
            ))
          : null}
        {error ? error : null}
      </EmptyStateBody>
      {button}
    </EmptyState>
  );
}
Example #6
Source File: NoActivationKeysFound.js    From sed-frontend with Apache License 2.0 6 votes vote down vote up
NoActivationKeysFound = (props) => {
  const { handleModalToggle } = props;
  return (
    <>
      <EmptyState>
        <EmptyStateIcon icon={AddCircleOIcon} />
        <Title headingLevel="h5" size="lg">
          No activation keys
        </Title>
        <EmptyStateBody>
          You currently have no activation keys to display. Activation keys
          allow you to register a system with system purpose, role and usage
          attached.
        </EmptyStateBody>
        <CreateActivationKeyButton onClick={handleModalToggle} />
      </EmptyState>
    </>
  );
}
Example #7
Source File: no-access.js    From sed-frontend with Apache License 2.0 6 votes vote down vote up
NoAccessView = () => (
  <Bullseye>
    <EmptyState>
      <EmptyStateIcon icon={LockIcon} />
      <Title headingLevel="h4" size="lg">
        Activation keys can only be accessed by organization administrators.
      </Title>
      <EmptyStateBody>
        If you already know your organization ID and activation key, you can
        register systems with RHC.
      </EmptyStateBody>
    </EmptyState>
  </Bullseye>
)
Example #8
Source File: index.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
RecsList = () => {
  const intl = useIntl();
  insights.chrome.updateDocumentTitle(
    intl.formatMessage(messages.documentTitle, {
      subnav: intl.formatMessage(messages.recommendations),
    })
  );

  return (
    <React.Fragment>
      <PageHeader className="ins-c-recommendations-header">
        <Title headingLevel="h1" ouiaId="page-header">
          {`${intl.formatMessage(messages.insightsHeader)} ${intl
            .formatMessage(messages.recommendations)
            .toLowerCase()}`}
        </Title>
      </PageHeader>
      <Main>
        <Suspense fallback={<Loading />}>
          <RecsListTable />
        </Suspense>
      </Main>
    </React.Fragment>
  );
}
Example #9
Source File: MessageState.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
MessageState = ({
  className,
  children,
  icon,
  iconClass,
  iconStyle,
  text,
  title,
  variant,
}) => (
  <EmptyState
    className={className}
    variant={variant}
    data-ouia-component-id="empty-state"
    data-ouia-component-type="PF4/EmptyState"
    data-ouia-safe={true}
  >
    {icon && (
      <EmptyStateIcon className={iconClass} style={iconStyle} icon={icon} />
    )}
    <Title headingLevel="h5" size="lg">
      {title}
    </Title>
    <EmptyStateBody style={{ marginBottom: '16px' }}>{text}</EmptyStateBody>
    {children}
  </EmptyState>
)
Example #10
Source File: EmptyStates.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
NoRecsForClusters = () => {
  const intl = useIntl();
  return (
    <EmptyState variant="small">
      <EmptyStateIcon icon={PlusCircleIcon} />
      <Title headingLevel="h2" size="2xl">
        {intl.formatMessage(messages.noRecsForClusterListTitle)}
      </Title>
      <EmptyStateBody>
        {intl.formatMessage(messages.noRecsForClusterListBody)}
      </EmptyStateBody>
      <Button
        component="a"
        variant="primary"
        href="https://console.redhat.com/openshift/create"
      >
        Create cluster
      </Button>
      <EmptyStateSecondaryActions>
        <Button
          component="a"
          variant="link"
          href="https://console.redhat.com/openshift/register"
        >
          Register cluster
        </Button>
        <Button
          component="a"
          variant="link"
          href="https://console.redhat.com/openshift/assisted-installer/clusters"
        >
          Assisted Installer clusters
        </Button>
      </EmptyStateSecondaryActions>
    </EmptyState>
  );
}
Example #11
Source File: EmptyStates.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
ComingSoon = () => {
  const intl = useIntl();
  return (
    <EmptyState variant="small" id="coming-soon-message">
      <EmptyStateIcon icon={InProgressIcon} color="#151515" />
      <Title headingLevel="h2" size="2xl">
        {intl.formatMessage(messages.comingSoonTitle)}
      </Title>
      <EmptyStateBody>
        {intl.formatMessage(messages.comingSoonBody)}
      </EmptyStateBody>
      <Link to="/recommendations">
        <Button variant="primary">Recommendations</Button>
      </Link>
    </EmptyState>
  );
}
Example #12
Source File: EmptyAccount.js    From malware-detection-frontend with Apache License 2.0 6 votes vote down vote up
EmptyAccount = ({ message, className }) => {
    const intl = useIntl();
    return (
        <EmptyState className={className} variant='large'>
            <EmptyStateIcon icon={WrenchIcon} />
            <Title headingLevel="h4" size="lg">
                {intl.formatMessage(messages.emptyAccountTitle)}
            </Title>
            <EmptyStateBody>
                {message}
            </EmptyStateBody>
            <Button
                variant="primary"
                component="a"
                href={'https://access.redhat.com/documentation/en-us/red_hat_insights/2022/html/' +
                'assessing_and_reporting_malware_signatures_on_rhel_systems_with_the_insights_for' +
                '_rhel_malware_service/'}
                target="_blank" >
                {intl.formatMessage(messages.emptyAccountButton)}
            </Button>
        </EmptyState>
    );
}
Example #13
Source File: BuildModalReview.js    From edge-frontend with Apache License 2.0 6 votes vote down vote up
BuildModalReview = ({ reviewObject, key }) => {
  return (
    <TextContent>
      <Title headingLevel="h3">
        <Text component={'b'}>{reviewObject.title}</Text>
      </Title>
      <TextList component={TextListVariants.dl}>
        {reviewObject.rows.map((row) => (
          <Fragment key={row.title + key}>
            <TextListItem component={TextListItemVariants.dt}>
              {row.title}
            </TextListItem>
            <TextListItem component={TextListItemVariants.dd}>
              {row.value}
            </TextListItem>
          </Fragment>
        ))}
      </TextList>
    </TextContent>
  );
}
Example #14
Source File: Loading.js    From content-preview with Apache License 2.0 6 votes vote down vote up
Loading = () => {
    const Spinner = () => (
        <span className="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
            <span className="pf-c-spinner__clipper" />
            <span className="pf-c-spinner__lead-ball" />
            <span className="pf-c-spinner__tail-ball" />
        </span>
    );
    return (
        <EmptyState>
            <EmptyStateIcon variant="container" component={Spinner} />
            <Title size="lg" headingLevel="h4">
                Loading
            </Title>
        </EmptyState>
    );
}
Example #15
Source File: LoadError.js    From content-preview with Apache License 2.0 6 votes vote down vote up
LoadDetailError = (props) => {
    let bodyMessage;
    if (props.bodyMessage === 'List') {
        bodyMessage = 'Try again later. Or report issue to @insights-rule-dev';
    } else if (props.bodyMessage === 'Detail') {
        bodyMessage = 'Use a right PluginName|ErrorKey in URL and try again... Or report issue to @insights-rule-dev';
    }

    return (
        <EmptyState>
            <EmptyStateIcon icon={BanIcon} />
            <Title size="lg" headingLevel="h4">
                Loading Error of {props.bodyMessage}
            </Title>
            <EmptyStateBody>
                {bodyMessage}
            </EmptyStateBody>
            <EmptyStatePrimary>
                Back to <Link to='/preview'>Content Preview</Link>
            </EmptyStatePrimary>
        </EmptyState>
    );
}
Example #16
Source File: AccessRequestsPage.js    From access-requests-frontend with Apache License 2.0 6 votes vote down vote up
AccessRequestsPage = ({ isInternal }) => {
  return (
    <Provider store={registry.getStore()}>
      <ErroReducerCatcher>
        <PageSection variant="light">
          <Title headingLevel="h1" className="pf-u-pb-sm">
            Access Requests
          </Title>
          <p>
            Below is a list of all submitted requests for read only account
            access.
          </p>
        </PageSection>
        <PageSection padding={{ default: 'noPadding' }}>
          <AccessRequestsTable isInternal={isInternal} />
        </PageSection>
      </ErroReducerCatcher>
    </Provider>
  );
}
Example #17
Source File: InactiveServicePage.js    From cockpit-wicked with GNU General Public License v2.0 6 votes vote down vote up
InactiveServicePage = () => {
    return (
        <EmptyState>
            <EmptyStateIcon icon={AlertIcon} />
            <Title headingLevel="h4" size="lg">
                {_("Wicked service is not active")}
            </Title>
            <EmptyStateBody>
                <p>
                    {_(`Seems that wicked service is not active. It could be either, the service is
                    not running or wicked is not installed.`)}
                </p>
                <p>
                    {_("For more help, please check the documentation linked below.")}
                </p>
            </EmptyStateBody>

            <EmptyStateSecondaryActions>
                <ExternalLink href="https://en.opensuse.org/Portal:Wicked">
                    openSUSE Wicked Portal
                </ExternalLink>
                <ExternalLink href="https://github.com/openSUSE/wicked/wiki/FAQ">
                    Wicked FAQ
                </ExternalLink>
                <ExternalLink href="https://github.com/openSUSE/wicked">
                    Public Wicked Repository
                </ExternalLink>
            </EmptyStateSecondaryActions>
        </EmptyState>
    );
}
Example #18
Source File: RoutingTab.js    From cockpit-wicked with GNU General Public License v2.0 6 votes vote down vote up
RoutingTab = () => {
    const dispatch = useNetworkDispatch();
    const { routes } = useNetworkState();

    useEffect(() => { fetchRoutes(dispatch) }, [dispatch]);

    const routesList = routes ? Object.values(routes) : [];

    const routesNotFound = () => (
        <EmptyState>
            <EmptyStateIcon icon={InfoCircleIcon} />
            <Title headingLevel="h4" size="lg">
                {_('No user-defined routes were found.')}
            </Title>
            <AddRoute />
        </EmptyState>
    );

    if (routesList.length === 0) {
        return routesNotFound();
    }

    return (
        <Card>
            <CardHeader>
                <CardActions>
                    <AddRoute />
                </CardActions>
                <CardTitle>
                    <Text component={TextVariants.h2}>{_("User-defined Routes")}</Text>
                </CardTitle>
            </CardHeader>
            <CardBody>
                <RoutesList routes={routesList} />
            </CardBody>
        </Card>
    );
}
Example #19
Source File: Empty.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
Empty = ({
  bgColor,
  icon,
  title,
  body,
  primaryAction,
  secondaryActions,
}) => (
  <EmptyState variant="large" style={{ backgroundColor: bgColor || '' }}>
    {icon && <EmptyStateIcon icon={iconMapper[icon]} />}
    <Title headingLevel="h4" size="lg">
      {title}
    </Title>
    <EmptyStateBody>{body}</EmptyStateBody>
    {primaryAction && (
      <>
        {primaryAction.href ? (
          <Button component={Link} to={primaryAction.href}>
            {primaryAction.text}
          </Button>
        ) : (
          <Button onClick={primaryAction.click} variant="primary">
            {primaryAction.text}
          </Button>
        )}
      </>
    )}
    <EmptyStateSecondaryActions>
      {secondaryActions.map(({ type, title, link, onClick }, index) => (
        <Button
          component={type === 'link' ? 'a' : 'button'}
          href={link}
          variant="link"
          target={type === 'link' ? '_blank' : ''}
          key={index}
          onClick={onClick}
        >
          {title}
          {link && <ExternalLinkAltIcon className="pf-u-ml-sm" />}
        </Button>
      ))}
    </EmptyStateSecondaryActions>
  </EmptyState>
)
Example #20
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 #21
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 #22
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 #23
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 #24
Source File: Recommendation.js    From ocp-advisor-frontend with Apache License 2.0 4 votes vote down vote up
Recommendation = ({ rule, ack, clusters, match }) => {
  const intl = useIntl();
  const dispatch = useDispatch();
  const notify = (data) => dispatch(addNotification(data));
  const recId = match.params.recommendationId;
  const [disableRuleModalOpen, setDisableRuleModalOpen] = useState(false);
  const [actionsDropdownOpen, setActionsDropdownOpen] = useState(false);
  const [viewSystemsModalOpen, setViewSystemsModalOpen] = useState(false);

  // rule's info
  const {
    isError,
    isUninitialized,
    isLoading,
    isFetching,
    isSuccess,
    data,
    refetch,
  } = rule;
  // justification note, last time acknowledged, etc.
  const { data: ackData, isFetching: ackIsFetching, refetch: refetchAck } = ack;
  const ruleDate = new Date(ackData?.updated_at || ackData?.created_at);
  // affected and acked clusters lists
  const {
    data: clustersData,
    isFetching: clustersIsFetching,
    refetch: refetchClusters,
  } = clusters;

  const content =
    isSuccess && data ? adjustOCPRule(data.content, recId) : undefined;
  const ackedClusters =
    !clustersIsFetching && clustersData ? clustersData.disabled : undefined;

  const afterDisableFn = async () => {
    refetch();
    refetchAck();
    refetchClusters();
  };

  const handleModalToggle = (disableRuleModalOpen) => {
    setDisableRuleModalOpen(disableRuleModalOpen);
  };

  const enableRecForHosts = async ({ uuids }) => {
    try {
      const requests = uuids.map((uuid) =>
        enableRuleForCluster({ uuid, recId })
      );
      await Promise.all(requests);
      refetch();
      refetchAck();
      refetchClusters();
      notify({
        variant: 'success',
        timeout: true,
        dismissable: true,
        title: intl.formatMessage(messages.recSuccessfullyEnabledForCluster),
      });
    } catch (error) {
      notify({
        variant: 'danger',
        dismissable: true,
        title: intl.formatMessage(messages.error),
        description: `${error}`,
      });
    }
  };

  const enableRule = async (rule) => {
    try {
      await Delete(`${BASE_URL}/v2/ack/${rule.data.content.rule_id}/`);
      notify({
        variant: 'success',
        timeout: true,
        dismissable: true,
        title: intl.formatMessage(messages.recSuccessfullyEnabled),
      });
      refetch();
    } catch (error) {
      handleModalToggle(false);
      notify({
        variant: 'danger',
        dismissable: true,
        title: intl.formatMessage(messages.error),
        description: `${error}`,
      });
    }
  };

  const messagesValues = useMemo(
    () => (content ? mapContentToValues(intl, content) : {}),
    [intl, content]
  );

  return (
    <React.Fragment>
      {viewSystemsModalOpen && (
        <ViewHostAcks
          handleModalToggle={(toggleModal) =>
            setViewSystemsModalOpen(toggleModal)
          }
          isModalOpen={viewSystemsModalOpen}
          clusters={clusters}
          afterFn={() => refetchClusters()}
          recId={recId}
        />
      )}
      {disableRuleModalOpen && (
        <DisableRule
          handleModalToggle={handleModalToggle}
          isModalOpen={disableRuleModalOpen}
          rule={content}
          afterFn={afterDisableFn}
        />
      )}
      <PageHeader className="pageHeaderOverride">
        <Breadcrumbs current={content?.description || recId} />
      </PageHeader>
      {(isUninitialized || isLoading || isFetching) && (
        <Main>
          <Loading />
        </Main>
      )}
      {isError && (
        <Main>
          <ErrorState />
        </Main>
      )}
      {!(isUninitialized || isLoading || isFetching) && isSuccess && (
        <React.Fragment>
          <Main className="pf-m-light pf-u-pt-sm">
            <RuleDetails
              messages={formatMessages(
                intl,
                RuleDetailsMessagesKeys,
                messagesValues
              )}
              product={AdvisorProduct.ocp}
              rule={content}
              isDetailsPage
              header={
                <React.Fragment>
                  <PageHeaderTitle
                    title={
                      <React.Fragment>
                        {content.description} <RuleLabels rule={content} />
                      </React.Fragment>
                    }
                  />
                  <p>
                    {intl.formatMessage(messages.rulesDetailsPubishdate, {
                      date: (
                        <DateFormat
                          date={new Date(content.publish_date)}
                          type="onlyDate"
                        />
                      ),
                    })}
                    {content.tags &&
                      (Array.isArray(content.tags) ? (
                        <LabelGroup
                          className="categoryLabels"
                          numLabels={1}
                          isCompact
                        >
                          {content.tags.reduce((labels, tag) => {
                            if (RULE_CATEGORIES[tag]) {
                              labels.push(
                                <Label
                                  key={`label-${tag}`}
                                  color="blue"
                                  isCompact
                                >
                                  {
                                    FILTER_CATEGORIES.category.values[
                                      RULE_CATEGORIES[tag] - 1
                                    ].label
                                  }
                                </Label>
                              );
                            }
                            return labels;
                          }, [])}
                        </LabelGroup>
                      ) : (
                        <Label isCompact>{content.tags}</Label>
                      ))}
                  </p>
                </React.Fragment>
              }
              onVoteClick={async (rule, rating) =>
                await Post(`${BASE_URL}/v2/rating`, {}, { rule, rating })
              }
            >
              <Flex>
                <FlexItem align={{ default: 'alignRight' }}>
                  <Dropdown
                    className="ins-c-rec-details__actions_dropdown"
                    onSelect={() =>
                      setActionsDropdownOpen(!actionsDropdownOpen)
                    }
                    position="right"
                    ouiaId="actions"
                    toggle={
                      <DropdownToggle
                        onToggle={(actionsDropdownOpen) =>
                          setActionsDropdownOpen(actionsDropdownOpen)
                        }
                        toggleIndicator={CaretDownIcon}
                      >
                        {intl.formatMessage(messages.actions)}
                      </DropdownToggle>
                    }
                    isOpen={actionsDropdownOpen}
                    dropdownItems={
                      content?.disabled
                        ? [
                            <DropdownItem
                              key="link"
                              ouiaId="enable"
                              onClick={() => {
                                enableRule(rule);
                              }}
                            >
                              {intl.formatMessage(messages.enableRule)}
                            </DropdownItem>,
                          ]
                        : [
                            <DropdownItem
                              key="link"
                              ouiaId="disable"
                              onClick={() => {
                                handleModalToggle(true);
                              }}
                            >
                              {intl.formatMessage(messages.disableRule)}
                            </DropdownItem>,
                          ]
                    }
                  />
                </FlexItem>
              </Flex>
            </RuleDetails>
          </Main>
          <Main>
            <React.Fragment>
              {(content?.hosts_acked_count ||
                ackedClusters?.length > 0 ||
                content?.disabled) && (
                <Card className="cardOverride" ouiaId="hosts-acked">
                  <CardHeader>
                    <Title headingLevel="h4" size="xl">
                      <BellSlashIcon size="sm" />
                      &nbsp;
                      {intl.formatMessage(
                        (content?.hosts_acked_count ||
                          ackedClusters?.length > 0) &&
                          !content?.disabled
                          ? messages.ruleIsDisabledForClusters
                          : messages.ruleIsDisabled
                      )}
                    </Title>
                  </CardHeader>
                  <CardBody>
                    {(content?.hosts_acked_count ||
                      ackedClusters?.length > 0) &&
                    !content?.disabled ? (
                      <React.Fragment>
                        {intl.formatMessage(
                          messages.ruleIsDisabledForClustersBody,
                          {
                            clusters: ackedClusters?.length,
                          }
                        )}
                        {!clustersIsFetching && ackedClusters?.length > 0 ? (
                          <React.Fragment>
                            &nbsp;
                            <Button
                              isInline
                              variant="link"
                              onClick={() => setViewSystemsModalOpen(true)}
                              ouiaId="view-clusters"
                            >
                              {intl.formatMessage(messages.viewClusters)}
                            </Button>
                          </React.Fragment>
                        ) : (
                          <OneLineLoader />
                        )}
                      </React.Fragment>
                    ) : (
                      !ackIsFetching &&
                      ackData && (
                        <React.Fragment>
                          {ackData?.justification
                            ? intl.formatMessage(
                                messages.ruleIsDisabledWithJustificaiton,
                                {
                                  date: (
                                    <span>
                                      <DateFormat
                                        date={ruleDate}
                                        type="onlyDate"
                                      />
                                    </span>
                                  ),
                                  reason: ackData.justification,
                                }
                              )
                            : intl.formatMessage(
                                messages.ruleIsDisabledWithoutJustificaiton,
                                {
                                  date: (
                                    <span>
                                      <DateFormat
                                        date={ruleDate}
                                        type="onlyDate"
                                      />
                                    </span>
                                  ),
                                }
                              )}
                        </React.Fragment>
                      )
                    )}
                  </CardBody>
                  <CardFooter>
                    {(content?.hosts_acked_count ||
                      ackedClusters?.length > 0) &&
                    !content?.disabled ? (
                      !clustersIsFetching && ackedClusters ? (
                        <Button
                          isInline
                          variant="link"
                          onClick={() =>
                            enableRecForHosts({
                              uuids: ackedClusters.map((c) => c.cluster_id),
                            })
                          }
                          ouiaId="enable"
                        >
                          {intl.formatMessage(messages.enableRuleForClusters)}
                        </Button>
                      ) : (
                        <OneLineLoader />
                      )
                    ) : (
                      <Button
                        isInline
                        variant="link"
                        onClick={() => enableRule(rule)}
                        ouiaId="enable"
                      >
                        {intl.formatMessage(messages.enableRule)}
                      </Button>
                    )}
                  </CardFooter>
                </Card>
              )}
              {!content?.disabled && (
                <React.Fragment>
                  <Title className="titleOverride" headingLevel="h3" size="2xl">
                    {intl.formatMessage(messages.affectedClusters)}
                  </Title>
                  <AffectedClustersTable
                    query={clusters}
                    rule={content}
                    afterDisableFn={afterDisableFn}
                  />
                </React.Fragment>
              )}
              {content?.disabled && (
                <MessageState
                  icon={BellSlashIcon}
                  title={intl.formatMessage(messages.ruleIsDisabled)}
                  text={intl.formatMessage(messages.ruleIsDisabledBody)}
                />
              )}
            </React.Fragment>
          </Main>
        </React.Fragment>
      )}
    </React.Fragment>
  );
}
Example #25
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 #26
Source File: dashboard.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    document.title = 'Dashboard | Ibutsu';
    const { widgets } = this.state;
    const project = getActiveProject();
    const dashboard = getActiveDashboard();
    return (
      <React.Fragment>
        <PageSection variant={PageSectionVariants.light}>
          <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
            <Flex>
              <FlexItem spacer={{ default: 'spacerLg' }}>
                <TextContent>
                  <Text component="h1">Dashboard</Text>
                </TextContent>
              </FlexItem>
              <FlexItem id="dashboard-selector" spacer={{ default: 'spacerNone' }}>
                <Select
                  ariaLabelTypeAhead="Select a dashboard"
                  placeholderText="No active dashboard"
                  variant={SelectVariant.typeahead}
                  isOpen={this.state.isDashboardSelectorOpen}
                  isDisabled={!project}
                  selections={this.state.selectedDashboard}
                  onToggle={this.onDashboardToggle}
                  onSelect={this.onDashboardSelect}
                  onClear={this.onDashboardClear}
                  onTypeaheadInputChanged={this.onDashboardChanged}
                  footer={this.state.dashboards.length == 10 && "Search for more..."}
                  isPlain
                >
                  {this.state.dashboards.map(dash => (
                    <SelectOption key={dash.id} value={dashboardToSelect(dash)} />
                  ))}
                </Select>
              </FlexItem>
              <FlexItem spacer={{ default: 'spacerNone' }}>
                <Button
                  aria-label="New dashboard"
                  variant="plain"
                  title="New dashboard"
                  isDisabled={!project}
                  onClick={this.onNewDashboardClick}
                >
                  <PlusCircleIcon />
                </Button>
              </FlexItem>
              <FlexItem>
                <Button
                  aria-label="Delete dashboard"
                  variant="plain"
                  title="Delete dashboard"
                  isDisabled={!dashboard}
                  onClick={this.onDeleteDashboardClick}
                >
                  <TimesCircleIcon />
                </Button>
              </FlexItem>
            </Flex>
            <Flex>
              <FlexItem>
                <Button
                  aria-label="Add widget"
                  variant="secondary"
                  title="Add widget"
                  isDisabled={!this.state.selectedDashboard}
                  onClick={this.onAddWidgetClick}
                >
                  <PlusCircleIcon /> Add Widget
                </Button>
              </FlexItem>
            </Flex>
          </Flex>
        </PageSection>
        <PageSection>
          {!!project && !!dashboard && !!widgets &&
          <Grid hasGutter>
            {widgets.map(widget => {
              if (KNOWN_WIDGETS.includes(widget.widget)) {
                return (
                  <GridItem xl={4} lg={6} md={12} key={widget.id}>
                    {(widget.type === "widget" && widget.widget === "jenkins-heatmap") &&
                      <JenkinsHeatmapWidget
                        title={widget.title}
                        params={widget.params}
                        includeAnalysisLink={true}
                        onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
                      />
                    }
                    {(widget.type === "widget" && widget.widget === "run-aggregator") &&
                      <GenericBarWidget
                        title={widget.title}
                        params={widget.params}
                        horizontal={true}
                        percentData={true}
                        barWidth={20}
                        onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
                      />
                    }
                    {(widget.type === "widget" && widget.widget === "result-summary") &&
                      <ResultSummaryWidget
                        title={widget.title}
                        params={widget.params}
                        onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
                      />
                    }
                    {(widget.type === "widget" && widget.widget === "result-aggregator") &&
                      <ResultAggregatorWidget
                        title={widget.title}
                        params={widget.params}
                        onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
                      />
                    }
                  </GridItem>
                );
              }
              else {
                return '';
              }
            })}
          </Grid>
          }
          {!project &&
          <EmptyState>
            <EmptyStateIcon icon={ArchiveIcon} />
            <Title headingLevel="h4" size="lg">
              No Project Selected
            </Title>
            <EmptyStateBody>
              There is currently no project selected. Please select a project from the dropdown in
              order to view the dashboard.
            </EmptyStateBody>
          </EmptyState>
          }
          {!!project && !dashboard &&
          <EmptyState>
            <EmptyStateIcon icon={TachometerAltIcon} />
            <Title headingLevel="h4" size="lg">
              No Dashboard Selected
            </Title>
            <EmptyStateBody>
              There is currently no dashboard selected. Please select a dashboard from the dropdown
              in order to view widgets, or create a new dashboard.
            </EmptyStateBody>
            <Button variant="primary" onClick={this.onNewDashboardClick}>New Dashboard</Button>
          </EmptyState>
          }
          {(!!project && !!dashboard && widgets.length === 0) &&
          <EmptyState>
            <EmptyStateIcon icon={CubesIcon} />
            <Title headingLevel="h4" size="lg">
              No Widgets
            </Title>
            <EmptyStateBody>
              This dashboard currently has no widgets defined.<br />Click on the &quot;Add Widget&quot; button
              below to add a widget to this dashboard.
            </EmptyStateBody>
            <Button variant="primary" onClick={this.onAddWidgetClick}>Add Widget</Button>
          </EmptyState>
          }
        </PageSection>
        <NewDashboardModal
          project={project}
          isOpen={this.state.isNewDashboardOpen}
          onSave={this.onNewDashboardSave}
          onClose={this.onNewDashboardClose}
        />
        <NewWidgetWizard
          dashboard={dashboard}
          isOpen={this.state.isWidgetWizardOpen}
          onSave={this.onNewWidgetSave}
          onClose={this.onNewWidgetClose}
        />
        <DeleteModal
          title="Delete dashboard"
          body={<>Would you like to delete the current dashboard? <strong>ALL WIDGETS</strong> on the dashboard will also be deleted.</>}
          isOpen={this.state.isDeleteDashboardOpen}
          onDelete={this.onDeleteDashboard}
          onClose={this.onDeleteDashboardClose}
        />
        <DeleteModal
          title="Delete widget"
          body="Would you like to delete the selected widget?"
          isOpen={this.state.isDeleteWidgetOpen}
          onDelete={this.onDeleteWidget}
          onClose={this.onDeleteWidgetClose}
        />
      </React.Fragment>
    );
  }
Example #27
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 #28
Source File: AccessRequestsTable.js    From access-requests-frontend with Apache License 2.0 4 votes vote down vote up
AccessRequestsTable = ({ isInternal }) => {
  const columns = isInternal
    ? [
        'Request ID',
        'Account number',
        'Start date',
        'End date',
        'Created',
        'Status',
      ]
    : [
        'Request ID',
        'First name',
        'Last name',
        'Start date',
        'End date',
        'Created',
        'Decision',
      ];

  // Sorting
  const [activeSortIndex, setActiveSortIndex] = React.useState(
    isInternal ? 4 : 5
  );
  const [activeSortDirection, setActiveSortDirection] = React.useState('desc');
  const onSort = (_ev, index, direction) => {
    setActiveSortIndex(index);
    setActiveSortDirection(direction);
  };

  // Pagination
  const [page, setPage] = React.useState(1);
  const [perPage, setPerPage] = React.useState(20);
  const AccessRequestsPagination = ({ id }) => (
    <Pagination
      itemCount={numRows}
      perPage={perPage}
      page={page}
      onSetPage={(_ev, pageNumber) => setPage(pageNumber)}
      id={'access-requests-table-pagination-' + id}
      variant={id}
      perPageOptions={[5, 10, 20, 50].map((n) => ({ title: n, value: n }))}
      onPerPageSelect={(_ev, perPage) => {
        setPage(1);
        setPerPage(perPage);
      }}
      isCompact={id === 'top'}
    />
  );

  AccessRequestsPagination.propTypes = {
    id: PropTypes.string,
  };

  // Filtering
  const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
  const [filterColumn, setFilterColumn] = React.useState(
    columns[isInternal ? 1 : 6]
  );
  const [isSelectOpen, setIsSelectOpen] = React.useState(false);
  const [statusSelections, setStatusSelections] = React.useState([]);

  // Harder than it needs to be to match rest of RBAC which doesn't wait
  // for user to click a button or press enter.
  const [accountFilter, setAccountFilter] = React.useState('');
  const [filtersDirty, setFiltersDirty] = React.useState(false);
  const hasFilters = statusSelections.length > 0 || accountFilter;

  // Row loading
  const [isLoading, setIsLoading] = React.useState(true);
  const [numRows, setNumRows] = React.useState(0);
  const [rows, setRows] = React.useState([]);
  const dispatch = useDispatch();
  const fetchAccessRequests = () => {
    setIsLoading(true);
    const listUrl = new URL(
      `${window.location.origin}${API_BASE}/cross-account-requests/`
    );

    isInternal
      ? listUrl.searchParams.append('query_by', 'user_id')
      : listUrl.searchParams.append('query_by', 'target_account');

    listUrl.searchParams.append('offset', (page - 1) * perPage);
    listUrl.searchParams.append('limit', perPage);
    // https://github.com/RedHatInsights/insights-rbac/blob/master/rbac/api/cross_access/view.py
    if (accountFilter) {
      listUrl.searchParams.append('account', accountFilter);
    }
    if (statusSelections.length > 0) {
      listUrl.searchParams.append('status', statusSelections.join(','));
    }
    const orderBy = `${activeSortDirection === 'desc' ? '-' : ''}${columns[
      activeSortIndex
    ]
      .toLowerCase()
      .replace(' ', '_')}`;
    listUrl.searchParams.append('order_by', orderBy);

    apiInstance
      .get(listUrl.href, { headers: { Accept: 'application/json' } })
      .then((res) => {
        setNumRows(res.meta.count);
        setRows(
          res.data.map((d) =>
            isInternal
              ? [
                  d.request_id,
                  d.target_account,
                  d.start_date,
                  d.end_date,
                  d.created,
                  d.status,
                ]
              : [
                  d.request_id,
                  d.first_name,
                  d.last_name,
                  d.start_date,
                  d.end_date,
                  d.created,
                  d.status,
                ]
          )
        );
        setIsLoading(false);
      })
      .catch((err) => {
        setIsLoading(false);
        dispatch(
          addNotification({
            variant: 'danger',
            title: 'Could not list access requests',
            description: err.message,
          })
        );
      });
  };
  const debouncedAccountFilter = useDebounce(accountFilter, 400);
  React.useEffect(() => {
    fetchAccessRequests();
  }, [
    debouncedAccountFilter,
    statusSelections,
    activeSortIndex,
    activeSortDirection,
    perPage,
    page,
  ]);

  // Modal actions
  const [openModal, setOpenModal] = React.useState({ type: null });
  const onModalClose = (isChanged) => {
    setOpenModal({ type: null });
    if (isChanged) {
      fetchAccessRequests();
    }
  };
  const modals = (
    <React.Fragment>
      {openModal.type === 'cancel' && (
        <CancelRequestModal
          requestId={openModal.requestId}
          onClose={onModalClose}
        />
      )}
      {['edit', 'create'].includes(openModal.type) && (
        <EditRequestModal
          variant={openModal.type}
          requestId={openModal.requestId}
          onClose={onModalClose}
        />
      )}
    </React.Fragment>
  );

  // Rendering
  const createButton = isInternal && (
    <Button variant="primary" onClick={() => setOpenModal({ type: 'create' })}>
      Create request
    </Button>
  );
  if (rows.length === 0 && !isLoading && !filtersDirty) {
    return (
      <Bullseye style={{ height: 'auto' }} className="pf-u-mt-lg">
        <EmptyState variant="large">
          <EmptyStateIcon icon={PlusCircleIcon} />
          <Title headingLevel="h3" size="lg">
            {isInternal ? 'No access requests' : 'You have no access requests'}
          </Title>
          <EmptyStateBody>
            {isInternal
              ? 'Click the button below to create an access request.'
              : 'You have no pending Red Hat access requests.'}
          </EmptyStateBody>
          {createButton}
        </EmptyState>
        {modals}
      </Bullseye>
    );
  }

  const selectLabelId = 'filter-status';
  const selectPlaceholder = `Filter by ${uncapitalize(
    columns[columns.length - 1]
  )}`;
  const clearFiltersButton = (
    <Button
      variant="link"
      onClick={() => {
        setStatusSelections([]);
        setAccountFilter('');
        setPage(1);
      }}
    >
      Clear filters
    </Button>
  );
  const toolbar = (
    <Toolbar id="access-requests-table-toolbar">
      <ToolbarContent>
        <ToolbarItem>
          <InputGroup>
            <Dropdown
              isOpen={isDropdownOpen}
              onSelect={(ev) => {
                setIsDropdownOpen(false);
                setFilterColumn(ev.target.value);
                setIsSelectOpen(false);
                setFiltersDirty(true);
              }}
              toggle={
                <DropdownToggle
                  onToggle={(isOpen) => setIsDropdownOpen(isOpen)}
                >
                  <FilterIcon /> {filterColumn}
                </DropdownToggle>
              }
              // https://marvelapp.com/prototype/257je526/screen/74764732
              dropdownItems={(isInternal ? [1, 5] : [6])
                .map((i) => columns[i])
                .map((colName) => (
                  // Filterable columns are RequestID, AccountID, and Status
                  <DropdownItem
                    key={colName}
                    value={colName}
                    component="button"
                  >
                    {capitalize(colName)}
                  </DropdownItem>
                ))}
            />
            {['Status', 'Decision'].includes(filterColumn) && (
              <React.Fragment>
                <span id={selectLabelId} hidden>
                  {selectPlaceholder}
                </span>
                <Select
                  aria-labelledby={selectLabelId}
                  variant="checkbox"
                  aria-label="Select statuses"
                  onToggle={(isOpen) => setIsSelectOpen(isOpen)}
                  onSelect={(_ev, selection) => {
                    setFiltersDirty(true);
                    if (statusSelections.includes(selection)) {
                      setStatusSelections(
                        statusSelections.filter((s) => s !== selection)
                      );
                    } else {
                      setStatusSelections([...statusSelections, selection]);
                    }
                    setPage(1);
                  }}
                  isOpen={isSelectOpen}
                  selections={Array.from(statusSelections)}
                  isCheckboxSelectionBadgeHidden
                  placeholderText={selectPlaceholder}
                >
                  {statuses.map((status) => (
                    <SelectOption key={status} value={status}>
                      {capitalize(status)}
                    </SelectOption>
                  ))}
                </Select>
              </React.Fragment>
            )}
            {filterColumn === 'Account number' && (
              <form
                style={{ display: 'flex' }}
                onSubmit={(ev) => ev.preventDefault()}
              >
                <TextInput
                  name={`${filterColumn}-filter`}
                  id={`${filterColumn}-filter`}
                  type="search"
                  iconVariant="search"
                  placeholder={`Filter by ${uncapitalize(filterColumn)}`}
                  aria-label={`${filterColumn} search input`}
                  value={accountFilter}
                  onChange={(val) => {
                    setAccountFilter(val), setFiltersDirty(true), setPage(1);
                  }}
                />
              </form>
            )}
          </InputGroup>
        </ToolbarItem>
        <ToolbarItem>{createButton}</ToolbarItem>
        <ToolbarItem variant="pagination" align={{ default: 'alignRight' }}>
          <AccessRequestsPagination id="top" />
        </ToolbarItem>
      </ToolbarContent>
      <ToolbarContent>
        <ChipGroup categoryName="Status">
          {statusSelections.map((status) => (
            <Chip
              key={status}
              onClick={() => {
                setStatusSelections(
                  statusSelections.filter((s) => s !== status)
                );
                setPage(1);
              }}
            >
              {status}
            </Chip>
          ))}
        </ChipGroup>
        {accountFilter && (
          <ChipGroup categoryName="Account number">
            <Chip
              onClick={() => {
                setAccountFilter(''), setPage(1);
              }}
            >
              {accountFilter}
            </Chip>
          </ChipGroup>
        )}
        {hasFilters && clearFiltersButton}
      </ToolbarContent>
    </Toolbar>
  );
  function getColumnWidth(columnIndex) {
    if (isInternal) {
      return columnIndex === 0 ? 30 : 15;
    }

    return [0, 6].includes(columnIndex) ? 20 : 10;
  }
  const { url } = useRouteMatch();
  const table = (
    <TableComposable aria-label="Access requests table" variant="compact">
      <Thead>
        <Tr>
          {columns.map((column, columnIndex) => (
            <Th
              key={columnIndex}
              {...(!column.includes('name') &&
                column !== 'Decision' && {
                  sort: {
                    sortBy: {
                      index: activeSortIndex,
                      direction: activeSortDirection,
                    },
                    onSort,
                    columnIndex,
                  },
                })}
              width={getColumnWidth(columnIndex)}
            >
              {column}
            </Th>
          ))}
          {isInternal && <Th />}
        </Tr>
      </Thead>
      <Tbody>
        {isLoading
          ? [...Array(rows.length || perPage).keys()].map((i) => (
              <Tr key={i}>
                {columns.map((name, j) => (
                  <Td key={j} dataLabel={name}>
                    <div
                      style={{ height: '30px' }}
                      className="ins-c-skeleton ins-c-skeleton__md"
                    >
                      {' '}
                    </div>
                  </Td>
                ))}
              </Tr>
            ))
          : rows.map((row, rowIndex) => (
              <Tr key={rowIndex}>
                <Td dataLabel={columns[0]}>
                  <Link to={`${url}${url.endsWith('/') ? '' : '/'}${row[0]}`}>
                    {row[0]}
                  </Link>
                </Td>
                <Td dataLabel={columns[1]}>{row[1]}</Td>
                <Td dataLabel={columns[2]}>{row[2]}</Td>
                <Td dataLabel={columns[3]}>{row[3]}</Td>
                <Td dataLabel={columns[4]}>{row[4]}</Td>
                {isInternal ? (
                  <Td dataLabel={columns[5]}>
                    <StatusLabel
                      requestId={row[0]}
                      status={row[5]}
                      onLabelClick={() => {
                        setStatusSelections([
                          ...statusSelections.filter((s) => s !== status),
                          status,
                        ]);
                        setPage(1);
                      }}
                      hideActions
                    />
                  </Td>
                ) : (
                  <Td dataLabel={columns[5]}>{row[5]}</Td>
                )}
                {isInternal ? (
                  // Different actions based on status
                  <Td
                    actions={getInternalActions(row[5], row[0], setOpenModal)}
                  />
                ) : (
                  <Td dataLabel={columns[6]}>
                    <StatusLabel requestId={row[0]} status={row[6]} />
                  </Td>
                )}
              </Tr>
            ))}
        {rows.length === 0 && hasFilters && (
          <Tr>
            <Td colSpan={columns.length}>
              <EmptyState variant="small">
                <EmptyStateIcon icon={SearchIcon} />
                <Title headingLevel="h2" size="lg">
                  No matching requests found
                </Title>
                <EmptyStateBody>
                  No results match the filter criteria. Remove all filters or
                  clear all filters to show results.
                </EmptyStateBody>
                {clearFiltersButton}
              </EmptyState>
            </Td>
          </Tr>
        )}
      </Tbody>
    </TableComposable>
  );

  return (
    <React.Fragment>
      {toolbar}
      {table}
      <AccessRequestsPagination id="bottom" />
      {modals}
    </React.Fragment>
  );
}
Example #29
Source File: ClusterHeader.js    From ocp-advisor-frontend with Apache License 2.0 4 votes vote down vote up
ClusterHeader = ({ clusterId, clusterData, clusterInfo }) => {
  const location = window.location;
  const [isOpen, setIsOpen] = useState(false);
  const intl = useIntl();
  // subscribe to the cluster data query
  const {
    isUninitialized: isUninitializedCluster,
    isFetching: isFetchingCluster,
    data: cluster,
  } = clusterData;

  const {
    isUninitialized: isUninitializedInfo,
    isFetching: isFetchingInfo,
    data: info,
  } = clusterInfo;

  const redirectOCM = (clusterId) => {
    location.assign(
      location.origin +
        (location.pathname.includes('beta') ? `/beta` : '') +
        `/openshift/details/${clusterId}`
    );
  };

  const dropDownItems = [
    <DropdownItem key="link" onClick={() => redirectOCM(clusterId)}>
      <snap>{intl.formatMessage(messages.clusterDetailsRedirect)}</snap>
    </DropdownItem>,
  ];

  return (
    <Grid id="cluster-header" md={12} hasGutter>
      <GridItem span={8}>
        <Title
          size="2xl"
          headingLevel="h1"
          id="cluster-header-title"
          ouiaId="cluster-name"
        >
          {isUninitializedInfo || isFetchingInfo ? (
            <Skeleton size="sm" />
          ) : (
            info?.display_name || clusterId
          )}
        </Title>
      </GridItem>
      <GridItem span={4} id="cluster-header-dropdown">
        <Dropdown
          position="right"
          onSelect={() => setIsOpen(!isOpen)}
          autoFocus={false}
          isOpen={isOpen}
          toggle={
            <DropdownToggle
              id="toggle-id-2"
              onToggle={(isOpen) => setIsOpen(isOpen)}
            >
              {intl.formatMessage(messages.dropDownActionSingleCluster)}
            </DropdownToggle>
          }
          dropdownItems={dropDownItems}
        />
      </GridItem>
      <GridItem>
        <Stack>
          <StackItem id="cluster-header-uuid">
            <span>UUID:</span> <span>{clusterId}</span>
          </StackItem>
          <StackItem id="cluster-header-last-seen">
            <span>{intl.formatMessage(messages.lastSeen)}: </span>
            <span>
              {isUninitializedCluster || isFetchingCluster ? (
                <OneLineLoader />
              ) : cluster?.report?.meta?.last_checked_at ? (
                <DateFormat
                  date={cluster?.report?.meta?.last_checked_at}
                  type="exact"
                />
              ) : (
                intl.formatMessage(messages.unknown)
              )}
            </span>
          </StackItem>
        </Stack>
      </GridItem>
    </Grid>
  );
}