react-virtualized#CellMeasurer TypeScript Examples

The following examples show how to use react-virtualized#CellMeasurer. 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: list.tsx    From gio-design with Apache License 2.0 5 votes vote down vote up
private renderListItem =
    (options: any) =>
    ({ index, style, parent }: { index: number; style: React.CSSProperties; parent: any }) => {
      const {
        isMultiple,
        required,
        value,
        valueKey,
        renderKey,
        disabledOptions,
        labelRenderer,
        getGroupIcon,
        allowDuplicate,
        placement = 'left',
        getPopupContainer,
      } = this.props;
      const option = options[index];
      const isGroup = get(option, 'type') === 'groupLabel';
      const label = labelRenderer ? labelRenderer(option) : get(option, 'label') || option;
      const optionKey = renderKey || valueKey;
      const key = optionKey ? option[optionKey] : option;

      const isSelectedAndRequired = this.getSelected(option) && required && (isMultiple ? value?.length === 1 : true);

      const isMax = this.checkIsMax(option);

      const disabled =
        isSelectedAndRequired ||
        isMax ||
        disabledOptions.indexOf(valueKey ? option[valueKey] : option) > -1 ||
        option.disabled;

      const groupIcon = getGroupIcon ? getGroupIcon(option.group) : null;
      return (
        <CellMeasurer key={key} cache={this._cache} parent={parent} columnIndex={0} rowIndex={index}>
          {isGroup ? (
            <Group
              key={option.label}
              name={option.label}
              option={option}
              style={{
                ...style,
                height: isNumber(style.height) ? (style.height as number) - 4 : style.height,
                paddingTop: index !== 0 ? '20px' : '0px',
              }}
              icon={groupIcon}
              isSelected={this.getSelected(option)}
              isMultiple={!!isMultiple}
              labelRenderer={labelRenderer}
            />
          ) : (
            <SelectOption
              key={key}
              style={{ ...style, height: isNumber(style.height) ? (style.height as number) - 4 : style.height }}
              option={option}
              title={!labelRenderer ? label : undefined}
              isSelected={this.getSelected(option)}
              isMultiple={!!isMultiple}
              allowDuplicate={allowDuplicate}
              onSelect={this.handleSelect}
              onClick={this.handleClick}
              disabled={disabled}
              hasGroupIcon={!!groupIcon}
              getPopupContainer={getPopupContainer}
              placement={placement}
            >
              {label}
            </SelectOption>
          )}
        </CellMeasurer>
      );
    };
Example #2
Source File: index.tsx    From metaflow-ui with Apache License 2.0 4 votes vote down vote up
LogList: React.FC<LogProps> = ({ logdata, fixedHeight, onScroll, downloadUrl, setFullscreen }) => {
  const { timezone } = useContext(TimezoneContext);
  const { t } = useTranslation();
  const rows = logdata.logs;
  const [stickBottom, setStickBottom] = useState(true);
  const [cache] = useState(
    new CellMeasurerCache({
      fixedWidth: true,
      minHeight: 25,
    }),
  );
  const _list = useRef<List>(null);
  const search = logdata.localSearch;
  const count = rows.length;

  const okCount = rows.reduce((okAmount, item) => {
    return typeof item === 'object' ? okAmount + 1 : okAmount;
  }, 0);

  const totalHeight = rows.reduce((val, _item, index) => {
    return val + (cache.getHeight(index, 0) || 0);
  }, 0);

  // Clear cached row heights on window resize events
  useEffect(() => {
    const listener = () => {
      cache.clearAll();
    };
    window.addEventListener('resize', listener);
    return () => window.removeEventListener('resize', listener);
  }, []); // eslint-disable-line

  // Force row height calculations after fetch ok

  useEffect(() => {
    if (_list?.current) {
      cache.clearAll();
      _list.current.recomputeRowHeights();
    }
  }, [okCount]); // eslint-disable-line

  useEffect(() => {
    if (stickBottom && _list) {
      _list.current?.scrollToRow(count);
    }
  }, [count, okCount, stickBottom]);

  //
  // Index tracking
  //

  const [scrollIndex, setIndex] = useState(0);
  const [debouncedIndex] = useDebounce(scrollIndex, 300);
  useEffect(() => {
    if (onScroll && !stickBottom) {
      onScroll(debouncedIndex);
    }
  }, [debouncedIndex, onScroll]); // eslint-disable-line

  //
  // Search features
  //

  const searchActive = search.result.active;
  const searchCurrent = search.result.current;
  const searchQuery = search.result.query;

  useEffect(() => {
    if (searchActive && search.result.result[searchCurrent]) {
      _list.current?.scrollToRow(search.result.result[searchCurrent].line);
    }
  }, [searchActive, searchCurrent, searchQuery]); //eslint-disable-line

  return (
    <div style={{ flex: '1 1 0' }} data-testid="loglist-wrapper">
      <LogActionBar
        data={logdata.logs}
        downloadlink={downloadUrl}
        setFullscreen={setFullscreen}
        search={logdata.localSearch}
        spaceAround={!!fixedHeight}
      />

      {rows.length === 0 && ['Ok', 'Error'].includes(logdata.preloadStatus) && logdata.status === 'NotAsked' && (
        <div data-testid="loglist-preload-empty">{t('task.no-preload-logs')}</div>
      )}

      {rows.length === 0 && logdata.status === 'Ok' && <div data-testid="loglist-empty">{t('task.no-logs')}</div>}

      {rows.length > 0 && (
        <LogListContainer data-testid="loglist-container">
          <AutoSizer disableHeight>
            {({ width }) => (
              <List
                ref={_list}
                overscanRowCount={5}
                rowCount={rows.length}
                rowHeight={cache.rowHeight}
                onRowsRendered={(data) => {
                  if (onScroll) {
                    setIndex(data.overscanStartIndex);
                  }
                }}
                deferredMeasurementCache={cache}
                onScroll={(args: { scrollTop: number; clientHeight: number; scrollHeight: number }) => {
                  if (args.scrollTop + args.clientHeight >= args.scrollHeight) {
                    setStickBottom(true);
                  } else if (stickBottom) {
                    setStickBottom(false);
                  }
                }}
                rowRenderer={({ index, style, key, parent }) => (
                  <CellMeasurer cache={cache} columnIndex={0} key={key} rowIndex={index} parent={parent}>
                    {() => {
                      const item = rows[index];

                      return (
                        <LogLine style={style} data-testid="log-line">
                          <LogLineNumber className="logline-number">{index}</LogLineNumber>
                          {getTimestamp(item, timezone)}
                          <LogLineText>
                            {typeof item === 'object' ? getLineText(item as Log, search.result) : 'Loading...'}
                          </LogLineText>
                        </LogLine>
                      );
                    }}
                  </CellMeasurer>
                )}
                height={fixedHeight ? fixedHeight - 16 : totalHeight < LIST_MAX_HEIGHT ? totalHeight : LIST_MAX_HEIGHT}
                width={width}
              />
            )}
          </AutoSizer>

          {!stickBottom && (
            <ScrollToBottomButton onClick={() => setStickBottom(true)} data-testid="loglist-stick-bottom">
              {t('run.scroll-to-bottom')}
            </ScrollToBottomButton>
          )}

          <PollLoader status={logdata.status} preloadStatus={logdata.preloadStatus} />
        </LogListContainer>
      )}
    </div>
  );
}
Example #3
Source File: PodLogs.tsx    From console with GNU Affero General Public License v3.0 4 votes vote down vote up
PodLogs = ({
  classes,
  tenant,
  namespace,
  podName,
  propLoading,
}: IPodLogsProps) => {
  const dispatch = useDispatch();
  const loadingTenant = useSelector(
    (state: AppState) => state.tenants.loadingTenant
  );
  const [highlight, setHighlight] = useState<string>("");
  const [logLines, setLogLines] = useState<string[]>([]);
  const [loading, setLoading] = useState<boolean>(true);

  const cache = new CellMeasurerCache({
    minWidth: 5,
    fixedHeight: false,
  });

  useEffect(() => {
    if (propLoading) {
      setLoading(true);
    }
  }, [propLoading]);

  useEffect(() => {
    if (loadingTenant) {
      setLoading(true);
    }
  }, [loadingTenant]);

  const renderLog = (logMessage: string, index: number) => {
    if (!logMessage) {
      return null;
    }
    // remove any non ascii characters, exclude any control codes
    logMessage = logMessage.replace(/([^\x20-\x7F])/g, "");

    // regex for terminal colors like e.g. `[31;4m `
    const tColorRegex = /((\[[0-9;]+m))/g;

    // get substring if there was a match for to split what
    // is going to be colored and what not, here we add color
    // only to the first match.
    let substr = logMessage.replace(tColorRegex, "");

    // in case highlight is set, we select the line that contains the requested string
    let highlightedLine =
      highlight !== ""
        ? logMessage.toLowerCase().includes(highlight.toLowerCase())
        : false;

    // if starts with multiple spaces add padding
    if (substr.startsWith("   ")) {
      return (
        <div
          key={index}
          className={`${highlightedLine ? classes.highlight : ""}`}
        >
          <span className={classes.tab}>{substr}</span>
        </div>
      );
    } else {
      // for all remaining set default class
      return (
        <div
          key={index}
          className={`${highlightedLine ? classes.highlight : ""}`}
        >
          <span className={classes.ansidefault}>{substr}</span>
        </div>
      );
    }
  };

  useEffect(() => {
    if (loading) {
      api
        .invoke(
          "GET",
          `/api/v1/namespaces/${namespace}/tenants/${tenant}/pods/${podName}`
        )
        .then((res: string) => {
          setLogLines(res.split("\n"));
          setLoading(false);
        })
        .catch((err: ErrorResponseHandler) => {
          dispatch(setErrorSnackMessage(err));
          setLoading(false);
        });
    }
  }, [loading, podName, namespace, tenant, dispatch]);

  function cellRenderer({ columnIndex, key, parent, index, style }: any) {
    return (
      // @ts-ignore
      <CellMeasurer
        cache={cache}
        columnIndex={columnIndex}
        key={key}
        parent={parent}
        rowIndex={index}
      >
        <div
          style={{
            ...style,
          }}
        >
          {renderLog(logLines[index], index)}
        </div>
      </CellMeasurer>
    );
  }

  return (
    <React.Fragment>
      <Grid item xs={12} className={classes.actionsTray}>
        <TextField
          placeholder="Highlight Line"
          className={classes.searchField}
          id="search-resource"
          label=""
          onChange={(val) => {
            setHighlight(val.target.value);
          }}
          InputProps={{
            disableUnderline: true,
            startAdornment: (
              <InputAdornment position="start">
                <SearchIcon />
              </InputAdornment>
            ),
          }}
          variant="standard"
        />
      </Grid>
      <Grid item xs={12}>
        <br />
      </Grid>
      <Grid item xs={12}>
        <Paper>
          <div className={classes.logList}>
            {logLines.length >= 1 && (
              // @ts-ignore
              <AutoSizer>
                {({ width, height }) => (
                  // @ts-ignore
                  <List
                    rowHeight={(item) => cache.rowHeight(item)}
                    overscanRowCount={15}
                    rowCount={logLines.length}
                    rowRenderer={cellRenderer}
                    width={width}
                    height={height}
                  />
                )}
              </AutoSizer>
            )}
          </div>
        </Paper>
      </Grid>
    </React.Fragment>
  );
}