<commit_before>import cx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import { FixedSizeList } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import AutoSizer from 'react-virtualized-auto-sizer';
import itemSelection from 'item-selection/immutable';
import useDirection from '../../hooks/useDirection';
import LoadingRow from './LoadingRow';

const {
  useCallback,
  useEffect,
  useRef,
  useState,
} = React;

/**
 * Check if two media lists are different, taking into account
 * pagination. If the new media list contains items where the previous
 * list doesn't, but every other item is identical, we assume
 * the new list has just loaded a page that wasn't loaded in the
 * previous one, and decide that the list is not really different.
 */
function didMediaChange(prev, next) {
  return prev.some((item, i) => item && next[i] && item._id !== next[i]._id);
}

const defaultMakeActions = () => null;

function BaseMediaList({
  className,
  media,
  listComponent: ListComponent,
  rowComponent: RowComponent,
  rowProps = {},
  onRequestPage,
  onOpenPreviewMediaDialog,
  // The `size` property is only necessary for lazy loading.
  size = null,
  makeActions = defaultMakeActions,
}) {
  const lastMediaRef = useRef(media);
  const [selection, setSelection] = useState(() => itemSelection(media));
  const inFlightPageRequests = useRef({});
  const direction = useDirection();

  useEffect(() => {
    const lastMedia = lastMediaRef.current;
    if (lastMedia !== media) {
      lastMediaRef.current = media;
      const selectedIndices = selection.getIndices();
      const mediaChanged = didMediaChange(lastMedia, media);
      setSelection(mediaChanged ? itemSelection(media) : itemSelection(media, selectedIndices));
    }
  }, [media, selection]);

  const selectItem = useCallback((index, event) => {
    event.preventDefault();

    if (event.shiftKey) {
      setSelection(selection.selectRange(index));
    } else if (event.ctrlKey) {
      setSelection(selection.selectToggle(index));
    } else {
      setSelection(selection.select(index));
    }
  }, [selection]);

  const renderRow = useCallback(({ index, style }) => {
    const selected = selection.isSelectedIndex(index);
    if (!media[index]) {
      return (
        <LoadingRow
          key={index}
          className="MediaList-row"
          style={style}
          selected={selected}
        />
      );
    }

    return (
      <RowComponent
        key={media[index] ? media[index]._id : index}
        {...rowProps}
        style={style}
        className="MediaList-row"
        media={media[index]}
        selected={selected}
        selection={selection.get()}
        onClick={(event) => selectItem(index, event)}
        onOpenPreviewMediaDialog={onOpenPreviewMediaDialog}
        makeActions={() => makeActions(media[index], selection, index)}
      />
    );
    // `RowComponent` should really be in this list but then react-hooks/exhaustive-deps complains.
    // We don't change it on the fly ever I think and shouldn't, but if we ever did have a reason
    // to do it, this might break :)
  }, [selection, media, rowProps, onOpenPreviewMediaDialog, makeActions, selectItem]);

  const mediaLength = media.length;
  const innerList = ({ height, onItemsRendered, ref }) => (
    <FixedSizeList
      itemCount={size || mediaLength}
      itemSize={56}
      height={height}
      onItemsRendered={onItemsRendered}
      ref={ref}
      width="100%"
      direction={direction}
      rerenderOnUpdate={selection}
    >
      {renderRow}
    </FixedSizeList>
  );

  // This is not used as a real React component.
  // eslint-disable-next-line react/prop-types<commit_msg>Fix `key` assignment for media row elements (#1899)<commit_after>import cx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import { FixedSizeList } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import AutoSizer from 'react-virtualized-auto-sizer';
import itemSelection from 'item-selection/immutable';
import useDirection from '../../hooks/useDirection';
import LoadingRow from './LoadingRow';

const {
  useCallback,
  useEffect,
  useRef,
  useState,
} = React;

/**
 * Check if two media lists are different, taking into account
 * pagination. If the new media list contains items where the previous
 * list doesn't, but every other item is identical, we assume
 * the new list has just loaded a page that wasn't loaded in the
 * previous one, and decide that the list is not really different.
 */
function didMediaChange(prev, next) {
  return prev.some((item, i) => item && next[i] && item._id !== next[i]._id);
}

const defaultMakeActions = () => null;

function BaseMediaList({
  className,
  media,
  listComponent: ListComponent,
  rowComponent: RowComponent,
  rowProps = {},
  onRequestPage,
  onOpenPreviewMediaDialog,
  // The `size` property is only necessary for lazy loading.
  size = null,
  makeActions = defaultMakeActions,
}) {
  const lastMediaRef = useRef(media);
  const [selection, setSelection] = useState(() => itemSelection(media));
  const inFlightPageRequests = useRef({});
  const direction = useDirection();

  const itemKey = useCallback((index) => {
    if (media[index]) {
      return media[index]._id;
    }
    return `unloaded_${index}`;
  }, [media]);

  useEffect(() => {
    const lastMedia = lastMediaRef.current;
    if (lastMedia !== media) {
      lastMediaRef.current = media;
      const selectedIndices = selection.getIndices();
      const mediaChanged = didMediaChange(lastMedia, media);
      setSelection(mediaChanged ? itemSelection(media) : itemSelection(media, selectedIndices));
    }
  }, [media, selection]);

  const selectItem = useCallback((index, event) => {
    event.preventDefault();

    if (event.shiftKey) {
      setSelection(selection.selectRange(index));
    } else if (event.ctrlKey) {
      setSelection(selection.selectToggle(index));
    } else {
      setSelection(selection.select(index));
    }
  }, [selection]);

  const renderRow = useCallback(({ index, style }) => {
    const selected = selection.isSelectedIndex(index);
    if (!media[index]) {
      return (
        <LoadingRow
          className="MediaList-row"
          style={style}
          selected={selected}
        />
      );
    }

    return (
      <RowComponent
        {...rowProps}
        style={style}
        className="MediaList-row"
        media={media[index]}
        selected={selected}
        selection={selection.get()}
        onClick={(event) => selectItem(index, event)}
        onOpenPreviewMediaDialog={onOpenPreviewMediaDialog}
        makeActions={() => makeActions(media[index], selection, index)}
      />
    );
    // `RowComponent` should really be in this list but then react-hooks/exhaustive-deps complains.
    // We don't change it on the fly ever I think and shouldn't, but if we ever did have a reason
    // to do it, this might break :)
  }, [selection, media, rowProps, onOpenPreviewMediaDialog, makeActions, selectItem]);

  const mediaLength = media.length;
  const innerList = ({ height, onItemsRendered, ref }) => (
    <FixedSizeList
      itemCount={size || mediaLength}
      itemSize={56}
      itemKey={itemKey}
      height={height}
      onItemsRendered={onItemsRendered}
      ref={ref}
      width="100%"
      direction={direction}
      rerenderOnUpdate={selection}
    >
      {renderRow}
    </FixedSizeList>
  );

  // This is not used as a real React component.
  // eslint-disable-next-line react/prop-types
{'fraction_non_alphanumeric': 0.12243825538623226, 'fraction_numerical': 0.0018392012611665792, 'mean_word_length': 3.350285714285714, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '811881', 'n_tokens_mistral': 2157, 'n_tokens_neox': 2144, 'n_words': 601}