@patternfly/react-core#Grid JavaScript Examples

The following examples show how to use @patternfly/react-core#Grid. 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: ReviewSection.js    From edge-frontend with Apache License 2.0 6 votes vote down vote up
ReviewSection = ({ title, data, testid }) => {
  return (
    <Grid className="pf-u-pb-xl" data-testid={testid} hasGutter>
      <GridItem span={12}>
        <Text component={TextVariants.h2}>{title}</Text>
      </GridItem>
      {data.map(({ name, value }) => (
        <Grid key={name}>
          <GridItem span={3}>
            <TextListItem component={TextListItemVariants.dt}>
              {name}
            </TextListItem>
          </GridItem>
          <GridItem span={9}>
            <TextListItem component={TextListItemVariants.dd}>
              {value}
            </TextListItem>
          </GridItem>
        </Grid>
      ))}
    </Grid>
  );
}
Example #2
Source File: DeviceSummaryTile.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
DeviceSummaryTileBase = ({
  orphaned,
  active,
  noReports,
  neverReported,
}) => (
  <Card className="tiles-card">
    <CardTitle>Device summary</CardTitle>
    <CardBody>
      <Grid>
        <GridItem span={6}>
          <Stack hasGutter>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {active}
              </Button>{' '}
              Active
            </StackItem>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {orphaned}
              </Button>{' '}
              Orphaned
            </StackItem>
          </Stack>
        </GridItem>
        <GridItem span={6}>
          <Stack hasGutter>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {noReports}
              </Button>
              Stale
            </StackItem>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {neverReported}
              </Button>
              Registered but never reported
            </StackItem>
          </Stack>
        </GridItem>
      </Grid>
    </CardBody>
  </Card>
)
Example #3
Source File: Details.js    From malware-detection-frontend with Apache License 2.0 5 votes vote down vote up
Details = () => {
    const intl = useIntl();
    const [isCodeEditorEnabled] = React.useState(false);
    const { id: sigId } = useParams();
    const breadcrumbs = [{ name: intl.formatMessage(messages.malwareDetectionSignatures),
        to: `${isBeta()}/insights/malware` }, { name: sigId, to: '#' }];
    const { data, loading } = useQuery(GET_SIGNATURE_DETAILS_PAGE, {
        variables: { ruleName: sigId  }
    });
    const sigDetailsData = data?.rulesList[0];
    const detailBlock = (title, detail) => <React.Fragment>
        <p className='ins-l-detailBlockHeader'>{title}</p>
        <p>{detail}</p>
    </React.Fragment>;

    return <React.Fragment>
        <PageHeader>
            <Breadcrumb items={breadcrumbs} />
            <Grid hasGutter>
                <GridItem md={12} sm={12}>
                    <Title headingLevel='h1' size={TitleSizes['3xl']} >{sigId}</Title>
                </GridItem>

                {isCodeEditorEnabled && (<GridItem md={7} sm={12}>
                    { sigDetailsData && <CodeEditor height='250px' code={sigDetailsData.rawRule} isReadOnly isDownloadEnabled isCopyEnabled />}
                </GridItem>)}

                {loading ? <Loading /> :
                    <GridItem md={isCodeEditorEnabled && 5 || 12} sm={12}>
                        <Grid hasGutter>
                            <GridItem xl2={isCodeEditorEnabled && 6 || 1} xl={isCodeEditorEnabled && 6 || 3} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.lastmatch), sigDetailsData?.lastMatchDate ?
                                    <DateFormat date={new Date(sigDetailsData.lastMatchDate)} type="onlyDate" />
                                    : intl.formatMessage(messages.never))}
                            </GridItem>
                            <GridItem xl2={isCodeEditorEnabled && 6 || 1} xl={isCodeEditorEnabled && 6 || 3} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.hostmatch),
                                    <span>{`${sigDetailsData?.affectedHosts?.totalCount}/${data?.hosts?.totalCount}`}</span>)}
                            </GridItem>
                            {isCodeEditorEnabled && <GridItem xl2={6} xl={6} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.description), sigDetailsData?.metadata?.description)}
                            </GridItem>}
                            <GridItem xl2={isCodeEditorEnabled && 6 || 1} xl={isCodeEditorEnabled && 6 || 3} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.enablement), sigDetailsData && <StatusLabel {...sigDetailsData} />)}
                            </GridItem>
                            <GridItem xl2={isCodeEditorEnabled && 6 || 2} xl={isCodeEditorEnabled && 6 || 3} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.author), sigDetailsData?.metadata?.author)}
                            </GridItem>
                            {!isCodeEditorEnabled && <GridItem xl2={7} xl={3} md={6} xs={12}>
                                {detailBlock(intl.formatMessage(messages.description), sigDetailsData?.metadata?.description)}
                            </GridItem>}
                        </Grid>
                    </GridItem>
                }
            </Grid>
        </PageHeader>
        <Main>
            <Title className='ins-l-tableBlockHeader' headingLevel='h1' size={TitleSizes['3xl']}>
                {intl.formatMessage(messages.affectedHosts)}
            </Title>
            <SigDetailsTable
                ruleName={sigId}
                isEmptyAccount={data?.hosts?.totalCount === 0}
                affectedCount={sigDetailsData?.affectedHosts?.totalCount}
            />
        </Main>
    </React.Fragment>;
}
Example #4
Source File: Signatures.js    From malware-detection-frontend with Apache License 2.0 5 votes vote down vote up
Signatures = () => {
    const intl = useIntl();
    const sigPageData = useQuery(GET_SIGNATURE_PAGE);
    const chartCmpData = useQuery(GET_TIME_SERIES_STATS);

    return <React.Fragment>
        <PageHeader>
            <Split hasGutter isWrappable>
                <SplitItem>
                    <PageHeaderTitle title={(<Popover
                        enableFlip
                        position={'right'}
                        headerContent={intl.formatMessage(messages.headerPopoverTitle)}
                        bodyContent={(<Grid hasGutter>
                            <GridItem>{intl.formatMessage(messages.headerPopoverBody1)}</GridItem>
                        </Grid>)}
                        footerContent={<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" rel="noopener noreferrer">
                            {intl.formatMessage(messages.headerPopoverFooter)} <ExternalLinkAltIcon />
                        </a>}
                    >
                        <Title headingLevel='h1' size={TitleSizes['3xl']}>
                            {intl.formatMessage(messages.malwareDetection)}
                            <OutlinedQuestionCircleIcon
                                color={'var(--pf-global--secondary-color--100)'}
                                className="pf-u-ml-sm pointer cves-header-questionmark"
                                style={{ verticalAlign: '-2' }}
                            />
                        </Title>
                    </Popover>)} />
                </SplitItem>
            </Split>
        </PageHeader>
        <Main>
            <Grid hasGutter>
                <GridItem lg={6} md={12}>
                    <Suspense fallback={<Loading />}><StatusCard {...sigPageData} /></Suspense>
                </GridItem>
                <GridItem lg={6} md={12}>
                    <Suspense fallback={<Loading />}><ChartCard sysStats={sigPageData}  chartStats={chartCmpData}/></Suspense>
                </GridItem>
                <GridItem span={12}>
                    <Suspense fallback={<Loading />}><SigTable /></Suspense>
                </GridItem>
            </Grid>
        </Main>
    </React.Fragment>;
}
Example #5
Source File: Footer.js    From operate-first.github.io-old with GNU General Public License v3.0 5 votes vote down vote up
Footer = () => (
  <footer key="footer-2" className="ws-org-pfsite-l-footer-dark pf-m-no-fill">
    <Grid className="pf-u-py-xl-on-sm pf-u-py-0-on-md pf-u-align-items-center">
      <GridItem md={2} mdOffset={1}>
        <Text
          component={TextVariants.a}
          href="//www.redhat.com"
          target="top"
          aria-label="Visit Red Hat.com"
        >
          <img src={redhatLogo} alt="Red Hat logo" width="100px" />
        </Text>
      </GridItem>
      <GridItem md={3}>
        <span className="ws-org-pfsite-site-copyright">Operate First is a Red Hat Initiative.</span>
      </GridItem>
      <GridItem md={6}>
        <Text
          component={TextVariants.a}
          href="//www.redhat.com/en/about/privacy-policy"
          target="top"
          aria-label="Privacy statement"
        >
          Privacy statement
        </Text>
        <Text
          component={TextVariants.a}
          href="//www.redhat.com/en/about/terms-use"
          target="top"
          aria-label="Terms of use"
        >
          Terms of use
        </Text>
        <Text
          component={TextVariants.a}
          href="//www.redhat.com/en/about/all-policies-guidelines"
          target="top"
          aria-label="All policies and guidelines"
        >
          All policies and guidelines
        </Text>
        <Text
          component={TextVariants.a}
          href="//thenounproject.com/exgoya/"
          target="top"
          aria-label="Operate First Logo Creator"
        >
          Creator of Operate-First Logo
        </Text>
        <Text
          component={TextVariants.a}
          href="//www.openstack.org/legal/community-code-of-conduct/"
          target="top"
          aria-label="Code of Conduct"
        >
          Code of Conduct
        </Text>
      </GridItem>
    </Grid>
  </footer>
)
Example #6
Source File: Details.js    From content-preview with Apache License 2.0 4 votes vote down vote up
Details = ({
    match,
    fetchContentDetails,
    details,
    fetchContentDetailsHits,
    contentDetailsHits
}) => {
    const [selectedListItem, setSelectedListItem] = useState(0);
    const capitalize = (string) => string[0].toUpperCase() + string.substring(1);
    const [expanded, setExpanded] = useState(true);
    const pyFilter = (data) => {
        const keysToInclude = Object.keys(data).filter(
            (key) => !key.includes('__')
        );
        const arrayObj = keysToInclude.map((key) => ({ [key]: data[key] }));

        return Object.assign({}, ...arrayObj);
    };

    const selectedPyData =
    selectedListItem >= 1 && pyFilter(contentDetailsHits[selectedListItem - 1]);
    const detailHref = `https://access.redhat.com/node/${details.node_id}`;
    const [freeStyle, setFreeStyle] = useState('');
    const [freeStyleValidated, setFreeStyleValidated] = useState('default');
    const [validFreeStyle, setValidFreeStyle] = useState('');
    const [helperText, setHelperText] = useState('Please enter valid JSON');
    const [kbaDetailsData, setLbaDetailsData] = useState({});
    const [kbaLoading, setKbaLoading] = useState(true);

    const freeStyleChange = (input) => {
        let isValid;
        const parser = (input) => {
            try {
                return JSON.parse(input);
            } catch (error) {
                return false;
            }
        };

        if (input.length > 0) {
            const validInput = parser(input);
            if (validInput) {
                isValid = 'success';
                setValidFreeStyle(validInput);
                setHelperText('Valid JSON! ?');
            } else {
                isValid = 'error';
                setValidFreeStyle('');
            }
        } else {
            isValid = 'default';
            setValidFreeStyle('');
            setHelperText('Please enter valid JSON');
        }

        setFreeStyleValidated(isValid);
        setFreeStyle(input);
    };

    const severityLabelColor = (severity) =>
        severity === 'ERROR'
            ? 'red'
            : severity === 'WARN'
                ? 'orange'
                : severity === 'INFO'
                    ? 'purple'
                    : 'blue';

    const fetchKbaDetails = async (kbaId) => {
        try {
            const kbaDetailsFetch = (
                await API.get(
                    `https://access.redhat.com/hydra/rest/search/kcs?q=id:(${kbaId})&fl=view_uri,id,publishedTitle&rows=1&redhat_client=$ADVISOR`,
                    {},
                    { credentials: 'include' }
                )
            ).data.response.docs;
            setLbaDetailsData(kbaDetailsFetch[0]);
            setKbaLoading(false);
        } catch (error) {
            console.error(error, 'KBA fetch failed.');
        }
    };

    const ruleDescription = (data, isGeneric) =>
        typeof data === 'string' &&
    Boolean(data) && (
            <span className={isGeneric && 'genericOverride'}>
                <Markdown rehypePlugins={[rehypeRaw, rehypeSanitize]}>{data}</Markdown>
            </span>
        );

    useEffect(() => {
        const detailName = { name: match.params.recDetail };
        fetchContentDetails(detailName);
        fetchContentDetailsHits(detailName);
        fetchKbaDetails(details.node_id);
    }, [
        fetchContentDetails,
        match.params.recDetail,
        fetchContentDetailsHits,
        details.node_id
    ]);

    return (
        <Page
            breadcrumb={
                <Breadcrumb>
                    <BreadcrumbItem>
                        <Link to="/preview">Content Preview</Link>
                    </BreadcrumbItem>
                    <BreadcrumbHeading to="#">{`${match.params.recDetail}`}</BreadcrumbHeading>
                </Breadcrumb>
            }
        >
            <PageHeader>
                <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
                    <PageHeaderTitle
                        title={
                            <>
                                {details.rule_id || 'loading...'}{' '}
                                {details.status !== undefined && (
                                    <Label color={details.status === 'active' ? 'green' : 'red'}>
                                        {capitalize(details.status)}
                                    </Label>
                                )}{' '}
                            </>
                        }
                    />
                    <Toolbar>
                        <HostSelector />
                    </Toolbar>
                </Flex>
            </PageHeader>
            <PageSection>
                <Grid hasGutter>
                    <GridItem span={6}>
                        <Stack hasGutter>
                            <Card>
                                <CardBody>
                                    <ExpandableSection
                                        toggleText={details.description}
                                        onToggle={() => setExpanded(!expanded)}
                                        isExpanded={expanded}
                                    >
                                        <Stack hasGutter>
                                            <StackItem>
                                                <p>
                                                    {`Publish Date: ${details.publish_date} | `}
                                                    {details.node_id ? (
                                                        <a href={detailHref}>{detailHref}</a>
                                                    ) : (
                                                        <Label variant="outline" color="gray">
                                                            No node_id present
                                                        </Label>
                                                    )}
                                                </p>
                                                {(details.reboot_required ||
                                                    details.category ||
                                                    details.severity) && (
                                                    <LabelGroup>
                                                        {details.reboot_required && (
                                                            <Label variant="outline" color="gray">
                                                                Reboot required
                                                            </Label>
                                                        )}
                                                        {details.category && (
                                                            <Label variant="outline" color="gray">
                                                                {details.category}
                                                            </Label>
                                                        )}
                                                        {details.severity && (
                                                            <Label
                                                                variant="outline"
                                                                color={severityLabelColor(details.severity)}
                                                            >
                                                                {details.severity}
                                                            </Label>
                                                        )}
                                                    </LabelGroup>
                                                )}
                                            </StackItem>
                                            <StackItem>
                                                <Stack hasGutter>
                                                    <StackItem>
                                                        <strong>Name:</strong>
                                                        {ruleDescription(details.name)}
                                                    </StackItem>
                                                    <StackItem>
                                                        <strong>Summary:</strong>
                                                        {ruleDescription(details.summary)}
                                                    </StackItem>
                                                    <StackItem>
                                                        <strong>Generic:</strong>
                                                        {ruleDescription(details.generic, true)}
                                                    </StackItem>
                                                </Stack>
                                            </StackItem>
                                            <StackItem>
                                                <Form>
                                                    <FormGroup
                                                        label="Free Style JSON input:"
                                                        type="string"
                                                        helperText={helperText}
                                                        helperTextInvalid="Not valid JSON"
                                                        fieldId="selection"
                                                        validated={freeStyleValidated}
                                                    >
                                                        <TextArea
                                                            value={freeStyle}
                                                            onChange={freeStyleChange}
                                                            isRequired
                                                            validated={freeStyleValidated}
                                                            aria-label="free style JSON input"
                                                        />
                                                    </FormGroup>
                                                </Form>
                                            </StackItem>
                                        </Stack>
                                    </ExpandableSection>
                                </CardBody>
                            </Card>
                            <DataList
                                className="pyDataList"
                                aria-label="selectable data list example"
                                selectedDataListItemId={selectedListItem}
                                onSelectDataListItem={(id) =>
                                    id !== selectedListItem
                                        ? setSelectedListItem(id)
                                        : setSelectedListItem(0)
                                }
                            >
                                {contentDetailsHits.map((item, key) => (
                                    <DataListItem
                                        aria-labelledby="selectable-action-item1"
                                        key={key + 1}
                                        id={key + 1}
                                    >
                                        <DataListItemRow className="overFlow">
                                            <DataListItemCells
                                                dataListCells={[
                                                    <DataListCell key="primary content">
                                                        <Split hasGutter>
                                                            <SplitItem>
                                                                <b>{item.__name}</b>
                                                            </SplitItem>
                                                            <SplitItem>
                                                                <Label color="blue">{item.__source}</Label>
                                                            </SplitItem>
                                                        </Split>
                                                        <h5>{item.__date}</h5>
                                                        <pre>{JSON.stringify(pyFilter(item), null, 2)}</pre>
                                                    </DataListCell>
                                                ]}
                                            />
                                        </DataListItemRow>
                                    </DataListItem>
                                ))}
                            </DataList>
                        </Stack>
                    </GridItem>
                    <GridItem span={6}>
                        <ReportDetails
                            report={{
                                ...details,
                                rule: details,
                                ...(selectedPyData && { details: selectedPyData }),
                                ...(validFreeStyle && { details: validFreeStyle }),
                                resolution: details.resolution
                            }}
                            kbaDetail={kbaDetailsData}
                            kbaLoading={kbaLoading}
                        />
                    </GridItem>
                </Grid>
            </PageSection>
        </Page>
    );
}
Example #7
Source File: index.js    From dbaas-ui with Apache License 2.0 4 votes vote down vote up
HomePage = () => {
  return (
    <React.Fragment>
      <PageHeader className="dbaas-home-page__header pf-u-p-2xl">
        <Grid>
          <GridItem sm={12} md={6}>
            <Title size="2xl" headingLevel="h1">
              Get started with Red Hat OpenShift Database Access
            </Title>
            <Stack hasGutter>
              <StackItem>
                <TextContent>
                  <Text size="lg" className="dbaas-home-page__subtitle">
                    Add-on service for managed OpenShift
                  </Text>
                  <Text>
                    Easily discover, consume, monitor, and manage databases as a
                    service on the managed OpenShift Platform. OpenShift
                    database access helps accelerate your development for
                    applications that use MongoDB Atlas, Crunchy Bridge and
                    CockroachDB managed database services.
                  </Text>
                </TextContent>
              </StackItem>
              <StackItem>
                <Button
                  iconPosition="right"
                  icon={<ExternalLinkAltIcon />}
                  component="a"
                  target="_blank"
                  variant="secondary"
                  href="https://access.redhat.com/documentation/en-us/red_hat_openshift_database_access/1/html-single/quick_start_guide/index"
                >
                  Get Started with OpenShift Database Access
                </Button>
              </StackItem>
            </Stack>
          </GridItem>
        </Grid>
      </PageHeader>
      <Main className="pf-u-pt-xl pf-u-pb-xl pf-u-pl-2xl pf-u-pr-2xl">
        <Title className="pf-u-mb-lg" headingLevel="h2" size="xl">
          Demo of OpenShift Database Access
        </Title>
        <Stack hasGutter>
          <StackItem>
            <Grid hasGutter>
              <GridItem md={6} sm={12}>
                <Stack hasGutter>
                  <StackItem>
                    <TextContent>
                      <Text>
                        <b>For database admins:</b> in this video you’ll learn
                        how to set up a cloud database service connection on
                        your OpenShift cluster for self-service consumption by
                        application developers.
                      </Text>
                    </TextContent>
                  </StackItem>
                  <StackItem>
                    <Button
                      iconPosition="right"
                      icon={<ExternalLinkAltIcon />}
                      target="_blank"
                      component="a"
                      variant="secondary"
                      href="https://youtu.be/vDrh3SnciL0"
                    >
                      View the demo
                    </Button>
                  </StackItem>
                </Stack>
              </GridItem>
              <GridItem md={6} sm={12}>
                <iframe
                  style={{ width: '100%', height: '315px' }}
                  width="560"
                  height="315"
                  src="https://www.youtube.com/embed/vDrh3SnciL0"
                  title="YouTube video player"
                  frameBorder="0"
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                  allowFullScreen
                ></iframe>
              </GridItem>
            </Grid>
          </StackItem>
          <StackItem>
            <Grid hasGutter>
              <GridItem md={6} sm={12}>
                <Stack hasGutter>
                  <StackItem>
                    <TextContent>
                      <Text>
                        <b>For application developers:</b> in this video, you’ll
                        learn how to quickly and easily connect your application
                        to a cloud database service on your OpenShift cluster.
                      </Text>
                    </TextContent>
                  </StackItem>
                  <StackItem>
                    <Button
                      iconPosition="right"
                      icon={<ExternalLinkAltIcon />}
                      target="_blank"
                      component="a"
                      variant="secondary"
                      href="https://youtu.be/qWaAwhxwjWs"
                    >
                      View the demo
                    </Button>
                  </StackItem>
                </Stack>
              </GridItem>
              <GridItem md={6} sm={12}>
                <iframe
                  style={{ width: '100%', height: '315px' }}
                  width="560"
                  height="315"
                  src="https://www.youtube.com/embed/qWaAwhxwjWs"
                  title="YouTube video player"
                  frameBorder="0"
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                  allowFullScreen
                ></iframe>
              </GridItem>
            </Grid>
          </StackItem>
        </Stack>
      </Main>
    </React.Fragment>
  );
}
Example #8
Source File: DeviceDetail.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
DeviceDetail = () => {
  const [imageId, setImageId] = useState(null);
  const { getRegistry } = useContext(RegistryContext);
  const { inventoryId, uuid } = useParams();
  const entity = useSelector(({ entityDetails }) => entityDetails?.entity);
  const groupName = useSelector(
    ({ groupsDetailReducer }) => groupsDetailReducer?.name
  );
  const deviceId = useSelector(
    ({ entityDetails }) => entityDetails?.entity?.id
  );

  const [imageData, setImageData] = useState();
  const [updateModal, setUpdateModal] = useState({
    isOpen: false,
    deviceData: null,
  });
  const [isDeviceStatusLoading, setIsDeviceStatusLoading] = useState(true);
  const [reload, setReload] = useState(false);
  useEffect(() => {
    insights.chrome.registerModule('inventory');
    insights.chrome?.hideGlobalFilter?.(true);
    insights.chrome.appAction('system-detail');
  }, []);

  useEffect(() => {
    (async () => {
      if (!entity?.display_name) {
        return;
      }
      const image_data = await getDeviceHasUpdate(deviceId);
      setImageData(image_data);
      setIsDeviceStatusLoading(false);
      setUpdateModal((prevState) => ({
        ...prevState,
        deviceData: [
          {
            display_name: entity.display_name,
            id: entity.id,
          },
        ],
        imageSetId: image_data?.ImageInfo?.Image?.ImageSetID,
      }));
      setImageId(image_data?.ImageInfo?.Image?.ID);
    })();
  }, [entity, reload]);

  useEffect(() => {
    insights?.chrome?.appObjectId?.(inventoryId);
  }, [inventoryId]);

  return (
    <>
      <DetailWrapper
        hideInvLink
        showTags
        onLoad={({ mergeWithDetail }) => {
          getRegistry().register({
            systemProfileStore,
            ...mergeWithDetail(deviceDetail),
          });
        }}
      >
        <PageHeader>
          <Breadcrumb ouiaId="systems-list">
            <BreadcrumbItem>
              <Link to={uuid ? `/groups` : '/inventory'}>
                {uuid ? 'Groups' : 'Systems'}
              </Link>
            </BreadcrumbItem>
            {uuid && (
              <BreadcrumbItem>
                {groupName ? (
                  <Link to={`/groups/${uuid}`}>{groupName}</Link>
                ) : (
                  <Skeleton size={SkeletonSize.xs} />
                )}
              </BreadcrumbItem>
            )}
            <BreadcrumbItem isActive>
              <div className="ins-c-inventory__detail--breadcrumb-name">
                {entity?.display_name || <Skeleton size={SkeletonSize.xs} />}
              </div>
            </BreadcrumbItem>
          </Breadcrumb>
          <InventoryDetailHead
            fallback=""
            actions={[
              {
                title: 'Update',
                isDisabled:
                  imageData?.UpdateTransactions?.[
                    imageData?.UpdateTransactions.length - 1
                  ]?.Status === 'BUILDING' ||
                  imageData?.UpdateTransactions?.[
                    imageData?.UpdateTransactions.length - 1
                  ]?.Status === 'CREATED' ||
                  !imageData?.ImageInfo?.UpdatesAvailable?.length > 0 ||
                  !updateModal.imageSetId,
                onClick: () => {
                  setUpdateModal((prevState) => ({
                    ...prevState,
                    isOpen: true,
                  }));
                },
              },
            ]}
            hideBack
            hideInvDrawer
          />

          {isDeviceStatusLoading ? (
            <Skeleton size={SkeletonSize.xs} />
          ) : imageData?.UpdateTransactions[
              imageData?.UpdateTransactions?.length - 1
            ]?.Status === 'BUILDING' ||
            imageData?.UpdateTransactions[
              imageData?.UpdateTransactions?.length - 1
            ]?.Status === 'CREATED' ? (
            <Status type="updating" isLabel={true} className="pf-u-mt-sm" />
          ) : imageData?.Device?.UpdateAvailable ? (
            <Status
              type="updateAvailable"
              isLabel={true}
              className="pf-u-mt-sm"
            />
          ) : (
            <Status type="running" isLabel={true} className="pf-u-mt-sm" />
          )}
        </PageHeader>
        <Grid gutter="md">
          <GridItem span={12}>
            <DeviceDetailTabs
              systemProfile={imageData}
              imageId={imageId}
              setUpdateModal={setUpdateModal}
              setReload={setReload}
            />
          </GridItem>
        </Grid>
        {updateModal.isOpen && (
          <Suspense
            fallback={
              <Bullseye>
                <Spinner />
              </Bullseye>
            }
          >
            <UpdateDeviceModal
              navigateBack={() => {
                history.push({ pathname: history.location.pathname });
                setUpdateModal((prevState) => {
                  return {
                    ...prevState,
                    isOpen: false,
                  };
                });
              }}
              setUpdateModal={setUpdateModal}
              updateModal={updateModal}
              refreshTable={() => setReload(true)}
            />
          </Suspense>
        )}
      </DetailWrapper>
    </>
  );
}
Example #9
Source File: ImageDetailTab.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
ImageDetailTab = ({ imageData, imageVersion }) => {
  const [data, setData] = useState({});

  useEffect(() => {
    imageVersion
      ? setData(imageVersion)
      : setData(imageData?.data?.Data?.images?.[0]);
  }, [imageData, imageVersion]);

  const createSkeleton = (rows) =>
    [...Array(rows * 2)].map((_, key) => <Skeleton width="180px" key={key} />);

  const dateFormat = () => <DateFormat date={data?.image?.['CreatedAt']} />;

  const detailsMapper = {
    Version: 'Version',
    Created: () => dateFormat(),
    'Type(s)': () =>
      data?.image?.['OutputTypes']?.map((outputType, index) => (
        <div key={index}>{outputType}</div>
      )),
    Release: () => distributionMapper?.[data?.image?.['Distribution']],
    //Size: 'Size',
    Description: 'Description',
  };

  const userInfoMapper = {
    Username: () => data?.image?.Installer?.Username,
    'SSH key': () => data?.image?.Installer?.SshKey,
  };
  const renderAdditionalPackageLink = () => {
    return (
      <Link
        to={`${paths['manage-images']}/${data?.image?.ImageSetID}/versions/${data?.image?.ID}/packages/additional`}
      >
        {data?.additional_packages}
      </Link>
    );
  };

  const renderTotalPackageLink = () => {
    return (
      <Link
        to={`${paths['manage-images']}/${data?.image?.ImageSetID}/versions/${data?.image?.ID}/packages/all`}
      >
        {data?.packages}
      </Link>
    );
  };

  const packageMapper = {
    'Total additional packages': renderAdditionalPackageLink,
    'Total packages': renderTotalPackageLink,
  };

  const packageDiffMapper = {
    Added: () => data?.update_added,
    Removed: () => data?.update_removed,
    Updated: () => data?.update_updated,
  };

  if (data?.image?.Installer?.Checksum) {
    detailsMapper['SHA-256 checksum'] = () => data?.image?.Installer?.Checksum;
  }

  if (data?.image?.Commit?.OSTreeCommit) {
    detailsMapper['Ostree commit hash'] = () =>
      data?.image?.Commit?.OSTreeCommit;
  }

  const buildTextList = (labelsToValueMapper) =>
    data
      ? Object.entries(labelsToValueMapper).map(([label, value], index) => {
          return (
            <Fragment key={index}>
              <TextListItem
                className="details-label"
                component={TextListItemVariants.dt}
              >
                {label}
              </TextListItem>
              {label === 'SHA-256 checksum' ||
              label === 'Ostree commit hash' ||
              (label === 'SSH key' && value()) ? (
                <TextListItem component={TextListItemVariants.dd}>
                  <ClipboardCopy
                    hoverTip="Copy"
                    clickTip="Copied"
                    variant="expansion"
                    className="pf-u-text-break-word"
                    id={`${label
                      .replace(/\s+/g, '-')
                      .toLowerCase()}-clipboard-copy`}
                  >
                    {typeof value === 'function'
                      ? value() || 'Unavailable'
                      : data?.image?.[value] || 'Unavailable'}
                  </ClipboardCopy>
                </TextListItem>
              ) : (
                <TextListItem
                  className="pf-u-text-break-word"
                  component={TextListItemVariants.dd}
                >
                  {typeof value === 'function'
                    ? value() === 0
                      ? 0
                      : value() || 'Unavailable'
                    : data?.image?.[value] || 'Unavailable'}
                </TextListItem>
              )}
            </Fragment>
          );
        })
      : null;

  return (
    <TextContent className="pf-u-ml-lg pf-u-mt-md">
      <Grid span={12}>
        <GridItem span={5}>
          <Text component={TextVariants.h2}>
            {imageVersion ? 'Details' : 'Most recent image'}
          </Text>
          <TextList component={TextListVariants.dl}>
            {buildTextList(detailsMapper) || createSkeleton(6)}
          </TextList>
          <Text component={TextVariants.h2}>User information </Text>
          <TextList component={TextListVariants.dl}>
            {buildTextList(userInfoMapper) || createSkeleton(2)}
          </TextList>
        </GridItem>
        <GridItem span={1} />
        <GridItem span={6}>
          <Text component={TextVariants.h2}>Packages </Text>
          <TextList component={TextListVariants.dl}>
            {buildTextList(packageMapper) || createSkeleton(3)}
          </TextList>
          <Text component={TextVariants.h2}>Changes from previous version</Text>
          <TextList component={TextListVariants.dl}>
            {buildTextList(packageDiffMapper) || createSkeleton(3)}
          </TextList>
        </GridItem>
      </Grid>
    </TextContent>
  );
}
Example #10
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>
  );
}
Example #11
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 #12
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 #13
Source File: run.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    let passed = 0, failed = 0, errors = 0, xfailed = 0, xpassed = 0, skipped = 0, not_run = 0;
    let created = 0;
    let calculatePasses = true;
    const { run, columns, rows, classificationTable, artifactTabs } = this.state;
    const jsonViewTheme = getTheme() === 'dark' ? 'tomorrow' : 'rjv-default';

    if (run.start_time) {
      created = new Date(run.start_time);
    }
    else {
      created = new Date(run.created);
    }
    if (run.summary) {
      if (run.summary.passes) {
        passed = run.summary.passes;
        calculatePasses = false;
      }
      if (run.summary.tests && calculatePasses) {
        passed = run.summary.tests;
      }
      if (run.summary.failures) {
        passed -= calculatePasses ? run.summary.failures : 0;
        failed = run.summary.failures;
      }
      if (run.summary.errors) {
        passed -= calculatePasses ? run.summary.errors : 0;
        errors = run.summary.errors;
      }
      if (run.summary.xfailures) {
        passed -= calculatePasses ? run.summary.xfailures : 0;
        xfailed = run.summary.xfailures;
      }
      if (run.summary.xpasses) {
        passed -= calculatePasses ? run.summary.xpasses : 0;
        xpassed = run.summary.xpasses;
      }
      if (run.summary.skips) {
        passed -= calculatePasses ? run.summary.skips : 0;
        skipped = run.summary.skips;
      }
      if (run.summary.not_run) {
        not_run = run.summary.not_run;
      }
      else if (run.summary.collected) {
        not_run = run.summary.collected - run.summary.tests;
      }
    }
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    }
    return (
      <React.Fragment>
        <PageSection variant={PageSectionVariants.light}>
          <TextContent>
            <Text component="h1" className="pf-c-title">Run {run.id}</Text>
          </TextContent>
        </PageSection>
        <PageSection>
          {!this.state.isRunValid &&
          <EmptyObject headingText="Run not found" returnLink="/runs" returnLinkText="Return to runs list" />
          }
          {this.state.isRunValid &&
            <Tabs activeKey={this.state.activeTab} onSelect={this.onTabSelect} isBox>
              <Tab eventKey={'summary'} title={<TabTitle icon={InfoCircleIcon} text="Summary" />}>
                <Card>
                  <CardBody style={{padding: 0}} id="run-detail">
                    <Grid style={{backgroundColor: '#fff'}}>
                      <GridItem span={6}>
                        <DataList selectedDataListItemId={null} aria-label="Run properties" style={{borderBottom: 'none', borderTop: 'none'}}>
                          <DataListItem aria-labelledby="Duration">
                            <DataListItemRow>
                              <DataListItemCells
                                dataListCells={[
                                  <DataListCell key={1} width={2}><strong>Duration:</strong></DataListCell>,
                                  <DataListCell key={2} width={4}>{round(run.duration)}s</DataListCell>
                                ]}
                              />
                            </DataListItemRow>
                          </DataListItem>
                          <DataListItem aria-labelledby="Started">
                            <DataListItemRow>
                              <DataListItemCells
                                dataListCells={[
                                  <DataListCell key={1} width={2}><strong>Started:</strong></DataListCell>,
                                  <DataListCell key={2} width={4}>{created.toLocaleString()}</DataListCell>
                                ]}
                              />
                            </DataListItemRow>
                          </DataListItem>
                          {run.metadata && run.metadata.component &&
                          <DataListItem aria-labelledby="Component">
                            <DataListItemRow>
                              <DataListItemCells
                                dataListCells={[
                                  <DataListCell key={1} width={2}><strong>Component:</strong></DataListCell>,
                                  <DataListCell key={2} width={4}>{run.metadata.component}</DataListCell>
                                ]}
                              />
                            </DataListItemRow>
                          </DataListItem>
                          }
                          {run.metadata && run.metadata.env &&
                            <DataListItem aria-labelledby="Environment">
                              <DataListItemRow>
                                <DataListItemCells
                                  dataListCells={[
                                    <DataListCell key={1} width={2}><strong>Environment:</strong></DataListCell>,
                                    <DataListCell key={2} width={4}>{run.metadata.env}</DataListCell>
                                  ]}
                                />
                              </DataListItemRow>
                            </DataListItem>
                          }
                          {run.metadata && run.metadata.tags &&
                            <DataListItem aria-labelledby="tags-label">
                              <DataListItemRow>
                                <DataListItemCells
                                  dataListCells={[
                                    <DataListCell key="tags-label" width={2}><strong>Tags:</strong></DataListCell>,
                                    <DataListCell key="tags-data" width={4}>
                                      <Flex>
                                        {run.metadata.tags.map((tag) => <FlexItem spacer={{ default: 'spacerXs' }} key={tag}><Label color="blue" variant="filled">{tag}</Label></FlexItem>)}
                                      </Flex>
                                    </DataListCell>
                                  ]}
                                />
                              </DataListItemRow>
                            </DataListItem>
                          }
                        {run.metadata && run.metadata.jenkins && run.metadata.jenkins.job_name &&
                          <DataListItem aria-labelledby="Jenkins Job Name">
                            <DataListItemRow>
                              <DataListItemCells
                                dataListCells={[
                                  <DataListCell key={1} width={2}><strong>Jenkins Job Name:</strong></DataListCell>,
                                  <DataListCell key={2} width={4}>{run.metadata.jenkins.job_name}</DataListCell>
                                ]}
                              />
                            </DataListItemRow>
                          </DataListItem>
                          }
                          {run.source &&
                            <DataListItem aria-labelledby="Source">
                              <DataListItemRow>
                                <DataListItemCells
                                  dataListCells={[
                                    <DataListCell key={1} width={2}><strong>Source:</strong></DataListCell>,
                                    <DataListCell key={2} width={4}>{run.source}</DataListCell>
                                  ]}
                                />
                              </DataListItemRow>
                            </DataListItem>
                          }
                        </DataList>
                      </GridItem>
                      <GridItem span={6}>
                        <DataList selectedDataListItemId={null} aria-label="Summary properties" style={{borderBottom: 0, borderTop: 0}}>
                          <DataListItem aria-labelledby="Summary">
                            <DataListItemRow>
                              <DataListItemCells
                                style={{paddingBottom: 0}}
                                dataListCells={[
                                  <DataListCell key={1} width={2}><strong>Summary:</strong></DataListCell>,
                                  <DataListCell key={2} width={4} style={{paddingTop: 0}}>
                                    <DataList selectedDataListItemId={null} aria-label="Summary" style={{borderBottom: 0, borderTop: 0}}>
                                      <DataListItem aria-labelledby="Total">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Total:</DataListCell>,
                                              <DataListCell key={2}>{run.summary.collected ? run.summary.collected : run.summary.tests}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Passed">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Passed:</DataListCell>,
                                              <DataListCell key={2}>{passed}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Failed">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Failed:</DataListCell>,
                                              <DataListCell key={2}>{failed}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Error">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Error:</DataListCell>,
                                              <DataListCell key={2}>{errors}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Xfailed">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Xfailed:</DataListCell>,
                                              <DataListCell key={2}>{xfailed}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Xpassed">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Xpassed:</DataListCell>,
                                              <DataListCell key={2}>{xpassed}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Skipped">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Skipped:</DataListCell>,
                                              <DataListCell key={2}>{skipped}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                      <DataListItem aria-labelledby="Not Run">
                                        <DataListItemRow>
                                          <DataListItemCells
                                            dataListCells={[
                                              <DataListCell key={1}>Not Run:</DataListCell>,
                                              <DataListCell key={2}>{not_run}</DataListCell>
                                            ]}
                                          />
                                        </DataListItemRow>
                                      </DataListItem>
                                    </DataList>
                                  </DataListCell>
                                ]}
                              />
                            </DataListItemRow>
                          </DataListItem>
                        </DataList>
                      </GridItem>
                    </Grid>
                  </CardBody>
                </Card>
              </Tab>
              <Tab eventKey={'results-list'} title={<TabTitle icon={CatalogIcon} text="Results List" />}>
                <Card className="pf-u-mt-lg">
                  <CardHeader>
                    <Flex style={{ width: '100%' }}>
                      <FlexItem grow={{ default: 'grow' }}>
                        <TextContent>
                          <Text component="h2" className="pf-c-title pf-m-xl">Test Results</Text>
                        </TextContent>
                      </FlexItem>
                      <FlexItem>
                        <Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
                      </FlexItem>
                      <FlexItem>
                        <Link to={`/results?run_id[eq]=${run.id}`} className="pf-c-button pf-m-primary" style={{marginLeft: '2px'}}>See all results <ChevronRightIcon /></Link>
                      </FlexItem>
                    </Flex>
                  </CardHeader>
                  <CardBody>
                    <FilterTable
                      columns={columns}
                      rows={rows}
                      pagination={pagination}
                      isEmpty={this.state.isEmpty}
                      isError={this.state.isError}
                      onSetPage={this.setPage}
                      onSetPageSize={this.pageSizeSelect}
                    />
                  </CardBody>
                </Card>
              </Tab>
              <Tab eventKey={'results-tree'} title={<TabTitle icon={RepositoryIcon} text="Results Tree" />}>
                <Card className="pf-u-mt-lg">
                  <CardBody>
                    <Grid gutter="sm">
                      {false && <GridItem span={12}>
                        <div style={{paddingTop: "1em"}}>
                          <TextInput value={this.state.treeSearch} type="text" onChange={this.onSearch} placeholder="Search tree..." aria-label="Filter tree" />
                        </div>
                      </GridItem>
                      }
                      {this.state.resultsTree.core.data.length === 0 &&
                        <GridItem span={12}>
                          <Bullseye><center><Spinner size="xl"/></center></Bullseye>
                        </GridItem>
                      }
                      {this.state.resultsTree.core.data !== 0 &&
                        <React.Fragment>
                          <GridItem span={5}>
                            <TreeView treeData={this.state.resultsTree} onChange={(e, data) => this.handleJSTreeChange(e, data)}/>
                          </GridItem>
                          <GridItem span={7}>
                            {this.state.testResult &&
                            <Card className={this.state.testResult.result}>
                              <CardHeader>
                                {this.state.testResult.test_id}
                                {this.state.testResult.metadata.markers &&
                                  <div style={{float: 'right'}}>
                                    {this.state.testResult.metadata.markers.map((marker) => {
                                      return <Badge isRead key={marker.name}>{marker.name}</Badge>;
                                    })}
                                  </div>
                                }
                              </CardHeader>
                              <CardBody style={{backgroundColor: "var(--pf-c-page__main-section--BackgroundColor)", paddingTop: "1.2em"}}>
                                <ResultView testResult={this.state.testResult}/>
                              </CardBody>
                            </Card>
                            }
                          </GridItem>
                        </React.Fragment>
                      }
                    </Grid>
                  </CardBody>
                </Card>
              </Tab>
              <Tab eventKey={'classify-failures'} title={<TabTitle icon={MessagesIcon} text="Classify Failures" />}>
                {classificationTable}
              </Tab>
              {artifactTabs}
              <Tab eventKey={'run-object'} title={<TabTitle icon={CodeIcon} text="Run Object" />}>
                <Card>
                  <CardBody>
                    <ReactJson src={run} name={null} iconStyle={"triangle"} collapseStringsAfterLength={120} enableClipboard={false} displayDataTypes={false} theme={jsonViewTheme} />
                  </CardBody>
                </Card>
              </Tab>
            </Tabs>
          }
        </PageSection>
      </React.Fragment>
    );
  }