@patternfly/react-core#Breadcrumb JavaScript Examples

The following examples show how to use @patternfly/react-core#Breadcrumb. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js    From ocp-advisor-frontend with Apache License 2.0 7 votes vote down vote up
Breadcrumbs = ({ current }) => {
  const intl = useIntl();
  const location = useLocation();
  const splitUrl = location.pathname.split('/');

  return (
    <div>
      <Breadcrumb ouiaId="detail">
        <BreadcrumbItem className="breadcrumb-item">
          <Link to={`/${splitUrl[1]}`}>
            {`${intl.formatMessage(messages.insightsHeader)} ${splitUrl[1]}`}
          </Link>
        </BreadcrumbItem>
        <BreadcrumbItem className="breadcrumb-item" isActive>
          {current}
        </BreadcrumbItem>
      </Breadcrumb>
    </div>
  );
}
Example #2
Source File: AccessRequestDetailsPage.js    From access-requests-frontend with Apache License 2.0 4 votes vote down vote up
BaseAccessRequestDetailsPage = ({ isInternal }) => {
  const [request, setRequest] = React.useState();
  const { requestId } = useParams();
  const dispatch = useDispatch();
  React.useEffect(() => {
    apiInstance
      .get(
        `${API_BASE}/cross-account-requests/${requestId}/${
          isInternal ? '?query_by=user_id' : '?query_by=target_account'
        }`,
        { headers: { Accept: 'application/json' } }
      )
      .then((res) => {
        if (res.errors) {
          throw Error(res.errors.map((e) => e.detail).join('\n'));
        }
        setRequest(res);
      })
      .catch((err) => {
        dispatch(
          addNotification({
            variant: 'danger',
            title: 'Could not load access request',
            description: err.message,
          })
        );
      });
  }, []);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      {updateModal.isOpen && (
        <Suspense
          fallback={
            <Bullseye>
              <Spinner />
            </Bullseye>
          }
        >
          <UpdateDeviceModal
            navigateBack={() => {
              history.push({ pathname: history.location.pathname });
              setUpdateModal((prevState) => {
                return {
                  ...prevState,
                  isOpen: false,
                };
              });
            }}
            setUpdateModal={setUpdateModal}
            updateModal={updateModal}
            refreshTable={fetchDevices}
          />
        </Suspense>
      )}
      {isDeleteModalOpen && (
        <DeleteGroupModal
          isModalOpen={isDeleteModalOpen}
          setIsModalOpen={setIsDeleteModalOpen}
          reloadData={() => history.push(paths['fleet-management'])}
          modalState={modalState}
        />
      )}
      {isRenameModalOpen && (
        <RenameGroupModal
          isModalOpen={isRenameModalOpen}
          setIsModalOpen={setIsRenameModalOpen}
          reloadData={() => fetchDevices()}
          modalState={modalState}
        />
      )}
    </>
  );
}
Example #6
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 #7
Source File: CompletedTaskDetails.js    From tasks-frontend with Apache License 2.0 4 votes vote down vote up
CompletedTaskDetails = () => {
  const { id } = useParams();
  const filters = Object.values(Filters);
  const [completedTaskDetails, setCompletedTaskDetails] =
    useState(LOADING_INFO_PANEL);
  const [completedTaskJobs, setCompletedTaskJobs] =
    useState(LOADING_JOBS_TABLE);
  const [error, setError] = useState();

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

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

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

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

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

    fetchData();
  }, []);

  return (
    <div>
      {error ? (
        <EmptyStateDisplay
          icon={ExclamationCircleIcon}
          color="#c9190b"
          title={'Task cannot be displayed'}
          text={TASK_ERROR}
          error={`Error ${error?.response?.status}: ${error?.message}`}
        />
      ) : (
        <React.Fragment>
          <PageHeader>
            <Breadcrumb ouiaId="completed-tasks-details-breadcrumb">
              <BreadcrumbItem to="/beta/insights/tasks/executed">
                Tasks
              </BreadcrumbItem>
              <BreadcrumbItem isActive>
                {completedTaskDetails.task_title}
              </BreadcrumbItem>
            </Breadcrumb>
            <Flex direction={{ default: 'column', md: 'row' }}>
              <Flex
                direction={{ default: 'column' }}
                flex={{ default: 'flex_1' }}
              >
                <FlexItem>
                  <PageHeaderTitle title={completedTaskDetails.task_title} />
                </FlexItem>
                <FlexItem>{completedTaskDetails.description}</FlexItem>
              </Flex>
              <FlexibleFlex
                data={completedTaskDetails}
                flexContents={COMPLETED_INFO_BUTTONS}
                flexProps={COMPLETED_INFO_BUTTONS_FLEX_PROPS}
              />
            </Flex>
          </PageHeader>
          <Main>
            <Card>
              <Flex
                className="completed-task-details-info-border"
                justifyContent={{ default: 'justifyContentSpaceBetween' }}
                direction={{ default: 'column', md: 'row' }}
              >
                <FlexibleFlex
                  data={completedTaskDetails}
                  flexContents={COMPLETED_INFO_PANEL}
                  flexProps={COMPLETED_INFO_PANEL_FLEX_PROPS}
                />
              </Flex>
            </Card>
            <br />
            <Card>
              <TasksTables
                label={`${completedTaskDetails.id}-completed-jobs`}
                ouiaId={`${completedTaskDetails.id}-completed-jobs-table`}
                columns={columns}
                items={completedTaskJobs}
                filters={{
                  filterConfig: filters,
                }}
                options={{
                  ...TASKS_TABLE_DEFAULTS,
                  exportable: {
                    ...TASKS_TABLE_DEFAULTS.exportable,
                    columns: exportableColumns,
                  },
                }}
                emptyRows={emptyRows('jobs')}
                isStickyHeader
              />
            </Card>
          </Main>
        </React.Fragment>
      )}
    </div>
  );
}