react-sortable-hoc#SortableContainer JavaScript Examples

The following examples show how to use react-sortable-hoc#SortableContainer. 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: repeater.js    From formality with GNU General Public License v3.0 6 votes vote down vote up
SortableList = SortableContainer(({items, id, template, onChangeChild, removeText, onRemove, addOnNonEmpty, addClass}) => {
  let classes = addClass ? ('repeater-rows ' + addClass) : 'repeater-rows'
  return el('div', {className: classes}, items.map((value, index) => {
    return el(SortableItem, {
      value,
      parentValue: items,
      index,
      nindex: index,
      onChangeChild,
      template,
      removeText,
      onRemove,
      addOnNonEmpty,
      key: id + '-repeater-item-' + value._key
    })
  }))
})
Example #2
Source File: infinite-list.js    From Lynx with MIT License 6 votes vote down vote up
SortableList = SortableContainer(({items}) => {
  return (
    <Infinite containerHeight={600} elementHeight={items.map(({height}) => height)}>
      {items.map(({value, height}, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} height={height} />
      ))}
    </Infinite>
  );
})
Example #3
Source File: drag-handle.js    From Lynx with MIT License 6 votes vote down vote up
SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
})
Example #4
Source File: basic.js    From Lynx with MIT License 6 votes vote down vote up
SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
})
Example #5
Source File: virtual-table-columns.js    From Lynx with MIT License 6 votes vote down vote up
SortableHeaderRowRenderer = SortableContainer(
  ({className, columns, style}) => (
    <div className={className} role="row" style={style}>
      {React.Children.map(columns, (column, index) => (
        <SortableHeader index={index}>
          {column}
        </SortableHeader>
      ))}
    </div>
  )
)
Example #6
Source File: PropsTree.js    From react-ui-builder-editor with GNU General Public License v3.0 6 votes vote down vote up
SortableTreeList = SortableContainer(({items, classes}) => {
  return (
    <div className={classes.listContainer}>
      {items.map((element, index) => {
        return (
          <SortableTreeItem key={`item-${index}`} index={index} element={element} />
        );
      })}
    </div>
  )
})
Example #7
Source File: PageTree.js    From react-ui-builder-editor with GNU General Public License v3.0 6 votes vote down vote up
SortableTreeList = SortableContainer(({items, classes}) => {
  return (
    <div className={classes.listContainer}>
      {items.map((element, index) => {
        return (
          <SortableTreeItem key={`item-${index}`} index={index} element={element} />
        );
      })}
    </div>
  )
})
Example #8
Source File: index.js    From DMS_React with GNU Affero General Public License v3.0 6 votes vote down vote up
ToDoList = SortableContainer(({toDos, onTodoSelect, onTodoChecked, onMarkAsStart, width}) => {
  return (
    <div className="module-list">
      <CustomScrollbars className="module-list-scroll scrollbar"
                        style={{height: width >= 1200 ? 'calc(100vh - 259px)' : 'calc(100vh - 238px)'}}>
        {toDos.map((todo, index) =>
          <ToDoItem key={index} index={index} todo={todo} onTodoSelect={onTodoSelect}
                    onMarkAsStart={onMarkAsStart}
                    onTodoChecked={onTodoChecked}/>
        )}
      </CustomScrollbars>
    </div>
  )
})
Example #9
Source File: DraggableColorList.js    From flat-ui-colors with MIT License 6 votes vote down vote up
DraggableColorList = SortableContainer(({ colors, removeColor }) => {
  return (
    <div style={{ height: '100%' }}>
      {colors.map((color, i) => (
        <DraggableColorBox
          index={i}
          key={color.name}
          color={color.color}
          name={color.name}
          handleClick={() => removeColor(color.name)}
        />
      ))}
    </div>
  );
})
Example #10
Source File: index.js    From ice-electron with MIT License 6 votes vote down vote up
SortableWrap = SortableContainer(({ projectPanels, isSorting }) => {
  return (
    <div className={styles.sortableWrap}>
      {projectPanels.map((panel, index) => {
        const { name, isAvailable } = panel;
        const Panel = panels[name];
        return Panel && isAvailable ? (
          <ErrorBoundary key={index} FallbackComponent={FallbackPanel}>
            <SortableItem
              element={<Panel {...panel} />}
              key={index}
              index={index}
              isSorting={isSorting}
            />
          </ErrorBoundary>
        ) : null;
      })}
    </div>
  );
})
Example #11
Source File: BuildPageModal.js    From ice-electron with MIT License 6 votes vote down vote up
SelectedBlocks = SortableContainer(({ blocks, onNameChange, onDelete, isSorting }) => {
  return (
    <div className={styles.blocks}>
      {
        blocks.length ?
          blocks.map((block, index) => {
            return (
              <SelectedBlock
                {...block}
                index={index}
                onNameChange={onNameChange}
                onDelete={onDelete}
                isSorting={isSorting}
                key={index}
              />
            );
          }) :
          <div className={styles.empty}>
            <img src="https://img.alicdn.com/tfs/TB1yGn2mYZnBKNjSZFrXXaRLFXa-182-149.png" alt="区块" />
            <FormattedMessage id="iceworks.project.panel.page.create.builder.empty" />
          </div>
      }
    </div>
  );
})
Example #12
Source File: Roster.js    From zengm-legacy with Apache License 2.0 6 votes vote down vote up
TBody = SortableContainer(({editable, players, season, selectedPid, showTradeFor}) => {
    return <tbody id="roster-tbody">
        {players.map((p, i) => {
            return <RosterRow
                key={p.pid}
                editable={editable}
                i={i}
                index={i}
                p={p}
                season={season}
                selectedPid={selectedPid}
                showTradeFor={showTradeFor}
            />;
        })}
    </tbody>;
})
Example #13
Source File: PageLayer.js    From dnd-builder with MIT License 6 votes vote down vote up
SortableContainer = sortableContainer(({ children, onScroll }) => {
  return (
    <ul
      className="jfReportSelectOption-list withDnd forPageLayer"
      onScroll={onScroll}
    >
      {children}
    </ul>
  );
})
Example #14
Source File: Ranker.js    From label-studio-frontend with Apache License 2.0 6 votes vote down vote up
SortableList = SortableContainer(({ item, items }) => {
  return (
    <List celled>
      {items.map((value, index) => (
        <SortableText
          key={`item-${index}`}
          index={index}
          value={value}
          color={value.backgroundColor}
          item={item}
          onClick={() => {}}
        />
      ))}
    </List>
  );
})
Example #15
Source File: List.js    From label-studio-frontend with Apache License 2.0 6 votes vote down vote up
SortableList = SortableContainer(({ item, items }) => {
  return (
    <List celled>
      {items.map((value, index) => (
        <SortableText
          key={`item-${index}`}
          index={index}
          value={value}
          color={value.backgroundColor}
          item={item}
          onClick={() => {}}
        />
      ))}
    </List>
  );
})
Example #16
Source File: index.jsx    From mixbox with GNU General Public License v3.0 6 votes vote down vote up
BodyContainer = SortableContainer(props => {
    const {
        children,
        ...others
    } = props;
    const children2 = props.children.flat(4).filter(item => !!item);

    return (
        <tbody {...others}>{children2.map((item, index) => {
            const {key} = item;

            return (
                <RowElement
                    key={key}
                    index={index}
                >
                    {item}
                </RowElement>
            );
        })}</tbody>
    );
})
Example #17
Source File: imageGroup.js    From egoshop with Apache License 2.0 6 votes vote down vote up
SortableList = SortableContainer(({ items, pressDelay, children }) => {
    return (
        <ul className={styles.sortableList}>
            {items.length > 0 ? items.map((value, index) => (
                <SortableItem key={`item-${index}`} index={index} value={value} />
            )) : null}
            <li>{children}</li>
        </ul>
    );
})
Example #18
Source File: SortableWidgetContainer.jsx    From covid with GNU General Public License v3.0 6 votes vote down vote up
DraggableWidgetsList = SortableContainer(
  ({ items: widgets, ...props }) => {
    const classes = useStyles()

    return (
      <Grid container spacing={3} className={classes.widgetsContainer}>
        {widgets.map(({ id, Component, payload }, index) => {
          // Use `id` for the key to optimize renders on reorder
          // The SortableElements will use the map method's index for sorting
          // Passthrough `id`, `Component` and `payload`
          return (
            <DraggableWidgetContainer
              key={id}
              index={index}
              {...props}
              {...{ id, Component, payload }}
            />
          )
        })}
      </Grid>
    )
  }
)
Example #19
Source File: TrackContainer.jsx    From Oud with MIT License 6 votes vote down vote up
TrackContainer = SortableContainer((props) => {
  return (
    <div>
      {props.tracks.map((track, index) => {
        return (
          <SortableTrackContainer
            key={track}
            index={index}
            idx={index}
            id={track}
            playTrack={props.playTrack}
            playing={props.playing}
            changePlayingState={props.changePlayingState}
            toggleDropdown={props.toggleDropdown}
          />
        );
      })}
      )
    </div>
  );
})
Example #20
Source File: sidebar.js    From neutron with Mozilla Public License 2.0 5 votes vote down vote up
SortableContainer = sortableContainer(({ children }) => <Box>{children}</Box>)
Example #21
Source File: drag-sorting-handler.jsx    From virtuoso-design-system with MIT License 5 votes vote down vote up
SortableContainer = sortableContainer(props => <tbody {...props} />)
Example #22
Source File: virtual-list.js    From Lynx with MIT License 5 votes vote down vote up
SortableList = SortableContainer(VirtualList, {withRef: true})
Example #23
Source File: PageList.js    From dnd-builder with MIT License 5 votes vote down vote up
PageList = SortableContainer(({
  acceptedItems,
  additionalPageItems,
  hashCode,
  itemAccessor,
  layoutSettings,
  onAnEventTrigger,
  onPageAdd,
  onPageClick,
  onPageDuplicate,
  onPageRemove,
  pages,
  selectedPages,
}) => {
  const pageContainerStyles = useRef({});
  const {
    reportBackgroundColor,
    reportLayoutHeight = 794,
    reportLayoutWidth = 1123,
  } = layoutSettings;
  const width = parseInt(reportLayoutWidth, 10);
  const height = parseInt(reportLayoutHeight, 10);
  const scale = getScaleForPageThumbnailLarge(width, height);

  pageContainerStyles.current = {
    height: height,
    transform: `scale(${scale})`,
    transformOrigin: '0 0',
    width: width,
  };

  return (
    <ul className="jfReport-pageThumbnailList d-flex j-between f-wrap">
      {pages.map(page => {
        const { backgroundColor } = page;
        const style = {
          ...pageContainerStyles.current,
          backgroundColor: backgroundColor ? backgroundColor : reportBackgroundColor || '#fff',
        };
        return (
          <PageItem
            key={`item-${page.id}-${page.order}`}
            acceptedItems={acceptedItems}
            additionalPageItems={additionalPageItems}
            hashCode={hashCode}
            index={page.order - 1}
            isSelected={selectedPages.indexOf(page.id) > -1}
            itemAccessor={itemAccessor}
            onAnEventTrigger={onAnEventTrigger}
            onPageAdd={onPageAdd}
            onPageClick={onPageClick}
            onPageDuplicate={onPageDuplicate}
            onPageRemove={onPageRemove}
            order={page.order}
            page={page}
            style={style}
          />
        );
      })}
      <div className="thumbnailWrapper forPageAdder d-flex j-end dir-col">
        <PageAdder
          onPageAdd={onPageAdd}
          pageCount={pages.length}
        />
      </div>
      <div className="spacer" />
      <div className="spacer" />
      <div className="spacer" />
    </ul>
  );
})
Example #24
Source File: index.jsx    From mixbox with GNU General Public License v3.0 5 votes vote down vote up
SortableContainerList = SortableContainer(props => {
    const {
        className,
        dataSource,
        activeKey,
        itemClass,
        onClose,
        onClick,
        itemWrapper,
        isSorting,
        ...others
    } = props;

    return (
        <div className={classNames('draggable-tabs-bar-root', className, {sorting: isSorting})} {...others}>
            {dataSource.map((item, index) => {
                const {key, title, closable} = item;
                const isActive = activeKey === key;
                let itemJsx = [
                    (
                        <div key="item" className="item-inner" onClick={(e) => onClick && onClick(item, e)}>
                            {title}
                        </div>
                    ),
                    (
                        closable ? (
                            <div key="close" className="close-wrapper" onClick={(e) => onClose && onClose(item, e)}>
                                <CloseOutlined/>
                            </div>
                        ) : null
                    ),
                ];

                if (itemWrapper) {
                    itemJsx = itemWrapper(itemJsx, item, 'draggable-tabs-bar-wrapper');
                } else {
                    itemJsx = <div className="draggable-tabs-bar-wrapper">{itemJsx}</div>;
                }
                return (
                    <SortableItem
                        key={key}
                        className={classNames(itemClass, {'active': isActive})}
                        index={index}
                    >
                        <div className="draggable-tabs-bar-horizontal-item-inner">{itemJsx}</div>
                    </SortableItem>
                );
            })}
        </div>
    );
})
Example #25
Source File: CampaignCannedResponsesForm.jsx    From Spoke with MIT License 5 votes vote down vote up
SortableList = SortableContainer(List, { withRef: true })
Example #26
Source File: PeopleList.jsx    From A2 with GNU General Public License v3.0 4 votes vote down vote up
PeopleListInternal = SortableContainer(
  ({
    className,
    people,
    paidPersonId,
    isSorting,
    peopleError,
    paidError,
    showErrors,
    onPayeeChange,
    onNameChange,
    onRemovePerson,
    onInputBlur
  }) => {
    // Animate new row entries: pop out and fade in.
    // They start at {START_SCALE} of the full size.
    const START_SCALE = 0.9;
    const handleAppear = el => {
      spring({
        onUpdate: val => {
          // eslint-disable-next-line no-param-reassign
          el.style.opacity = val;

          const scale = val * (1 - START_SCALE) + START_SCALE;
          // eslint-disable-next-line no-param-reassign
          el.style.transform = `scale(${scale})`;
        }
      });
    };

    // Keep track of when it is animating - we don't want to show error bubbles then.
    const [isAnimating, setIsAnimating] = useState(false);
    const handleStart = () => setIsAnimating(true);
    const handleComplete = () => setIsAnimating(false);

    // When the user drag-and-drops a row to swap their order,
    // we do not want the row to snap back to its original position
    // and re-animated to the new position.
    const shouldFlip = () => !isSorting;

    return (
      <ul className={[styles.peopleList, className].join(" ")}>
        {people.allIds.map((id, i) => (
          <Flipped
            flipId={id}
            key={id}
            onAppear={handleAppear}
            onStart={handleStart}
            onComplete={handleComplete}
            shouldFlip={shouldFlip}
          >
            <PersonRow
              index={i}
              person={people.byId[id]}
              hasPaid={id === paidPersonId}
              nameError={peopleError[id]}
              paidError={i === people.allIds.length - 1 ? paidError : ""}
              showErrors={showErrors && !isAnimating}
              onSetPayer={() => paidPersonId === id && onPayeeChange(null)}
              onSetPayee={() => paidPersonId !== id && onPayeeChange(id)}
              onNameChange={event => onNameChange(id, event.target.value)}
              onRemove={() => onRemovePerson(id)}
              onInputBlur={onInputBlur}
              style={{
                // Fix for error bubble overlap bug.
                // To reproduce:
                // 1. Disable this fix
                // 2. Go to /home/split
                // 3. Press 'Split'
                // 4. Delete first row
                // 5. Delete second row
                // You should now see the name error bubble clipped in the first row.
                // Repeat several times to check.
                position: "relative",
                zIndex: people.allIds.length - i
              }}
            />
          </Flipped>
        ))}
      </ul>
    );
  }
)
Example #27
Source File: SortablePageList.js    From dnd-builder with MIT License 4 votes vote down vote up
SortablePageList = Component => {
  class ReactWindowList extends PureComponent {
    constructor(props) {
      super(props);

      this.sortablePageListRef = createRef();
      this.sortableOuterRef = createRef();
    }

    get itemData() {
      const {
        acceptedItems,
        additionalPageItems,
        disableInteraction,
        hashCode,
        itemAccessor,
        onAnEventTrigger,
        onPageAdd,
        onPageClick,
        onPageDuplicate,
        onPageRemove,
        pageContainerStyle,
        pageGetter,
        selectedPageIndex,
      } = this.props;
      return createItemData(
        acceptedItems,
        additionalPageItems,
        disableInteraction,
        hashCode,
        itemAccessor,
        onAnEventTrigger,
        onPageAdd,
        onPageClick,
        onPageDuplicate,
        onPageRemove,
        pageContainerStyle,
        pageGetter,
        selectedPageIndex,
      );
    }

    render() {
      const { height, pageCount, width } = this.props;

      return (
        <Component
          ref={this.sortablePageListRef}
          height={height}
          itemCount={pageCount}
          itemData={this.itemData}
          itemSize={127}
          outerRef={this.sortableOuterRef}
          width={width}
        >
          {SortablePageItemRenderer}
        </Component>
      );
    }
  }

  ReactWindowList.propTypes = {
    acceptedItems: PropTypes.shape({}),
    additionalPageItems: PropTypes.arrayOf(PropTypes.node),
    disableInteraction: PropTypes.arrayOf(PropTypes.string),
    hashCode: PropTypes.string,
    height: PropTypes.number,
    itemAccessor: PropTypes.func,
    onAnEventTrigger: PropTypes.func,
    onPageAdd: PropTypes.func,
    onPageClick: PropTypes.func,
    onPageDuplicate: PropTypes.func,
    onPageRemove: PropTypes.func,
    pageContainerStyle: PropTypes.shape({}),
    pageCount: PropTypes.number,
    pageGetter: PropTypes.func,
    selectedPageIndex: PropTypes.number,
    width: PropTypes.number,
  };

  ReactWindowList.defaultProps = {
    acceptedItems: {},
    additionalPageItems: [],
    disableInteraction: [],
    hashCode: '',
    height: 0,
    itemAccessor: () => {},
    onAnEventTrigger: () => {},
    onPageAdd: () => {},
    onPageClick: () => {},
    onPageDuplicate: () => {},
    onPageRemove: () => {},
    pageContainerStyle: {},
    pageCount: 0,
    pageGetter: () => {},
    selectedPageIndex: 1,
    width: 0,
  };

  return SortableContainer(ReactWindowList, { withRef: true });
}
Example #28
Source File: SamplesTable.jsx    From ui with MIT License 4 votes vote down vote up
SamplesTable = forwardRef((props, ref) => {
  const dispatch = useDispatch();
  const [tableData, setTableData] = useState([]);

  const experiments = useSelector((state) => state.experiments);
  const samples = useSelector((state) => state.samples);
  const areSamplesLoading = useSelector((state) => state.samples.meta.loading);

  const activeExperimentId = useSelector((state) => state.experiments.meta.activeExperimentId);
  const activeExperiment = useSelector((state) => state.experiments[activeExperimentId]);

  const [sampleNames, setSampleNames] = useState(new Set());
  const DragHandle = sortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />);

  const initialTableColumns = [
    {
      fixed: 'left',
      index: 0,
      key: 'sort',
      dataIndex: 'sort',
      width: 30,
      render: () => <DragHandle />,
    },
    {
      className: `${integrationTestConstants.classes.SAMPLE_CELL}`,
      index: 1,
      key: 'sample',
      title: 'Sample',
      dataIndex: 'name',
      fixed: true,
      render: (text, record, indx) => <SampleNameCell cellInfo={{ text, record, indx }} />,
    },
    {
      index: 2,
      key: 'barcodes',
      title: 'barcodes.tsv',
      dataIndex: 'barcodes',
      render: (tableCellData) => <UploadCell columnId='barcodes' tableCellData={tableCellData} />,
    },
    {
      index: 3,
      key: 'genes',
      title: 'genes.tsv',
      dataIndex: 'genes',
      render: (tableCellData) => <UploadCell columnId='genes' tableCellData={tableCellData} />,
    },
    {
      index: 4,
      key: 'matrix',
      title: 'matrix.mtx',
      dataIndex: 'matrix',
      render: (tableCellData) => <UploadCell columnId='matrix' tableCellData={tableCellData} />,
    },
  ];

  const [tableColumns, setTableColumns] = useState(initialTableColumns);

  useEffect(() => {
    if (activeExperiment.sampleIds.length > 0) {
      // if there are samples - build the table columns
      setSampleNames(new Set(activeExperiment.sampleIds.map((id) => samples[id]?.name.trim())));
      const metadataColumns = activeExperiment.metadataKeys.map(
        (metadataKey) => createInitializedMetadataColumn(metadataKeyToName(metadataKey)),
      ) || [];
      setTableColumns([...initialTableColumns, ...metadataColumns]);
    } else {
      setTableColumns([]);
      setSampleNames(new Set());
    }
  }, [samples, activeExperiment]);

  useConditionalEffect(() => {
    dispatch(loadSamples(activeExperimentId));
  }, [activeExperiment?.sampleIds], { lazy: true });

  const deleteMetadataColumn = (name) => {
    dispatch(deleteMetadataTrack(name, activeExperimentId));
  };

  const createInitializedMetadataColumn = (name) => {
    const key = metadataNameToKey(name);

    return {
      key,
      title: () => (
        <MetadataColumnTitle
          name={name}
          sampleNames={sampleNames}
          setCells={setCells}
          deleteMetadataColumn={deleteMetadataColumn}
          activeExperimentId={activeExperimentId}
        />
      ),
      width: 200,
      dataIndex: key,
      render: (cellValue, record, rowIdx) => (
        <EditableFieldCell
          cellText={cellValue}
          dataIndex={key}
          rowIdx={rowIdx}
          onAfterSubmit={(newValue) => {
            dispatch(updateValueInMetadataTrack(activeExperimentId, record.uuid, key, newValue));
          }}
        />
      ),
    };
  };

  const onMetadataCreate = (name) => {
    dispatch(createMetadataTrack(name, activeExperimentId));
  };

  useImperativeHandle(ref, () => ({

    createMetadataColumn() {
      const key = temporaryMetadataKey(tableColumns);
      const metadataCreateColumn = {
        key,
        fixed: 'right',
        title: () => (
          <MetadataPopover
            existingMetadata={activeExperiment.metadataKeys}
            onCreate={(name) => {
              onMetadataCreate(name);
            }}
            onCancel={() => {
              deleteMetadataColumn(key);
            }}
            message='Provide new metadata track name'
            visible
          >
            <Space>
              New Metadata Track
            </Space>
          </MetadataPopover>
        ),
        width: 200,
      };
      setTableColumns([...tableColumns, metadataCreateColumn]);
    },
  }));

  const MASS_EDIT_ACTIONS = [
    'REPLACE_EMPTY',
    'REPLACE_ALL',
    'CLEAR_ALL',
  ];

  const setCells = (value, metadataKey, actionType) => {
    if (!MASS_EDIT_ACTIONS.includes(actionType)) return;

    const canUpdateCell = (sampleUuid, action) => {
      if (action !== 'REPLACE_EMPTY') return true;

      const isMetadataEmpty = (uuid) => (
        !samples[uuid].metadata[metadataKey]
        || samples[uuid].metadata[metadataKey] === METADATA_DEFAULT_VALUE
      );

      return isMetadataEmpty(sampleUuid);
    };

    activeExperiment.sampleIds.forEach(
      (sampleUuid) => {
        if (canUpdateCell(sampleUuid, actionType)) {
          dispatch(updateValueInMetadataTrack(activeExperimentId, sampleUuid, metadataKey, value));
        }
      },
    );
  };

  useEffect(() => {
    if (activeExperiment.sampleIds.length === 0) {
      setTableData([]);
      return;
    }

    const newData = activeExperiment.sampleIds.map((sampleUuid, idx) => {
      // upload problems sometimes lead to partial updates and incosistent states
      // in this situation it's possible that the sampleUuid does not exist
      // this a temporary fix so that the whole UI doesn't crash preventing the
      // user from removing the dataset or uploading another one.
      const sampleFiles = samples[sampleUuid]?.files || {};

      const barcodesFile = sampleFiles['barcodes.tsv.gz'] ?? { upload: { status: UploadStatus.FILE_NOT_FOUND } };
      const genesFile = sampleFiles['features.tsv.gz'] ?? { upload: { status: UploadStatus.FILE_NOT_FOUND } };
      const matrixFile = sampleFiles['matrix.mtx.gz'] ?? { upload: { status: UploadStatus.FILE_NOT_FOUND } };

      const barcodesData = { sampleUuid, file: barcodesFile };
      const genesData = { sampleUuid, file: genesFile };
      const matrixData = { sampleUuid, file: matrixFile };

      return {
        key: idx,
        name: samples[sampleUuid]?.name || 'UPLOAD ERROR: Please reupload sample',
        uuid: sampleUuid,
        barcodes: barcodesData,
        genes: genesData,
        matrix: matrixData,
        ...samples[sampleUuid]?.metadata,
      };
    });
    setTableData(newData);
  }, [experiments, samples, activeExperimentId]);

  const noDataComponent = (
    <ExampleExperimentsSpace
      introductionText='Start uploading your samples by clicking on Add samples.'
      imageStyle={{ height: 60 }}
    />
  );

  const onSortEnd = async ({ oldIndex, newIndex }) => {
    if (oldIndex !== newIndex) {
      const newData = arrayMoveImmutable(tableData, oldIndex, newIndex).filter((el) => !!el);
      const newSampleOrder = newData.map((sample) => sample.uuid);

      try {
        await dispatch(reorderSamples(activeExperimentId, oldIndex, newIndex, newSampleOrder));
      } catch (e) {
        // If the fetch fails, avoid doing setTableData(newData)
        return;
      }

      setTableData(newData);
    }
  };

  const SortableRow = sortableElement((otherProps) => <tr {...otherProps} className={`${otherProps.className} drag-visible`} />);
  const SortableTable = sortableContainer((otherProps) => <tbody {...otherProps} />);

  const DragContainer = (otherProps) => (
    <SortableTable
      useDragHandle
      disableAutoscroll
      helperClass='row-dragging'
      onSortEnd={onSortEnd}
      {...otherProps}
    />
  );

  const DraggableRow = (otherProps) => {
    const index = tableData.findIndex((x) => x.key === otherProps['data-row-key']);
    return <SortableRow index={index} {...otherProps} />;
  };

  const renderLoader = () => (
    <>
      <Row justify='center'>
        <ClipLoader
          size={50}
          color='#8f0b10'
        />
      </Row>

      <Row justify='center'>
        <Text>
          We&apos;re getting your samples ...
        </Text>
      </Row>
    </>
  );

  const renderSamplesTable = () => (
    <Row>
      <Col>
        <Table
          id='samples-table'
          size='small'
          scroll={{
            x: 'max-content',
          }}
          bordered
          columns={tableColumns}
          dataSource={tableData}
          sticky
          pagination={false}
          locale={{ emptyText: noDataComponent }}
          components={{
            body: {
              wrapper: DragContainer,
              row: DraggableRow,
            },
          }}
        />
      </Col>
    </Row>
  );

  return (
    <>
      {areSamplesLoading ? renderLoader() : renderSamplesTable()}
    </>
  );
})