mirror of
https://github.com/haiwen/seahub.git
synced 2025-07-13 06:55:59 +00:00
fix: metadata loading error, view op done (#6660)
* fix: metadata loading error, view op done * feat: update code --------- Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
parent
24fcc9d34b
commit
0aa7c7da00
@ -1,219 +0,0 @@
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import toaster from '../../../../components/toast';
|
||||
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, MAX_LOAD_NUMBER } from '../../constants';
|
||||
import { CommonlyUsedHotkey, getValidGroupbys } from '../../_basic';
|
||||
import { gettext } from '../../utils';
|
||||
import { useMetadata } from '../../hooks';
|
||||
import TableMain from './table-main';
|
||||
import Gallery from './gallery';
|
||||
import { Utils } from '../../../../utils/utils';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const Container = () => {
|
||||
const [isLoadingMore, setLoadingMore] = useState(false);
|
||||
const { metadata, errorMsg, store } = useMetadata();
|
||||
const containerRef = useRef(null);
|
||||
|
||||
const onKeyDown = useCallback((event) => {
|
||||
if (event.target.className.includes('editor-main')) return;
|
||||
if (CommonlyUsedHotkey.isModF(event)) {
|
||||
event.preventDefault();
|
||||
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SEARCH_CELLS);
|
||||
return;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isGroupView = useMemo(() => {
|
||||
const validGroupbys = getValidGroupbys(metadata.view.groupbys, metadata.columns);
|
||||
return validGroupbys.length > 0;
|
||||
}, [metadata]);
|
||||
|
||||
const loadMore = useCallback(async () => {
|
||||
if (!metadata.hasMore) return;
|
||||
setLoadingMore(true);
|
||||
|
||||
try {
|
||||
await store.loadMore(PER_LOAD_NUMBER);
|
||||
setLoadingMore(false);
|
||||
} catch (error) {
|
||||
const errorMsg = Utils.getErrorMsg(error);
|
||||
toaster.danger(errorMsg);
|
||||
setLoadingMore(false);
|
||||
return;
|
||||
}
|
||||
|
||||
}, [metadata, store]);
|
||||
|
||||
const loadAll = useCallback(async (maxLoadNumber, callback) => {
|
||||
if (!metadata.hasMore) return;
|
||||
setLoadingMore(true);
|
||||
const rowsCount = metadata.row_ids.length;
|
||||
const loadNumber = rowsCount % MAX_LOAD_NUMBER !== 0 ? MAX_LOAD_NUMBER - rowsCount % MAX_LOAD_NUMBER : MAX_LOAD_NUMBER;
|
||||
try {
|
||||
await store.loadMore(loadNumber);
|
||||
setLoadingMore(false);
|
||||
} catch (error) {
|
||||
const errorMsg = Utils.getErrorMsg(error);
|
||||
toaster.danger(errorMsg);
|
||||
setLoadingMore(false);
|
||||
return;
|
||||
}
|
||||
if (store.data.hasMore && store.data.row_ids.length < maxLoadNumber) {
|
||||
loadAll(maxLoadNumber, callback);
|
||||
} else {
|
||||
typeof callback === 'function' && callback(store.data.hasMore);
|
||||
setLoadingMore(false);
|
||||
}
|
||||
}, [metadata, store]);
|
||||
|
||||
const modifyRecords = useCallback((rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste = false) => {
|
||||
store.modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste);
|
||||
}, [store]);
|
||||
|
||||
const modifyRecord = useCallback((rowId, updates, oldRowData, originalUpdates, originalOldRowData) => {
|
||||
const rowIds = [rowId];
|
||||
const idRowUpdates = { [rowId]: updates };
|
||||
const idOriginalRowUpdates = { [rowId]: originalUpdates };
|
||||
const idOldRowData = { [rowId]: oldRowData };
|
||||
const idOriginalOldRowData = { [rowId]: originalOldRowData };
|
||||
modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData);
|
||||
}, [modifyRecords]);
|
||||
|
||||
const getAdjacentRowsIds = useCallback((rowIds) => {
|
||||
const rowIdsLen = metadata.row_ids.length;
|
||||
let rowIdsInOrder = [];
|
||||
let upperRowIds = [];
|
||||
let belowRowIds = [];
|
||||
let rowIdMap = {};
|
||||
rowIds.forEach(rowId => rowIdMap[rowId] = rowId);
|
||||
metadata.row_ids.forEach((rowId, index) => {
|
||||
if (!rowIdMap[rowId]) {
|
||||
return;
|
||||
}
|
||||
const upperRowId = index === 0 ? null : metadata.row_ids[index - 1];
|
||||
const belowRowId = index === rowIdsLen - 1 ? null : metadata.row_ids[index + 1];
|
||||
rowIdsInOrder.push(rowId);
|
||||
upperRowIds.push(upperRowId);
|
||||
belowRowIds.push(belowRowId);
|
||||
});
|
||||
return { rowIdsInOrder, upperRowIds, belowRowIds };
|
||||
}, [metadata]);
|
||||
|
||||
const modifyFilters = useCallback((filters, filterConjunction, basicFilters) => {
|
||||
store.modifyFilters(filterConjunction, filters, basicFilters);
|
||||
}, [store]);
|
||||
|
||||
const modifySorts = useCallback((sorts) => {
|
||||
store.modifySorts(sorts);
|
||||
}, [store]);
|
||||
|
||||
const modifyGroupbys = useCallback((groupbys) => {
|
||||
store.modifyGroupbys(groupbys);
|
||||
}, [store]);
|
||||
|
||||
const modifyHiddenColumns = useCallback((hiddenColumns) => {
|
||||
store.modifyHiddenColumns(hiddenColumns);
|
||||
}, [store]);
|
||||
|
||||
const renameColumn = useCallback((columnKey, newName, oldName) => {
|
||||
store.renameColumn(columnKey, newName, oldName);
|
||||
}, [store]);
|
||||
|
||||
const deleteColumn = useCallback((columnKey, oldColumn) => {
|
||||
store.deleteColumn(columnKey, oldColumn);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnData = useCallback((columnKey, newData, oldData) => {
|
||||
store.modifyColumnData(columnKey, newData, oldData);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnWidth = useCallback((columnKey, newWidth) => {
|
||||
store.modifyColumnWidth(columnKey, newWidth);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
||||
store.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
||||
}, [store]);
|
||||
|
||||
const recordGetterById = useCallback((recordId) => {
|
||||
return metadata.id_row_map[recordId];
|
||||
}, [metadata]);
|
||||
|
||||
const recordGetter = useCallback((recordIndex) => {
|
||||
const recordId = metadata.view.rows[recordIndex];
|
||||
return recordId && recordGetterById(recordId);
|
||||
}, [metadata, recordGetterById]);
|
||||
|
||||
const groupRecordGetter = useCallback((groupRecordIndex) => {
|
||||
if (!window.sfMetadataBody || !window.sfMetadataBody.getGroupRecordByIndex) return null;
|
||||
const groupRecord = window.sfMetadataBody.getGroupRecordByIndex(groupRecordIndex);
|
||||
const recordId = groupRecord.rowId;
|
||||
return recordId && recordGetterById(recordId);
|
||||
}, [recordGetterById]);
|
||||
|
||||
const recordGetterByIndex = useCallback(({ isGroupView, groupRecordIndex, recordIndex }) => {
|
||||
if (isGroupView) return groupRecordGetter(groupRecordIndex);
|
||||
return recordGetter(recordIndex);
|
||||
}, [groupRecordGetter, recordGetter]);
|
||||
|
||||
const getTableContentRect = useCallback(() => {
|
||||
return containerRef?.current?.getBoundingClientRect() || { x: 0, right: window.innerWidth };
|
||||
}, [containerRef]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
const eventBus = window.sfMetadataContext.eventBus;
|
||||
const unsubscribeModifyFilters = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_FILTERS, modifyFilters);
|
||||
const unsubscribeModifySorts = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_SORTS, modifySorts);
|
||||
const unsubscribeModifyGroupbys = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_GROUPBYS, modifyGroupbys);
|
||||
const unsubscribeModifyHiddenColumns = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_HIDDEN_COLUMNS, modifyHiddenColumns);
|
||||
const unsubscribeModifyColumnOrder = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_COLUMN_ORDER, modifyColumnOrder);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
unsubscribeModifyFilters();
|
||||
unsubscribeModifySorts();
|
||||
unsubscribeModifyGroupbys();
|
||||
unsubscribeModifyHiddenColumns();
|
||||
unsubscribeModifyColumnOrder();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sf-metadata-wrapper">
|
||||
<div className="sf-metadata-main">
|
||||
{errorMsg && (<div className="d-center-middle error">{gettext(errorMsg)}</div>)}
|
||||
{!errorMsg && (
|
||||
<div className="sf-metadata-container" ref={containerRef}>
|
||||
{metadata.view.type === 'table' && (
|
||||
<TableMain
|
||||
isGroupView={isGroupView}
|
||||
isLoadingMore={isLoadingMore}
|
||||
loadMore={loadMore}
|
||||
metadata={metadata}
|
||||
modifyRecord={modifyRecord}
|
||||
modifyRecords={modifyRecords}
|
||||
recordGetterById={recordGetterById}
|
||||
recordGetterByIndex={recordGetterByIndex}
|
||||
getTableContentRect={getTableContentRect}
|
||||
getAdjacentRowsIds={getAdjacentRowsIds}
|
||||
loadAll={loadAll}
|
||||
renameColumn={renameColumn}
|
||||
deleteColumn={deleteColumn}
|
||||
modifyColumnData={modifyColumnData}
|
||||
modifyColumnWidth={modifyColumnWidth}
|
||||
modifyColumnOrder={modifyColumnOrder}
|
||||
/>
|
||||
)}
|
||||
{metadata.view.type === 'image' && (<Gallery />)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Container;
|
@ -1,15 +1,196 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CenteredLoading } from '@seafile/sf-metadata-ui-component';
|
||||
import toaster from '../../../../components/toast';
|
||||
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER, MAX_LOAD_NUMBER } from '../../constants';
|
||||
import { CommonlyUsedHotkey, getValidGroupbys } from '../../_basic';
|
||||
import { gettext } from '../../utils';
|
||||
import { useMetadata } from '../../hooks';
|
||||
import Container from './container';
|
||||
import TableMain from './table-main';
|
||||
import Gallery from './gallery';
|
||||
import { Utils } from '../../../../utils/utils';
|
||||
|
||||
import './index.css';
|
||||
|
||||
const Table = () => {
|
||||
const { isLoading } = useMetadata();
|
||||
const [isLoadingMore, setLoadingMore] = useState(false);
|
||||
const { isLoading, metadata, errorMsg, store } = useMetadata();
|
||||
const containerRef = useRef(null);
|
||||
|
||||
const onKeyDown = useCallback((event) => {
|
||||
if (event.target.className.includes('editor-main')) return;
|
||||
if (CommonlyUsedHotkey.isModF(event)) {
|
||||
event.preventDefault();
|
||||
window.sfMetadataContext.eventBus.dispatch(EVENT_BUS_TYPE.SEARCH_CELLS);
|
||||
return;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isGroupView = useMemo(() => {
|
||||
if (isLoading || !metadata) return false;
|
||||
const validGroupbys = getValidGroupbys(metadata.view.groupbys, metadata.columns);
|
||||
return validGroupbys.length > 0;
|
||||
}, [isLoading, metadata]);
|
||||
|
||||
const loadMore = useCallback(async () => {
|
||||
if (!metadata.hasMore) return;
|
||||
setLoadingMore(true);
|
||||
|
||||
try {
|
||||
await store.loadMore(PER_LOAD_NUMBER);
|
||||
setLoadingMore(false);
|
||||
} catch (error) {
|
||||
const errorMsg = Utils.getErrorMsg(error);
|
||||
toaster.danger(errorMsg);
|
||||
setLoadingMore(false);
|
||||
return;
|
||||
}
|
||||
|
||||
}, [metadata, store]);
|
||||
|
||||
const loadAll = useCallback(async (maxLoadNumber, callback) => {
|
||||
if (!metadata.hasMore) return;
|
||||
setLoadingMore(true);
|
||||
const rowsCount = metadata.row_ids.length;
|
||||
const loadNumber = rowsCount % MAX_LOAD_NUMBER !== 0 ? MAX_LOAD_NUMBER - rowsCount % MAX_LOAD_NUMBER : MAX_LOAD_NUMBER;
|
||||
try {
|
||||
await store.loadMore(loadNumber);
|
||||
setLoadingMore(false);
|
||||
} catch (error) {
|
||||
const errorMsg = Utils.getErrorMsg(error);
|
||||
toaster.danger(errorMsg);
|
||||
setLoadingMore(false);
|
||||
return;
|
||||
}
|
||||
if (store.data.hasMore && store.data.row_ids.length < maxLoadNumber) {
|
||||
loadAll(maxLoadNumber, callback);
|
||||
} else {
|
||||
typeof callback === 'function' && callback(store.data.hasMore);
|
||||
setLoadingMore(false);
|
||||
}
|
||||
}, [metadata, store]);
|
||||
|
||||
const modifyRecords = useCallback((rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste = false) => {
|
||||
store.modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste);
|
||||
}, [store]);
|
||||
|
||||
const modifyRecord = useCallback((rowId, updates, oldRowData, originalUpdates, originalOldRowData) => {
|
||||
const rowIds = [rowId];
|
||||
const idRowUpdates = { [rowId]: updates };
|
||||
const idOriginalRowUpdates = { [rowId]: originalUpdates };
|
||||
const idOldRowData = { [rowId]: oldRowData };
|
||||
const idOriginalOldRowData = { [rowId]: originalOldRowData };
|
||||
modifyRecords(rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData);
|
||||
}, [modifyRecords]);
|
||||
|
||||
const getAdjacentRowsIds = useCallback((rowIds) => {
|
||||
const rowIdsLen = metadata.row_ids.length;
|
||||
let rowIdsInOrder = [];
|
||||
let upperRowIds = [];
|
||||
let belowRowIds = [];
|
||||
let rowIdMap = {};
|
||||
rowIds.forEach(rowId => rowIdMap[rowId] = rowId);
|
||||
metadata.row_ids.forEach((rowId, index) => {
|
||||
if (!rowIdMap[rowId]) {
|
||||
return;
|
||||
}
|
||||
const upperRowId = index === 0 ? null : metadata.row_ids[index - 1];
|
||||
const belowRowId = index === rowIdsLen - 1 ? null : metadata.row_ids[index + 1];
|
||||
rowIdsInOrder.push(rowId);
|
||||
upperRowIds.push(upperRowId);
|
||||
belowRowIds.push(belowRowId);
|
||||
});
|
||||
return { rowIdsInOrder, upperRowIds, belowRowIds };
|
||||
}, [metadata]);
|
||||
|
||||
const renameColumn = useCallback((columnKey, newName, oldName) => {
|
||||
store.renameColumn(columnKey, newName, oldName);
|
||||
}, [store]);
|
||||
|
||||
const deleteColumn = useCallback((columnKey, oldColumn) => {
|
||||
store.deleteColumn(columnKey, oldColumn);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnData = useCallback((columnKey, newData, oldData) => {
|
||||
store.modifyColumnData(columnKey, newData, oldData);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnWidth = useCallback((columnKey, newWidth) => {
|
||||
store.modifyColumnWidth(columnKey, newWidth);
|
||||
}, [store]);
|
||||
|
||||
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
||||
store.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
||||
}, [store]);
|
||||
|
||||
const recordGetterById = useCallback((recordId) => {
|
||||
return metadata.id_row_map[recordId];
|
||||
}, [metadata]);
|
||||
|
||||
const recordGetter = useCallback((recordIndex) => {
|
||||
const recordId = metadata.view.rows[recordIndex];
|
||||
return recordId && recordGetterById(recordId);
|
||||
}, [metadata, recordGetterById]);
|
||||
|
||||
const groupRecordGetter = useCallback((groupRecordIndex) => {
|
||||
if (!window.sfMetadataBody || !window.sfMetadataBody.getGroupRecordByIndex) return null;
|
||||
const groupRecord = window.sfMetadataBody.getGroupRecordByIndex(groupRecordIndex);
|
||||
const recordId = groupRecord.rowId;
|
||||
return recordId && recordGetterById(recordId);
|
||||
}, [recordGetterById]);
|
||||
|
||||
const recordGetterByIndex = useCallback(({ isGroupView, groupRecordIndex, recordIndex }) => {
|
||||
if (isGroupView) return groupRecordGetter(groupRecordIndex);
|
||||
return recordGetter(recordIndex);
|
||||
}, [groupRecordGetter, recordGetter]);
|
||||
|
||||
const getTableContentRect = useCallback(() => {
|
||||
return containerRef?.current?.getBoundingClientRect() || { x: 0, right: window.innerWidth };
|
||||
}, [containerRef]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (isLoading) return (<CenteredLoading />);
|
||||
return (<Container />);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sf-metadata-wrapper">
|
||||
<div className="sf-metadata-main">
|
||||
{errorMsg && (<div className="d-center-middle error">{gettext(errorMsg)}</div>)}
|
||||
{!errorMsg && (
|
||||
<div className="sf-metadata-container" ref={containerRef}>
|
||||
{metadata.view.type === 'table' && (
|
||||
<TableMain
|
||||
isGroupView={isGroupView}
|
||||
isLoadingMore={isLoadingMore}
|
||||
loadMore={loadMore}
|
||||
metadata={metadata}
|
||||
modifyRecord={modifyRecord}
|
||||
modifyRecords={modifyRecords}
|
||||
recordGetterById={recordGetterById}
|
||||
recordGetterByIndex={recordGetterByIndex}
|
||||
getTableContentRect={getTableContentRect}
|
||||
getAdjacentRowsIds={getAdjacentRowsIds}
|
||||
loadAll={loadAll}
|
||||
renameColumn={renameColumn}
|
||||
deleteColumn={deleteColumn}
|
||||
modifyColumnData={modifyColumnData}
|
||||
modifyColumnWidth={modifyColumnWidth}
|
||||
modifyColumnOrder={modifyColumnOrder}
|
||||
/>
|
||||
)}
|
||||
{metadata.view.type === 'image' && (<Gallery />)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Table;
|
||||
|
@ -45,6 +45,26 @@ export const MetadataProvider = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
const modifyFilters = useCallback((filters, filterConjunction, basicFilters) => {
|
||||
window.sfMetadataStore.modifyFilters(filterConjunction, filters, basicFilters);
|
||||
}, []);
|
||||
|
||||
const modifySorts = useCallback((sorts) => {
|
||||
window.sfMetadataStore.modifySorts(sorts);
|
||||
}, []);
|
||||
|
||||
const modifyGroupbys = useCallback((groupbys) => {
|
||||
window.sfMetadataStore.modifyGroupbys(groupbys);
|
||||
}, []);
|
||||
|
||||
const modifyHiddenColumns = useCallback((hiddenColumns) => {
|
||||
window.sfMetadataStore.modifyHiddenColumns(hiddenColumns);
|
||||
}, []);
|
||||
|
||||
const modifyColumnOrder = useCallback((sourceColumnKey, targetColumnKey) => {
|
||||
window.sfMetadataStore.modifyColumnOrder(sourceColumnKey, targetColumnKey);
|
||||
}, []);
|
||||
|
||||
// init
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
@ -72,6 +92,11 @@ export const MetadataProvider = ({
|
||||
const unsubscribeHandleTableError = eventBus.subscribe(EVENT_BUS_TYPE.TABLE_ERROR, handleTableError);
|
||||
const unsubscribeUpdateRows = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_TABLE_ROWS, updateMetadata);
|
||||
const unsubscribeReloadData = eventBus.subscribe(EVENT_BUS_TYPE.RELOAD_DATA, reloadMetadata);
|
||||
const unsubscribeModifyFilters = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_FILTERS, modifyFilters);
|
||||
const unsubscribeModifySorts = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_SORTS, modifySorts);
|
||||
const unsubscribeModifyGroupbys = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_GROUPBYS, modifyGroupbys);
|
||||
const unsubscribeModifyHiddenColumns = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_HIDDEN_COLUMNS, modifyHiddenColumns);
|
||||
const unsubscribeModifyColumnOrder = eventBus.subscribe(EVENT_BUS_TYPE.MODIFY_COLUMN_ORDER, modifyColumnOrder);
|
||||
|
||||
return () => {
|
||||
window.sfMetadataContext.destroy();
|
||||
@ -81,6 +106,11 @@ export const MetadataProvider = ({
|
||||
unsubscribeHandleTableError();
|
||||
unsubscribeUpdateRows();
|
||||
unsubscribeReloadData();
|
||||
unsubscribeModifyFilters();
|
||||
unsubscribeModifySorts();
|
||||
unsubscribeModifyGroupbys();
|
||||
unsubscribeModifyHiddenColumns();
|
||||
unsubscribeModifyColumnOrder();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [repoID, viewID]);
|
||||
|
Loading…
Reference in New Issue
Block a user