mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-21 03:18:23 +00:00
feat: metadata checkbox (#6295)
* feat: metadata checkbox * feat: optimize checkbox * feat: update code * feat: update code --------- Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
14
frontend/package-lock.json
generated
14
frontend/package-lock.json
generated
@@ -17,7 +17,7 @@
|
|||||||
"@seafile/sdoc-editor": "1.0.7",
|
"@seafile/sdoc-editor": "1.0.7",
|
||||||
"@seafile/seafile-calendar": "0.0.12",
|
"@seafile/seafile-calendar": "0.0.12",
|
||||||
"@seafile/seafile-editor": "1.0.99",
|
"@seafile/seafile-editor": "1.0.99",
|
||||||
"@seafile/sf-metadata-ui-component": "0.0.8",
|
"@seafile/sf-metadata-ui-component": "0.0.9",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||||
"@uiw/react-codemirror": "^4.19.4",
|
"@uiw/react-codemirror": "^4.19.4",
|
||||||
"chart.js": "2.9.4",
|
"chart.js": "2.9.4",
|
||||||
@@ -4953,9 +4953,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@seafile/sf-metadata-ui-component": {
|
"node_modules/@seafile/sf-metadata-ui-component": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.9.tgz",
|
||||||
"integrity": "sha512-5lHcPLC5HQtjfBXS47KUYfM3lSwW2KSH17S+eF1JBrEbeM7SGUN8p//sTMmUcSHwBn0VPs8BxWIvQWRQgVwz3g==",
|
"integrity": "sha512-J0D3DK1TI16QPlhAeBp64ilcKO7pCX9w03Q94D1Ni7phLquqZwCD3PFFyRgv6oUkWtGojTL++SiLVTTXubI68g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@seafile/seafile-calendar": "0.0.24",
|
"@seafile/seafile-calendar": "0.0.24",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
@@ -32160,9 +32160,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@seafile/sf-metadata-ui-component": {
|
"@seafile/sf-metadata-ui-component": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.9.tgz",
|
||||||
"integrity": "sha512-5lHcPLC5HQtjfBXS47KUYfM3lSwW2KSH17S+eF1JBrEbeM7SGUN8p//sTMmUcSHwBn0VPs8BxWIvQWRQgVwz3g==",
|
"integrity": "sha512-J0D3DK1TI16QPlhAeBp64ilcKO7pCX9w03Q94D1Ni7phLquqZwCD3PFFyRgv6oUkWtGojTL++SiLVTTXubI68g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@seafile/seafile-calendar": "0.0.24",
|
"@seafile/seafile-calendar": "0.0.24",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
"@seafile/sdoc-editor": "1.0.7",
|
"@seafile/sdoc-editor": "1.0.7",
|
||||||
"@seafile/seafile-calendar": "0.0.12",
|
"@seafile/seafile-calendar": "0.0.12",
|
||||||
"@seafile/seafile-editor": "1.0.99",
|
"@seafile/seafile-editor": "1.0.99",
|
||||||
"@seafile/sf-metadata-ui-component": "0.0.8",
|
"@seafile/sf-metadata-ui-component": "0.0.9",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||||
"@uiw/react-codemirror": "^4.19.4",
|
"@uiw/react-codemirror": "^4.19.4",
|
||||||
"chart.js": "2.9.4",
|
"chart.js": "2.9.4",
|
||||||
|
1
frontend/src/assets/icons/checkbox.svg
Normal file
1
frontend/src/assets/icons/checkbox.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720076454490" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15388" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M128 32h768c54.4 0 96 41.6 96 96v768c0 54.4-41.6 96-96 96H128c-54.4 0-96-41.6-96-96V128c0-54.4 41.6-96 96-96z m275.2 713.6c12.8 12.8 28.8 19.2 41.6 19.2 19.2 0 28.8-6.4 41.6-19.2l323.2-323.2c25.6-25.6 25.6-60.8 0-83.2s-60.8-25.6-83.2 0l-281.6 281.6-124.8-128c-25.6-25.6-60.8-25.6-83.2 0s-25.6 60.8 0 83.2l166.4 169.6z" p-id="15389"></path></svg>
|
After Width: | Height: | Size: 679 B |
@@ -6,5 +6,8 @@ export const NOT_DISPLAY_COLUMN_KEYS = [
|
|||||||
PRIVATE_COLUMN_KEY.MTIME,
|
PRIVATE_COLUMN_KEY.MTIME,
|
||||||
PRIVATE_COLUMN_KEY.CREATOR,
|
PRIVATE_COLUMN_KEY.CREATOR,
|
||||||
PRIVATE_COLUMN_KEY.LAST_MODIFIER,
|
PRIVATE_COLUMN_KEY.LAST_MODIFIER,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const VIEW_NOT_DISPLAY_COLUMN_KEYS = [
|
||||||
PRIVATE_COLUMN_KEY.IS_DIR,
|
PRIVATE_COLUMN_KEY.IS_DIR,
|
||||||
];
|
];
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
import CellType from './type';
|
import CellType from './type';
|
||||||
|
|
||||||
const DATE_COLUMN_OPTIONS = [
|
const DATE_COLUMN_OPTIONS = [
|
||||||
CellType.CTIME, CellType.MTIME,
|
CellType.CTIME,
|
||||||
|
CellType.MTIME,
|
||||||
];
|
];
|
||||||
const NUMERIC_COLUMNS_TYPES = [
|
const NUMERIC_COLUMNS_TYPES = [
|
||||||
|
|
||||||
];
|
];
|
||||||
const COLLABORATOR_COLUMN_TYPES = [
|
const COLLABORATOR_COLUMN_TYPES = [
|
||||||
CellType.CREATOR, CellType.LAST_MODIFIER,
|
CellType.CREATOR,
|
||||||
|
CellType.LAST_MODIFIER,
|
||||||
];
|
];
|
||||||
|
|
||||||
// date
|
// date
|
||||||
|
@@ -8,6 +8,7 @@ const COLUMNS_ICON_CONFIG = {
|
|||||||
[CellType.DEFAULT]: 'text',
|
[CellType.DEFAULT]: 'text',
|
||||||
[CellType.TEXT]: 'text',
|
[CellType.TEXT]: 'text',
|
||||||
[CellType.FILE_NAME]: 'text',
|
[CellType.FILE_NAME]: 'text',
|
||||||
|
[CellType.CHECKBOX]: 'checkbox',
|
||||||
};
|
};
|
||||||
|
|
||||||
const COLUMNS_ICON_NAME = {
|
const COLUMNS_ICON_NAME = {
|
||||||
@@ -18,6 +19,7 @@ const COLUMNS_ICON_NAME = {
|
|||||||
[CellType.DEFAULT]: 'Text',
|
[CellType.DEFAULT]: 'Text',
|
||||||
[CellType.TEXT]: 'Text',
|
[CellType.TEXT]: 'Text',
|
||||||
[CellType.FILE_NAME]: 'File name',
|
[CellType.FILE_NAME]: 'File name',
|
||||||
|
[CellType.CHECKBOX]: 'Checkbox',
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@@ -31,5 +31,6 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
NOT_DISPLAY_COLUMN_KEYS
|
NOT_DISPLAY_COLUMN_KEYS,
|
||||||
|
VIEW_NOT_DISPLAY_COLUMN_KEYS,
|
||||||
} from './common';
|
} from './common';
|
||||||
|
@@ -6,6 +6,7 @@ const CellType = {
|
|||||||
LAST_MODIFIER: 'last-modifier',
|
LAST_MODIFIER: 'last-modifier',
|
||||||
MTIME: 'mtime',
|
MTIME: 'mtime',
|
||||||
FILE_NAME: 'file-name',
|
FILE_NAME: 'file-name',
|
||||||
|
CHECKBOX: 'checkbox',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CellType;
|
export default CellType;
|
||||||
|
@@ -70,6 +70,11 @@ const FILTER_COLUMN_OPTIONS = {
|
|||||||
FILTER_PREDICATE_TYPE.IS_NOT,
|
FILTER_PREDICATE_TYPE.IS_NOT,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
[CellType.CHECKBOX]: {
|
||||||
|
filterPredicateList: [
|
||||||
|
FILTER_PREDICATE_TYPE.IS,
|
||||||
|
],
|
||||||
|
},
|
||||||
[CellType.URL]: {
|
[CellType.URL]: {
|
||||||
filterPredicateList: [
|
filterPredicateList: [
|
||||||
FILTER_PREDICATE_TYPE.CONTAINS,
|
FILTER_PREDICATE_TYPE.CONTAINS,
|
||||||
|
@@ -20,6 +20,7 @@ export {
|
|||||||
SINGLE_CELL_VALUE_COLUMN_TYPE_MAP,
|
SINGLE_CELL_VALUE_COLUMN_TYPE_MAP,
|
||||||
PRIVATE_COLUMN_KEY,
|
PRIVATE_COLUMN_KEY,
|
||||||
NOT_DISPLAY_COLUMN_KEYS,
|
NOT_DISPLAY_COLUMN_KEYS,
|
||||||
|
VIEW_NOT_DISPLAY_COLUMN_KEYS,
|
||||||
} from './column';
|
} from './column';
|
||||||
export {
|
export {
|
||||||
FILTER_CONJUNCTION_TYPE,
|
FILTER_CONJUNCTION_TYPE,
|
||||||
|
@@ -47,6 +47,7 @@ export {
|
|||||||
HEADER_HEIGHT_TYPE,
|
HEADER_HEIGHT_TYPE,
|
||||||
PRIVATE_COLUMN_KEY,
|
PRIVATE_COLUMN_KEY,
|
||||||
NOT_DISPLAY_COLUMN_KEYS,
|
NOT_DISPLAY_COLUMN_KEYS,
|
||||||
|
VIEW_NOT_DISPLAY_COLUMN_KEYS,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -106,7 +107,6 @@ export {
|
|||||||
isMac,
|
isMac,
|
||||||
base64ToFile,
|
base64ToFile,
|
||||||
bytesToSize,
|
bytesToSize,
|
||||||
getErrorMsg,
|
|
||||||
DateUtils,
|
DateUtils,
|
||||||
CommonlyUsedHotkey,
|
CommonlyUsedHotkey,
|
||||||
LocalStorage,
|
LocalStorage,
|
||||||
|
@@ -36,23 +36,6 @@ export const bytesToSize = (bytes) => {
|
|||||||
return (bytes / (1000 ** i)).toFixed(1) + ' ' + sizes[i];
|
return (bytes / (1000 ** i)).toFixed(1) + ' ' + sizes[i];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getErrorMsg = (error) => {
|
|
||||||
let errorMsg = '';
|
|
||||||
if (error.response) {
|
|
||||||
if (error.response.status === 403) {
|
|
||||||
errorMsg = 'Permission_denied';
|
|
||||||
} else if (error.response.data &&
|
|
||||||
error.response.data['error_msg']) {
|
|
||||||
errorMsg = error.response.data['error_msg'];
|
|
||||||
} else {
|
|
||||||
errorMsg = 'Error';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorMsg = 'Please_check_the_network';
|
|
||||||
}
|
|
||||||
return errorMsg;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isFunction = (functionToCheck) => {
|
export const isFunction = (functionToCheck) => {
|
||||||
const getType = {};
|
const getType = {};
|
||||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||||
|
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Filter checkbox
|
||||||
|
* @param {bool} checked
|
||||||
|
* @param {bool} filter_term
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
const checkboxFilter = (checked, { filter_term }) => {
|
||||||
|
const filterTerm = filter_term || false;
|
||||||
|
const normalizedChecked = typeof checked === 'string' ? checked.toLocaleUpperCase() === 'TRUE' : checked || false;
|
||||||
|
return normalizedChecked === filterTerm;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
checkboxFilter,
|
||||||
|
};
|
@@ -1,3 +1,4 @@
|
|||||||
export { creatorFilter } from './creator';
|
export { creatorFilter } from './creator';
|
||||||
export { dateFilter } from './date';
|
export { dateFilter } from './date';
|
||||||
export { textFilter } from './text';
|
export { textFilter } from './text';
|
||||||
|
export { checkboxFilter } from './checkbox';
|
||||||
|
@@ -6,6 +6,7 @@ import {
|
|||||||
creatorFilter,
|
creatorFilter,
|
||||||
dateFilter,
|
dateFilter,
|
||||||
textFilter,
|
textFilter,
|
||||||
|
checkboxFilter,
|
||||||
} from './filter-column';
|
} from './filter-column';
|
||||||
import {
|
import {
|
||||||
FILTER_CONJUNCTION_TYPE,
|
FILTER_CONJUNCTION_TYPE,
|
||||||
@@ -30,6 +31,9 @@ const getFilterResult = (row, filter, { username, userId }) => {
|
|||||||
case CellType.CREATOR: {
|
case CellType.CREATOR: {
|
||||||
return creatorFilter(cellValue, filter, username);
|
return creatorFilter(cellValue, filter, username);
|
||||||
}
|
}
|
||||||
|
case CellType.CHECKBOX: {
|
||||||
|
return checkboxFilter(cellValue, filter);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -74,7 +74,6 @@ export {
|
|||||||
isMac,
|
isMac,
|
||||||
base64ToFile,
|
base64ToFile,
|
||||||
bytesToSize,
|
bytesToSize,
|
||||||
getErrorMsg,
|
|
||||||
isFunction,
|
isFunction,
|
||||||
isEmpty,
|
isEmpty,
|
||||||
isEmptyObject,
|
isEmptyObject,
|
||||||
|
@@ -33,7 +33,9 @@ class GroupbySetter extends Component {
|
|||||||
|
|
||||||
const groupbysLength = groupbys ? groupbys.length : 0;
|
const groupbysLength = groupbys ? groupbys.length : 0;
|
||||||
const activated = groupbysLength > 0;
|
const activated = groupbysLength > 0;
|
||||||
let groupbyMessage = gettext('Group');
|
|
||||||
|
// need to translate to Group
|
||||||
|
let groupbyMessage = gettext('Group_by');
|
||||||
if (groupbysLength === 1) {
|
if (groupbysLength === 1) {
|
||||||
groupbyMessage = gettext('Grouped by 1 column');
|
groupbyMessage = gettext('Grouped by 1 column');
|
||||||
} else if (groupbysLength > 1) {
|
} else if (groupbysLength > 1) {
|
||||||
|
@@ -404,6 +404,9 @@ class FilterItem extends React.Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
case CellType.CHECKBOX: {
|
||||||
|
return this.getInputComponent('checkbox');
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -108,10 +108,6 @@
|
|||||||
color: unset;
|
color: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-term .selector-collaborator .sf-metadata-icon-drop-down {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters-list .selector-collaborator .selected-option-show {
|
.filters-list .selector-collaborator .selected-option-show {
|
||||||
text-overflow: unset;
|
text-overflow: unset;
|
||||||
}
|
}
|
||||||
@@ -297,10 +293,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filters-list .filter-checkbox-predicate .sf-metadata-select .selected-option-show {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-item .collaborator,
|
.dropdown-item .collaborator,
|
||||||
.filters-list .option-group .option-group-content .collaborator {
|
.filters-list .option-group .option-group-content .collaborator {
|
||||||
background-color: unset;
|
background-color: unset;
|
||||||
|
@@ -14,7 +14,7 @@ const RecordDetailsDialog = () => {
|
|||||||
updateCollaboratorsCache,
|
updateCollaboratorsCache,
|
||||||
queryUserAPI: window.sfMetadataContext.userService.queryUser,
|
queryUserAPI: window.sfMetadataContext.userService.queryUser,
|
||||||
record: recordDetails,
|
record: recordDetails,
|
||||||
fields: metadata.columns,
|
fields: metadata.view.columns,
|
||||||
fieldIconConfig: COLUMNS_ICON_CONFIG,
|
fieldIconConfig: COLUMNS_ICON_CONFIG,
|
||||||
onToggle: closeRecordDetails,
|
onToggle: closeRecordDetails,
|
||||||
};
|
};
|
||||||
|
@@ -1,12 +1,14 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { toaster } from '@seafile/sf-metadata-ui-component';
|
import toaster from '../../../../components/toast';
|
||||||
import { EVENT_BUS_TYPE } from '../../constants';
|
import { EVENT_BUS_TYPE } from '../../constants';
|
||||||
import { CommonlyUsedHotkey, getErrorMsg } from '../../_basic';
|
import { CommonlyUsedHotkey } from '../../_basic';
|
||||||
import { gettext } from '../../utils';
|
import { gettext } from '../../utils';
|
||||||
import { useMetadata } from '../../hooks';
|
import { useMetadata } from '../../hooks';
|
||||||
import TableTool from './table-tool';
|
import TableTool from './table-tool';
|
||||||
import TableMain from './table-main';
|
import TableMain from './table-main';
|
||||||
import RecordDetailsDialog from '../record-details-dialog';
|
import RecordDetailsDialog from '../record-details-dialog';
|
||||||
|
import { PER_LOAD_NUMBER, MAX_LOAD_NUMBER } from '../../constants';
|
||||||
|
import { Utils } from '../../../../utils/utils';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -38,17 +40,39 @@ const Container = () => {
|
|||||||
setLoadingMore(true);
|
setLoadingMore(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await store.loadMore();
|
await store.loadMore(PER_LOAD_NUMBER);
|
||||||
setLoadingMore(false);
|
setLoadingMore(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMsg = getErrorMsg(error);
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
toaster.danger(gettext(errorMsg));
|
toaster.danger(errorMsg);
|
||||||
setLoadingMore(false);
|
setLoadingMore(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [metadata, store]);
|
}, [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) => {
|
const modifyRecords = useCallback((rowIds, idRowUpdates, idOriginalRowUpdates, idOldRowData, idOriginalOldRowData, isCopyPaste = false) => {
|
||||||
// todo: store op
|
// todo: store op
|
||||||
}, []);
|
}, []);
|
||||||
@@ -144,7 +168,7 @@ const Container = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="sf-metadata-wrapper">
|
<div className="sf-metadata-wrapper">
|
||||||
<TableTool view={metadata.view} columns={metadata.columns} modifyFilters={modifyFilters} modifySorts={modifySorts} modifyGroupbys={modifyGroupbys} modifyHiddenColumns={modifyHiddenColumns} />
|
<TableTool view={metadata.view} modifyFilters={modifyFilters} modifySorts={modifySorts} modifyGroupbys={modifyGroupbys} modifyHiddenColumns={modifyHiddenColumns} />
|
||||||
<div className="sf-metadata-main">
|
<div className="sf-metadata-main">
|
||||||
{errorMsg && (<div className="d-center-middle error">{gettext(errorMsg)}</div>)}
|
{errorMsg && (<div className="d-center-middle error">{gettext(errorMsg)}</div>)}
|
||||||
{!errorMsg && (
|
{!errorMsg && (
|
||||||
@@ -161,6 +185,7 @@ const Container = () => {
|
|||||||
getTableContentWidth={getTableContentWidth}
|
getTableContentWidth={getTableContentWidth}
|
||||||
getTableContentLeft={getTableContentLeft}
|
getTableContentLeft={getTableContentLeft}
|
||||||
getAdjacentRowsIds={getAdjacentRowsIds}
|
getAdjacentRowsIds={getAdjacentRowsIds}
|
||||||
|
loadAll={loadAll}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@@ -32,7 +32,7 @@ const TableMain = ({ metadata, modifyRecord, modifyRecords, loadMore, loadAll, s
|
|||||||
return (
|
return (
|
||||||
<div className={classnames('table-main-container container-fluid p-0', { [`group-level-${groupbysCount + 1}`]: groupbysCount > 0 })}>
|
<div className={classnames('table-main-container container-fluid p-0', { [`group-level-${groupbysCount + 1}`]: groupbysCount > 0 })}>
|
||||||
<Records
|
<Records
|
||||||
columns={metadata.columns}
|
columns={metadata.view.columns}
|
||||||
recordIds={metadata.view.rows || []}
|
recordIds={metadata.view.rows || []}
|
||||||
groups={metadata.groups}
|
groups={metadata.groups}
|
||||||
groupbys={metadata.groupbys}
|
groupbys={metadata.groupbys}
|
||||||
@@ -41,7 +41,7 @@ const TableMain = ({ metadata, modifyRecord, modifyRecords, loadMore, loadAll, s
|
|||||||
hasMore={metadata.hasMore}
|
hasMore={metadata.hasMore}
|
||||||
gridUtils={gridUtils}
|
gridUtils={gridUtils}
|
||||||
scrollToLoadMore={loadMore}
|
scrollToLoadMore={loadMore}
|
||||||
clickToLoadMore={loadAll}
|
loadAll={loadAll}
|
||||||
groupOffsetLeft={groupOffset}
|
groupOffsetLeft={groupOffset}
|
||||||
modifyRecord={updateRecord}
|
modifyRecord={updateRecord}
|
||||||
updateRecords={updateRecords}
|
updateRecords={updateRecords}
|
||||||
|
@@ -115,26 +115,17 @@ class Records extends Component {
|
|||||||
|
|
||||||
resizeColumnWidth = (column, width) => {
|
resizeColumnWidth = (column, width) => {
|
||||||
if (width < 50) return;
|
if (width < 50) return;
|
||||||
const { table, columns, } = this.props;
|
const { columns } = this.props;
|
||||||
const newColumn = Object.assign({}, column, { width });
|
const newColumn = Object.assign({}, column, { width });
|
||||||
const index = columns.findIndex(item => item.key === column.key);
|
const index = columns.findIndex(item => item.key === column.key);
|
||||||
let updateColumns = columns.slice(0);
|
let updateColumns = columns.slice(0);
|
||||||
updateColumns[index] = newColumn;
|
updateColumns[index] = newColumn;
|
||||||
updateColumns = setColumnOffsets(updateColumns);
|
updateColumns = setColumnOffsets(updateColumns);
|
||||||
const columnMetrics = recalculate(updateColumns, columns, table._id);
|
const columnMetrics = recalculate(updateColumns, columns);
|
||||||
this.setState({ columnMetrics }, () => {
|
this.setState({ columnMetrics }, () => {
|
||||||
const oldValue = localStorage.getItem('pages_columns_width');
|
const oldValue = window.sfMetadataContext.localStorage.getItem('columns_width') || {};
|
||||||
let pagesColumnsWidth = {};
|
window.sfMetadataContext.localStorage.setItem('columns_width', { ...oldValue, [column.key]: width });
|
||||||
if (oldValue) {
|
|
||||||
pagesColumnsWidth = JSON.parse(oldValue);
|
|
||||||
}
|
|
||||||
const page = window.app.getPage();
|
|
||||||
const { id: pageId } = page;
|
|
||||||
let pageColumnsWidth = pagesColumnsWidth[pageId] || {};
|
|
||||||
const key = `${table._id}-${column.key}`;
|
|
||||||
pageColumnsWidth[key] = width;
|
|
||||||
const updated = Object.assign({}, pagesColumnsWidth, { [pageId]: pageColumnsWidth });
|
|
||||||
localStorage.setItem('pages_columns_width', JSON.stringify(updated));
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -742,7 +733,7 @@ class Records extends Component {
|
|||||||
recordGetterById={this.props.recordGetterById}
|
recordGetterById={this.props.recordGetterById}
|
||||||
recordGetterByIndex={this.props.recordGetterByIndex}
|
recordGetterByIndex={this.props.recordGetterByIndex}
|
||||||
getRecordsSummaries={() => {}}
|
getRecordsSummaries={() => {}}
|
||||||
clickToLoadMore={this.props.clickToLoadMore}
|
loadAll={this.props.loadAll}
|
||||||
/>
|
/>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
@@ -768,7 +759,7 @@ Records.propTypes = {
|
|||||||
updateRecords: PropTypes.func,
|
updateRecords: PropTypes.func,
|
||||||
recordGetterById: PropTypes.func,
|
recordGetterById: PropTypes.func,
|
||||||
recordGetterByIndex: PropTypes.func,
|
recordGetterByIndex: PropTypes.func,
|
||||||
clickToLoadMore: PropTypes.func,
|
loadAll: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Records;
|
export default Records;
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { toaster } from '@seafile/sf-metadata-ui-component';
|
import toaster from '../../../../../../components/toast';
|
||||||
import { gettext } from '../../../../../../utils/constants';
|
import { gettext } from '../../../../../../utils/constants';
|
||||||
|
|
||||||
class LoadAllTip extends React.Component {
|
class LoadAllTip extends React.Component {
|
||||||
|
|
||||||
onClick = () => {
|
onClick = () => {
|
||||||
toaster.closeAll();
|
toaster.closeAll();
|
||||||
this.props.clickToLoadMore(100000);
|
this.props.load(100000);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -21,7 +21,7 @@ class LoadAllTip extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LoadAllTip.propTypes = {
|
LoadAllTip.propTypes = {
|
||||||
clickToLoadMore: PropTypes.func
|
load: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LoadAllTip;
|
export default LoadAllTip;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { toaster } from '@seafile/sf-metadata-ui-component';
|
import toaster from '../../../../../../components/toast';
|
||||||
import { isFunction } from '../../../../_basic';
|
import { isFunction } from '../../../../_basic';
|
||||||
import { isNameColumn } from '../../../../utils/column-utils';
|
import { isNameColumn } from '../../../../utils/column-utils';
|
||||||
import { TABLE_SUPPORT_EDIT_TYPE_MAP } from '../../../../constants';
|
import { TABLE_SUPPORT_EDIT_TYPE_MAP } from '../../../../constants';
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Loading, toaster } from '@seafile/sf-metadata-ui-component';
|
import { Loading } from '@seafile/sf-metadata-ui-component';
|
||||||
|
import toaster from '../../../../../../../components/toast';
|
||||||
import { Z_INDEX } from '../../../../../_basic';
|
import { Z_INDEX } from '../../../../../_basic';
|
||||||
import LoadAllTip from '../load-all-tip';
|
import LoadAllTip from '../load-all-tip';
|
||||||
import RecordMetrics from '../../../../../utils/record-metrics';
|
import RecordMetrics from '../../../../../utils/record-metrics';
|
||||||
@@ -17,9 +18,9 @@ class RecordsFooter extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const loadNumber = this.props.recordsCount < 50000 ? 50000 : 100000;
|
const loadNumber = this.props.recordsCount < 50000 ? 50000 : 100000;
|
||||||
this.props.clickToLoadMore(loadNumber, (hasMore) => {
|
this.props.loadAll(loadNumber, (hasMore) => {
|
||||||
if (hasMore) {
|
if (hasMore) {
|
||||||
toaster.success(<LoadAllTip clickToLoadMore={this.props.clickToLoadMore} />, { duration: 5 });
|
toaster.success(<LoadAllTip load={this.props.loadAll} />, { duration: 5 });
|
||||||
} else {
|
} else {
|
||||||
toaster.success(gettext('All records loaded'));
|
toaster.success(gettext('All records loaded'));
|
||||||
}
|
}
|
||||||
@@ -108,7 +109,7 @@ class RecordsFooter extends React.Component {
|
|||||||
<div className="rows-record d-flex text-nowrap" style={{ width: recordWidth }}>
|
<div className="rows-record d-flex text-nowrap" style={{ width: recordWidth }}>
|
||||||
<span>{this.getRecord()}</span>
|
<span>{this.getRecord()}</span>
|
||||||
{!isLoadingMore && hasMore &&
|
{!isLoadingMore && hasMore &&
|
||||||
<span className="load-all ml-4" onClick={this.onClick}>{gettext('Load_all')}</span>
|
<span className="load-all ml-4" onClick={this.onClick}>{gettext('Load all')}</span>
|
||||||
}
|
}
|
||||||
{isLoadingMore &&
|
{isLoadingMore &&
|
||||||
<span className="loading-message ml-4">
|
<span className="loading-message ml-4">
|
||||||
@@ -144,7 +145,7 @@ RecordsFooter.propTypes = {
|
|||||||
recordGetterById: PropTypes.func,
|
recordGetterById: PropTypes.func,
|
||||||
recordGetterByIndex: PropTypes.func,
|
recordGetterByIndex: PropTypes.func,
|
||||||
getRecordsSummaries: PropTypes.func,
|
getRecordsSummaries: PropTypes.func,
|
||||||
clickToLoadMore: PropTypes.func,
|
loadAll: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RecordsFooter;
|
export default RecordsFooter;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import deepCopy from 'deep-copy';
|
import deepCopy from 'deep-copy';
|
||||||
import { toaster } from '@seafile/sf-metadata-ui-component';
|
import toaster from '../../../../../../components/toast';
|
||||||
import {
|
import {
|
||||||
CellType,
|
CellType,
|
||||||
NOT_SUPPORT_EDIT_COLUMN_TYPE_MAP,
|
NOT_SUPPORT_EDIT_COLUMN_TYPE_MAP,
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { FilterSetter, GroupbySetter, SortSetter, HideColumnSetter } from '../../data-process-setter';
|
import { FilterSetter, GroupbySetter, SortSetter, HideColumnSetter } from '../../data-process-setter';
|
||||||
@@ -8,7 +8,11 @@ import { useCollaborators } from '../../../hooks';
|
|||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
const TableTool = ({ searcherActive, view, columns, modifyFilters, modifySorts, modifyGroupbys, modifyHiddenColumns }) => {
|
const TableTool = ({ searcherActive, view, modifyFilters, modifySorts, modifyGroupbys, modifyHiddenColumns }) => {
|
||||||
|
|
||||||
|
const columns = useMemo(() => {
|
||||||
|
return view.available_columns;
|
||||||
|
}, [view]);
|
||||||
|
|
||||||
const { collaborators } = useCollaborators();
|
const { collaborators } = useCollaborators();
|
||||||
|
|
||||||
@@ -62,7 +66,6 @@ const TableTool = ({ searcherActive, view, columns, modifyFilters, modifySorts,
|
|||||||
TableTool.propTypes = {
|
TableTool.propTypes = {
|
||||||
searcherActive: PropTypes.bool,
|
searcherActive: PropTypes.bool,
|
||||||
view: PropTypes.object,
|
view: PropTypes.object,
|
||||||
columns: PropTypes.array,
|
|
||||||
modifyFilters: PropTypes.func,
|
modifyFilters: PropTypes.func,
|
||||||
modifySorts: PropTypes.func,
|
modifySorts: PropTypes.func,
|
||||||
modifyGroupbys: PropTypes.func,
|
modifyGroupbys: PropTypes.func,
|
||||||
|
@@ -97,7 +97,10 @@ export const DEFAULT_COLUMNS = [
|
|||||||
{ name: 'Is_dir', type: CellType.TEXT, width: 200, editable: false, key: 'is_dir' },
|
{ name: 'Is_dir', type: CellType.TEXT, width: 200, editable: false, key: 'is_dir' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const PER_PAGE_COUNT = 1000;
|
export const PER_LOAD_NUMBER = 1000;
|
||||||
|
|
||||||
|
// dtable-db limit loads up to 10,000 rows at a time
|
||||||
|
export const MAX_LOAD_NUMBER = 10000;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
EVENT_BUS_TYPE,
|
EVENT_BUS_TYPE,
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React, { useContext, useEffect, useRef, useState, useCallback } from 'react';
|
import React, { useContext, useEffect, useRef, useState, useCallback } from 'react';
|
||||||
import { toaster } from '@seafile/sf-metadata-ui-component';
|
import toaster from '../../../components/toast';
|
||||||
import { gettext } from '../../../utils/constants';
|
|
||||||
import { getErrorMsg } from '../_basic';
|
|
||||||
import Context from '../context';
|
import Context from '../context';
|
||||||
import Store from '../store';
|
import Store from '../store';
|
||||||
import { EVENT_BUS_TYPE } from '../constants';
|
import { EVENT_BUS_TYPE, PER_LOAD_NUMBER } from '../constants';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
|
||||||
const MetadataContext = React.createContext(null);
|
const MetadataContext = React.createContext(null);
|
||||||
|
|
||||||
@@ -22,8 +21,8 @@ export const MetadataProvider = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleTableError = useCallback((error) => {
|
const handleTableError = useCallback((error) => {
|
||||||
const errorMsg = getErrorMsg(error);
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
toaster.danger(gettext(errorMsg));
|
toaster.danger(errorMsg);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const updateMetadata = useCallback((data) => {
|
const updateMetadata = useCallback((data) => {
|
||||||
@@ -39,12 +38,12 @@ export const MetadataProvider = ({
|
|||||||
const repoId = window.sfMetadataContext.getSetting('repoID');
|
const repoId = window.sfMetadataContext.getSetting('repoID');
|
||||||
storeRef.current = new Store({ context: window.sfMetadataContext, repoId });
|
storeRef.current = new Store({ context: window.sfMetadataContext, repoId });
|
||||||
storeRef.current.initStartIndex();
|
storeRef.current.initStartIndex();
|
||||||
storeRef.current.loadData().then(() => {
|
storeRef.current.loadData(PER_LOAD_NUMBER).then(() => {
|
||||||
setMetadata(storeRef.current.data);
|
setMetadata(storeRef.current.data);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
const errorMsg = getErrorMsg(error);
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
toaster.danger(gettext(errorMsg));
|
toaster.danger(errorMsg);
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsubscribeServerTableChanged = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SERVER_TABLE_CHANGED, tableChanged);
|
const unsubscribeServerTableChanged = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.SERVER_TABLE_CHANGED, tableChanged);
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { PER_PAGE_COUNT } from '../../constants';
|
|
||||||
import View from './view';
|
import View from './view';
|
||||||
|
|
||||||
class Metadata {
|
class Metadata {
|
||||||
@@ -12,10 +11,9 @@ class Metadata {
|
|||||||
this.id_row_map[record._id] = record;
|
this.id_row_map[record._id] = record;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hasMore = this.rows.length === PER_PAGE_COUNT;
|
this.hasMore = true;
|
||||||
|
this.recordsCount = this.row_ids.length;
|
||||||
this.recordsCount = object.recordsCount || this.row_ids.length;
|
this.view = new View(object.view || {}, this.columns);
|
||||||
this.view = new View(object.view || {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
|
import { VIEW_NOT_DISPLAY_COLUMN_KEYS } from '../../_basic';
|
||||||
|
|
||||||
class View {
|
class View {
|
||||||
constructor(object) {
|
constructor(object, columns) {
|
||||||
this.filters = object.filters || [];
|
this.filters = object.filters || [];
|
||||||
this.filter_conjunction = object.filter_conjunction || 'Or';
|
this.filter_conjunction = object.filter_conjunction || 'Or';
|
||||||
this.sorts = object.sorts || [];
|
this.sorts = object.sorts || [];
|
||||||
this.groupbys = object.groupbys || [];
|
this.groupbys = object.groupbys || [];
|
||||||
this.groups = object.groups;
|
this.groups = object.groups;
|
||||||
this.rows = object.rows || [];
|
this.rows = object.rows || [];
|
||||||
// this.available_columns = object.available_columns || [];
|
this.available_columns = columns || [];
|
||||||
|
this.columns = this.available_columns.filter(column => !VIEW_NOT_DISPLAY_COLUMN_KEYS.includes(column.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,7 @@ import DataProcessor from './data-processor';
|
|||||||
import ServerOperator from './server-operator';
|
import ServerOperator from './server-operator';
|
||||||
import { getColumns } from '../utils/column-utils';
|
import { getColumns } from '../utils/column-utils';
|
||||||
import { Metadata, User } from '../model';
|
import { Metadata, User } from '../model';
|
||||||
import { PER_PAGE_COUNT } from '../constants';
|
import { PER_LOAD_NUMBER } from '../constants';
|
||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class Store {
|
|||||||
this.repoId = props.repoId;
|
this.repoId = props.repoId;
|
||||||
this.data = null;
|
this.data = null;
|
||||||
this.context = props.context;
|
this.context = props.context;
|
||||||
this.startIndex = 1;
|
this.startIndex = 0;
|
||||||
this.redos = [];
|
this.redos = [];
|
||||||
this.undos = [];
|
this.undos = [];
|
||||||
this.pendingOperations = [];
|
this.pendingOperations = [];
|
||||||
@@ -28,7 +28,7 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initStartIndex = () => {
|
initStartIndex = () => {
|
||||||
this.startIndex = 1;
|
this.startIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
saveView = () => {
|
saveView = () => {
|
||||||
@@ -37,21 +37,25 @@ class Store {
|
|||||||
this.context.localStorage.setItem('view', view);
|
this.context.localStorage.setItem('view', view);
|
||||||
};
|
};
|
||||||
|
|
||||||
async loadData() {
|
async loadData(limit = PER_LOAD_NUMBER) {
|
||||||
const res = await this.context.getMetadata({ page: this.startIndex });
|
const res = await this.context.getMetadata({ start: this.startIndex, limit });
|
||||||
const view = this.context.localStorage.getItem('view');
|
const view = this.context.localStorage.getItem('view');
|
||||||
let data = new Metadata({ rows: res?.data?.results || [], columns: getColumns(res?.data?.metadata), view });
|
const rows = res?.data?.results || [];
|
||||||
|
const columns = getColumns(res?.data?.metadata);
|
||||||
|
let data = new Metadata({ rows, columns, view });
|
||||||
data.view.rows = data.row_ids;
|
data.view.rows = data.row_ids;
|
||||||
|
const loadedCount = rows.length;
|
||||||
|
data.hasMore = loadedCount === limit;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.startIndex += 1;
|
this.startIndex += loadedCount;
|
||||||
const collaboratorsRes = await this.context.getCollaborators();
|
const collaboratorsRes = await this.context.getCollaborators();
|
||||||
this.collaborators = Array.isArray(collaboratorsRes?.data?.user_list) ? collaboratorsRes.data.user_list.map(user => new User(user)) : [];
|
this.collaborators = Array.isArray(collaboratorsRes?.data?.user_list) ? collaboratorsRes.data.user_list.map(user => new User(user)) : [];
|
||||||
DataProcessor.run(this.data);
|
DataProcessor.run(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadMore() {
|
async loadMore(limit) {
|
||||||
if (!this.data) return;
|
if (!this.data) return;
|
||||||
const res = await this.context.getMetadata(this.repoId, { page: this.startIndex });
|
const res = await this.context.getMetadata({ start: this.startIndex, limit });
|
||||||
const rows = res?.data?.results || [];
|
const rows = res?.data?.results || [];
|
||||||
if (!Array.isArray(rows) || rows.length === 0) {
|
if (!Array.isArray(rows) || rows.length === 0) {
|
||||||
this.hasMore = false;
|
this.hasMore = false;
|
||||||
@@ -63,8 +67,10 @@ class Store {
|
|||||||
this.data.row_ids.push(record._id);
|
this.data.row_ids.push(record._id);
|
||||||
this.data.id_row_map[record._id] = record;
|
this.data.id_row_map[record._id] = record;
|
||||||
});
|
});
|
||||||
this.data.hasMore = rows.length === PER_PAGE_COUNT;
|
const loadedCount = rows.length;
|
||||||
this.startIndex += 1;
|
this.data.hasMore = loadedCount === limit;
|
||||||
|
this.data.recordsCount = this.data.row_ids.length;
|
||||||
|
this.startIndex = this.startIndex + loadedCount;
|
||||||
DataProcessor.run(this.data);
|
DataProcessor.run(this.data);
|
||||||
this.context.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_TABLE_CHANGED);
|
this.context.eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_TABLE_CHANGED);
|
||||||
}
|
}
|
||||||
|
@@ -132,31 +132,27 @@ export function isColumnSupportDirectEdit(cell, columns) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _getCustomColumnsWidth = () => {
|
const _getCustomColumnsWidth = () => {
|
||||||
// todo
|
return window.sfMetadataContext.localStorage.getItem('columns_width') || {};
|
||||||
return {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const recalculate = (columns, allColumns, tableId) => {
|
export const recalculate = (columns, allColumns) => {
|
||||||
const displayColumns = columns;
|
const displayColumns = columns;
|
||||||
const displayAllColumns = allColumns;
|
const displayAllColumns = allColumns;
|
||||||
const pageColumnsWidth = _getCustomColumnsWidth(); // get columns width from local storage
|
const pageColumnsWidth = _getCustomColumnsWidth(); // get columns width from local storage
|
||||||
const totalWidth = displayColumns.reduce((total, column) => {
|
const totalWidth = displayColumns.reduce((total, column) => {
|
||||||
const key = `${tableId}-${column.key}`;
|
const width = pageColumnsWidth[column.key] || column.width;
|
||||||
const width = pageColumnsWidth[key] || column.width;
|
|
||||||
total += width;
|
total += width;
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
}, 0);
|
||||||
let left = SEQUENCE_COLUMN_WIDTH;
|
let left = SEQUENCE_COLUMN_WIDTH;
|
||||||
const frozenColumns = displayColumns.filter(c => isFrozen(c));
|
const frozenColumns = displayColumns.filter(c => isFrozen(c));
|
||||||
const frozenColumnsWidth = frozenColumns.reduce((w, column) => {
|
const frozenColumnsWidth = frozenColumns.reduce((w, column) => {
|
||||||
const key = `${tableId}-${column.key}`;
|
const width = pageColumnsWidth[column.key] || column.width;
|
||||||
const width = pageColumnsWidth[key] || column.width;
|
|
||||||
return w + width;
|
return w + width;
|
||||||
}, 0);
|
}, 0);
|
||||||
const lastFrozenColumnKey = frozenColumnsWidth > 0 ? frozenColumns[frozenColumns.length - 1].key : null;
|
const lastFrozenColumnKey = frozenColumnsWidth > 0 ? frozenColumns[frozenColumns.length - 1].key : null;
|
||||||
const newColumns = displayColumns.map((column, index) => {
|
const newColumns = displayColumns.map((column, index) => {
|
||||||
const key = `${tableId}-${column.key}`;
|
const width = pageColumnsWidth[column.key] || column.width;
|
||||||
const width = pageColumnsWidth[key] || column.width;
|
|
||||||
column.idx = index; // set column idx
|
column.idx = index; // set column idx
|
||||||
column.left = left; // set column offset
|
column.left = left; // set column offset
|
||||||
column.width = width;
|
column.width = width;
|
||||||
@@ -192,9 +188,9 @@ export const getColumnName = (key, name) => {
|
|||||||
case PRIVATE_COLUMN_KEY.FILE_MTIME:
|
case PRIVATE_COLUMN_KEY.FILE_MTIME:
|
||||||
return gettext('File last modified time');
|
return gettext('File last modified time');
|
||||||
case PRIVATE_COLUMN_KEY.IS_DIR:
|
case PRIVATE_COLUMN_KEY.IS_DIR:
|
||||||
return gettext('Is dir');
|
return gettext('Is folder');
|
||||||
case PRIVATE_COLUMN_KEY.PARENT_DIR:
|
case PRIVATE_COLUMN_KEY.PARENT_DIR:
|
||||||
return gettext('Parent dir');
|
return gettext('Parent folder');
|
||||||
case PRIVATE_COLUMN_KEY.FILE_NAME:
|
case PRIVATE_COLUMN_KEY.FILE_NAME:
|
||||||
return gettext('File name');
|
return gettext('File name');
|
||||||
default:
|
default:
|
||||||
@@ -218,6 +214,8 @@ const getColumnType = (key, type) => {
|
|||||||
return CellType.LAST_MODIFIER;
|
return CellType.LAST_MODIFIER;
|
||||||
case PRIVATE_COLUMN_KEY.FILE_NAME:
|
case PRIVATE_COLUMN_KEY.FILE_NAME:
|
||||||
return CellType.FILE_NAME;
|
return CellType.FILE_NAME;
|
||||||
|
case PRIVATE_COLUMN_KEY.IS_DIR:
|
||||||
|
return CellType.CHECKBOX;
|
||||||
default:
|
default:
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -225,6 +223,7 @@ const getColumnType = (key, type) => {
|
|||||||
|
|
||||||
export const getColumns = (columns) => {
|
export const getColumns = (columns) => {
|
||||||
if (!Array.isArray(columns) || columns.length === 0) return [];
|
if (!Array.isArray(columns) || columns.length === 0) return [];
|
||||||
|
const columnsWidth = window.sfMetadataContext.localStorage.getItem('columns_width') || {};
|
||||||
const validColumns = columns.map((column) => {
|
const validColumns = columns.map((column) => {
|
||||||
const { type, key, name, ...params } = column;
|
const { type, key, name, ...params } = column;
|
||||||
return {
|
return {
|
||||||
@@ -232,7 +231,7 @@ export const getColumns = (columns) => {
|
|||||||
type: getColumnType(key, type),
|
type: getColumnType(key, type),
|
||||||
name: getColumnName(key, name),
|
name: getColumnName(key, name),
|
||||||
...params,
|
...params,
|
||||||
width: 200,
|
width: columnsWidth[key] || 200,
|
||||||
};
|
};
|
||||||
}).filter(column => !NOT_DISPLAY_COLUMN_KEYS.includes(column.key));
|
}).filter(column => !NOT_DISPLAY_COLUMN_KEYS.includes(column.key));
|
||||||
let displayColumns = [];
|
let displayColumns = [];
|
||||||
|
@@ -153,24 +153,24 @@ class MetadataRecords(APIView):
|
|||||||
#args check
|
#args check
|
||||||
parent_dir = request.GET.get('parent_dir')
|
parent_dir = request.GET.get('parent_dir')
|
||||||
name = request.GET.get('name')
|
name = request.GET.get('name')
|
||||||
page = request.GET.get('page', 1)
|
start = request.GET.get('start', 0)
|
||||||
per_page = request.GET.get('per_page', 1000)
|
limit = request.GET.get('limit', 100)
|
||||||
is_dir = request.GET.get('is_dir')
|
is_dir = request.GET.get('is_dir')
|
||||||
order_by = request.GET.get('order_by')
|
order_by = request.GET.get('order_by')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
page = int(page)
|
start = int(start)
|
||||||
per_page = int(per_page)
|
limit = int(limit)
|
||||||
except:
|
except:
|
||||||
page = 1
|
start = 0
|
||||||
per_page = 1000
|
limit = 1000
|
||||||
|
|
||||||
if page <= 0:
|
if start < 0:
|
||||||
error_msg = 'page invalid'
|
error_msg = 'start invalid'
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
if per_page <= 0:
|
if limit < 0:
|
||||||
error_msg = 'per_page invalid'
|
error_msg = 'limit invalid'
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
if is_dir:
|
if is_dir:
|
||||||
@@ -199,7 +199,7 @@ class MetadataRecords(APIView):
|
|||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = list_metadata_records(repo_id, request.user.username, parent_dir, name, is_dir, page, per_page, order_by)
|
results = list_metadata_records(repo_id, request.user.username, parent_dir, name, is_dir, start, limit, order_by)
|
||||||
except ConnectionError as err:
|
except ConnectionError as err:
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
status_code, reason = err
|
status_code, reason = err
|
||||||
|
@@ -2,7 +2,7 @@ import requests, jwt, time
|
|||||||
from seahub.settings import METADATA_SERVER_URL, METADATA_SERVER_SECRET_KEY
|
from seahub.settings import METADATA_SERVER_URL, METADATA_SERVER_SECRET_KEY
|
||||||
|
|
||||||
|
|
||||||
def list_metadata_records(repo_id, user, parent_dir=None, name=None, is_dir=None, page=None, per_page=25, order_by=None):
|
def list_metadata_records(repo_id, user, parent_dir=None, name=None, is_dir=None, start=0, limit=1000, order_by=None):
|
||||||
from seafevents.repo_metadata.metadata_server_api import METADATA_TABLE
|
from seafevents.repo_metadata.metadata_server_api import METADATA_TABLE
|
||||||
|
|
||||||
sql = f'SELECT \
|
sql = f'SELECT \
|
||||||
@@ -44,10 +44,7 @@ def list_metadata_records(repo_id, user, parent_dir=None, name=None, is_dir=None
|
|||||||
`{METADATA_TABLE.columns.is_dir.name}` DESC, \
|
`{METADATA_TABLE.columns.is_dir.name}` DESC, \
|
||||||
`{METADATA_TABLE.columns.file_name.name}` ASC'
|
`{METADATA_TABLE.columns.file_name.name}` ASC'
|
||||||
|
|
||||||
if page:
|
sql += f' LIMIT {start}, {limit};'
|
||||||
sql += f' LIMIT {(page - 1) * per_page}, {page * per_page}'
|
|
||||||
|
|
||||||
sql += ';'
|
|
||||||
|
|
||||||
metadata_server_api = MetadataServerAPI(repo_id, user)
|
metadata_server_api = MetadataServerAPI(repo_id, user)
|
||||||
response_results = metadata_server_api.query_rows(sql, parameters)
|
response_results = metadata_server_api.query_rows(sql, parameters)
|
||||||
|
Reference in New Issue
Block a user