mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-03 16:10:26 +00:00
feat: filename support open a file (#6304)
* feat: filename support open a file * feat: add currentRepoInfo * feat: op 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
@@ -19,7 +19,7 @@
|
|||||||
"@seafile/sdoc-editor": "1.0.11",
|
"@seafile/sdoc-editor": "1.0.11",
|
||||||
"@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.9",
|
"@seafile/sf-metadata-ui-component": "0.0.10",
|
||||||
"@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",
|
||||||
@@ -4970,9 +4970,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@seafile/sf-metadata-ui-component": {
|
"node_modules/@seafile/sf-metadata-ui-component": {
|
||||||
"version": "0.0.9",
|
"version": "0.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.10.tgz",
|
||||||
"integrity": "sha512-J0D3DK1TI16QPlhAeBp64ilcKO7pCX9w03Q94D1Ni7phLquqZwCD3PFFyRgv6oUkWtGojTL++SiLVTTXubI68g==",
|
"integrity": "sha512-WP1SH6NbP4tH3ZQ1dgzFKPpYfFzhDD/uzPktxJFpBX66xnTWlBirqYl5IHkyJ5nx6vuXG9CcRc9LhNyl+r3jeg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@seafile/seafile-calendar": "0.0.24",
|
"@seafile/seafile-calendar": "0.0.24",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
@@ -32193,9 +32193,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@seafile/sf-metadata-ui-component": {
|
"@seafile/sf-metadata-ui-component": {
|
||||||
"version": "0.0.9",
|
"version": "0.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/@seafile/sf-metadata-ui-component/-/sf-metadata-ui-component-0.0.10.tgz",
|
||||||
"integrity": "sha512-J0D3DK1TI16QPlhAeBp64ilcKO7pCX9w03Q94D1Ni7phLquqZwCD3PFFyRgv6oUkWtGojTL++SiLVTTXubI68g==",
|
"integrity": "sha512-WP1SH6NbP4tH3ZQ1dgzFKPpYfFzhDD/uzPktxJFpBX66xnTWlBirqYl5IHkyJ5nx6vuXG9CcRc9LhNyl+r3jeg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@seafile/seafile-calendar": "0.0.24",
|
"@seafile/seafile-calendar": "0.0.24",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
"@seafile/sdoc-editor": "1.0.11",
|
"@seafile/sdoc-editor": "1.0.11",
|
||||||
"@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.9",
|
"@seafile/sf-metadata-ui-component": "0.0.10",
|
||||||
"@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",
|
||||||
|
@@ -16,6 +16,7 @@ const propTypes = {
|
|||||||
lastModified: PropTypes.string,
|
lastModified: PropTypes.string,
|
||||||
latestContributor: PropTypes.string,
|
latestContributor: PropTypes.string,
|
||||||
onLinkClick: PropTypes.func.isRequired,
|
onLinkClick: PropTypes.func.isRequired,
|
||||||
|
currentRepoInfo: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirColumnFile extends React.Component {
|
class DirColumnFile extends React.Component {
|
||||||
@@ -60,7 +61,7 @@ class DirColumnFile extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className="w-100 h-100 o-hidden d-flex" style={{ paddingRight: 10, flexDirection: 'column', alignItems: 'center' }}>
|
<div className="w-100 h-100 o-hidden d-flex" style={{ paddingRight: 10, flexDirection: 'column', alignItems: 'center' }}>
|
||||||
<div className="" style={{ width: '100%', height: 10, zIndex: 7, transform: 'translateZ(1000px)', position: 'relative', background: '#fff' }}></div>
|
<div className="" style={{ width: '100%', height: 10, zIndex: 7, transform: 'translateZ(1000px)', position: 'relative', background: '#fff' }}></div>
|
||||||
<SeafileMetadata repoID={this.props.repoID} />
|
<SeafileMetadata repoID={this.props.repoID} currentRepoInfo={this.props.currentRepoInfo} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -190,6 +190,7 @@ class DirColumnView extends React.Component {
|
|||||||
isFileLoadedErr={this.props.isFileLoadedErr}
|
isFileLoadedErr={this.props.isFileLoadedErr}
|
||||||
filePermission={this.props.filePermission}
|
filePermission={this.props.filePermission}
|
||||||
content={this.props.content}
|
content={this.props.content}
|
||||||
|
currentRepoInfo={this.props.currentRepoInfo}
|
||||||
lastModified={this.props.lastModified}
|
lastModified={this.props.lastModified}
|
||||||
latestContributor={this.props.latestContributor}
|
latestContributor={this.props.latestContributor}
|
||||||
onLinkClick={this.props.onLinkClick}
|
onLinkClick={this.props.onLinkClick}
|
||||||
|
@@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Editor from './editor';
|
||||||
|
|
||||||
|
const EditorContainer = (props) => {
|
||||||
|
if (!props.column) return null;
|
||||||
|
return (<Editor { ...props } />);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
EditorContainer.propTypes = {
|
||||||
|
table: PropTypes.object,
|
||||||
|
columns: PropTypes.array,
|
||||||
|
isGroupView: PropTypes.bool,
|
||||||
|
scrollTop: PropTypes.number,
|
||||||
|
scrollLeft: PropTypes.number,
|
||||||
|
firstEditorKeyDown: PropTypes.object,
|
||||||
|
openEditorMode: PropTypes.string,
|
||||||
|
portalTarget: PropTypes.any,
|
||||||
|
editorPosition: PropTypes.object,
|
||||||
|
record: PropTypes.object,
|
||||||
|
column: PropTypes.object,
|
||||||
|
width: PropTypes.number.isRequired,
|
||||||
|
height: PropTypes.number.isRequired,
|
||||||
|
left: PropTypes.number.isRequired,
|
||||||
|
top: PropTypes.number.isRequired,
|
||||||
|
onCommit: PropTypes.func,
|
||||||
|
onCommitCancel: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditorContainer;
|
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
class EditorPortal extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
target: PropTypes.instanceOf(Element).isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep track of when the modal element is added to the DOM
|
||||||
|
state = {
|
||||||
|
isMounted: false
|
||||||
|
};
|
||||||
|
|
||||||
|
el = document.createElement('div');
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.target.appendChild(this.el);
|
||||||
|
// eslint-disable-next-line react/no-did-mount-set-state
|
||||||
|
this.setState({ isMounted: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.props.target.removeChild(this.el);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
// Don't render the portal until the component has mounted,
|
||||||
|
// So the portal can safely access the DOM.
|
||||||
|
if (!this.state.isMounted) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReactDOM.createPortal(
|
||||||
|
this.props.children,
|
||||||
|
this.el,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditorPortal;
|
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { CellType } from '../../_basic';
|
||||||
|
import FileNameEditor from './file-name-editor';
|
||||||
|
|
||||||
|
const Editor = (props) => {
|
||||||
|
|
||||||
|
switch (props.column.type) {
|
||||||
|
case CellType.FILE_NAME: {
|
||||||
|
return (<FileNameEditor {...props} />);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Editor.propTypes = {
|
||||||
|
column: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Editor;
|
@@ -0,0 +1,95 @@
|
|||||||
|
import React, { useEffect, useMemo } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ModalPortal } from '@seafile/sf-metadata-ui-component';
|
||||||
|
import { PRIVATE_COLUMN_KEY } from '../../_basic';
|
||||||
|
import { Utils } from '../../../../utils/utils';
|
||||||
|
import ImageDialog from '../../../../components/dialog/image-dialog';
|
||||||
|
import { serviceURL, siteRoot, thumbnailSizeForOriginal } from '../../../../utils/constants';
|
||||||
|
|
||||||
|
const FileNameEditor = ({ column, record, onCommitCancel }) => {
|
||||||
|
const _isDir = useMemo(() => {
|
||||||
|
const isDirValue = record[PRIVATE_COLUMN_KEY.IS_DIR];
|
||||||
|
if (typeof isDirValue === 'string') return isDirValue.toUpperCase() === 'TRUE';
|
||||||
|
return isDirValue;
|
||||||
|
}, [record]);
|
||||||
|
|
||||||
|
const fileName = useMemo(() => {
|
||||||
|
const { key } = column;
|
||||||
|
return record[key];
|
||||||
|
}, [column, record]);
|
||||||
|
|
||||||
|
const fileType = useMemo(() => {
|
||||||
|
if (_isDir) return 'folder';
|
||||||
|
if (!fileName) return '';
|
||||||
|
const index = fileName.lastIndexOf('.');
|
||||||
|
if (index === -1) return '';
|
||||||
|
const suffix = fileName.slice(index).toLowerCase();
|
||||||
|
if (Utils.imageCheck(fileName)) return 'image';
|
||||||
|
if (suffix === '.sdoc') return 'sdoc';
|
||||||
|
return 'file';
|
||||||
|
}, [_isDir, fileName]);
|
||||||
|
|
||||||
|
const parentDir = useMemo(() => {
|
||||||
|
const value = record[PRIVATE_COLUMN_KEY.PARENT_DIR];
|
||||||
|
if (value === '/') return '';
|
||||||
|
return value;
|
||||||
|
}, [record]);
|
||||||
|
|
||||||
|
const repoID = useMemo(() => {
|
||||||
|
return window.sfMetadataContext.getSetting('repoID');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const path = useMemo(() => {
|
||||||
|
return Utils.encodePath(Utils.joinPath(parentDir, fileName));
|
||||||
|
}, [parentDir, fileName]);
|
||||||
|
|
||||||
|
const url = useMemo(() => {
|
||||||
|
return `${siteRoot}lib/${repoID}/file${path}`;
|
||||||
|
}, [path, repoID]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (fileType === 'image') return;
|
||||||
|
onCommitCancel && onCommitCancel();
|
||||||
|
}, [fileType, onCommitCancel]);
|
||||||
|
|
||||||
|
if (fileType === 'image') {
|
||||||
|
const fileExt = fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase();
|
||||||
|
const isGIF = fileExt === 'gif';
|
||||||
|
const useThumbnail = window.sfMetadataContext.getSetting('currentRepoInfo')?.encrypted;
|
||||||
|
let src = '';
|
||||||
|
if (useThumbnail && !isGIF) {
|
||||||
|
src = `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`;
|
||||||
|
} else {
|
||||||
|
src = `${siteRoot}repo/${repoID}/raw${path}`;
|
||||||
|
}
|
||||||
|
const images = [
|
||||||
|
{ 'name': fileName, 'url': url, 'src': src },
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<ModalPortal>
|
||||||
|
<ImageDialog
|
||||||
|
imageItems={images}
|
||||||
|
imageIndex={0}
|
||||||
|
closeImagePopup={onCommitCancel}
|
||||||
|
moveToPrevImage={() => {}}
|
||||||
|
moveToNextImage={() => {}}
|
||||||
|
/>
|
||||||
|
</ModalPortal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileType || fileType === 'sdoc') {
|
||||||
|
window.open(serviceURL + url);
|
||||||
|
} else {
|
||||||
|
window.open(window.location.href + Utils.encodePath(Utils.joinPath(parentDir, fileName)));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileNameEditor.propTypes = {
|
||||||
|
column: PropTypes.object,
|
||||||
|
record: PropTypes.object,
|
||||||
|
onCommitCancel: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FileNameEditor;
|
@@ -0,0 +1,7 @@
|
|||||||
|
import EditorPortal from './editor-portal';
|
||||||
|
import EditorContainer from './editor-container';
|
||||||
|
|
||||||
|
export {
|
||||||
|
EditorPortal,
|
||||||
|
EditorContainer,
|
||||||
|
};
|
@@ -2,7 +2,7 @@ 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 '../../../../../../components/toast';
|
import toaster from '../../../../../../components/toast';
|
||||||
import { isFunction } from '../../../../_basic';
|
import { PRIVATE_COLUMN_KEY, 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';
|
||||||
import { isCellValueChanged } from '../../../../utils/cell-comparer';
|
import { isCellValueChanged } from '../../../../utils/cell-comparer';
|
||||||
@@ -75,9 +75,7 @@ class RecordCell extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onCellMouseDown = (e) => {
|
onCellMouseDown = (e) => {
|
||||||
if (e.button === 2) {
|
if (e.button === 2) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { column, groupRecordIndex, recordIndex, cellMetaData } = this.props;
|
const { column, groupRecordIndex, recordIndex, cellMetaData } = this.props;
|
||||||
const cell = { idx: column.idx, groupRecordIndex, rowIdx: recordIndex };
|
const cell = { idx: column.idx, groupRecordIndex, rowIdx: recordIndex };
|
||||||
|
|
||||||
@@ -133,9 +131,16 @@ class RecordCell extends React.Component {
|
|||||||
toaster.warning(message);
|
toaster.warning(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
isDir = () => {
|
||||||
|
const { record } = this.props;
|
||||||
|
const isDirValue = record[PRIVATE_COLUMN_KEY.IS_DIR];
|
||||||
|
if (typeof isDirValue === 'string') return isDirValue.toUpperCase() === 'TRUE';
|
||||||
|
return isDirValue;
|
||||||
|
};
|
||||||
|
|
||||||
render = () => {
|
render = () => {
|
||||||
const { frozen, record, column, needBindEvents, height, bgColor } = this.props;
|
const { frozen, record, column, needBindEvents, height, bgColor } = this.props;
|
||||||
const { key, name, left, width } = column;
|
const { key, left, width } = column;
|
||||||
const readonly = true;
|
const readonly = true;
|
||||||
const commentCount = isNameColumn(column) && this.getCommentCount();
|
const commentCount = isNameColumn(column) && this.getCommentCount();
|
||||||
const hasComment = !!commentCount;
|
const hasComment = !!commentCount;
|
||||||
@@ -151,7 +156,7 @@ class RecordCell extends React.Component {
|
|||||||
cellStyle['backgroundColor'] = bgColor;
|
cellStyle['backgroundColor'] = bgColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cellValue = record[name] || record[key];
|
let cellValue = record[key];
|
||||||
const cellEvents = needBindEvents && this.getEvents();
|
const cellEvents = needBindEvents && this.getEvents();
|
||||||
const props = {
|
const props = {
|
||||||
className,
|
className,
|
||||||
@@ -159,7 +164,7 @@ class RecordCell extends React.Component {
|
|||||||
...cellEvents,
|
...cellEvents,
|
||||||
};
|
};
|
||||||
const cellContent = (
|
const cellContent = (
|
||||||
<CellFormatter readonly={readonly} value={cellValue} field={column} isDir={record['_is_dir'] === 'True'} />
|
<CellFormatter readonly={readonly} value={cellValue} field={column} isDir={this.isDir()} />
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -25,6 +25,7 @@ import { getGroupRecordByIndex } from '../../../../utils/group-metrics';
|
|||||||
import DragMask from '../drag-mask';
|
import DragMask from '../drag-mask';
|
||||||
import DragHandler from '../drag-handler';
|
import DragHandler from '../drag-handler';
|
||||||
import { gettext } from '../../../../../../utils/constants';
|
import { gettext } from '../../../../../../utils/constants';
|
||||||
|
import { EditorPortal, EditorContainer } from '../../../cell-editor';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -32,53 +33,6 @@ const READONLY_PREVIEW_COLUMNS = [
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
table: PropTypes.object,
|
|
||||||
columns: PropTypes.array,
|
|
||||||
canAddRow: PropTypes.bool,
|
|
||||||
isGroupView: PropTypes.bool,
|
|
||||||
recordsCount: PropTypes.number,
|
|
||||||
recordMetrics: PropTypes.object,
|
|
||||||
groups: PropTypes.array,
|
|
||||||
groupMetrics: PropTypes.object,
|
|
||||||
rowHeight: PropTypes.number,
|
|
||||||
groupOffsetLeft: PropTypes.number,
|
|
||||||
frozenColumnsWidth: PropTypes.number,
|
|
||||||
enableCellSelect: PropTypes.bool,
|
|
||||||
getRowTop: PropTypes.func,
|
|
||||||
scrollTop: PropTypes.number,
|
|
||||||
getScrollLeft: PropTypes.func,
|
|
||||||
getTableContentRect: PropTypes.func,
|
|
||||||
getMobileFloatIconStyle: PropTypes.func,
|
|
||||||
onToggleMobileMoreOperations: PropTypes.func,
|
|
||||||
onToggleInsertRecordDialog: PropTypes.func,
|
|
||||||
onCellRangeSelectionStarted: PropTypes.func,
|
|
||||||
onCellRangeSelectionUpdated: PropTypes.func,
|
|
||||||
onCellRangeSelectionCompleted: PropTypes.func,
|
|
||||||
selectNone: PropTypes.func,
|
|
||||||
onCheckCellIsEditable: PropTypes.func,
|
|
||||||
editorPortalTarget: PropTypes.instanceOf(Element).isRequired,
|
|
||||||
modifyRecord: PropTypes.func.isRequired,
|
|
||||||
recordGetterByIndex: PropTypes.func,
|
|
||||||
recordGetterById: PropTypes.func,
|
|
||||||
updateRecords: PropTypes.func,
|
|
||||||
deleteRecordsLinks: PropTypes.func,
|
|
||||||
paste: PropTypes.func,
|
|
||||||
editMobileCell: PropTypes.func,
|
|
||||||
getVisibleIndex: PropTypes.func,
|
|
||||||
onHitBottomBoundary: PropTypes.func,
|
|
||||||
onHitTopBoundary: PropTypes.func,
|
|
||||||
onCellClick: PropTypes.func,
|
|
||||||
scrollToColumn: PropTypes.func,
|
|
||||||
setRecordsScrollLeft: PropTypes.func,
|
|
||||||
getGroupCanvasScrollTop: PropTypes.func,
|
|
||||||
setGroupCanvasScrollTop: PropTypes.func,
|
|
||||||
appPage: PropTypes.object,
|
|
||||||
onFillingDragRows: PropTypes.func,
|
|
||||||
onCellsDragged: PropTypes.func,
|
|
||||||
gridUtils: PropTypes.object,
|
|
||||||
getCopiedRecordsAndColumnsFromRange: PropTypes.func,
|
|
||||||
};
|
|
||||||
class InteractionMasks extends React.Component {
|
class InteractionMasks extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
@@ -478,7 +432,7 @@ class InteractionMasks extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
modifyRecord = (updated, closeEditor = true) => {
|
onCommit = (updated, closeEditor = true) => {
|
||||||
this.props.modifyRecord(updated);
|
this.props.modifyRecord(updated);
|
||||||
if (closeEditor) {
|
if (closeEditor) {
|
||||||
this.closeEditor();
|
this.closeEditor();
|
||||||
@@ -1057,7 +1011,6 @@ class InteractionMasks extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
renderSingleCellSelectView = () => {
|
renderSingleCellSelectView = () => {
|
||||||
const { columns } = this.props;
|
const { columns } = this.props;
|
||||||
const {
|
const {
|
||||||
@@ -1157,7 +1110,8 @@ class InteractionMasks extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { selectedRange, draggedRange } = this.state;
|
const { selectedRange, isEditorEnabled, draggedRange, selectedPosition, firstEditorKeyDown, openEditorMode, editorPosition } = this.state;
|
||||||
|
const { table, columns, isGroupView, recordGetterByIndex, scrollTop, getScrollLeft, editorPortalTarget } = this.props;
|
||||||
const isSelectedSingleCell = selectedRangeIsSingleCell(selectedRange);
|
const isSelectedSingleCell = selectedRangeIsSingleCell(selectedRange);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -1178,11 +1132,81 @@ class InteractionMasks extends React.Component {
|
|||||||
)}
|
)}
|
||||||
{isSelectedSingleCell && this.renderSingleCellSelectView()}
|
{isSelectedSingleCell && this.renderSingleCellSelectView()}
|
||||||
{!isSelectedSingleCell && this.renderCellRangeSelectView()}
|
{!isSelectedSingleCell && this.renderCellRangeSelectView()}
|
||||||
|
{isEditorEnabled && (
|
||||||
|
<EditorPortal target={editorPortalTarget}>
|
||||||
|
<EditorContainer
|
||||||
|
table={table}
|
||||||
|
columns={columns}
|
||||||
|
isGroupView={isGroupView}
|
||||||
|
scrollTop={scrollTop}
|
||||||
|
firstEditorKeyDown={firstEditorKeyDown}
|
||||||
|
openEditorMode={openEditorMode}
|
||||||
|
portalTarget={editorPortalTarget}
|
||||||
|
scrollLeft={getScrollLeft()}
|
||||||
|
record={getSelectedRow({ selectedPosition, isGroupView, recordGetterByIndex })}
|
||||||
|
column={getSelectedColumn({ selectedPosition, columns })}
|
||||||
|
onCommit={this.onCommit}
|
||||||
|
onCommitCancel={this.onCommitCancel}
|
||||||
|
editorPosition={editorPosition}
|
||||||
|
{...{
|
||||||
|
...this.getSelectedDimensions(selectedPosition),
|
||||||
|
...this.state.editorPosition
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</EditorPortal>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionMasks.propTypes = propTypes;
|
InteractionMasks.propTypes = {
|
||||||
|
table: PropTypes.object,
|
||||||
|
columns: PropTypes.array,
|
||||||
|
canAddRow: PropTypes.bool,
|
||||||
|
isGroupView: PropTypes.bool,
|
||||||
|
recordsCount: PropTypes.number,
|
||||||
|
recordMetrics: PropTypes.object,
|
||||||
|
groups: PropTypes.array,
|
||||||
|
groupMetrics: PropTypes.object,
|
||||||
|
rowHeight: PropTypes.number,
|
||||||
|
groupOffsetLeft: PropTypes.number,
|
||||||
|
frozenColumnsWidth: PropTypes.number,
|
||||||
|
enableCellSelect: PropTypes.bool,
|
||||||
|
getRowTop: PropTypes.func,
|
||||||
|
scrollTop: PropTypes.number,
|
||||||
|
getScrollLeft: PropTypes.func,
|
||||||
|
getTableContentRect: PropTypes.func,
|
||||||
|
getMobileFloatIconStyle: PropTypes.func,
|
||||||
|
onToggleMobileMoreOperations: PropTypes.func,
|
||||||
|
onToggleInsertRecordDialog: PropTypes.func,
|
||||||
|
onCellRangeSelectionStarted: PropTypes.func,
|
||||||
|
onCellRangeSelectionUpdated: PropTypes.func,
|
||||||
|
onCellRangeSelectionCompleted: PropTypes.func,
|
||||||
|
selectNone: PropTypes.func,
|
||||||
|
onCheckCellIsEditable: PropTypes.func,
|
||||||
|
editorPortalTarget: PropTypes.instanceOf(Element).isRequired,
|
||||||
|
modifyRecord: PropTypes.func.isRequired,
|
||||||
|
recordGetterByIndex: PropTypes.func,
|
||||||
|
recordGetterById: PropTypes.func,
|
||||||
|
updateRecords: PropTypes.func,
|
||||||
|
deleteRecordsLinks: PropTypes.func,
|
||||||
|
paste: PropTypes.func,
|
||||||
|
editMobileCell: PropTypes.func,
|
||||||
|
getVisibleIndex: PropTypes.func,
|
||||||
|
onHitBottomBoundary: PropTypes.func,
|
||||||
|
onHitTopBoundary: PropTypes.func,
|
||||||
|
onCellClick: PropTypes.func,
|
||||||
|
scrollToColumn: PropTypes.func,
|
||||||
|
setRecordsScrollLeft: PropTypes.func,
|
||||||
|
getGroupCanvasScrollTop: PropTypes.func,
|
||||||
|
setGroupCanvasScrollTop: PropTypes.func,
|
||||||
|
appPage: PropTypes.object,
|
||||||
|
onFillingDragRows: PropTypes.func,
|
||||||
|
onCellsDragged: PropTypes.func,
|
||||||
|
gridUtils: PropTypes.object,
|
||||||
|
getCopiedRecordsAndColumnsFromRange: PropTypes.func,
|
||||||
|
onCommit: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
export default InteractionMasks;
|
export default InteractionMasks;
|
||||||
|
@@ -76,7 +76,7 @@ class Context {
|
|||||||
};
|
};
|
||||||
|
|
||||||
canModifyRow = (row) => {
|
canModifyRow = (row) => {
|
||||||
return false;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
getPermission = () => {
|
getPermission = () => {
|
||||||
|
@@ -120,15 +120,13 @@ export const setColumnOffsets = (columns) => {
|
|||||||
|
|
||||||
export function isColumnSupportEdit(cell, columns) {
|
export function isColumnSupportEdit(cell, columns) {
|
||||||
const column = columns[cell.idx];
|
const column = columns[cell.idx];
|
||||||
if (column?.type === CellType.LINK_FORMULA && [CellType.IMAGE, CellType.FILE].includes(column?.data?.array_type)) {
|
if (column.type === CellType.FILE_NAME) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isColumnSupportDirectEdit(cell, columns) {
|
export function isColumnSupportDirectEdit(cell, columns) {
|
||||||
const column = columns[cell.idx];
|
const column = columns[cell.idx];
|
||||||
return [].includes(column?.type);
|
return [CellType.CHECKBOX].includes(column?.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const _getCustomColumnsWidth = () => {
|
const _getCustomColumnsWidth = () => {
|
||||||
@@ -172,21 +170,17 @@ export const recalculate = (columns, allColumns) => {
|
|||||||
export const getColumnName = (key, name) => {
|
export const getColumnName = (key, name) => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case PRIVATE_COLUMN_KEY.CTIME:
|
case PRIVATE_COLUMN_KEY.CTIME:
|
||||||
|
case PRIVATE_COLUMN_KEY.FILE_CTIME:
|
||||||
return gettext('Created time');
|
return gettext('Created time');
|
||||||
case PRIVATE_COLUMN_KEY.MTIME:
|
case PRIVATE_COLUMN_KEY.MTIME:
|
||||||
|
case PRIVATE_COLUMN_KEY.FILE_MTIME:
|
||||||
return gettext('Last modified time');
|
return gettext('Last modified time');
|
||||||
case PRIVATE_COLUMN_KEY.CREATOR:
|
case PRIVATE_COLUMN_KEY.CREATOR:
|
||||||
|
case PRIVATE_COLUMN_KEY.FILE_CREATOR:
|
||||||
return gettext('Creator');
|
return gettext('Creator');
|
||||||
case PRIVATE_COLUMN_KEY.LAST_MODIFIER:
|
case PRIVATE_COLUMN_KEY.LAST_MODIFIER:
|
||||||
return gettext('Last modifier');
|
|
||||||
case PRIVATE_COLUMN_KEY.FILE_CREATOR:
|
|
||||||
return gettext('File creator');
|
|
||||||
case PRIVATE_COLUMN_KEY.FILE_MODIFIER:
|
case PRIVATE_COLUMN_KEY.FILE_MODIFIER:
|
||||||
return gettext('File modifier');
|
return gettext('Last modifier');
|
||||||
case PRIVATE_COLUMN_KEY.FILE_CTIME:
|
|
||||||
return gettext('File created time');
|
|
||||||
case PRIVATE_COLUMN_KEY.FILE_MTIME:
|
|
||||||
return gettext('File last modified time');
|
|
||||||
case PRIVATE_COLUMN_KEY.IS_DIR:
|
case PRIVATE_COLUMN_KEY.IS_DIR:
|
||||||
return gettext('Is folder');
|
return gettext('Is folder');
|
||||||
case PRIVATE_COLUMN_KEY.PARENT_DIR:
|
case PRIVATE_COLUMN_KEY.PARENT_DIR:
|
||||||
|
Reference in New Issue
Block a user