@patternfly/react-core#StackItem JavaScript Examples

The following examples show how to use @patternfly/react-core#StackItem. 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: EmptyStates.js    From ocp-advisor-frontend with Apache License 2.0 6 votes vote down vote up
ErrorState = () => {
  const intl = useIntl();
  return (
    <MessageState
      title={intl.formatMessage(messages.errorStateTitle)}
      text={
        <Stack>
          <StackItem>{intl.formatMessage(messages.errorStateBody)}</StackItem>
          <StackItem>
            <DefaultErrorMessage />
          </StackItem>
        </Stack>
      }
      icon={ExclamationCircleIcon}
      iconStyle={{ color: globalDangerColor100.value }}
    />
  );
}
Example #2
Source File: LogNestedtable.js    From sed-frontend with Apache License 2.0 6 votes vote down vote up
LogNestedTable = ({ services, isInsights }) => {
  return (
    <Stack>
      <StackItem>
        <TextContent>
          <Text component={TextVariants.h3}>State pushed to systems</Text>
        </TextContent>
      </StackItem>
      <Table
        aria-label="Active services Table"
        className="sed-c-services__table"
        cells={columns}
        rows={[
          {
            noPadding: true,
            cells: [
              'Connected to Red Hat Insighsts',
              isInsights ? 'on' : 'off',
            ],
          },
          ...Object.entries(services).map(([key, value]) => [
            rowMapper[key],
            value === 'enabled' ? 'on' : 'off',
          ]),
        ]}
        variant="compact"
      >
        <TableHeader />
        <TableBody />
      </Table>
    </Stack>
  );
}
Example #3
Source File: customPackage.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
CustomPackageLabel = () => {
  const { getState, change } = useFormApi();
  const addedRepos = getState()?.values?.['third-party-repositories'];
  const initialRepos = getState()?.values?.['initial-custom-repositories'];
  const customPackages = getState()?.values?.['custom-packages'];

  const release = getState()?.values?.release;
  const releaseName = release !== undefined ? releaseMapper[release] : '';

  useEffect(() => {
    change('validate-custom-repos', true);
    change('show-custom-packages', true);
  }, []);

  return (
    <>
      <TextContent>
        <Text>
          Add packages from{' '}
          <Popover
            style={{ visibility: 'visible' }}
            position="bottom"
            headerContent="Custom Repositories"
            bodyContent={
              <Stack>
                {addedRepos.map((repo) => (
                  <StackItem key={repo}>
                    <Text>{repo.name}</Text>
                  </StackItem>
                ))}
              </Stack>
            }
          >
            <Button variant="link" isInline>
              {addedRepos.length} custom repositories
            </Button>{' '}
            to your
          </Popover>
          <b> {releaseName}</b> image.
        </Text>
      </TextContent>
      {addedRepos.length === 0 && customPackages.length > 0
        ? showAlert('danger')
        : checkRepoNameMismatch(initialRepos, addedRepos, customPackages)
        ? showAlert('warning')
        : null}
    </>
  );
}
Example #4
Source File: ImageVersionDetail.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
ImageVersionDetail = ({ data, imageVersion }) => {
  const history = useHistory();
  const [isUpdateWizardOpen, setIsUpdateWizardOpen] = useState(false);
  const [imageData, setImageData] = useState({});

  useEffect(() => {
    setImageData(data);
  }, [data]);

  const openUpdateWizard = () => {
    history.push({
      pathname: history.location.pathname,
      search: new URLSearchParams({
        update_image: true,
      }).toString(),
    });
    setIsUpdateWizardOpen(true);
  };

  return (
    <Fragment>
      <PageHeader className="pf-m-light">
        <Stack hasGutter>
          <StackItem>
            <DetailsHead
              imageData={imageData}
              imageVersion={imageVersion}
              openUpdateWizard={openUpdateWizard}
            />
          </StackItem>
        </Stack>
        <StackItem>
          <Text>{data?.Description}</Text>
        </StackItem>
      </PageHeader>
      <ImageDetailTabs imageData={imageData} imageVersion={imageVersion} />
      {isUpdateWizardOpen && (
        <Suspense
          fallback={
            <Bullseye>
              <Spinner />
            </Bullseye>
          }
        >
          <UpdateImageWizard
            navigateBack={() => {
              history.push({ pathname: history.location.pathname });
              setIsUpdateWizardOpen(false);
            }}
            updateimageVersionId={data?.ID}
          />
        </Suspense>
      )}
    </Fragment>
  );
}
Example #5
Source File: DeviceSummaryTile.js    From edge-frontend with Apache License 2.0 5 votes vote down vote up
DeviceSummaryTileBase = ({
  orphaned,
  active,
  noReports,
  neverReported,
}) => (
  <Card className="tiles-card">
    <CardTitle>Device summary</CardTitle>
    <CardBody>
      <Grid>
        <GridItem span={6}>
          <Stack hasGutter>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {active}
              </Button>{' '}
              Active
            </StackItem>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {orphaned}
              </Button>{' '}
              Orphaned
            </StackItem>
          </Stack>
        </GridItem>
        <GridItem span={6}>
          <Stack hasGutter>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {noReports}
              </Button>
              Stale
            </StackItem>
            <StackItem>
              <Button isDisabled isInline className="pf-u-pr-md" variant="link">
                {neverReported}
              </Button>
              Registered but never reported
            </StackItem>
          </Stack>
        </GridItem>
      </Grid>
    </CardBody>
  </Card>
)
Example #6
Source File: TasksPage.js    From tasks-frontend with Apache License 2.0 5 votes vote down vote up
TasksPage = ({ tab }) => {
  const history = useHistory();
  const [tabIndex, setTab] = useState(tab);
  const [runTaskModalOpened, setRunTaskModalOpened] = useState(false);
  const [activeTask, setActiveTask] = useState({});
  const [error, setError] = useState();

  useEffect(() => {
    if (tab === 0) {
      history.push('available');
    }
  }, []);

  const updateTab = (event, index) => {
    history.push(index ? 'executed' : 'available');
    setTab(index);
  };

  const openTaskModal = async (slug) => {
    const task = await fetchAvailableTask(slug);
    if (task?.response?.status && task?.response?.status !== 200) {
      setError(task);
      dispatchNotification({
        variant: 'danger',
        title: 'Error',
        description: task.message,
        dismissable: true,
      });
    } else {
      setActiveTask(task);
    }

    setRunTaskModalOpened(true);
  };

  return (
    <React.Fragment>
      <RunTaskModal
        error={error}
        task={activeTask}
        isOpen={runTaskModalOpened}
        setModalOpened={setRunTaskModalOpened}
      />
      <PageHeader>
        <FlexibleFlex
          flexContents={TASKS_PAGE_HEADER}
          flexProps={TASKS_PAGE_HEADER_FLEX_PROPS}
        />
      </PageHeader>
      <TasksTabs
        className="tabs-background"
        tabIndex={tabIndex}
        updateTab={updateTab}
        tabsList={TASKS_PAGE_TABS}
      />
      <Main>
        <Stack hasGutter>
          <StackItem>
            {tabIndex === 0 ? (
              <AvailableTasks openTaskModal={openTaskModal} />
            ) : (
              <CompletedTasksTable />
            )}
          </StackItem>
        </Stack>
      </Main>
    </React.Fragment>
  );
}
Example #7
Source File: Details.js    From content-preview with Apache License 2.0 4 votes vote down vote up
Details = ({
    match,
    fetchContentDetails,
    details,
    fetchContentDetailsHits,
    contentDetailsHits
}) => {
    const [selectedListItem, setSelectedListItem] = useState(0);
    const capitalize = (string) => string[0].toUpperCase() + string.substring(1);
    const [expanded, setExpanded] = useState(true);
    const pyFilter = (data) => {
        const keysToInclude = Object.keys(data).filter(
            (key) => !key.includes('__')
        );
        const arrayObj = keysToInclude.map((key) => ({ [key]: data[key] }));

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

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

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

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

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

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

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

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

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

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

  const [response, fetchImageSetDetails] = useApi({
    api: getImageSet,
    id: imageId,
    tableReload: true,
  });

  const { data, isLoading } = response;

  const openUpdateWizard = (id) => {
    history.push({
      pathname: history.location.pathname,
      search: new URLSearchParams({
        update_image: true,
      }).toString(),
    });
    setUpdateWizard((prevState) => ({
      ...prevState,
      isOpen: !prevState.isLoading,
      updateId: id,
    }));
  };

  useEffect(() => {
    imageVersionId
      ? setImageVersion(
          data?.Data?.images?.[
            data?.Data?.images?.findIndex(
              (image) => image?.image?.ID == imageVersionId
            )
          ]
        )
      : setImageVersion(null);
  }, [response, imageVersionId]);

  useEffect(() => {
    fetchImageSetDetails();
  }, [imageId]);

  return (
    <Fragment>
      <PageHeader className="pf-m-light">
        <Stack hasGutter>
          <StackItem>
            <DetailsHead
              imageData={response}
              imageVersion={imageVersion}
              openUpdateWizard={openUpdateWizard}
            />
          </StackItem>
        </Stack>
      </PageHeader>
      <ImageDetailTabs
        imageData={response}
        urlParam={imageId}
        imageVersion={imageVersion}
        openUpdateWizard={openUpdateWizard}
        isLoading={isLoading}
      />
      {updateWizard.isOpen && (
        <Suspense
          fallback={
            <Bullseye>
              <Spinner />
            </Bullseye>
          }
        >
          <UpdateImageWizard
            navigateBack={() => {
              history.push({ pathname: history.location.pathname });
              setUpdateWizard((prevState) => ({ ...prevState, isOpen: false }));
            }}
            updateImageID={updateWizard.updateId}
          />
        </Suspense>
      )}
    </Fragment>
  );
}
Example #10
Source File: ClusterHeader.js    From ocp-advisor-frontend with Apache License 2.0 4 votes vote down vote up
ClusterHeader = ({ clusterId, clusterData, clusterInfo }) => {
  const location = window.location;
  const [isOpen, setIsOpen] = useState(false);
  const intl = useIntl();
  // subscribe to the cluster data query
  const {
    isUninitialized: isUninitializedCluster,
    isFetching: isFetchingCluster,
    data: cluster,
  } = clusterData;

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

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

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

  return (
    <Grid id="cluster-header" md={12} hasGutter>
      <GridItem span={8}>
        <Title
          size="2xl"
          headingLevel="h1"
          id="cluster-header-title"
          ouiaId="cluster-name"
        >
          {isUninitializedInfo || isFetchingInfo ? (
            <Skeleton size="sm" />
          ) : (
            info?.display_name || clusterId
          )}
        </Title>
      </GridItem>
      <GridItem span={4} id="cluster-header-dropdown">
        <Dropdown
          position="right"
          onSelect={() => setIsOpen(!isOpen)}
          autoFocus={false}
          isOpen={isOpen}
          toggle={
            <DropdownToggle
              id="toggle-id-2"
              onToggle={(isOpen) => setIsOpen(isOpen)}
            >
              {intl.formatMessage(messages.dropDownActionSingleCluster)}
            </DropdownToggle>
          }
          dropdownItems={dropDownItems}
        />
      </GridItem>
      <GridItem>
        <Stack>
          <StackItem id="cluster-header-uuid">
            <span>UUID:</span> <span>{clusterId}</span>
          </StackItem>
          <StackItem id="cluster-header-last-seen">
            <span>{intl.formatMessage(messages.lastSeen)}: </span>
            <span>
              {isUninitializedCluster || isFetchingCluster ? (
                <OneLineLoader />
              ) : cluster?.report?.meta?.last_checked_at ? (
                <DateFormat
                  date={cluster?.report?.meta?.last_checked_at}
                  type="exact"
                />
              ) : (
                intl.formatMessage(messages.unknown)
              )}
            </span>
          </StackItem>
        </Stack>
      </GridItem>
    </Grid>
  );
}
Example #11
Source File: 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 #12
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 #13
Source File: Email.js    From user-preferences-frontend with Apache License 2.0 4 votes vote down vote up
Email = () => {
  const dispatch = useDispatch();

  const [emailConfig, setEmailConfig] = useState({});
  const isLoaded = useLoaded(async () => {
    await insights.chrome.auth.getUser();
    register(emailPreferences);
    setEmailConfig(await calculateEmailConfig(config, dispatch));
  });

  const store = useSelector(({ emailPreferences }) => emailPreferences);

  const saveValues = async ({ unsubscribe, ...values }) => {
    const promises = Object.entries(emailConfig)
      .filter(([, { isVisible }]) => isVisible === true)
      .map(([application, { localFile, schema, url, apiName }]) => {
        if (
          !localFile &&
          !schema &&
          store?.[application]?.schema &&
          Object.keys(store?.[application]?.schema).length > 0
        ) {
          const action = saveEmailValues({ application, values, url, apiName });
          dispatch(action);

          return {
            promise: action.payload,
            meta: action.meta,
          };
        }
      })
      .filter(Boolean);

    const { success, error } = await distributeSuccessError(promises);
    dispatchMessages(dispatch, success, error);
  };

  const calculateSection = (key, schema) => {
    return getSection(key, schema, store?.[key], (isVisible) => {
      const { ...config } = emailConfig;
      if (isVisible === false) {
        delete config[key];
      } else {
        config[key] = {
          ...config[key],
          isVisible,
        };
      }

      setEmailConfig(config);
    });
  };

  return (
    <React.Fragment>
      <PageHeader>
        <PageHeaderTitle title="Email preferences" />
      </PageHeader>
      <Main className="pref-email">
        <Stack hasGutter>
          <StackItem>
            <YourInformation />
          </StackItem>
          <StackItem>
            <Card ouiaId="user-pref-email-subscriptions-card">
              <CardHeader className="pf-u-pb-0">
                <TextContent>
                  <Text component={TextVariants.h2}>Email subscriptions</Text>
                  <Text component={TextVariants.p}>
                    Select the emails you want to receive.
                  </Text>
                </TextContent>
              </CardHeader>
              <CardBody className="pref-email_form">
                {isLoaded ? (
                  <FormRender
                    componentMapper={{
                      ...componentMapper,
                      [DESCRIPTIVE_CHECKBOX]: DescriptiveCheckbox,
                      [LOADER]: Loader,
                      [DATA_LIST]: DataListLayout,
                    }}
                    FormTemplate={(props) => (
                      <FormTemplate {...props} FormButtons={FormButtons} />
                    )}
                    schema={{
                      fields: [
                        {
                          name: 'email-preferences',
                          component: DATA_LIST,
                          sections: Object.entries(emailConfig).map(
                            ([key, schema]) => calculateSection(key, schema)
                          ),
                        },
                      ],
                    }}
                    onSubmit={saveValues}
                  />
                ) : (
                  <Bullseye>
                    <Spinner />
                  </Bullseye>
                )}
              </CardBody>
            </Card>
          </StackItem>
        </Stack>
      </Main>
    </React.Fragment>
  );
}
Example #14
Source File: Notification.js    From user-preferences-frontend with Apache License 2.0 4 votes vote down vote up
Notification = () => {
  const { bundleName } = useParams();
  const navigateTo = useChromePush();
  const dispatch = useDispatch();
  const store = useSelector(
    ({ notificationPreferences }) => notificationPreferences
  );
  const bundleDisplayTitle = notificationConfigForBundle(bundleName)?.title;

  useEffect(() => {
    register(notificationPreferences);
  }, []);

  useEffect(() => {
    (async () => {
      await insights.chrome.auth.getUser();
      if (bundleName) {
        dispatch(getNotificationSchema({ bundleName }));
      }
    })();
  }, [bundleName]);

  const { isLoaded, schema } = useMemo(() => {
    if (store?.loaded) {
      const schema = { ...store.schema };
      if (schema.fields) {
        schema.fields = [...schema.fields];
        schema.fields[0].sections = [...schema.fields[0].sections];
        schema.fields[0].sections.push({
          fields: unsubscribe,
        });
      } else {
        schema.fields = [];
      }

      return {
        isLoaded: true,
        schema: schema,
      };
    }
    return {
      isLoaded: false,
      schema: [],
    };
  }, [store]);

  const saveValues = useCallback(
    async ({ unsubscribe, ...values }) => {
      const action = saveNotificationValues({ bundleName, values });
      dispatch(action);
      try {
        await action.payload;
        dispatch(
          addNotification({
            dismissable: false,
            variant: 'success',
            title: `Notification preferences successfully saved`,
          })
        );
      } catch (e) {
        dispatch(
          addNotification({
            dismissable: false,
            variant: 'danger',
            title: `Notification preferences unsuccessfully saved`,
          })
        );
      }
    },
    [bundleName]
  );

  return (
    <React.Fragment>
      <PageHeader>
        <Split>
          <SplitItem isFilled>
            <PageHeaderTitle
              className="notif-page-header"
              title={`My Notifications | ${bundleDisplayTitle}`}
            />
            <StackItem>
              This service allows you to opt-in and out of receiving
              notifications. Your Organization Administrator has configured
              which notifications you can or can not receive in their{' '}
              <a
                onClick={(e) =>
                  navigateTo(e, `/settings/notifications/${bundleName}`)
                }
                href={`/settings/notifications/${bundleName}`}
              >
                Settings
              </a>
              .
            </StackItem>
          </SplitItem>
        </Split>
      </PageHeader>
      <Main className="pref-notification">
        <Stack hasGutter>
          <StackItem>
            <Card ouiaId="user-pref-notification-subscriptions-card">
              <CardHeader className="pf-u-pb-0"></CardHeader>
              <CardBody className="pref-notification_form">
                {isLoaded ? (
                  <FormRender
                    componentMapper={{
                      ...componentMapper,
                      [DESCRIPTIVE_CHECKBOX]: DescriptiveCheckbox,
                      [LOADER]: Loader,
                      [DATA_LIST]: DataListLayout,
                    }}
                    FormTemplate={(props) => (
                      <FormTemplate {...props} FormButtons={FormButtons} />
                    )}
                    schema={schema}
                    onSubmit={saveValues}
                  />
                ) : (
                  <Bullseye>
                    <Spinner />
                  </Bullseye>
                )}
              </CardBody>
            </Card>
          </StackItem>
        </Stack>
      </Main>
    </React.Fragment>
  );
}
Example #15
Source File: new-widget-wizard.js    From ibutsu-server with MIT License 4 votes vote down vote up
render() {
    const { widgetTypes, selectedType, selectedTypeId, stepIdReached, isTitleValid, areParamsFilled } = this.state;
    const steps = [
      {
        id: 1,
        name: 'Select type',
        enableNext: selectedType,
        component: (
          <Form>
            <Title headingLevel="h1" size="xl">Select a widget type</Title>
            {widgetTypes.map(widgetType => {
              return (
                <div key={widgetType.id}>
                  <Radio id={widgetType.id} value={widgetType.id} label={widgetType.title} description={widgetType.description} isChecked={selectedTypeId === widgetType.id} onChange={this.onSelectType}/>
                </div>
              );
            })}
          </Form>
        )
      },
      {
        id: 2,
        name: 'Set info',
        canJumpTo: stepIdReached >= 2,
        enableNext: isTitleValid,
        component: (
          <Form isHorizontal>
            <Title headingLevel="h1" size="xl">Set widget information</Title>
            <FormGroup label="Title" fieldId="widget-title" helperText="A title for the widget" validated={this.isTitleValid} helperTextInvalid="Please enter a title for this widget" helperTextInvalidIcon={<ExclamationCircleIcon/>} isRequired>
              <TextInput type="text" id="widget-title" name="widget-title" value={this.state.title} onChange={this.onTitleChange} validated={this.state.isTitleValid} isRequired />
            </FormGroup>
            <FormGroup label="Weight" fieldId="widget-weight" helperText="How widgets are ordered on the dashboard">
              <TextInput type="number" id="widget-weight" name="widget-weight" value={this.state.weight} onChange={this.onWeightChange} />
            </FormGroup>
          </Form>
        )
      },
      {
        id: 3,
        name: 'Set parameters',
        canJumpTo: stepIdReached >= 3,
        enableNext: areParamsFilled,
        component: (
          <Form isHorizontal>
            <Title headingLevel="h1" size="xl">Set widget parameters</Title>
            {!!selectedType && selectedType.params.map(param => {
              return (
                <React.Fragment key={param.name}>
                {(param.type === 'string' || param.type === 'integer' || param.type === 'float') &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    helperText={<Linkify componentDecorator={linkifyDecorator}>{param.description}</Linkify>}
                    isRequired={param.required}>
                    <TextInput
                      value={this.state.params[param.name]}
                      type={(param.type === 'integer' || param.type === 'float') ? 'number' : 'text'}
                      id={param.name}
                      aria-describedby={`${param.name}-helper`}
                      name={param.name}
                      onChange={this.onParamChange}
                      isRequired={param.required}
                    />
                  </FormGroup>
                }
                {param.type === 'boolean' &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    isRequired={param.required}
                    hasNoPaddingTop>
                    <Checkbox
                      isChecked={this.state.params[param.name]}
                      onChange={this.onParamChange}
                      id={param.name}
                      name={param.name}
                      label={param.description} />
                  </FormGroup>
                }
                {param.type === 'list' &&
                  <FormGroup
                    label={param.name}
                    fieldId={param.name}
                    helperText={`${param.description}. Place items on separate lines.`}>
                    isRequired={param.required}
                    <TextArea
                      id={param.name}
                      name={param.name}
                      isRequired={param.required}
                      value={this.state.params[param.name]}
                      onChange={this.onParamChange}
                      resizeOrientation='vertical' />
                  </FormGroup>
                }
                </React.Fragment>
              );
            })}
          </Form>
        )
      },
      {
        id: 4,
        name: 'Review details',
        canJumpTo: stepIdReached >= 4,
        nextButtonText: 'Finish',
        component: (
          <Stack hasGutter>
            <StackItem>
              <Title headingLevel="h1" size="xl">Review details</Title>
            </StackItem>
            <StackItem>
              <Grid hasGutter>
                <GridItem span="2">
                  <Title headingLevel="h4">Title</Title>
                </GridItem>
                <GridItem span="10">
                  <TextContent><Text>{this.state.title}</Text></TextContent>
                </GridItem>
                <GridItem span="2">
                  <Title headingLevel="h4">Weight</Title>
                </GridItem>
                <GridItem span="10">
                  <TextContent><Text>{this.state.weight}</Text></TextContent>
                </GridItem>
                <GridItem span="2">
                  <Title headingLevel="h4">Parameters</Title>
                </GridItem>
                <GridItem span="10">
                  <Table
                    cells={["Name", "Value"]}
                    variant="compact"
                    borders="compactBorderless"
                    rows={Object.entries(this.state.params).map(param => { return [param[0], param[1].toString()]; })}
                    aria-label="Parameters">
                    <TableHeader />
                    <TableBody />
                  </Table>
                </GridItem>
              </Grid>
            </StackItem>
          </Stack>
        )
      }
    ];
    return (
      <Modal
        isOpen={this.props.isOpen}
        variant={ModalVariant.large}
        showClose={false}
        onClose={this.onClose}
        hasNoBodyWrapper
        aria-describedby="add-widget-description"
        aria-labelledby="add-widget-title"
      >
        <Wizard
          titleId="add-widget-title"
          descriptionId="add-widget-description"
          title="Add Widget"
          description="Add a widget to the current dashboard"
          steps={steps}
          onNext={this.onNext}
          onSave={this.onSave}
          onClose={this.onClose}
          height={400}
        />
      </Modal>
    );
  }
Example #16
Source File: AddressesDataList.js    From cockpit-wicked with GNU General Public License v2.0 4 votes vote down vote up
AddressesDataList = ({ addresses, updateAddresses, allowEmpty = true }) => {
    const addAddress = () => {
        const address = createAddressConfig();
        const currentAddresses = [...addresses];
        currentAddresses.push(address);
        updateAddresses(currentAddresses);
    };

    const updateAddress = (id, field, value) => {
        const nextAddresses = [...addresses];
        const address = nextAddresses.find((addr) => addr.id == id);
        address[field] = value;

        // TODO: check if this do not generate not needed re-renders
        updateAddresses(nextAddresses);
    };

    const deleteAddress = (id) => {
        const nextAddresses = [...addresses];
        const addressIdx = nextAddresses.findIndex((addr) => addr.id == id);
        nextAddresses.splice(addressIdx, 1);
        updateAddresses(nextAddresses);
    };

    const renderAddress = ({ id, local, label }) => {
        const renderDeleteAction = () => {
            if (!allowEmpty && addresses.length === 1) return null;

            return (
                <DataListAction>
                    <Button variant="secondory" className="btn-sm" onClick={() => deleteAddress(id)}>
                        <MinusIcon />
                    </Button>
                </DataListAction>
            );
        };

        const cells = [
            <DataListCell key={`address-${id}-local`}>
                <IPInput
                  defaultValue={local}
                  onChange={(value) => updateAddress(id, 'local', value)}
                  placeholder={_("Address")}
                  aria-label={_("Address")}
                />
            </DataListCell>,
            <DataListCell key={`address-${id}-label`}>
                <TextInput
                  defaultValue={label}
                  onChange={(value) => updateAddress(id, 'label', value)}
                  placeholder={_("Label")}
                  aria-label={_("Label")}
                />
            </DataListCell>
        ];

        return (
            <DataListItem key={`address-${id}`}>
                <DataListItemRow>
                    <DataListItemCells dataListCells={cells} />
                    { renderDeleteAction() }
                </DataListItemRow>
            </DataListItem>
        );
    };

    return (
        <Stack className="data-list-form" hasGutter>
            <StackItem>
                <Split hasGutter>
                    <SplitItem isFilled />
                    <SplitItem>
                        <Button variant="primary" className="btn-sm" onClick={() => addAddress() }>
                            <PlusIcon />
                        </Button>
                    </SplitItem>
                </Split>
            </StackItem>
            <StackItem>
                <DataList isCompact aria-label={_("Addresses data list")}>
                    {addresses.map((address) => renderAddress(address))}
                </DataList>
            </StackItem>
        </Stack>
    );
}