@patternfly/react-core#Flex JavaScript Examples

The following examples show how to use @patternfly/react-core#Flex. 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: Tiles.js    From edge-frontend with Apache License 2.0 6 votes vote down vote up
Tiles = () => {
  const { getRegistry } = useContext(RegistryContext);
  const dispatch = useDispatch();
  useEffect(() => {
    const registered = getRegistry().register({
      imagesReducer,
      deviceSummaryReducer,
    });
    loadImages(dispatch);
    loadDeviceSummary(dispatch);
    return () => registered();
  }, [dispatch]);
  return (
    <Flex className="tiles">
      <FlexItem>
        <DeviceSummaryTile />
      </FlexItem>
    </Flex>
  );
}
Example #2
Source File: FlexibleFlex.js    From tasks-frontend with Apache License 2.0 6 votes vote down vote up
FlexibleFlex = ({ data, flexContents, flexProps }) => {
  return flexContents.map((item) => {
    return (
      <Flex key={item.match} {...flexProps}>
        {Array.isArray(item.children)
          ? item.children.map((content) => renderFlexItem(content))
          : renderFlexItem(item.children)}
        {item.match
          ? item.renderFunc
            ? renderFlexItem(
                item.renderFunc(item.match.map((prop) => data[prop]))
              )
            : renderFlexItem(data[item.match])
          : null}
      </Flex>
    );
  });
}
Example #3
Source File: certificateList.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 6 votes vote down vote up
function getExpirationTime(cert) {
    if (cert.autorenew && cert.autorenew.v) {
        return _("Auto-renews before ") + prettyTime(cert["not-valid-after"].v).toLowerCase();
    } else {
        const expiry = new Date(Number(cert["not-valid-after"].v) * 1000);
        const now = new Date();
        const diffSeconds = (expiry - now) / 1000;
        const diffDays = diffSeconds / 86400;

        if (diffSeconds < 0) { // Expired
            if (diffDays > -28) { // Expired X days ago
                return (
                    <Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
                        <TimesCircleIcon className="ct-icon-times-circle" />
                        <FlexItem>{_("Expired ") + expiry.toLocaleDateString(dateLocale())}</FlexItem>
                    </Flex>
                );
            }
            return (
                <Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
                    <TimesCircleIcon className="ct-icon-times-circle" />
                    <FlexItem>{_("Expired on ") + prettyTime(cert["not-valid-after"].v)}</FlexItem>
                </Flex>
            );
        }

        // Expires
        if (diffDays < 28) { // Expires in X days
            return (
                <Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
                    <ExclamationTriangleIcon className="ct-icon-exclamation-triangle" />
                    <FlexItem>{_("Expires ") + expiry.toLocaleDateString(dateLocale())}</FlexItem>
                </Flex>
            );
        }
        return _("Expires on ") + prettyTime(cert["not-valid-after"].v);
    }
}
Example #4
Source File: tokens.js    From ibutsu-server with MIT License 5 votes vote down vote up
render() {
    document.title = 'User Tokens | Ibutsu';
    const { columns, rows } = this.state;
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    };
    return (
      <React.Fragment>
        <PageSection id="page" variant={PageSectionVariants.light}>
          <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
            <FlexItem spacer={{ default: 'spacerLg' }}>
              <TextContent>
                <Text className="title" component="h1">Tokens</Text>
              </TextContent>
            </FlexItem>
            <FlexItem>
              <Button
                aria-label="Add token"
                variant="secondary"
                title="Add token"
                onClick={this.onAddTokenClick}
              >
                <PlusCircleIcon /> Add Token
              </Button>
            </FlexItem>
          </Flex>
        </PageSection>
        <PageSection>
          <Card>
            <CardBody className="pf-u-p-0">
              <FilterTable
                columns={columns}
                rows={rows}
                pagination={pagination}
                isEmpty={this.state.isEmpty}
                isError={this.state.isError}
                onSetPage={this.setPage}
                onSetPageSize={this.setPageSize}
              />
            </CardBody>
          </Card>
        </PageSection>
        <AddTokenModal
          isOpen={this.state.isAddTokenOpen}
          onSave={this.onAddTokenSave}
          onClose={this.onAddTokenClose}
        />
        <DeleteModal
          title="Delete token"
          body="Would you like to delete the selected token?"
          isOpen={this.state.isDeleteTokenOpen}
          onDelete={this.onDeleteToken}
          onClose={this.onDeleteTokenClose}
        />
      </React.Fragment>
    );
  }
Example #5
Source File: CardBuilder.tests.js    From tasks-frontend with Apache License 2.0 5 votes vote down vote up
describe('TasksTables', () => {
  let props;

  beforeEach(() => {
    props = {
      cardClass: '',
    };
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  it('should render correctly', () => {
    const { asFragment } = render(
      <CardBuilder {...props}>
        <CardBuilderContent content="Task title" type="title" />
        <CardBuilderContent content="Task description" type="body" />
        <CardBuilderContent
          content={
            <Flex direction={{ default: 'column' }}>
              <FlexItem>
                <a href="#">Download preview of playbook</a>
              </FlexItem>
              <FlexItem>
                <RunTaskButton
                  isFirst
                  openTaskModal={jest.fn()}
                  task={availableTasksTableItems[0]}
                  variant="primary"
                />
              </FlexItem>
            </Flex>
          }
          type="footer"
        />
      </CardBuilder>
    );

    expect(asFragment()).toMatchSnapshot();
  });
});
Example #6
Source File: AvailableTasksTable.js    From tasks-frontend with Apache License 2.0 5 votes vote down vote up
AvailableTasksTable = ({ availableTasks, error, openTaskModal }) => {
  return (
    <div aria-label="available-tasks-table">
      {error ? (
        <EmptyStateDisplay
          icon={ExclamationCircleIcon}
          color="#c9190b"
          title={'Available tasks cannot be displayed'}
          text={TASKS_ERROR}
          error={`Error ${error?.response?.status}: ${error?.message}`}
        />
      ) : !availableTasks?.length ? (
        <EmptyStateDisplay
          title={EMPTY_TASKS_TITLE}
          text={EMPTY_TASKS_MESSAGE}
        />
      ) : (
        availableTasks?.map((task) => {
          return (
            <React.Fragment aria-label={task.title} key={task.title}>
              <CardBuilder>
                <CardBuilderContent content={task.title} type="title" />
                <CardBuilderContent
                  className="card-task-description"
                  content={task.description}
                  type="body"
                />
                <CardBuilderContent
                  content={
                    <Flex direction={{ default: 'column' }}>
                      <FlexItem>
                        <a
                          href={`${TASKS_API_ROOT}${AVAILABLE_TASKS_ROOT}/${task.slug}/playbook`}
                        >
                          Download preview of playbook
                        </a>
                      </FlexItem>
                      <FlexItem>
                        <RunTaskButton
                          slug={task.slug}
                          isFirst
                          variant="primary"
                          openTaskModal={openTaskModal}
                        />
                      </FlexItem>
                    </Flex>
                  }
                  type="footer"
                />
              </CardBuilder>
              <br />
            </React.Fragment>
          );
        })
      )}
    </div>
  );
}
Example #7
Source File: RunTaskModal.js    From tasks-frontend with Apache License 2.0 5 votes vote down vote up
RunTaskModal = ({ error, task, isOpen, setModalOpened }) => {
  const [selectedIds, setSelectedIds] = useState([]);
  const dispatch = useDispatch();

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

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

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

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

    setSelectedIds(newSelectedIds);
  };

  return (
    <Modal
      aria-label="run-task-modal"
      title={task.title || 'Error'}
      isOpen={isOpen}
      onClose={() => setModalOpened(false)}
      width={'70%'}
    >
      {error ? (
        <EmptyStateDisplay
          icon={ExclamationCircleIcon}
          color="#c9190b"
          title={'This task cannot be displayed'}
          text={TASK_ERROR}
          error={`Error ${error?.response?.status}: ${error?.message}`}
        />
      ) : (
        <React.Fragment>
          <Flex>
            <FlexItem>
              <b>Task description</b>
            </FlexItem>
          </Flex>
          <Flex style={{ paddingBottom: '8px' }}>
            <FlexItem>{task.description}</FlexItem>
          </Flex>
          <Flex>
            <FlexItem>
              <a
                href={`${TASKS_API_ROOT}${AVAILABLE_TASKS_ROOT}/${task.slug}/playbook`}
              >
                Download preview of playbook
              </a>
            </FlexItem>
          </Flex>
          <br />
          <b>Systems to run tasks on</b>
          <SystemTable selectedIds={selectedIds} selectIds={selectIds} />
        </React.Fragment>
      )}
    </Modal>
  );
}
Example #8
Source File: classify-failures.js    From ibutsu-server with MIT License 5 votes vote down vote up
render() {
    const {
      columns,
      rows,
      selectedResults,
      includeSkipped,
      filters
    } = this.state;
    const { run_id } = this.props
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    }
    // filters for the metadata
    const resultFilters = [
      <MetaFilter
        key="metafilter"
        // user_properties fields shouldn't be injected here
        fieldOptions={FILTERABLE_RESULT_FIELDS}
        runId={run_id}
        setFilter={this.setFilter}
        customFilters={{'result': filters['result']}}
      />,
    ]
    return (
      <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 Failures</Text>
              </TextContent>
            </FlexItem>
            <FlexItem>
              <TextContent>
                <Checkbox id="include-skips" label="Include skips, xfails" isChecked={includeSkipped} aria-label="include-skips-checkbox" onChange={this.onSkipCheck}/>
              </TextContent>
            </FlexItem>
            <FlexItem>
              <MultiClassificationDropdown selectedResults={selectedResults} refreshFunc={this.refreshResults}/>
            </FlexItem>
            <FlexItem>
              <Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
            </FlexItem>
          </Flex>
        </CardHeader>
        <CardBody>
          <FilterTable
            columns={columns}
            rows={rows}
            pagination={pagination}
            isEmpty={this.state.isEmpty}
            isError={this.state.isError}
            onCollapse={this.onCollapse}
            onSetPage={this.setPage}
            onSetPageSize={this.pageSizeSelect}
            canSelectAll={true}
            onRowSelect={this.onTableRowSelect}
            variant={TableVariant.compact}
            activeFilters={this.state.filters}
            filters={resultFilters}
            onRemoveFilter={this.removeFilter}
            hideFilters={["run_id", "project_id"]}
          />
        </CardBody>
      </Card>
    );
  }
Example #9
Source File: CompletedTaskDetails.js    From tasks-frontend with Apache License 2.0 4 votes vote down vote up
CompletedTaskDetails = () => {
  const { id } = useParams();
  const filters = Object.values(Filters);
  const [completedTaskDetails, setCompletedTaskDetails] =
    useState(LOADING_INFO_PANEL);
  const [completedTaskJobs, setCompletedTaskJobs] =
    useState(LOADING_JOBS_TABLE);
  const [error, setError] = useState();

  const isError = (result) => {
    return result?.response?.status && result?.response?.status !== 200;
  };

  const setErrors = (result) => {
    setError(result);
    dispatchNotification({
      variant: 'danger',
      title: 'Error',
      description: result.message,
      dismissable: true,
    });
  };

  useEffect(() => {
    const fetchData = async () => {
      let taskDetails = await fetchExecutedTask(id);

      if (isError(taskDetails)) {
        setErrors(taskDetails);
      } else {
        const taskJobs = await fetchExecutedTaskJobs(id);

        if (isError(taskJobs)) {
          setErrors(taskJobs);
        } else {
          taskDetails.messages_count = taskJobs.filter((item) => {
            return item.message !== 'No vulnerability found.';
          }).length;
          taskDetails.system_count = taskJobs.length;
          await setCompletedTaskDetails(taskDetails);
          await setCompletedTaskJobs(taskJobs);
        }
      }
    };

    fetchData();
  }, []);

  return (
    <div>
      {error ? (
        <EmptyStateDisplay
          icon={ExclamationCircleIcon}
          color="#c9190b"
          title={'Task cannot be displayed'}
          text={TASK_ERROR}
          error={`Error ${error?.response?.status}: ${error?.message}`}
        />
      ) : (
        <React.Fragment>
          <PageHeader>
            <Breadcrumb ouiaId="completed-tasks-details-breadcrumb">
              <BreadcrumbItem to="/beta/insights/tasks/executed">
                Tasks
              </BreadcrumbItem>
              <BreadcrumbItem isActive>
                {completedTaskDetails.task_title}
              </BreadcrumbItem>
            </Breadcrumb>
            <Flex direction={{ default: 'column', md: 'row' }}>
              <Flex
                direction={{ default: 'column' }}
                flex={{ default: 'flex_1' }}
              >
                <FlexItem>
                  <PageHeaderTitle title={completedTaskDetails.task_title} />
                </FlexItem>
                <FlexItem>{completedTaskDetails.description}</FlexItem>
              </Flex>
              <FlexibleFlex
                data={completedTaskDetails}
                flexContents={COMPLETED_INFO_BUTTONS}
                flexProps={COMPLETED_INFO_BUTTONS_FLEX_PROPS}
              />
            </Flex>
          </PageHeader>
          <Main>
            <Card>
              <Flex
                className="completed-task-details-info-border"
                justifyContent={{ default: 'justifyContentSpaceBetween' }}
                direction={{ default: 'column', md: 'row' }}
              >
                <FlexibleFlex
                  data={completedTaskDetails}
                  flexContents={COMPLETED_INFO_PANEL}
                  flexProps={COMPLETED_INFO_PANEL_FLEX_PROPS}
                />
              </Flex>
            </Card>
            <br />
            <Card>
              <TasksTables
                label={`${completedTaskDetails.id}-completed-jobs`}
                ouiaId={`${completedTaskDetails.id}-completed-jobs-table`}
                columns={columns}
                items={completedTaskJobs}
                filters={{
                  filterConfig: filters,
                }}
                options={{
                  ...TASKS_TABLE_DEFAULTS,
                  exportable: {
                    ...TASKS_TABLE_DEFAULTS.exportable,
                    columns: exportableColumns,
                  },
                }}
                emptyRows={emptyRows('jobs')}
                isStickyHeader
              />
            </Card>
          </Main>
        </React.Fragment>
      )}
    </div>
  );
}
Example #10
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>
    );
  }
Example #11
Source File: project-list.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    document.title = 'Projects - Administration | Ibutsu';
    const { columns, rows, textFilter } = this.state;
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    };
    const filters = [
      <TextInput type="text" id="filter" placeholder="Search for project..." value={textFilter || ''} onChange={this.onTextChanged} style={{height: "inherit"}} key="textFilter"/>
    ];
    return (
      <React.Fragment>
        <PageSection id="page" variant={PageSectionVariants.light}>
          <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
            <Flex>
              <FlexItem spacer={{ default: 'spacerLg' }}>
                <TextContent>
                  <Text className="title" component="h1" ouiaId="admin-projects">Projects</Text>
                </TextContent>
              </FlexItem>
            </Flex>
            <Flex>
              <FlexItem>
                <Button
                  aria-label="Add project"
                  variant="secondary"
                  title="Add project"
                  ouiaId="admin-projects-add"
                  component={(props: any) => <Link {...props} to="/admin/projects/new" />}
                >
                  <PlusCircleIcon /> Add Project
                </Button>
              </FlexItem>
            </Flex>
          </Flex>
        </PageSection>
        <PageSection className="pf-u-pb-0">
          <Card>
            <CardBody className="pf-u-p-0">
              <FilterTable
                columns={columns}
                rows={rows}
                filters={filters}
                pagination={pagination}
                isEmpty={this.state.isEmpty}
                isError={this.state.isError}
                onSetPage={this.setPage}
                onSetPageSize={this.setPageSize}
              />
            </CardBody>
          </Card>
        </PageSection>
        <Modal
          title="Confirm Delete"
          variant="small"
          isOpen={this.state.isDeleteModalOpen}
          onClose={this.onDeleteModalClose}
          actions={[
            <Button
              key="delete"
              variant="danger"
              ouiaId="admin-projects-modal-delete"
              isLoading={this.state.isDeleting}
              isDisabled={this.state.isDeleting}
              onClick={this.onModalDeleteClick}
            >
              {this.state.isDeleting ? 'Deleting...' : 'Delete'}
            </Button>,
            <Button
              key="cancel"
              variant="secondary"
              ouiaId="admin-projects-modal-cancel"
              isDisabled={this.state.isDeleting}
              onClick={this.onDeleteModalClose}
            >
              Cancel
            </Button>
          ]}
        >
          Are you sure you want to delete &ldquo;{this.state.selectedProject && this.state.selectedProject.title}&rdquo;? This cannot be undone!
        </Modal>
      </React.Fragment>
    );
  }
Example #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: test-history.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const {
      columns,
      rows,
      onlyFailures,
      historySummary,
      dropdownSelection
    } = this.state;
    const pagination = {
      pageSize: this.state.pageSize,
      page: this.state.page,
      totalItems: this.state.totalItems
    }
    const dropdownValues = Object.assign({
      "1 Week": 0.25,
      "2 Weeks": 0.5,
      "1 Month": 1.0,
      "2 Months": 2.0,
      "3 Months": 3.0,
      "5 Months": 5.0
    })
    let dropdownItems = [];
    Object.keys(dropdownValues).forEach(key => {
      dropdownItems.push(
        <DropdownItem key={key} value={dropdownValues[key]} autoFocus={key === dropdownSelection}>
          {key}
        </DropdownItem>
      )
    });

    return (
      <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 History
                </Text>
              </TextContent>
            </FlexItem>
            <FlexItem>
              <TextContent>
                <Checkbox id="only-failures" label="Only show failures/errors" isChecked={onlyFailures} aria-label="only-failures-checkbox" onChange={this.onFailuresCheck}/>
              </TextContent>
            </FlexItem>
            <FlexItem>
              <Dropdown
                toggle={<DropdownToggle isDisabled={false} onToggle={this.onDropdownToggle}>Time range</DropdownToggle>}
                onSelect={this.onDropdownSelect}
                isOpen={this.state.isDropdownOpen}
                dropdownItems={dropdownItems}
              />
            </FlexItem>
            <FlexItem>
              <Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
            </FlexItem>
          </Flex>
        </CardHeader>
        <CardBody>
          <FilterTable
            columns={columns}
            rows={rows}
            pagination={pagination}
            isEmpty={this.state.isEmpty}
            isError={this.state.isError}
            onCollapse={this.onCollapse}
            onSetPage={this.setPage}
            onSetPageSize={this.pageSizeSelect}
            canSelectAll={false}
            variant={TableVariant.compact}
            activeFilters={this.state.filters}
            filters={[
              <Text key="summary" component="h4">
                Summary:&nbsp;
                {historySummary &&
                <RunSummary summary={historySummary}/>
                }
              </Text>,
              <Text key="last-passed" component="h4">Last passed:&nbsp;{this.state.lastPassedDate}</Text>,
            ]}
            onRemoveFilter={this.removeFilter}
            hideFilters={["project_id", "result", "test_id"]}
          />
        </CardBody>
      </Card>
    );
  }
Example #14
Source File: result.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    let { testResult, artifactTabs, activeTab, testHistoryTable } = this.state;
    const jsonViewTheme = getTheme() === 'dark' ? 'tomorrow' : 'rjv-default';
    if (activeTab === null) {
      activeTab = this.getDefaultTab();
    }
    let resultIcon = getIconForResult('pending');
    let startTime = new Date();
    let parameters = <div/>;
    let runLink = '';
    if (testResult) {
      resultIcon = getIconForResult(testResult.result);
      startTime = new Date(testResult.start_time);
      parameters = Object.keys(testResult.params).map((key) => <div key={key}>{key} = {testResult.params[key]}</div>);
      runLink = <Link to={`/runs/${testResult.run_id}`}>{testResult.run_id}</Link>;
    }
    return (
      <React.Fragment>
        {this.state.testResult &&
        <Tabs activeKey={activeTab} onSelect={this.onTabSelect} isBox>
          {!this.props.hideSummary &&
          <Tab eventKey="summary" title={<TabTitle icon={InfoCircleIcon} text="Summary" />}>
            <Card>
              <CardBody style={{padding: 0}}>
                <DataList selectedDataListItemId={null} aria-label="Test Result" style={{borderBottom: "none", borderTop: "none"}}>
                  <DataListItem isExpanded={false} aria-labelledby="result-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="result-label" width={2}><strong>Result:</strong></DataListCell>,
                          <DataListCell key="result-data" width={4}><span className={testResult.result}>{resultIcon} {testResult.result}</span></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  <DataListItem aria-labelledby="run-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="run-label" width={2}><strong>Run:</strong></DataListCell>,
                          <DataListCell key="run-data" width={4}>{runLink}</DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  {testResult.component &&
                  <DataListItem aria-labelledby="component-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="component-label" width={2}><strong>Component:</strong></DataListCell>,
                          <DataListCell key="component-data" width={4}><Link to={`/results?component[eq]=${testResult.component}`}>{testResult.component}</Link></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  {testResult.metadata && testResult.metadata.code_link &&
                  <DataListItem aria-labelledby="code-link-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="code-link-label" width={2}><strong>Code Link:</strong></DataListCell>,
                          <DataListCell key="code-link-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.code_link}</Linkify></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  {testResult.metadata && testResult.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>
                              {testResult.metadata.tags.map((tag) => <FlexItem spacer={{ default: 'spacerXs' }} key={tag}><Label color="blue" variant="filled">{tag}</Label></FlexItem>)}
                            </Flex>
                          </DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  {testResult.result === 'skipped' && testResult.metadata && testResult.metadata.skip_reason &&
                  <DataListItem aria-labelledby="skip-reason-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="skip-reason-label" width={2}><strong>Reason skipped:</strong></DataListCell>,
                          <DataListCell key="skip-reason-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.skip_reason}</Linkify></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  {testResult.result === 'xfailed' && testResult.metadata && testResult.metadata.xfail_reason &&
                  <DataListItem aria-labelledby="xfail-reason-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="xfail-reason-label" width={2}><strong>Reason xfailed:</strong></DataListCell>,
                          <DataListCell key="xfail-reason-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.xfail_reason}</Linkify></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  {(testResult.result === 'failed' || testResult.result === 'error' || testResult.result === 'skipped') &&
                  <DataListItem aria-labelledby="classification-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="classification-label" width={2}><strong>Classification:</strong></DataListCell>,
                          <DataListCell key="classification-data" width={4}>
                            <ClassificationDropdown testResult={testResult} />
                          </DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  }
                  <DataListItem aria-labelledby="duration">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="duration-label" width={2}><strong>Duration:</strong></DataListCell>,
                          <DataListCell key="duration-data" width={4} style={{paddingTop: 0, paddingBottom: 0, marginBottom: "-25px"}}>
                            <DataList selectedDataListItemId={null} aria-label="Durations" style={{borderTop: "none"}}>
                              {(testResult.start_time ? testResult.start_time : testResult.starttime) > 0 &&
                                <DataListItem className="pf-u-p-0" aria-labelledby="started-label">
                                  <DataListItemRow>
                                    <DataListItemCells
                                      dataListCells={[
                                        <DataListCell key="started-label" className="pf-u-p-sm">Started at:</DataListCell>,
                                        <DataListCell key="started-data" className="pf-u-p-sm">{startTime.toLocaleString()}</DataListCell>
                                      ]}
                                    />
                                  </DataListItemRow>
                                </DataListItem>
                              }
                              <DataListItem className="pf-u-p-0" aria-labelledby="total-label">
                                <DataListItemRow>
                                  <DataListItemCells
                                    dataListCells={[
                                      <DataListCell key="total-label" className="pf-u-p-sm">Total:</DataListCell>,
                                      <DataListCell key="total-data" className="pf-u-p-sm">{round(testResult.duration)}s</DataListCell>
                                    ]}
                                  />
                                </DataListItemRow>
                              </DataListItem>
                              {testResult.metadata && testResult.metadata.durations &&
                                <React.Fragment>
                                  {testResult.metadata.durations.setup &&
                                    <DataListItem className="pf-u-p-0" aria-labelledby="setup-label">
                                      <DataListItemRow>
                                        <DataListItemCells
                                          dataListCells={[
                                            <DataListCell key="setup-label" className="pf-u-p-sm">Set up:</DataListCell>,
                                            <DataListCell key="setup-data" className="pf-u-p-sm">{round(testResult.metadata.durations.setup)}s</DataListCell>
                                          ]}
                                        />
                                      </DataListItemRow>
                                    </DataListItem>
                                  }
                                  {testResult.metadata.durations.call &&
                                    <DataListItem className="pf-u-p-0" aria-labelledby="call-label">
                                      <DataListItemRow>
                                        <DataListItemCells
                                          dataListCells={[
                                            <DataListCell key="call-label" className="pf-u-p-sm">Call:</DataListCell>,
                                            <DataListCell key="call-data" className="pf-u-p-sm">{round(testResult.metadata.durations.call)}s</DataListCell>
                                          ]}
                                        />
                                      </DataListItemRow>
                                   </DataListItem>
                                  }
                                  {testResult.metadata.durations.teardown &&
                                    <DataListItem className="pf-u-p-0" aria-labelledby="teardown-label">
                                      <DataListItemRow>
                                        <DataListItemCells
                                          dataListCells={[
                                            <DataListCell key="teardown-label" className="pf-u-p-sm">Tear down:</DataListCell>,
                                            <DataListCell key="teardown-data" className="pf-u-p-sm">{round(testResult.metadata.durations.teardown)}s</DataListCell>
                                          ]}
                                        />
                                      </DataListItemRow>
                                    </DataListItem>
                                  }
                                </React.Fragment>
                              }
                            </DataList>
                          </DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  {testResult.metadata && testResult.metadata.statuses &&
                    <DataListItem aria-labelledby="stages-label">
                      <DataListItemRow>
                        <DataListItemCells
                          dataListCells={[
                            <DataListCell key="stages-label" width={2}><strong>Stages:</strong></DataListCell>,
                            <DataListCell key="stages-data" width={4} style={{paddingBottom: 0, paddingTop: 0, marginBottom: "-25px"}}>
                              <DataList selectedDataListItemId={null} aria-label="Stages" style={{borderTop: "none"}}>
                                {testResult.metadata.statuses.setup &&
                                  <DataListItem className="pf-u-p-0" aria-labelledby="setup-label">
                                    <DataListItemRow>
                                      <DataListItemCells
                                        dataListCells={[
                                          <DataListCell key="setup-label" className="pf-u-p-sm">Set up:</DataListCell>,
                                          <DataListCell key="setup-data" className="pf-u-p-sm">{testResult.metadata.statuses.setup[0]} {testResult.metadata.statuses.setup[1] && "(xfail)"}</DataListCell>
                                        ]}
                                      />
                                    </DataListItemRow>
                                  </DataListItem>
                                }
                                {testResult.metadata.statuses.call &&
                                  <DataListItem className="pf-u-p-0" aria-labelledby="call-label">
                                    <DataListItemRow>
                                      <DataListItemCells
                                        dataListCells={[
                                          <DataListCell key="call-label" className="pf-u-p-sm">Call:</DataListCell>,
                                          <DataListCell key="call-data" className="pf-u-p-sm">{testResult.metadata.statuses.call[0]} {testResult.metadata.statuses.call[1] && "(xfail)"}</DataListCell>
                                        ]}
                                      />
                                    </DataListItemRow>
                                  </DataListItem>
                                }
                                {testResult.metadata.statuses.teardown &&
                                  <DataListItem className="pf-u-p-0" aria-labelledby="teardown-label">
                                    <DataListItemRow>
                                      <DataListItemCells
                                        dataListCells={[
                                          <DataListCell key="teardown-label" className="pf-u-p-sm">Tear down:</DataListCell>,
                                          <DataListCell key="teardown-data" className="pf-u-p-sm">{testResult.metadata.statuses.teardown[0]} {testResult.metadata.statuses.teardown[1] && "(xfail)"}</DataListCell>
                                        ]}
                                      />
                                    </DataListItemRow>
                                  </DataListItem>
                                }
                              </DataList>
                            </DataListCell>
                          ]}
                        />
                      </DataListItemRow>
                    </DataListItem>
                  }
                  <DataListItem aria-labelledby="source-label">
                    <DataListItemRow>
                      <DataListItemCells
                        dataListCells={[
                          <DataListCell key="source-label" width={2}><strong>Source:</strong></DataListCell>,
                          <DataListCell key="source-data" width={4}><Link to={`/results?source[eq]=${testResult.source}`}>{testResult.source}</Link></DataListCell>
                        ]}
                      />
                    </DataListItemRow>
                  </DataListItem>
                  {parameters.length > 0 &&
                    <DataListItem aria-labelledby="params-label">
                      <DataListItemRow>
                        <DataListItemCells
                          dataListCells={[
                              <DataListCell key="params-label" width={2}><strong>Parameters:</strong></DataListCell>,
                              <DataListCell key="params-data" width={4}>{parameters}</DataListCell>
                          ]}
                        />
                      </DataListItemRow>
                    </DataListItem>
                  }
                  {testResult.metadata && Object.prototype.hasOwnProperty.call(testResult, 'short_tb') &&
                    <DataListItem aria-labelledby="traceback-label">
                      <DataListItemRow>
                        <DataListItemCells
                          dataListCells={[
                              <DataListCell key="traceback-label" width={2}><strong>Traceback:</strong></DataListCell>,
                              <DataListCell key="traceback-data" width={4}><div style={{overflow: "scroll", width: "100%"}}><pre><code>{testResult.metadata.short_tb}</code></pre></div></DataListCell>
                          ]}
                        />
                      </DataListItemRow>
                    </DataListItem>
                  }
                </DataList>
              </CardBody>
            </Card>
          </Tab>
          }
          {artifactTabs}
          {!this.props.hideTestHistory &&
          <Tab eventKey="test-history" title={<TabTitle icon={SearchIcon} text="Test History"/>}>
          {testHistoryTable}
          </Tab>
          }
          {!this.props.hideTestObject &&
          <Tab eventKey="test-object" title={<TabTitle icon={CodeIcon} text="Test Object" />}>
            <Card>
              <CardBody>
                <ReactJson src={testResult} name={null} iconStyle={"triangle"} collapseStringsAfterLength={120} enableClipboard={false} displayDataTypes={false} theme={jsonViewTheme} />
              </CardBody>
            </Card>
          </Tab>
          }
        </Tabs>
        }
      </React.Fragment>
    );
  }
Example #15
Source File: ibutsu-header.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    document.title = 'Ibutsu';
    const apiUiUrl = Settings.serverUrl + '/ui/';
    const uploadParams = {};
    if (this.state.selectedProject && this.state.selectedProject.project) {
      uploadParams['project'] = this.state.selectedProject.project.id;
    }
    const topNav = (
      <Flex>
        <FlexItem id="project-selector">
          <Select
            ariaLabelTypeAhead="Select a project"
            placeholderText="No active project"
            variant={SelectVariant.typeahead}
            isOpen={this.state.isProjectSelectorOpen}
            selections={this.state.selectedProject}
            onToggle={this.onProjectToggle}
            onSelect={this.onProjectSelect}
            onClear={this.onProjectClear}
            onTypeaheadInputChanged={this.onProjectsChanged}
            footer={this.state.projects.length == 10 && "Search for more..."}
          >
            {this.state.projects.map(project => (
              <SelectOption key={project.id} value={projectToOption(project)} description={project.name} />
            ))}
          </Select>
        </FlexItem>
      </Flex>
    );
    const headerTools = (
      <PageHeaderTools>
        <PageHeaderToolsGroup className={css(accessibleStyles.srOnly, accessibleStyles.visibleOnLg)}>
          <PageHeaderToolsItem>
            <Button variant="plain" onClick={this.toggleAbout}><QuestionCircleIcon /></Button>
          </PageHeaderToolsItem>
          <PageHeaderToolsItem>
            <FileUpload component="button" className="pf-c-button pf-m-plain" isUnstyled name="importFile" url={`${Settings.serverUrl}/import`} params={uploadParams} multiple={false} beforeUpload={this.onBeforeUpload} afterUpload={this.onAfterUpload} title="Import xUnit XML or Ibutsu Archive"><UploadIcon /> Import</FileUpload>
          </PageHeaderToolsItem>
          <PageHeaderToolsItem>
            <a href={apiUiUrl} className="pf-c-button pf-m-plain" target="_blank" rel="noopener noreferrer"><ServerIcon/> API</a>
          </PageHeaderToolsItem>
          <PageHeaderToolsItem>
            <Switch id="dark-theme" label={<MoonIcon />} isChecked={this.state.isDarkTheme} onChange={this.onThemeChanged} />
          </PageHeaderToolsItem>
          <PageHeaderToolsItem id="user-dropdown">
            <UserDropdown eventEmitter={this.eventEmitter}/>
          </PageHeaderToolsItem>
        </PageHeaderToolsGroup>
      </PageHeaderTools>
    );
    return (
      <React.Fragment>
        <AboutModal
          isOpen={this.state.isAboutOpen}
          onClose={this.toggleAbout}
          brandImageSrc="/images/ibutsu.svg"
          brandImageAlt="Ibutsu"
          productName="Ibutsu"
          backgroundImageSrc="/images/about-bg.jpg"
          trademark="Copyright (c) 2021 Red Hat, Inc."
        >
          <TextContent>
            <TextList component="dl">
              <TextListItem component="dt">Version</TextListItem>
              <TextListItem component="dd">{this.state.version}</TextListItem>
              <TextListItem component="dt">Source code</TextListItem>
              <TextListItem component="dd"><a href="https://github.com/ibutsu/ibutsu-server" target="_blank" rel="noopener noreferrer">github.com/ibutsu/ibutsu-server</a></TextListItem>
              <TextListItem component="dt">Documentation</TextListItem>
              <TextListItem component="dd"><a href="https://docs.ibutsu-project.org/" target="_blank" rel="noopener noreferrer">docs.ibutsu-project.org</a></TextListItem>
              <TextListItem component="dt">Report bugs</TextListItem>
              <TextListItem component="dd"><a href="https://github.com/ibutsu/ibutsu-server/issues/new" target="_blank" rel="noopener noreferrer">Submit an issue</a></TextListItem>
            </TextList>
          </TextContent>
          <p style={{marginTop: "2rem"}}>* Note: artifact files (screenshots, logs) are retained for 3 months</p>
        </AboutModal>
        <PageHeader
          logo={<Brand src="/images/ibutsu-wordart-164.png" alt="Ibutsu"/>}
          logoComponent={Link}
          logoProps={{to: '/'}}
          headerTools={headerTools}
          showNavToggle={true}
          topNav={topNav}
        />
      </React.Fragment>
    );
  }
Example #16
Source File: filtertable.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const {
      isEmpty,
      isError,
      onCollapse,
      onRowSelect,
      onApplyFilter,
      onRemoveFilter,
      onClearFilters,
      onApplyReport,
      onSetPage,
      onSetPageSize,
      variant
    } = this.props;
    let columns = this.props.columns || [];
    let rows = this.props.rows || [];
    let actions = this.props.actions || [];
    let filters = this.props.filters || [];
    let hideFilters = this.props.hideFilters || [];
    let activeFilters = this.props.activeFilters || {};
    let pagination = this.props.pagination || {page: 0, pageSize: 0, totalItems: 0};
    let canSelectAll = this.props.canSelectAll || false;
    return (
      <React.Fragment>
        <Flex>
          {(filters || onApplyFilter) &&
          <Flex spaceItems={{default: 'spaceItemsXs'}} grow={{default: 'grow'}}>
            {filters && filters.map((filter, index) => {
              return (
                <FlexItem key={index}>{filter}</FlexItem>
              );
            })}
            {onApplyFilter &&
            <FlexItem>
              <Button onClick={onApplyFilter}>Apply Filter</Button>
            </FlexItem>
            }
          </Flex>
          }
          <Flex align={{default: 'alignRight'}}>
            <FlexItem>
              <Pagination
                perPage={pagination.pageSize}
                page={pagination.page}
                variant={PaginationVariant.top}
                itemCount={pagination.totalItems}
                onSetPage={onSetPage}
                onPerPageSelect={onSetPageSize}
                isCompact
              />
            </FlexItem>
          </Flex>
        </Flex>
        {Object.keys(activeFilters).length > 0 &&
        <Flex style={{marginTop: "1rem"}}>
          <Flex>
            <FlexItem>
              Active filters
            </FlexItem>
          </Flex>
          <Flex grow={{default: 'grow'}}>
            {Object.keys(activeFilters).map(key => (
            <FlexItem spacer={{ default: 'spacerXs'}} key={key}>
              {!hideFilters.includes(key) &&
              <ChipGroup categoryName={key}>
                <Chip onClick={() => onRemoveFilter(key)}>
                  {(typeof activeFilters[key] === 'object') &&
                    <React.Fragment>
                      <Badge isRead={true}>{activeFilters[key]['op']}</Badge>
                      {activeFilters[key]['val']}
                    </React.Fragment>
                  }
                  {(typeof activeFilters[key] !== 'object') && activeFilters[key]}
                </Chip>
              </ChipGroup>
              }
            </FlexItem>
            ))}
          </Flex>
          {onApplyReport &&
          <Flex>
            <FlexItem style={{marginLeft: "0.75em"}}>
              <Button onClick={onApplyReport} variant="secondary">Use Active Filters in Report</Button>
            </FlexItem>
          </Flex>
          }
        </Flex>
        }
        <Table
          cells={columns}
          rows={rows}
          actions={actions}
          aria-label="List"
          canSelectAll={canSelectAll}
          onCollapse={onCollapse}
          onSelect={onRowSelect}
          variant={variant}
        >
          <TableHeader />
          <TableBody />
        </Table>
        {isEmpty && <TableEmptyState onClearFilters={onClearFilters} />}
        {isError && <TableErrorState onClearFilters={onClearFilters} />}
        <Pagination
          widgetId="pagination-options-menu-bottom"
          perPage={pagination.pageSize}
          page={pagination.page}
          variant={PaginationVariant.bottom}
          itemCount={pagination.totalItems}
          dropDirection="up"
          onSetPage={onSetPage}
          onPerPageSelect={onSetPageSize}
          style={{marginTop: "1rem"}}
        />
      </React.Fragment>
    );
  }
Example #17
Source File: certificateList.jsx    From cockpit-certificates with GNU Lesser General Public License v2.1 4 votes vote down vote up
generalDetails = ({ idPrefix, cas, cert, certPath, onAutorenewChanged }) => {
    const caName = getCAName(cas, cert);

    return (<Flex justifyContent={{ default: "justifyContentCenter" }}>
        <Flex direction={{ default:"column" }} flex={{ default: 'flex_1' }}>
            <DescriptionList isHorizontal>
                {cert.status && cert.status.v && <DescriptionListGroup>
                    <DescriptionListTerm>{_("Status")}</DescriptionListTerm>
                    <DescriptionListDescription id={`${idPrefix}-general-status`}>
                        {cert.stuck.v && (
                            <Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
                                <ExclamationTriangleIcon className="ct-icon-exclamation-triangle" />
                                <span id={`${idPrefix}-general-stuck`}>{_("Stuck: ")}</span>
                            </Flex>
                        )}
                        <Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
                            <FlexItem>
                                {cert.status.v.includes('_')
                                    ? cert.status.v
                                    : cert.status.v.charAt(0) + cert.status.v.slice(1).toLowerCase()}
                            </FlexItem>
                            <Tooltip position={TooltipPosition.top}
                                entryDelay={0}
                                content={certificateStates[cert.status.v]}>
                                <span className="info-circle">
                                    <InfoAltIcon />
                                </span>
                            </Tooltip>
                        </Flex>
                    </DescriptionListDescription>
                </DescriptionListGroup>}

                {cert.ca && cert.ca.v && <DescriptionListGroup>
                    <DescriptionListTerm>{_("Certificate authority")}</DescriptionListTerm>
                    <DescriptionListDescription id={`${idPrefix}-general-ca`}>{caName == "SelfSign" ? _("Self-signed") : caName}</DescriptionListDescription>
                </DescriptionListGroup>}

                {cert["not-valid-after"] && cert["not-valid-after"].v !== 0 && <DescriptionListGroup>
                    <DescriptionListTerm>
                        {_("Valid")}
                    </DescriptionListTerm>
                    <DescriptionListDescription id={`${idPrefix}-general-validity`}>
                        {prettyTime(cert["not-valid-before"].v) +
                        _(" to ") + prettyTime(cert["not-valid-after"].v)}
                    </DescriptionListDescription>
                </DescriptionListGroup>}

                {cert.autorenew && <DescriptionListGroup>
                    <DescriptionListTerm>
                        {_("Auto-renewal")}
                    </DescriptionListTerm>
                    <DescriptionListDescription>
                        <Checkbox id={`${idPrefix}-general-autorenewal`}
                                  isChecked={cert.autorenew.v}
                                  label={_("Renew before expiration")}
                                  onChange={() => onAutorenewChanged(cert, certPath)} />
                    </DescriptionListDescription>
                </DescriptionListGroup>}
            </DescriptionList>
        </Flex>
        <Flex direction={{ default:"column" }} flex={{ default: 'flex_1' }}>
            <DescriptionList isHorizontal>
                {cert.subject && cert.subject.v && <DescriptionListGroup>
                    <DescriptionListTerm>
                        {_("Subject name")}
                    </DescriptionListTerm>
                    <DescriptionListDescription>
                        <span id={`${idPrefix}-general-subject`}>{cert.subject.v}</span>
                    </DescriptionListDescription>
                </DescriptionListGroup>}

                {cert.principal && cert.principal.v.length > 0 && <DescriptionListGroup>
                    <DescriptionListTerm>
                        {_("Principal name")}
                    </DescriptionListTerm>
                    <DescriptionListDescription>
                        <span id={`${idPrefix}-general-principal`}>{cert.principal.v.join(", ")}</span>
                    </DescriptionListDescription>
                </DescriptionListGroup>}

                {cert.hostname && cert.hostname.v.length > 0 && <DescriptionListGroup>
                    <DescriptionListTerm>
                        {_("DNS name")}
                    </DescriptionListTerm>
                    <DescriptionListDescription>
                        <span id={`${idPrefix}-general-dns`}>{cert.hostname.v.join(", ")}</span>
                    </DescriptionListDescription>
                </DescriptionListGroup>}
            </DescriptionList>
        </Flex>
    </Flex>);
}
Example #18
Source File: AccessRequestDetailsPage.js    From access-requests-frontend with Apache License 2.0 4 votes vote down vote up
BaseAccessRequestDetailsPage = ({ isInternal }) => {
  const [request, setRequest] = React.useState();
  const { requestId } = useParams();
  const dispatch = useDispatch();
  React.useEffect(() => {
    apiInstance
      .get(
        `${API_BASE}/cross-account-requests/${requestId}/${
          isInternal ? '?query_by=user_id' : '?query_by=target_account'
        }`,
        { headers: { Accept: 'application/json' } }
      )
      .then((res) => {
        if (res.errors) {
          throw Error(res.errors.map((e) => e.detail).join('\n'));
        }
        setRequest(res);
      })
      .catch((err) => {
        dispatch(
          addNotification({
            variant: 'danger',
            title: 'Could not load access request',
            description: err.message,
          })
        );
      });
  }, []);

  // Modal actions
  const [openModal, setOpenModal] = React.useState({ type: null });
  const onModalClose = () => setOpenModal({ type: null });
  const actions = getInternalActions(
    request && request.status,
    requestId,
    setOpenModal
  );
  const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);

  const requestDisplayProps = [
    ...(isInternal
      ? ['request_id', 'target_account']
      : ['first_name', 'last_name']),
    'start_date',
    'end_date',
    'created',
  ];
  return (
    <React.Fragment>
      <PageSection variant="light">
        <Breadcrumb>
          <BreadcrumbItem
            render={() => (
              <Link to={isInternal ? '/' : '/access-requests'}>
                {!isInternal && 'Red Hat '}Access Requests
              </Link>
            )}
          />
          <BreadcrumbItem>{requestId}</BreadcrumbItem>
        </Breadcrumb>
        <Flex direction={{ default: 'column', md: 'row' }}>
          <FlexItem grow={{ default: 'grow' }}>
            <Title headingLevel="h1" size="2xl" className="pf-u-pt-md">
              {requestId}
            </Title>
          </FlexItem>
          {isInternal && actions.items.length > 0 && (
            <FlexItem alignSelf={{ default: 'alignRight' }}>
              <Dropdown
                position="right"
                toggle={
                  <KebabToggle
                    onToggle={() => setIsDropdownOpen(!isDropdownOpen)}
                    id="actions-toggle"
                  />
                }
                isOpen={isDropdownOpen}
                isPlain
                dropdownItems={actions.items.map(({ title, onClick }) => (
                  <DropdownItem
                    key={title}
                    component="button"
                    onClick={onClick}
                  >
                    {title}
                  </DropdownItem>
                ))}
                isDisabled={actions.disable}
              />
            </FlexItem>
          )}
        </Flex>
      </PageSection>
      <PageSection>
        <Flex
          spaceItems={{ xl: 'spaceItemsLg' }}
          direction={{ default: 'column', lg: 'row' }}
        >
          <FlexItem
            flex={{ default: 'flex_1' }}
            alignSelf={{ default: 'alignSelfStretch' }}
          >
            <Card ouiaId="request-details" style={{ height: '100%' }}>
              <CardTitle>
                <Title headingLevel="h2" size="xl">
                  Request details
                </Title>
              </CardTitle>
              <CardBody>
                {!request ? (
                  <Spinner size="xl" />
                ) : (
                  <React.Fragment>
                    <div className="pf-u-pb-md">
                      {isInternal ? (
                        <div>
                          <label>
                            <b>Request status</b>
                          </label>
                          <br />
                          <Label
                            className="pf-u-mt-sm"
                            {...getLabelProps(request.status)}
                          >
                            {capitalize(request.status)}
                          </Label>
                        </div>
                      ) : (
                        <React.Fragment>
                          <label>
                            <b>Request decision</b>
                          </label>
                          <br />
                          <StatusLabel
                            requestId={requestId}
                            status={request.status}
                          />
                        </React.Fragment>
                      )}
                    </div>
                    {requestDisplayProps.map((prop, key) => (
                      <div className="pf-u-pb-md" key={key}>
                        <label>
                          <b>
                            {capitalize(
                              prop.replace(/_/g, ' ').replace('id', 'ID')
                            )}
                          </b>
                        </label>
                        <br />
                        <div>{request[prop]}</div>
                      </div>
                    ))}
                  </React.Fragment>
                )}
              </CardBody>
            </Card>
          </FlexItem>
          <FlexItem
            flex={{ default: 'flex_3' }}
            grow={{ default: 'grow' }}
            alignSelf={{ default: 'alignSelfStretch' }}
          >
            <Card ouiaId="request-roles" style={{ height: '100%' }}>
              <CardTitle>
                <Title headingLevel="h2" size="xl">
                  Roles requested
                </Title>
              </CardTitle>
              <CardBody>
                {!request ? (
                  <Spinner size="xl" />
                ) : (
                  <MUARolesTable roles={request.roles} />
                )}
              </CardBody>
            </Card>
          </FlexItem>
        </Flex>
      </PageSection>
      {openModal.type === 'cancel' && (
        <CancelRequestModal requestId={requestId} onClose={onModalClose} />
      )}
      {openModal.type === 'edit' && (
        <EditRequestModal
          variant="edit"
          requestId={requestId}
          onClose={onModalClose}
        />
      )}
    </React.Fragment>
  );
}
Example #19
Source File: index.js    From sed-frontend with Apache License 2.0 4 votes vote down vote up
SamplePage = () => {
  const history = useHistory();
  const { getRegistry } = useContext(RegistryContext);
  const [confirmChangesOpen, setConfirmChangesOpen] = useState(false);
  const [madeChanges, setMadeChanges] = useState(false);
  const [isEditing, setIsEditing] = useState(false);
  const dataRef = useRef();
  const dispatch = useDispatch();

  const activeStateLoaded = useSelector(
    ({ activeStateReducer }) => activeStateReducer?.loaded
  );
  const { useOpenSCAP, enableCloudConnector, hasInsights } = useSelector(
    ({ activeStateReducer }) => ({
      useOpenSCAP: activeStateReducer?.values?.useOpenSCAP,
      enableCloudConnector: activeStateReducer?.values?.enableCloudConnector,
      hasInsights: activeStateReducer?.values?.hasInsights,
    }),
    shallowEqual
  );
  const { systemsCount } = useSelector(
    ({ connectedSystemsReducer }) => ({
      systemsLoaded: connectedSystemsReducer?.loaded,
      systemsCount: connectedSystemsReducer?.total,
    }),
    shallowEqual
  );

  useEffect(() => {
    getRegistry().register({
      activeStateReducer,
      logReducer,
      connectedSystemsReducer,
    });
    dispatch(fetchCurrState());
    dispatch(fetchConnectedHosts());
  }, [getRegistry]);

  useEffect(() => {
    insights?.chrome?.appAction?.('cloud-connector-dashboard');
  }, []);

  return (
    <React.Fragment>
      <Route
        exact
        path={paths.logModal}
        render={() => (
          <Suspense
            fallback={
              <Bullseye>
                <Spinner />
              </Bullseye>
            }
          >
            <ConnectLog />
          </Suspense>
        )}
      />
      <PageHeader className="page-header">
        <Split hasGutter className="page-title">
          <SplitItem isFilled>
            <Flex>
              <FlexItem spacer={{ default: 'spacerSm' }}>
                <PageHeaderTitle title="Remote Host Configuration Manager" />
              </FlexItem>
              <FlexItem>
                <AboutRemoteHostConfigPopover />
              </FlexItem>
            </Flex>
          </SplitItem>
          <SplitItem>
            <Button onClick={() => history.push(paths.logModal)} variant="link">
              View log
            </Button>
          </SplitItem>
        </Split>
        <Stack hasGutter>
          <StackItem>
            Selections here affect Red Hat Enterprise Linux (RHEL) systems
            connected to Red Hat with remote host configuration (rhc). Upon
            saving changes, Ansible Playbooks are automatically pushed to
            connected systems to update the configuration of the connection to
            Red Hat.
          </StackItem>
          <StackItem>
            <a
              target="_blank"
              rel="noopener noreferrer"
              href={
                'https://access.redhat.com/documentation/en-us/red_hat_insights/2022/html-single/red_hat_connector_configuration_guide/index'
              }
            >
              Connecting with Red Hat
              {<ExternalLinkAltIcon className="pf-u-ml-sm" />}
            </a>
          </StackItem>
        </Stack>
      </PageHeader>
      <Page>
        <div className="dashboard__content">
          {activeStateLoaded ||
          (useOpenSCAP !== undefined && enableCloudConnector !== undefined) ? (
            <Services
              madeChanges={madeChanges}
              setConfirmChangesOpen={setConfirmChangesOpen}
              setMadeChanges={setMadeChanges}
              setIsEditing={setIsEditing}
              isEditing={isEditing}
              defaults={{
                useOpenSCAP,
                enableCloudConnector,
                hasInsights,
              }}
              onChange={(data) => {
                dataRef.current = data;
              }}
            />
          ) : (
            <Bullseye>
              <Spinner className="pf-u-p-lg" size="xl" />
            </Bullseye>
          )}
        </div>
      </Page>
      <ConfirmChangesModal
        isOpen={confirmChangesOpen}
        handleCancel={() => setConfirmChangesOpen(false)}
        systemsCount={systemsCount}
        data={dataRef.current}
        handleConfirm={() => {
          setConfirmChangesOpen(false);
          (async () => {
            const saveAction = saveCurrState(dataRef.current);
            dispatch(saveAction);
            await saveAction.payload;
            dispatch(
              addNotification({
                variant: 'success',
                title: 'Changes saved',
                description:
                  'Your service enablement changes were applied to connected systems',
              })
            );
            setMadeChanges(false);
            setIsEditing(false);
          })();
        }}
      />
    </React.Fragment>
  );
}
Example #20
Source File: Services.js    From sed-frontend with Apache License 2.0 4 votes vote down vote up
Services = ({
  defaults,
  setConfirmChangesOpen,
  onChange,
  isEditing,
  setIsEditing,
}) => {
  const initState = {
    enableCloudConnector: {
      value: defaults.enableCloudConnector,
      isDisabled: false,
    },
    useOpenSCAP: { value: defaults.useOpenSCAP, isDisabled: false },
  };
  const [formState, setFormState] = useState(initState);
  const [madeChanges, setMadeChanges] = useState(false);

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

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

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

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

  return (
    <Stack hasGutter className="pf-u-p-md">
      <StackItem>
        <Toolbar id="toolbar-items">
          <ToolbarContent>
            {!isEditing && (
              <ToolbarItem>
                {!hasAccess ? (
                  <Tooltip
                    content={
                      <div>
                        To perform this action, you must be granted the
                        &quot;System Administrator&quot; role by your
                        Organization Administrator in your Setting&apos;s User
                        Access area.
                      </div>
                    }
                  >
                    {changeSettingsButton(isLoading, hasAccess, setIsEditing)}
                  </Tooltip>
                ) : (
                  changeSettingsButton(isLoading, hasAccess, setIsEditing)
                )}
              </ToolbarItem>
            )}
            {isEditing && (
              <>
                <ToolbarItem>
                  <Button
                    ouiaId="primary-save-button"
                    onClick={() => setConfirmChangesOpen(true)}
                    isDisabled={!madeChanges}
                  >
                    Save changes
                  </Button>
                </ToolbarItem>
                <ToolbarItem>
                  <Button
                    ouiaId="secondary-cancel-button"
                    onClick={() => cancelEditing()}
                    variant="secondary"
                  >
                    Cancel
                  </Button>
                </ToolbarItem>
                <ToolbarItem>
                  <Alert
                    variant="info"
                    isInline
                    isPlain
                    title="Changes will affect all systems connected with Red Hat connector"
                  />
                </ToolbarItem>
              </>
            )}
          </ToolbarContent>
        </Toolbar>
      </StackItem>
      <StackItem>
        <TableComposable aria-label="Settings table">
          <Thead>
            <Tr>
              <Th>Permission</Th>
              <Th>Status</Th>
            </Tr>
          </Thead>
          <Tbody>
            {permissions.map((row) => (
              <Tr key={row.name}>
                <Td
                  dataLabel="Permission"
                  width={80}
                  style={row.secondary && { paddingLeft: 70, fontSize: 14 }}
                >
                  <Stack>
                    <StackItem>
                      <Flex>
                        <FlexItem>
                          <b>{row.name}</b>
                        </FlexItem>
                        {row.additionalInfo && (
                          <FlexItem
                            style={{ color: 'var(--pf-global--Color--100)' }}
                          >
                            <i>{row.additionalInfo}</i>
                          </FlexItem>
                        )}
                      </Flex>
                    </StackItem>
                    <StackItem style={{ fontSize: 14 }}>
                      {row.description}
                    </StackItem>
                    {row.links && (
                      <StackItem className="stack-item">
                        <Flex>
                          {row.links.map((link) => (
                            <FlexItem key={link.name}>
                              <a
                                href={link.link}
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                {link.name}
                                <ExternalLinkAltIcon className="pf-u-ml-sm" />
                              </a>
                            </FlexItem>
                          ))}
                        </Flex>
                      </StackItem>
                    )}
                  </Stack>
                </Td>
                {!isEditing && <Td dataLabel="Status">{getStatusIcon(row)}</Td>}
                {isEditing && (
                  <Td dataLabel="Status">
                    <ToggleGroup aria-label="Default with single selectable">
                      <ToggleGroupItem
                        text="Enabled"
                        isSelected={formState[row.id].value}
                        onChange={() =>
                          setFormState({
                            ...formState,
                            [row.id]: { ...formState[row.id], value: true },
                          })
                        }
                        isDisabled={formState[row.id].isDisabled}
                      />
                      <ToggleGroupItem
                        text="Disabled"
                        isSelected={!formState[row.id].value}
                        onChange={() =>
                          setFormState({
                            ...formState,
                            [row.id]: { ...formState[row.id], value: false },
                          })
                        }
                        isDisabled={formState[row.id].isDisabled}
                      />
                    </ToggleGroup>
                  </Td>
                )}
              </Tr>
            ))}
          </Tbody>
        </TableComposable>
      </StackItem>
    </Stack>
  );
}
Example #21
Source File: ActivationKeys.js    From sed-frontend with Apache License 2.0 4 votes vote down vote up
ActivationKeys = () => {
  const queryClient = useQueryClient();
  const user = queryClient.getQueryData('user');
  const { isLoading, error, data } = useActivationKeys();
  const [isOpen, setisOpen] = useState(false);
  const [currentKeyName, setCurrentKeyName] = useState('');

  const [isDeleteActivationKeyModalOpen, setIsDeleteActivationKeyModalOpen] =
    useState(false);
  const [isEditActivationKeyModalOpen, setIsEditActivationKeyModalOpen] =
    useState(false);
  const handleModalToggle = () => {
    setisOpen(!isOpen);
  };

  const actions = (activationKeyName) => {
    return [
      {
        title: 'Edit',
        onClick: () => handleEditActivationKeyModalToggle(activationKeyName),
      },
      {
        title: 'Delete',
        onClick: () => handleDeleteActivationKeyModalToggle(activationKeyName),
      },
    ];
  };
  let pageContent;
  if (isLoading) {
    pageContent = <Loading />;
  } else if (!isLoading && !error && !data.length) {
    pageContent = (
      <NoActivationKeysFound handleModalToggle={handleModalToggle} />
    );
  } else if (!isLoading && !error && data.length) {
    pageContent = (
      <>
        <ActionGroup>
          <CreateActivationKeyButton onClick={handleModalToggle} />
        </ActionGroup>
        <ActivationKeysTable actions={actions} />
      </>
    );
  }

  const setKeyName = (modalOpen, name) => {
    let currentName = modalOpen ? '' : name;
    setCurrentKeyName(currentName);
  };

  const handleDeleteActivationKeyModalToggle = (name) => {
    setKeyName(isDeleteActivationKeyModalOpen, name);
    setIsDeleteActivationKeyModalOpen(!isDeleteActivationKeyModalOpen);
  };

  const handleEditActivationKeyModalToggle = (name) => {
    setKeyName(isEditActivationKeyModalOpen, name);
    setIsEditActivationKeyModalOpen(!isEditActivationKeyModalOpen);
  };

  const Page = () => {
    return (
      <React.Fragment>
        <PageHeader>
          <Split hasGutter className="page-title">
            <SplitItem isFilled>
              <Flex>
                <FlexItem spacer={{ default: 'spacerSm' }}>
                  <PageHeaderTitle title="Activation Keys" />
                </FlexItem>
                <FlexItem>
                  <ActivationKeysDocsPopover orgId={user.orgId} />
                </FlexItem>
              </Flex>
            </SplitItem>
          </Split>
          <TextContent>
            <Text component={TextVariants.p}>
              Organization ID: {user.orgId}
            </Text>
          </TextContent>
        </PageHeader>
        <Main>
          <PageSection variant={PageSectionVariants.light}>
            {pageContent}
          </PageSection>
        </Main>
        <CreateActivationKeyModal
          isOpen={isOpen}
          handleModalToggle={handleModalToggle}
        />
        <EditActivationKeyModal
          isOpen={isEditActivationKeyModalOpen}
          handleModalToggle={handleEditActivationKeyModalToggle}
          activationKeyName={currentKeyName}
        />
        <DeleteActivationKeyConfirmationModal
          handleModalToggle={handleDeleteActivationKeyModalToggle}
          isOpen={isDeleteActivationKeyModalOpen}
          name={currentKeyName}
        />
      </React.Fragment>
    );
  };

  if (user.rbacPermissions.canReadActivationKeys) {
    return <Page />;
  } else {
    return <NoAccessView />;
  }
}
Example #22
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 #23
Source File: GroupsDetail.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
GroupsDetail = () => {
  const dispatch = useDispatch();
  const params = useParams();
  const history = useHistory();
  const { groupId } = params;

  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
  const [isAddModalOpen, setIsAddModalOpen] = useState(false);
  const [removeModal, setRemoveModal] = useState({
    isOpen: false,
    name: '',
    deviceId: null,
  });
  const [updateModal, setUpdateModal] = useState({
    isOpen: false,
    deviceData: null,
    imageData: null,
  });
  const [response, fetchDevices] = useApi({
    api: getGroupById,
    id: groupId,
    tableReload: true,
  });
  const { data, isLoading, hasError } = response;
  const groupName = data?.DeviceGroup?.Name;
  const [deviceIds, getDeviceIds] = useState([]);
  const [hasModalSubmitted, setHasModalSubmitted] = useState(false);
  const [modalState, setModalState] = useState({ id: null, name: '' });
  const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
  const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);

  const handleDeleteModal = (id, name) => {
    setModalState({ id, name });
    setIsDeleteModalOpen(true);
  };

  const handleRenameModal = (id, name) => {
    setModalState({ id, name });
    setIsRenameModalOpen(true);
  };

  const removeDeviceLabel = () =>
    `Do you want to remove ${
      deviceIds.length > 0
        ? `${deviceIds.length} system${deviceIds.length === 1 ? '' : 's'}`
        : `${removeModal.name}`
    } from ${groupName}?`;

  useEffect(() => {
    history.push({
      pathname: history.location.pathname,
      search: stateToUrlSearch('add_system_modal=true', isAddModalOpen),
    });
  }, [isAddModalOpen]);

  const handleSingleDeviceRemoval = () => {
    const statusMessages = {
      onSuccess: {
        title: 'Success',
        description: `${removeModal.name} has been removed successfully`,
      },
      onError: { title: 'Error', description: 'Failed to remove device' },
    };
    apiWithToast(
      dispatch,
      () => removeDeviceFromGroupById(groupId, removeModal.deviceId),
      statusMessages
    );
    setTimeout(() => setHasModalSubmitted(true), 800);
  };

  const handleBulkDeviceRemoval = () => {
    const statusMessages = {
      onSuccess: {
        title: 'Success',
        description: `${deviceIds.length} systems have been removed successfully`,
      },
      onError: { title: 'Error', description: 'failed to remove systems' },
    };
    apiWithToast(
      dispatch,
      () =>
        removeDevicesFromGroup(
          parseInt(groupId),
          deviceIds.map((device) => ({ ID: device.deviceID }))
        ),
      statusMessages
    );
    setTimeout(() => setHasModalSubmitted(true), 800);
  };

  return (
    <>
      <PageHeader className="pf-m-light">
        {groupName ? (
          <Breadcrumb>
            <BreadcrumbItem>
              <Link to={`${paths['fleet-management']}`}>Groups</Link>
            </BreadcrumbItem>
            <BreadcrumbItem>{groupName}</BreadcrumbItem>
          </Breadcrumb>
        ) : (
          <Breadcrumb isActive>
            <Skeleton width="100px" />
          </Breadcrumb>
        )}
        <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
          <FlexItem>
            {groupName ? (
              <PageHeaderTitle title={groupName} />
            ) : (
              <Skeleton width="150px" />
            )}
          </FlexItem>
          <FlexItem>
            <Dropdown
              position={DropdownPosition.right}
              toggle={
                <DropdownToggle
                  id="image-set-details-dropdown"
                  toggleIndicator={CaretDownIcon}
                  onToggle={(newState) => setIsDropdownOpen(newState)}
                  isDisabled={false}
                >
                  Actions
                </DropdownToggle>
              }
              isOpen={isDropdownOpen}
              dropdownItems={[
                <DropdownItem
                  key="delete-device-group"
                  onClick={() => handleDeleteModal(groupId, groupName)}
                >
                  Delete group
                </DropdownItem>,
                <DropdownItem
                  key="rename-device-group"
                  onClick={() => handleRenameModal(groupId, groupName)}
                >
                  Rename group
                </DropdownItem>,
                <DropdownItem
                  key="update-all-devices"
                  isDisabled={canUpdateSelectedDevices({
                    deviceData: data?.DevicesView?.devices?.map((device) => ({
                      imageSetId: device?.ImageSetID,
                    })),
                    imageData: data?.DevicesView?.devices?.some(
                      (device) => device.ImageID
                    ),
                  })}
                  onClick={() => {
                    setIsDropdownOpen(false);
                    setUpdateModal((prevState) => ({
                      ...prevState,
                      isOpen: true,
                      deviceData: data?.DevicesView?.devices?.map((device) => ({
                        id: device?.DeviceUUID,
                        display_name:
                          device?.DeviceName === ''
                            ? 'localhost'
                            : device?.DeviceName,
                      })),
                      imageSetId: data?.DevicesView?.devices.find(
                        (device) => device.ImageSetID
                      )?.ImageSetID,
                    }));
                  }}
                >
                  Update
                </DropdownItem>,
              ]}
            />
          </FlexItem>
        </Flex>
      </PageHeader>
      <Main className="edge-devices">
        {!emptyStateNoFliters(
          isLoading,
          data?.DeviceGroup?.Devices.length,
          history
        ) ? (
          <DeviceTable
            data={data?.DevicesView?.devices || []}
            count={data?.DevicesView?.total}
            isLoading={isLoading}
            hasError={hasError}
            hasCheckbox={true}
            handleSingleDeviceRemoval={handleSingleDeviceRemoval}
            kebabItems={[
              {
                isDisabled: !(deviceIds.length > 0),
                title: 'Remove from group',
                onClick: () =>
                  setRemoveModal({
                    name: '',
                    deviceId: null,
                    isOpen: true,
                  }),
              },
              {
                isDisabled: canUpdateSelectedDevices({
                  deviceData: deviceIds,
                  imageData: deviceIds[0]?.updateImageData,
                }),
                title: 'Update selected',
                onClick: () =>
                  setUpdateModal((prevState) => ({
                    ...prevState,
                    isOpen: true,
                    deviceData: [...deviceIds],
                    imageSetId: deviceIds.find((device) => device?.imageSetId)
                      .imageSetId,
                  })),
              },
            ]}
            selectedItems={getDeviceIds}
            setRemoveModal={setRemoveModal}
            setIsAddModalOpen={setIsAddModalOpen}
            setUpdateModal={setUpdateModal}
            hasModalSubmitted={hasModalSubmitted}
            setHasModalSubmitted={setHasModalSubmitted}
            fetchDevices={fetchDevices}
            isAddSystemsView={true}
          />
        ) : (
          <Flex justifyContent={{ default: 'justifyContentCenter' }}>
            <Empty
              icon="plus"
              title="Add systems to the group"
              body="Create groups to help manage your systems more effectively."
              primaryAction={{
                text: 'Add systems',
                click: () => setIsAddModalOpen(true),
              }}
              secondaryActions={[
                {
                  type: 'link',
                  title: 'Learn more about system groups',
                  link: 'https://access.redhat.com/documentation/en-us/edge_management/2022/html-single/working_with_systems_in_the_edge_management_application/index',
                },
              ]}
            />
          </Flex>
        )}
      </Main>
      {isAddModalOpen && (
        <AddSystemsToGroupModal
          groupId={groupId}
          closeModal={() => setIsAddModalOpen(false)}
          isOpen={isAddModalOpen}
          reloadData={fetchDevices}
          groupName={data?.DeviceGroup?.Name}
        />
      )}
      {removeModal.isOpen && (
        <Modal
          isOpen={removeModal.isOpen}
          openModal={() => setRemoveModal(false)}
          title={'Remove from group'}
          submitLabel={'Remove'}
          variant="danger"
          schema={{
            fields: [
              {
                component: componentTypes.PLAIN_TEXT,
                name: 'warning-text',
                label: removeDeviceLabel(),
              },
            ],
          }}
          onSubmit={
            removeModal.deviceId
              ? handleSingleDeviceRemoval
              : handleBulkDeviceRemoval
          }
          reloadData={fetchDevices}
        />
      )}

      {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={fetchDevices}
          />
        </Suspense>
      )}
      {isDeleteModalOpen && (
        <DeleteGroupModal
          isModalOpen={isDeleteModalOpen}
          setIsModalOpen={setIsDeleteModalOpen}
          reloadData={() => history.push(paths['fleet-management'])}
          modalState={modalState}
        />
      )}
      {isRenameModalOpen && (
        <RenameGroupModal
          isModalOpen={isRenameModalOpen}
          setIsModalOpen={setIsRenameModalOpen}
          reloadData={() => fetchDevices()}
          modalState={modalState}
        />
      )}
    </>
  );
}
Example #24
Source File: Groups.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
Groups = () => {
  const history = useHistory();
  const [response, fetchGroups] = useApi({
    api: getGroups,
    tableReload: true,
  });
  const { data, isLoading, hasError } = response;

  const [modalState, setModalState] = useState({ id: null, name: '' });
  const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
  const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);
  const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);

  const handleRenameModal = (id, name) => {
    setModalState({ id, name });
    setIsRenameModalOpen(true);
  };

  const handleDeleteModal = (id, name) => {
    setModalState({ id, name });
    setIsDeleteModalOpen(true);
  };

  return (
    <>
      <PageHeader className="pf-m-light">
        <PageHeaderTitle title="Groups" />
      </PageHeader>
      <Main className="edge-devices">
        {!emptyStateNoFliters(isLoading, data?.count, history) ? (
          <GroupTable
            data={data?.data || []}
            count={data?.count}
            isLoading={isLoading}
            hasError={hasError}
            handleRenameModal={handleRenameModal}
            handleDeleteModal={handleDeleteModal}
            handleCreateModal={() => setIsCreateModalOpen(true)}
            fetchGroups={fetchGroups}
          />
        ) : (
          <Flex justifyContent={{ default: 'justifyContentCenter' }}>
            <Empty
              icon="plus"
              title="Create a system group"
              body="Create system groups to help manage your devices more effectively."
              primaryAction={{
                text: 'Create group',
                click: () => setIsCreateModalOpen(true),
              }}
              secondaryActions={[
                {
                  type: 'link',
                  title: 'Learn more about system groups',
                  link: 'https://access.redhat.com/documentation/en-us/edge_management/2022/html-single/working_with_systems_in_the_edge_management_application/index',
                },
              ]}
            />
          </Flex>
        )}
      </Main>

      {isCreateModalOpen && (
        <CreateGroupModal
          isModalOpen={isCreateModalOpen}
          setIsModalOpen={setIsCreateModalOpen}
          reloadData={fetchGroups}
        />
      )}
      {isRenameModalOpen && (
        <RenameGroupModal
          isModalOpen={isRenameModalOpen}
          setIsModalOpen={setIsRenameModalOpen}
          reloadData={fetchGroups}
          modalState={modalState}
        />
      )}
      {isDeleteModalOpen && (
        <DeleteGroupModal
          isModalOpen={isDeleteModalOpen}
          setIsModalOpen={setIsDeleteModalOpen}
          reloadData={fetchGroups}
          modalState={modalState}
        />
      )}
    </>
  );
}
Example #25
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>
    );
}