@patternfly/react-core#Split JavaScript Examples

The following examples show how to use @patternfly/react-core#Split. 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: Status.js    From edge-frontend with Apache License 2.0 6 votes vote down vote up
Status = ({
  type,
  isLabel = false,
  toolTipContent = '',
  className = '',
}) => {
  const { text, Icon, color, labelColor } =
    Object.prototype.hasOwnProperty.call(statusMapper, type)
      ? statusMapper[type]
      : statusMapper['default'];

  return (
    <>
      {isLabel ? (
        <Label color={labelColor} icon={<Icon />} className={className}>
          {text}
        </Label>
      ) : (
        <Split style={{ color }} className={className}>
          <SplitItem className="pf-u-mr-sm">
            {toolTipContent ? (
              <Tooltip content="blargh">
                <Icon />
              </Tooltip>
            ) : (
              <Icon />
            )}
          </SplitItem>
          <SplitItem>
            <p>{text}</p>
          </SplitItem>
        </Split>
      )}
    </>
  );
}
Example #2
Source File: InterfaceDetails.js    From cockpit-wicked with GNU General Public License v2.0 6 votes vote down vote up
InterfaceDetails = ({ iface, connection }) => {
    const renderFullDetails = () => {
        if (connection.exists) {
            return (
                <>
                    { iface.type === interfaceTypeEnum.BONDING && bondDetails(connection) }
                    { iface.type === interfaceTypeEnum.BRIDGE && bridgeDetails(connection) }
                    { iface.type === interfaceTypeEnum.VLAN && vlanDetails(connection) }
                    { iface.type === interfaceTypeEnum.WIRELESS && wirelessDetails(iface, connection) }
                    { ipV4Details(connection) }
                    { ipV6Details(connection) }
                </>
            );
        }
    };

    return (
        <>
            {renderError(iface.error)}

            <Split hasGutter>
                <SplitItem isFilled>
                    <dl className="details-list">
                        { iface.mac && macAddress(iface) }
                        {startMode(connection)}
                        {renderFullDetails()}
                    </dl>
                </SplitItem>
                <SplitItem>
                    <InterfaceActions iface={iface} connection={connection} />
                </SplitItem>
            </Split>
        </>
    );
}
Example #3
Source File: StatusBar.js    From cockpit-wicked with GNU General Public License v2.0 6 votes vote down vote up
StatusBar = ({
    showSpinner = false,
    children
}) => {
    return (
        <PageSection className="content-header-extra">
            <Split hasGutter id="state" className="content-header-extra--state">
                { showSpinner && <SplitItem><Spinner size="md" /></SplitItem> }
                <SplitItem isFilled>{children}</SplitItem>
            </Split>
        </PageSection>
    );
}
Example #4
Source File: Signatures.js    From malware-detection-frontend with Apache License 2.0 5 votes vote down vote up
Signatures = () => {
    const intl = useIntl();
    const sigPageData = useQuery(GET_SIGNATURE_PAGE);
    const chartCmpData = useQuery(GET_TIME_SERIES_STATS);

    return <React.Fragment>
        <PageHeader>
            <Split hasGutter isWrappable>
                <SplitItem>
                    <PageHeaderTitle title={(<Popover
                        enableFlip
                        position={'right'}
                        headerContent={intl.formatMessage(messages.headerPopoverTitle)}
                        bodyContent={(<Grid hasGutter>
                            <GridItem>{intl.formatMessage(messages.headerPopoverBody1)}</GridItem>
                        </Grid>)}
                        footerContent={<a
                            href={'https://access.redhat.com/documentation/en-us/red_hat_insights/2022/html/' +
                            'assessing_and_reporting_malware_signatures_on_rhel_systems_with_the_insights_for' +
                            '_rhel_malware_service/'}
                            target="__blank" rel="noopener noreferrer">
                            {intl.formatMessage(messages.headerPopoverFooter)} <ExternalLinkAltIcon />
                        </a>}
                    >
                        <Title headingLevel='h1' size={TitleSizes['3xl']}>
                            {intl.formatMessage(messages.malwareDetection)}
                            <OutlinedQuestionCircleIcon
                                color={'var(--pf-global--secondary-color--100)'}
                                className="pf-u-ml-sm pointer cves-header-questionmark"
                                style={{ verticalAlign: '-2' }}
                            />
                        </Title>
                    </Popover>)} />
                </SplitItem>
            </Split>
        </PageHeader>
        <Main>
            <Grid hasGutter>
                <GridItem lg={6} md={12}>
                    <Suspense fallback={<Loading />}><StatusCard {...sigPageData} /></Suspense>
                </GridItem>
                <GridItem lg={6} md={12}>
                    <Suspense fallback={<Loading />}><ChartCard sysStats={sigPageData}  chartStats={chartCmpData}/></Suspense>
                </GridItem>
                <GridItem span={12}>
                    <Suspense fallback={<Loading />}><SigTable /></Suspense>
                </GridItem>
            </Grid>
        </Main>
    </React.Fragment>;
}
Example #5
Source File: EditRequestModal.js    From access-requests-frontend with Apache License 2.0 4 votes vote down vote up
RequestDetailsForm = ({
  user = {},
  targetAccount,
  setTargetAccount,
  targetOrg,
  setTargetOrg,
  start,
  setStart,
  end,
  setEnd,
  disableAccount,
  disableOrgId,
  isLoading,
  error,
}) => {
  let [startDate, setStartDate] = React.useState();
  const [validatedAccount, setValidatedAccount] = React.useState(
    error ? 'error' : 'default'
  );

  const [validatedOrgId, setValidatedOrgId] = React.useState(
    error ? 'error' : 'default'
  );

  // https://github.com/RedHatInsights/insights-rbac/blob/master/rbac/api/cross_access/model.py#L49
  const startValidator = (date) => {
    if (isValidDate(date)) {
      if (date < today) {
        setEnd('');
        return 'Start date must be today or later';
      }
      if (date > maxStartDate) {
        setEnd('');
        return 'Start date must be within 60 days of today';
      }
    }

    return '';
  };

  const endValidator = (date) => {
    if (isValidDate(startDate)) {
      if (startDate > date) {
        return 'End date must be after from date';
      }
    }

    const maxToDate = new Date(startDate);
    maxToDate.setFullYear(maxToDate.getFullYear() + 1);
    if (date > maxToDate) {
      return 'Access duration may not be longer than one year';
    }

    return '';
  };

  const onStartChange = (str, date) => {
    setStartDate(new Date(date));
    setStart(str);
    if (isValidDate(date) && !startValidator(date)) {
      date.setDate(date.getDate() + 7);
      setEnd(dateFormat(date));
    } else {
      setEnd('');
    }
  };

  const onEndChange = (str, date) => {
    if (endValidator(date)) {
      setEnd('');
    } else {
      setEnd(str);
    }
  };

  return (
    <Form onSubmit={(ev) => ev.preventDefault()} isDisabled={isLoading}>
      <Title headingLevel="h2">Request details</Title>
      <Split hasGutter>
        <SplitItem isFilled>
          <FormGroup label="First name" labelIcon={getLabelIcon('first name')}>
            <TextInput id="first-name" value={user.first_name} isDisabled />
          </FormGroup>
        </SplitItem>
        <SplitItem isFilled>
          <FormGroup label="Last name" labelIcon={getLabelIcon('last name')}>
            <TextInput id="last-name" value={user.last_name} isDisabled />
          </FormGroup>
        </SplitItem>
      </Split>
      <FormGroup
        label="Account number"
        isRequired
        labelIcon={getLabelIcon('account number')}
        helperText="Enter the account number you would like access to"
        helperTextInvalid="Please enter a valid account number"
        validated={validatedAccount}
      >
        <TextInput
          id="account-number"
          value={targetAccount}
          onChange={(val) => {
            setTargetAccount(val);
            setValidatedAccount('default');
          }}
          isRequired
          placeholder="Example, 8675309"
          validated={validatedAccount}
          isDisabled={disableAccount}
        />
      </FormGroup>
      <FormGroup
        label="Organization id"
        isRequired
        labelIcon={getLabelIcon('organization id')}
        helperText="Enter the organization id you would like access to"
        helperTextInvalid="Please enter a valid organization id"
        validated={validatedOrgId}
      >
        <TextInput
          id="org-id"
          value={targetOrg}
          onChange={(val) => {
            setTargetOrg(val);
            setValidatedOrgId('default');
          }}
          isRequired
          placeholder="Example, 1234567"
          validated={validatedOrgId}
          isDisabled={disableOrgId}
        />
      </FormGroup>
      <FormGroup
        label="Access duration"
        isRequired
        labelIcon={getLabelIcon('access duration')}
      >
        <Split>
          <SplitItem>
            <DatePicker
              width="300px"
              aria-label="Start date"
              value={start}
              dateFormat={dateFormat}
              dateParse={dateParse}
              placeholder="mm/dd/yyyy"
              onChange={onStartChange}
              validators={[startValidator]}
            />
          </SplitItem>
          <SplitItem style={{ padding: '6px 12px 0 12px' }}>to</SplitItem>
          <SplitItem>
            <DatePicker
              width="300px"
              aria-label="End date"
              value={end}
              dateFormat={dateFormat}
              dateParse={dateParse}
              placeholder="mm/dd/yyyy"
              onChange={onEndChange}
              validators={[endValidator]}
              rangeStart={start}
            />
          </SplitItem>
        </Split>
      </FormGroup>
    </Form>
  );
}
Example #6
Source File: Details.js    From content-preview with Apache License 2.0 4 votes vote down vote up
Details = ({
    match,
    fetchContentDetails,
    details,
    fetchContentDetailsHits,
    contentDetailsHits
}) => {
    const [selectedListItem, setSelectedListItem] = useState(0);
    const capitalize = (string) => string[0].toUpperCase() + string.substring(1);
    const [expanded, setExpanded] = useState(true);
    const pyFilter = (data) => {
        const keysToInclude = Object.keys(data).filter(
            (key) => !key.includes('__')
        );
        const arrayObj = keysToInclude.map((key) => ({ [key]: data[key] }));

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

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

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

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

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

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

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

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

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

    return (
        <Page
            breadcrumb={
                <Breadcrumb>
                    <BreadcrumbItem>
                        <Link to="/preview">Content Preview</Link>
                    </BreadcrumbItem>
                    <BreadcrumbHeading to="#">{`${match.params.recDetail}`}</BreadcrumbHeading>
                </Breadcrumb>
            }
        >
            <PageHeader>
                <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
                    <PageHeaderTitle
                        title={
                            <>
                                {details.rule_id || 'loading...'}{' '}
                                {details.status !== undefined && (
                                    <Label color={details.status === 'active' ? 'green' : 'red'}>
                                        {capitalize(details.status)}
                                    </Label>
                                )}{' '}
                            </>
                        }
                    />
                    <Toolbar>
                        <HostSelector />
                    </Toolbar>
                </Flex>
            </PageHeader>
            <PageSection>
                <Grid hasGutter>
                    <GridItem span={6}>
                        <Stack hasGutter>
                            <Card>
                                <CardBody>
                                    <ExpandableSection
                                        toggleText={details.description}
                                        onToggle={() => setExpanded(!expanded)}
                                        isExpanded={expanded}
                                    >
                                        <Stack hasGutter>
                                            <StackItem>
                                                <p>
                                                    {`Publish Date: ${details.publish_date} | `}
                                                    {details.node_id ? (
                                                        <a href={detailHref}>{detailHref}</a>
                                                    ) : (
                                                        <Label variant="outline" color="gray">
                                                            No node_id present
                                                        </Label>
                                                    )}
                                                </p>
                                                {(details.reboot_required ||
                                                    details.category ||
                                                    details.severity) && (
                                                    <LabelGroup>
                                                        {details.reboot_required && (
                                                            <Label variant="outline" color="gray">
                                                                Reboot required
                                                            </Label>
                                                        )}
                                                        {details.category && (
                                                            <Label variant="outline" color="gray">
                                                                {details.category}
                                                            </Label>
                                                        )}
                                                        {details.severity && (
                                                            <Label
                                                                variant="outline"
                                                                color={severityLabelColor(details.severity)}
                                                            >
                                                                {details.severity}
                                                            </Label>
                                                        )}
                                                    </LabelGroup>
                                                )}
                                            </StackItem>
                                            <StackItem>
                                                <Stack hasGutter>
                                                    <StackItem>
                                                        <strong>Name:</strong>
                                                        {ruleDescription(details.name)}
                                                    </StackItem>
                                                    <StackItem>
                                                        <strong>Summary:</strong>
                                                        {ruleDescription(details.summary)}
                                                    </StackItem>
                                                    <StackItem>
                                                        <strong>Generic:</strong>
                                                        {ruleDescription(details.generic, true)}
                                                    </StackItem>
                                                </Stack>
                                            </StackItem>
                                            <StackItem>
                                                <Form>
                                                    <FormGroup
                                                        label="Free Style JSON input:"
                                                        type="string"
                                                        helperText={helperText}
                                                        helperTextInvalid="Not valid JSON"
                                                        fieldId="selection"
                                                        validated={freeStyleValidated}
                                                    >
                                                        <TextArea
                                                            value={freeStyle}
                                                            onChange={freeStyleChange}
                                                            isRequired
                                                            validated={freeStyleValidated}
                                                            aria-label="free style JSON input"
                                                        />
                                                    </FormGroup>
                                                </Form>
                                            </StackItem>
                                        </Stack>
                                    </ExpandableSection>
                                </CardBody>
                            </Card>
                            <DataList
                                className="pyDataList"
                                aria-label="selectable data list example"
                                selectedDataListItemId={selectedListItem}
                                onSelectDataListItem={(id) =>
                                    id !== selectedListItem
                                        ? setSelectedListItem(id)
                                        : setSelectedListItem(0)
                                }
                            >
                                {contentDetailsHits.map((item, key) => (
                                    <DataListItem
                                        aria-labelledby="selectable-action-item1"
                                        key={key + 1}
                                        id={key + 1}
                                    >
                                        <DataListItemRow className="overFlow">
                                            <DataListItemCells
                                                dataListCells={[
                                                    <DataListCell key="primary content">
                                                        <Split hasGutter>
                                                            <SplitItem>
                                                                <b>{item.__name}</b>
                                                            </SplitItem>
                                                            <SplitItem>
                                                                <Label color="blue">{item.__source}</Label>
                                                            </SplitItem>
                                                        </Split>
                                                        <h5>{item.__date}</h5>
                                                        <pre>{JSON.stringify(pyFilter(item), null, 2)}</pre>
                                                    </DataListCell>
                                                ]}
                                            />
                                        </DataListItemRow>
                                    </DataListItem>
                                ))}
                            </DataList>
                        </Stack>
                    </GridItem>
                    <GridItem span={6}>
                        <ReportDetails
                            report={{
                                ...details,
                                rule: details,
                                ...(selectedPyData && { details: selectedPyData }),
                                ...(validFreeStyle && { details: validFreeStyle }),
                                resolution: details.resolution
                            }}
                            kbaDetail={kbaDetailsData}
                            kbaLoading={kbaLoading}
                        />
                    </GridItem>
                </Grid>
            </PageSection>
        </Page>
    );
}
Example #7
Source File: DetailsHeader.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
DetailsHead = ({ imageData, imageVersion, openUpdateWizard }) => {
  const [isOpen, setIsOpen] = useState(false);
  const [data, setData] = useState({});

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

  return (
    <>
      {!imageData.isLoading && imageData.hasError ? (
        <Breadcrumb>
          <BreadcrumbItem>
            <Link to={paths['manage-images']}>Back to Manage Images</Link>
          </BreadcrumbItem>
        </Breadcrumb>
      ) : (
        <>
          <Breadcrumb>
            <BreadcrumbItem>
              <Link to={paths['manage-images']}>Manage Images</Link>
            </BreadcrumbItem>
            {imageVersion ? (
              <BreadcrumbItem>
                <Link to={`${paths['manage-images']}/${data?.image_set?.ID}`}>
                  {data?.image_set?.Name}
                </Link>
              </BreadcrumbItem>
            ) : (
              <BreadcrumbItem isActive>
                {data?.image_set?.Name || <Skeleton width="100px" />}
              </BreadcrumbItem>
            )}
            {imageVersion && (
              <BreadcrumbItem isActive>
                {imageVersion?.image?.Version}
              </BreadcrumbItem>
            )}
          </Breadcrumb>

          <TextContent>
            <Split>
              <SplitItem>
                <TextList component="dl">
                  <TextListItem
                    component="h1"
                    className="grid-align-center pf-u-mb-0"
                  >
                    {data?.image_set?.Name || <Skeleton width="150px" />}
                  </TextListItem>
                  <TextListItem className="pf-u-pt-sm" component="dd">
                    {data?.Status || data?.images?.[0]?.image?.Status ? (
                      <Status
                        type={data?.images?.[0]?.image?.Status.toLowerCase()}
                      />
                    ) : (
                      <Skeleton width="100px" />
                    )}
                  </TextListItem>
                  {imageVersion?.image?.UpdatedAt ||
                  data?.images?.[0].image?.UpdatedAt ? (
                    <TextListItem component="p">
                      {`Last updated `}
                      <DateFormat
                        date={
                          imageVersion
                            ? imageVersion?.image?.UpdatedAt
                            : data?.images?.[0].image?.UpdatedAt
                        }
                      />
                    </TextListItem>
                  ) : (
                    <Skeleton width="200px" />
                  )}
                </TextList>
              </SplitItem>
              <SplitItem isFilled></SplitItem>
              <SplitItem>
                <Dropdown
                  position={DropdownPosition.right}
                  toggle={
                    <DropdownToggle
                      id="image-set-details-dropdown"
                      toggleIndicator={CaretDownIcon}
                      onToggle={(newState) => setIsOpen(newState)}
                      isDisabled={
                        (imageVersion
                          ? imageVersion?.image?.Status
                          : data?.Images?.[0]?.Status) === 'BUILDING' || false
                      }
                    >
                      Actions
                    </DropdownToggle>
                  }
                  isOpen={isOpen}
                  dropdownItems={dropdownItems(
                    data,
                    imageVersion,
                    openUpdateWizard
                  )}
                />
              </SplitItem>
            </Split>
          </TextContent>
        </>
      )}
    </>
  );
}
Example #8
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 #9
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 #10
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 #11
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>
    );
}