@material-ui/icons#ExpandLess TypeScript Examples

The following examples show how to use @material-ui/icons#ExpandLess. 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: DiscloseSlippageSelector.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
function Component({
  className,
  value,
  ...selectorProps
}: DiscloseSlippageSelectorProps) {
  const [{ open }, setOpen] = useLocalStorage<{ open: boolean }>(
    '__anchor_slippage__',
    { open: false },
  );

  return (
    <details className={className} {...(open ? { open: true } : {})}>
      <summary
        onClick={(event) => {
          event.preventDefault();
          setOpen({ open: !open });
        }}
      >
        {open ? <ExpandLess /> : <ExpandMore />}
        <IconSpan>
          Slippage Tolerance{' '}
          <InfoTooltip>
            The transaction will revert if the price changes by more than the
            defined percentage.{' '}
          </InfoTooltip>
          : {big(value).mul(100).toFixed()}%
        </IconSpan>
      </summary>

      <SlippageSelector value={value} {...selectorProps} className="selector" />
    </details>
  );
}
Example #2
Source File: ExpandableElement.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function ExpandableElement({ children, expandable, defaultOpen }: Props): ReactElement | null {
  const classes = useStyles()
  const [open, setOpen] = useState<boolean>(Boolean(defaultOpen))

  const handleClick = () => {
    setOpen(!open)
  }

  return (
    <div className={`${classes.root} ${classes.rootLevel2}`}>
      <ListItem button onClick={handleClick} className={classes.header}>
        {children}
        {open ? <ExpandLess /> : <ExpandMore />}
      </ListItem>
      <Collapse in={open} timeout="auto" unmountOnExit>
        <div className={classes.contentLevel12}>{expandable}</div>
      </Collapse>
    </div>
  )
}
Example #3
Source File: MoreMenu.tsx    From anchor-web-app with Apache License 2.0 5 votes vote down vote up
function MoreMenuBase({ children, className }: MoreMenuProps) {
  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

  return (
    <>
      <MoreButton
        onClick={(event: MouseEvent<HTMLButtonElement>) =>
          setAnchorEl(event.currentTarget)
        }
      >
        More {anchorEl ? <ExpandLess /> : <ExpandMore />}
      </MoreButton>

      <Popover
        open={!!anchorEl}
        anchorEl={anchorEl}
        onClose={() => setAnchorEl(null)}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'right',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'right',
        }}
        className={className}
      >
        <MenuList variant="menu">
          {Children.map(children, (child) => {
            return cloneElement(child, {
              children: (
                <IconSpan>
                  {child.props.children} <ChevronRightRounded />
                </IconSpan>
              ),
            });
          })}
        </MenuList>
      </Popover>
    </>
  );
}
Example #4
Source File: GovBanner.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
GovBanner: React.FC = () => {
  const classes = useStyles();
  const [expanded, setExpanded] = useState(false);

  return (
    <>
      <div className={classes.root}>
        <div className={classes.inner}>
          <img src={flagIcon} alt="usa flag" className={classes.flag} />
          <div className={classes.textWrap}>
            <div className={classes.text}>
              An official website of the United States government
            </div>
            <button
              className={clsx(classes.text, classes.btn, classes.btnExpand)}
              onClick={() => setExpanded((exp) => !exp)}
            >
              Here&apos;s how you know{' '}
              {expanded ? (
                <ExpandLess fontSize="small" />
              ) : (
                <ExpandMore fontSize="small" />
              )}
            </button>
          </div>
        </div>
      </div>
      {expanded && (
        <div className={classes.root}>
          <div className={clsx(classes.inner, classes.infoInner)}>
            <div className={classes.info}>
              <div className={classes.infoIcon}>
                <img src={govIcon} alt="Dot Gov" />
              </div>
              <div className={classes.infoText}>
                <p>
                  <strong>The .gov means it’s official.</strong>
                  <br />
                  Federal government websites often end in .gov or .mil. Before
                  sharing sensitive information, make sure you’re on a federal
                  government site.
                </p>
              </div>
            </div>
            <div className={classes.info}>
              <div className={classes.infoIcon}>
                <img src={httpsIcon} alt="HTTPS" />
              </div>
              <div className={classes.infoText}>
                <p>
                  <strong>This site is secure.</strong>
                  <br />
                  The <strong>https://</strong> ensures that you are connecting
                  to the official website and that any information you provide
                  is encrypted and transmitted securely.
                </p>
              </div>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
Example #5
Source File: ExpandableList.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
export default function ExpandableList({ children, label, level, defaultOpen, info }: Props): ReactElement | null {
  const classes = useStyles()
  const [open, setOpen] = useState<boolean>(Boolean(defaultOpen))

  const handleClick = () => {
    setOpen(!open)
  }

  let rootLevelClass = ''
  let typographyVariant: 'h1' | 'h2' | 'h3' = 'h1'
  let contentLevelClass = classes.contentLevel0

  if (level === 1) {
    rootLevelClass = classes.rootLevel1
    typographyVariant = 'h2'
    contentLevelClass = classes.contentLevel12
  } else if (level === 2) {
    rootLevelClass = classes.rootLevel2
    typographyVariant = 'h3'
    contentLevelClass = classes.contentLevel12
  }

  return (
    <div className={`${classes.root} ${rootLevelClass}`}>
      <ListItem button onClick={handleClick} className={classes.header}>
        <ListItemText primary={<Typography variant={typographyVariant}>{label}</Typography>} />
        <div style={{ display: 'flex' }}>
          {!open && (
            <Typography variant="body2" className={classes.infoText}>
              {info}
            </Typography>
          )}
          {open ? <ExpandLess /> : <ExpandMore />}
        </div>
      </ListItem>
      <Collapse in={open} timeout="auto" unmountOnExit>
        <div className={contentLevelClass}>{children}</div>
      </Collapse>
    </div>
  )
}
Example #6
Source File: Scores.tsx    From dashboard with Apache License 2.0 5 votes vote down vote up
Scores = ({ score, nested }: ScoreProps) => {
  const [show, setShow] = useState(false)
  const { palette } = useTheme()

  let { op_name, operands, value, ref_id, description } = score
  if (!op_name && !operands && !value) {
    return <></>
  }

  const toggleShow = () => {
    setShow((prev) => !prev)
  }

  const canToggle = operands && operands.length > 0

  return (
    <div style={{ paddingLeft: nested ? "10px" : "0px" }}>
      <ListItem button={canToggle} onClick={toggleShow}>
        <Grid container>
          <Grid item xs={4}>
            <Box paddingTop="0.75rem">
              <Typography noWrap fontSize="1.25rem">
                {score.value || "0.12341234"}
              </Typography>
            </Box>
          </Grid>
          <Grid item xs={7}>
            <Box>
              <Typography noWrap>{op_name}</Typography>
              <Typography noWrap color={palette.grey[500]}>
                {description}
              </Typography>
            </Box>
          </Grid>
        </Grid>
        {canToggle && (
          <ListItemSecondaryAction>
            ({operands?.length}){show ? <ExpandLess /> : <ExpandMore />}
          </ListItemSecondaryAction>
        )}
      </ListItem>
      {operands && (
        <div>
          <Collapse in={show}>
            <List>
              {operands.map((operand, index) => (
                <Scores score={operand} key={`${index}-${ref_id}`} nested />
              ))}
            </List>
          </Collapse>
        </div>
      )}
    </div>
  )
}
Example #7
Source File: SwaggerView.tsx    From dashboard with Apache License 2.0 5 votes vote down vote up
SwaggerView = () => {
  const [show, setShow] = useState(false)
  const [host, setHost] = useState(getInitialHostAndPort().host)
  const [port, setPort] = useState(getInitialHostAndPort().port)
  const [endpoint, setEndpoint] = useState(DEFAULT_ENDPOINT)
  const [url, setURL] = useState(formatURL(host, port, endpoint))

  const updateURL = () => {
    setURL(formatURL(host, port, endpoint))
  }

  const toggleShow = () => {
    setShow((prev) => !prev)
  }

  return (
    <Container data-name="debuggingTool">
      <Box textAlign="right">
        <Button onClick={toggleShow}>
          endpoint settings {show ? <ExpandLess /> : <ExpandMore />}
        </Button>
      </Box>
      <Collapse in={show}>
        <Box paddingTop="2.5em">
          <Grid container spacing={2}>
            <Grid item xs={4}>
              <TextInput
                label="Host"
                variant="outlined"
                value={host}
                onChange={(e) => setHost(e.target.value)}
              />
            </Grid>
            <Grid item xs={2}>
              <TextInput
                label="Port"
                variant="outlined"
                value={port}
                onChange={(e) => setPort(e.target.value)}
              />
            </Grid>
            <Grid item xs={4}>
              <TextInput
                label="OpenAPI Schema"
                variant="outlined"
                value={endpoint}
                onChange={(e) => setEndpoint(e.target.value)}
              />
            </Grid>
            <Grid item xs={2}>
              <FullSizeButton onClick={updateURL} variant="contained">
                Set
              </FullSizeButton>
            </Grid>
          </Grid>
        </Box>
      </Collapse>
      <SwaggerUIReact
        url={url}
        presets={[WrappedComponents]}
        requestInterceptor={(r) => console.log("request:", r)}
        responseInterceptor={(r) => console.log("response:", r)}
      />
    </Container>
  )
}
Example #8
Source File: Facets.tsx    From cognitive-search-static-web-apps-sample-ui with MIT License 5 votes vote down vote up
render(): JSX.Element {

        const state = this.props.state;

        return (<FacetList component="nav">

            {state.facets.map(facetState => {

                var facetComponent: JSX.Element = null;
                switch (facetState.facetType) {
                    case FacetTypeEnum.BooleanFacet:
                        facetComponent = (<BooleanFacet state={facetState.state as BooleanFacetState} inProgress={this.props.inProgress} />);
                    break;
                    case FacetTypeEnum.NumericFacet:
                        facetComponent = (<NumericFacet state={facetState.state as NumericFacetState} inProgress={this.props.inProgress} />);
                    break;
                    case FacetTypeEnum.DateFacet:
                        facetComponent = (<DateFacet state={facetState.state as DateFacetState} inProgress={this.props.inProgress} />);
                    break;
                    case FacetTypeEnum.StringFacet:
                        facetComponent = (<StringFacet state={facetState.state as StringFacetState} inProgress={this.props.inProgress} />);
                    break;
                    case FacetTypeEnum.StringCollectionFacet:
                        facetComponent = (<StringCollectionFacet state={facetState.state as StringCollectionFacetState} inProgress={this.props.inProgress} />);
                    break;
                }

                // Getting reference to a proper getHintText method in this a bit unusual and not very strongly typed way
                const getHintTextFunc = facetComponent?.type.getHintText;

                return (<div key={facetState.displayName}>
                
                    <FacetListItem disableRipple={true} button onClick={() => state.toggleExpand(facetState.fieldName)}>
                        <ListItemText
                            primary={facetState.displayName}
                            secondary={getHintTextFunc ? getHintTextFunc(facetState.state) : ''}
                        />
                        {!!facetState.isExpanded ? <ExpandLess /> : <ExpandMore />}
                    </FacetListItem>

                    <Collapse in={facetState.isExpanded} timeout={200} unmountOnExit>
                        {facetComponent}
                    </Collapse>
                    
                </div>);
            })}
                
        </FacetList>);
    }
Example #9
Source File: ModTableRow.tsx    From ow-mod-manager with MIT License 4 votes vote down vote up
ModTableRow: React.FunctionComponent<Props> = ({ mod }) => {
  const styles = useStyles();
  const theme = useTheme();
  const missingDependencyNames = useRecoilValue(missingDependencyIdsState(mod));
  const isModOutdated = isOutdated(mod);
  const isModBroken = isBroken(mod);
  const addonMods = useRecoilValue(addonModList);
  const [isAddonsExpanded, setIsAddonsExpanded] = useState(false);
  const isAddon = mod.parent && !mod.localVersion;
  const enabledMods = useRecoilValue(enabledModList);
  const forceExpandAddons = useRecoilValue(isFiltering);
  const shouldExpandAddons = forceExpandAddons || isAddonsExpanded;
  const rowRef = useRef<HTMLTableRowElement>(null);
  const isLoading = useRecoilValue(modIsLoadingState(mod.uniqueName));

  useEffect(() => {
    if (!isLoading || !rowRef.current) return;

    rowRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'nearest',
    });
  }, [isLoading]);

  const addons = useMemo(
    () => addonMods.filter((addon) => addon.parent === mod.uniqueName),
    [addonMods, mod.uniqueName]
  );

  const conflictingMods = useMemo(
    () =>
      mod.conflicts && mod.conflicts.length > 0
        ? enabledMods
            .filter((enabledMod) =>
              mod.conflicts?.includes(enabledMod.uniqueName)
            )
            .map((enabledMod) => enabledMod.name)
        : [],
    [enabledMods, mod.conflicts]
  );

  const isModConflicting = mod.isEnabled && conflictingMods.length > 0;

  const handleExpandClick = () =>
    setIsAddonsExpanded((isExpanded) => !isExpanded);

  const getVersionColor = () => {
    if (isModBroken) {
      return 'default';
    }
    if (isModOutdated) {
      return 'secondary';
    }
    if (isInstalled(mod)) {
      return 'primary';
    }
    return 'default';
  };

  const getVersion = () => {
    if (isInstalled(mod)) {
      return mod.localVersion;
    }
    if (mod.remoteVersion) {
      return mod.remoteVersion;
    }
    return modsText.versionNotAvailable;
  };

  const getClassName = () => {
    let className = styles.tableRow;
    if (isModBroken || isModConflicting) {
      className += ` ${styles.brokenRow}`;
    } else if (isLoading) {
      className += ` ${styles.loading}`;
    } else if (missingDependencyNames.length > 0) {
      className += ` ${styles.missingDependencyRow}`;
    } else if (isAddon) {
      className += ` ${styles.addonRow}`;
    }
    return className;
  };

  const getModText = () => {
    if (isModBroken) {
      return modsText.modLoadError(mod.errors);
    }
    if (missingDependencyNames.length > 0) {
      return modsText.missingDependencyWarning(
        missingDependencyNames.join(', ')
      );
    }
    if (isModConflicting) {
      return modsText.conflictingModWarning(conflictingMods.join(', '));
    }
    return mod.description;
  };

  return (
    <>
      <TableRow className={getClassName()} key={mod.uniqueName} ref={rowRef}>
        <TableCell className={styles.tableCell}>
          <Box display="flex">
            {isAddon && (
              <Box
                bgcolor={theme.palette.background.paper}
                width="8px"
                minWidth="8px"
                marginRight={2}
                marginLeft={1}
                borderRadius="8px"
              />
            )}
            <Box width="100%">
              <Typography variant="subtitle1">
                <Box display="inline-block" mr={2}>
                  {mod.name}
                </Box>
                <Typography className={styles.modAuthor} variant="caption">
                  {' by '}
                  {mod.author}
                </Typography>
                <Typography variant="caption" />
              </Typography>
              <Box
                color={
                  isModBroken || isModConflicting
                    ? theme.palette.secondary.light
                    : theme.palette.text.secondary
                }
              >
                <Typography className={styles.modText} variant="caption">
                  {getModText()}
                </Typography>
              </Box>
              {addons.length > 0 && !forceExpandAddons && (
                <ButtonBase
                  className={styles.addonExpander}
                  onClick={handleExpandClick}
                >
                  <Box
                    display="flex"
                    alignItems="center"
                    borderRadius={theme.shape.borderRadius}
                    maxWidth="100%"
                  >
                    {shouldExpandAddons ? <ExpandLess /> : <ExpandMore />}

                    <Typography variant="caption" noWrap>
                      {addons.length}
                      {' addons available: '}
                      {addons.map((addon) => addon.name).join(', ')}
                    </Typography>
                  </Box>
                </ButtonBase>
              )}
            </Box>
          </Box>
        </TableCell>
        <TableCell className={styles.tableCell} align="right">
          {mod.downloadCount || '-'}
        </TableCell>
        <TableCell className={styles.tableCell}>
          <Chip
            color={getVersionColor()}
            label={getVersion()}
            className={styles.versionChip}
          />
          {!isModBroken && isModOutdated && (
            <div className={styles.outdatedChip}>{modsText.outdated}</div>
          )}
        </TableCell>
        <TableCell className={styles.tableCell}>
          <ModActions mod={mod} />
        </TableCell>
      </TableRow>
      {shouldExpandAddons &&
        addons.map((addon) => (
          <ModTableRow key={addon.uniqueName} mod={addon} />
        ))}
    </>
  );
}
Example #10
Source File: DomainDetails.tsx    From crossfeed with Creative Commons Zero v1.0 Universal 4 votes vote down vote up
DomainDetails: React.FC<Props> = (props) => {
  const { domainId } = props;
  const { getDomain } = useDomainApi(false);
  const { user } = useAuthContext();
  const [domain, setDomain] = useState<Domain>();
  const classes = useStyles();
  const history = useHistory();

  const fetchDomain = useCallback(async () => {
    try {
      setDomain(undefined);
      const result = await getDomain(domainId);
      setDomain(result);
    } catch (e) {
      console.error(e);
    }
  }, [domainId, getDomain]);

  useEffect(() => {
    fetchDomain();
  }, [fetchDomain]);

  const webInfo = useMemo(() => {
    if (!domain) {
      return [];
    }
    const categoriesToProducts: Record<string, Set<string>> = {};
    for (const service of domain.services) {
      for (const product of service.products) {
        const version = product.version ? ` ${product.version}` : '';
        const value = product.name + version;
        const name =
          product.tags && product.tags.length > 0 ? product.tags[0] : 'Misc';
        if (!categoriesToProducts[name]) {
          categoriesToProducts[name] = new Set();
        }
        categoriesToProducts[name].add(value);
      }
    }
    return Object.entries(categoriesToProducts).reduce(
      (acc, [name, value]) => [
        ...acc,
        {
          label: name,
          value: Array.from(value).join(', ')
        }
      ],
      [] as any
    );
  }, [domain]);

  const overviewInfo = useMemo(() => {
    if (!domain) {
      return [];
    }
    const ret = [];
    if (domain.ip) {
      ret.push({
        label: 'IP',
        value: domain.ip
      });
    }
    ret.push({
      label: 'First Seen',
      value: `${differenceInCalendarDays(
        Date.now(),
        parseISO(domain.createdAt)
      )} days ago`
    });
    ret.push({
      label: 'Last Seen',
      value: `${differenceInCalendarDays(
        Date.now(),
        parseISO(domain.updatedAt)
      )} days ago`
    });
    if (domain.country) {
      ret.push({
        label: 'Country',
        value: domain.country
      });
    }
    if (domain.cloudHosted) {
      ret.push({
        label: 'Cloud Hosted',
        value: 'Yes'
      });
    }
    ret.push({
      label: 'Organization',
      value: domain.organization.name
    });
    return ret;
  }, [domain]);

  const [hiddenRows, setHiddenRows] = React.useState<{
    [key: string]: boolean;
  }>({});

  const formatBytes = (bytes: number, decimals = 2): string => {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  };

  const generateWebpageList = (tree: any, prefix = '') => {
    return (
      <List
        className={`${classes.listRoot}${prefix ? ' ' + classes.nested : ''}`}
      >
        {Object.keys(tree).map((key) => {
          const isWebpage =
            'url' in tree[key] && typeof tree[key]['url'] === 'string';
          if (!isWebpage) {
            const newPrefix = prefix + '/' + key;
            return (
              <>
                <ListItem
                  button
                  onClick={() => {
                    setHiddenRows((hiddenRows: any) => {
                      hiddenRows[newPrefix] =
                        newPrefix in hiddenRows ? !hiddenRows[newPrefix] : true;
                      return { ...hiddenRows };
                    });
                  }}
                  key={newPrefix}
                >
                  <ListItemText primary={(prefix ? '' : '/') + key + '/'} />
                  {hiddenRows[newPrefix] ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse
                  in={!hiddenRows[newPrefix]}
                  timeout="auto"
                  unmountOnExit
                >
                  {generateWebpageList(tree[key], newPrefix)}
                </Collapse>
              </>
            );
          }
          const page = tree[key] as Webpage;
          const parsed = new URL(page.url);
          const split = parsed.pathname
            .replace(/\/$/, '') // Remove trailing slash
            .split('/');
          return (
            <ListItem
              button
              divider={true}
              key={page.url}
              onClick={() => window.open(page.url, '_blank')}
            >
              <ListItemText
                primary={(prefix ? '' : '/') + split.pop()}
                secondary={
                  page.status + ' • ' + formatBytes(page.responseSize ?? 0, 1)
                }
              ></ListItemText>
            </ListItem>
          );
        })}
      </List>
    );
  };

  if (!domain) {
    return null;
  }

  const url =
    (domain.services.find((service) => service.port === 443)
      ? 'https://'
      : 'http://') + domain.name;

  const { webpages = [] } = domain;
  webpages.sort((a, b) => (a.url > b.url ? 1 : -1));
  const webpageTree = generateWebpageTree(webpages);
  const webpageList = generateWebpageList(webpageTree);

  return (
    <Paper classes={{ root: classes.root }}>
      <div className={classes.title}>
        <h4>
          <Link to={`/inventory/domain/${domain.id}`}>{domain.name}</Link>
        </h4>

        <a href={url} target="_blank" rel="noopener noreferrer">
          <LinkOffIcon />
        </a>
      </div>
      <div className={classes.inner}>
        {overviewInfo.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Overview</h4>
            <DefinitionList items={overviewInfo} />
          </div>
        )}
        {webInfo.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Known Products</h4>
            <DefinitionList items={webInfo} />
          </div>
        )}

        {domain.vulnerabilities.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Vulnerabilities</h4>
            <Accordion className={classes.accordionHeaderRow} disabled>
              <AccordionSummary>
                <Typography className={classes.accordionHeading}>
                  Title
                </Typography>
                <Typography className={classes.vulnDescription}>
                  Serverity
                </Typography>
                <Typography className={classes.vulnDescription}>
                  State
                </Typography>
                <Typography className={classes.vulnDescription}>
                  Created
                </Typography>
              </AccordionSummary>
            </Accordion>
            {domain.vulnerabilities.map((vuln) => (
              <Accordion
                className={classes.accordion}
                key={vuln.id}
                onClick={(event) => {
                  event.stopPropagation();
                  history.push('/inventory/vulnerability/' + vuln.id);
                }}
              >
                <AccordionSummary>
                  <Typography className={classes.accordionHeading}>
                    {vuln.title}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.severity}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.state}
                  </Typography>
                  <Typography className={classes.vulnDescription}>
                    {vuln.createdAt
                      ? `${differenceInCalendarDays(
                          Date.now(),
                          parseISO(vuln.createdAt)
                        )} days ago`
                      : ''}
                  </Typography>
                </AccordionSummary>
              </Accordion>
            ))}
          </div>
        )}
        {domain.services.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Ports</h4>
            <Accordion className={classes.accordionHeaderRow} disabled>
              <AccordionSummary expandIcon={<ExpandMore />}>
                <Typography className={classes.accordionHeading}>
                  Port
                </Typography>
                <Typography className={classes.accordionHeading}>
                  Products
                </Typography>
                <Typography className={classes.lastSeen}>Last Seen</Typography>
              </AccordionSummary>
            </Accordion>
            {domain.services.map((service) => {
              const products = service.products
                .map(
                  (product) =>
                    product.name +
                    (product.version ? ` ${product.version}` : '')
                )
                .join(', ');
              return (
                <Accordion className={classes.accordion} key={service.id}>
                  <AccordionSummary expandIcon={<ExpandMore />}>
                    <Typography className={classes.accordionHeading}>
                      {service.port}
                    </Typography>
                    <Typography className={classes.accordionHeading}>
                      {products}
                    </Typography>
                    <Typography className={classes.lastSeen}>
                      {service.lastSeen
                        ? `${differenceInCalendarDays(
                            Date.now(),
                            parseISO(service.lastSeen)
                          )} days ago`
                        : ''}
                    </Typography>
                  </AccordionSummary>
                  {service.products.length > 0 && (
                    <AccordionDetails>
                      <DefinitionList
                        items={[
                          {
                            label: 'Products',
                            value: products
                          },
                          {
                            label: 'Banner',
                            value:
                              (user?.userType === 'globalView' ||
                                user?.userType === 'globalAdmin') &&
                              service.banner
                                ? service.banner
                                : 'None'
                          }
                        ]}
                      />
                    </AccordionDetails>
                  )}
                </Accordion>
              );
            })}
          </div>
        )}
        {domain.webpages?.length > 0 && (
          <div className={classes.section}>
            <h4 className={classes.subtitle}>Site Map</h4>
            {webpageList}
          </div>
        )}
      </div>
    </Paper>
  );
}
Example #11
Source File: FlowChartNodes.tsx    From dashboard with Apache License 2.0 4 votes vote down vote up
PropertyListItem = ({
  itemKey,
  itemValue,
  nested,
}: {
  itemKey: string
  itemValue: any
  nested?: boolean
}) => {
  const [show, setShow] = useState(false)
  const { palette } = useTheme()

  const toggleShow = () => {
    setShow((prev) => !prev)
  }

  let isObject = false
  if (typeof itemValue === "object" && itemValue !== null) {
    isObject = true
  }

  if (isObject && isEmpty(itemValue)) return null
  if (
    itemValue === 0 ||
    itemValue === "unset" ||
    itemValue === null ||
    itemValue === "" ||
    itemValue === {}
  )
    return null

  return (
    <div
      style={{
        marginLeft: nested ? "2em" : "0px",
        borderLeft: `1px solid ${palette.grey[500]}`,
        backgroundColor: show
          ? isObject
            ? `${palette.grey[100]}80`
            : palette.grey[200]
          : "inherit",
      }}
    >
      <ListItem button onClick={toggleShow} style={{ paddingLeft: "0px" }}>
        <Grid container>
          <Grid item xs={6}>
            <Typography noWrap>
              <ListMarker color={palette.grey[500]} />
              {itemKey}
            </Typography>
          </Grid>
          <Grid item xs={6}>
            <Typography noWrap>
              {isObject ? (
                <LightText color={palette.grey[500]}>Object</LightText>
              ) : (
                String(itemValue)
              )}
            </Typography>
          </Grid>
        </Grid>
        <ListItemSecondaryAction>
          {isObject && <>({Object.keys(itemValue).length})</>}
          {show ? <ExpandLess /> : <ExpandMore />}
        </ListItemSecondaryAction>
      </ListItem>
      <Collapse in={show}>
        {isObject ? (
          Object.keys(itemValue).length ? (
            show && <PropertyList data={itemValue} nested />
          ) : (
            <ListItem>
              <WrappedText>This Object is empty</WrappedText>
            </ListItem>
          )
        ) : (
          <ListItem>
            <WrappedText>
              <div>
                <b>key: </b>
                {itemKey}
              </div>
              <div>
                <b>value: </b>
                {itemValue}
              </div>
            </WrappedText>
          </ListItem>
        )}
      </Collapse>
    </div>
  )
}