mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 14:50:29 +00:00
Merge branch '7.0'
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
require('react-app-polyfill/ie9');
|
||||||
|
require('react-app-polyfill/stable');
|
||||||
|
|
||||||
if (typeof Promise === 'undefined') {
|
if (typeof Promise === 'undefined') {
|
||||||
// Rejection tracking prevents a common issue where React gets into an
|
// Rejection tracking prevents a common issue where React gets into an
|
||||||
// inconsistent state due to an error, but it gets swallowed by a Promise,
|
// inconsistent state due to an error, but it gets swallowed by a Promise,
|
||||||
|
97
frontend/package-lock.json
generated
97
frontend/package-lock.json
generated
@@ -773,12 +773,35 @@
|
|||||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.1",
|
||||||
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
|
||||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
"integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.3.0",
|
"follow-redirects": "1.5.10",
|
||||||
"is-buffer": "^1.1.5"
|
"is-buffer": "^2.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"follow-redirects": {
|
||||||
|
"version": "1.5.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||||
|
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "=3.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"axobject-query": {
|
"axobject-query": {
|
||||||
@@ -1751,9 +1774,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "2.5.5",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
|
||||||
"integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=",
|
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
@@ -4030,6 +4053,12 @@
|
|||||||
"toggle-selection": "^1.0.3"
|
"toggle-selection": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"core-js": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
@@ -12002,6 +12031,52 @@
|
|||||||
"prop-types": "^15.6.0"
|
"prop-types": "^15.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-app-polyfill": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-LbVpT1NdzTdDDs7xEZdebjDrqsvKi5UyVKUQqtTYYNyC1JJYVAwNQWe4ybWvoT2V2WW9PGVO2u5Y6aVj4ER/Ow==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"core-js": "3.0.1",
|
||||||
|
"object-assign": "4.1.1",
|
||||||
|
"promise": "8.0.2",
|
||||||
|
"raf": "3.4.1",
|
||||||
|
"regenerator-runtime": "0.13.2",
|
||||||
|
"whatwg-fetch": "3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"promise": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"asap": "~2.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.13.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
|
||||||
|
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"whatwg-fetch": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-codemirror": {
|
"react-codemirror": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-codemirror/-/react-codemirror-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-codemirror/-/react-codemirror-1.0.0.tgz",
|
||||||
@@ -13272,9 +13347,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"seafile-js": {
|
"seafile-js": {
|
||||||
"version": "0.2.88",
|
"version": "0.2.89",
|
||||||
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.88.tgz",
|
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.89.tgz",
|
||||||
"integrity": "sha512-JrHDA9MZCiHmPSZL1lZbIovKcei7JAD8meKIyRuD59E8hDnjQv0qoDzVNwo8MYPVSNdzHhSaFQGm/4mFi+Rugw==",
|
"integrity": "sha512-TFjcRVI4m0TQC6eFgIEv1T6pCmvQOIDCIyAK0ROlYTX5IqI91cgr71T8mjLtpM7ms1PszwMoFUAP22ZXXTdfZg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"form-data": "^2.3.2",
|
"form-data": "^2.3.2",
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
"react-responsive": "^6.1.1",
|
"react-responsive": "^6.1.1",
|
||||||
"react-select": "^2.4.1",
|
"react-select": "^2.4.1",
|
||||||
"reactstrap": "^6.4.0",
|
"reactstrap": "^6.4.0",
|
||||||
"seafile-js": "^0.2.88",
|
"seafile-js": "^0.2.89",
|
||||||
"socket.io-client": "^2.2.0",
|
"socket.io-client": "^2.2.0",
|
||||||
"sw-precache-webpack-plugin": "0.11.4",
|
"sw-precache-webpack-plugin": "0.11.4",
|
||||||
"unified": "^7.0.0",
|
"unified": "^7.0.0",
|
||||||
@@ -120,6 +120,7 @@
|
|||||||
"i18next": "^11.3.2",
|
"i18next": "^11.3.2",
|
||||||
"i18next-browser-languagedetector": "^2.2.0",
|
"i18next-browser-languagedetector": "^2.2.0",
|
||||||
"i18next-xhr-backend": "^1.5.1",
|
"i18next-xhr-backend": "^1.5.1",
|
||||||
|
"react-app-polyfill": "^1.0.1",
|
||||||
"react-dev-utils": "^5.0.0",
|
"react-dev-utils": "^5.0.0",
|
||||||
"react-i18next": "^7.6.1",
|
"react-i18next": "^7.6.1",
|
||||||
"webpack": "3.8.1",
|
"webpack": "3.8.1",
|
||||||
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import listener from './globalEventListener';
|
import listener from './globalEventListener';
|
||||||
import { hideMenu } from './actions';
|
import { hideMenu } from './actions';
|
||||||
import { callIfExists } from './helpers';
|
import { callIfExists } from './helpers';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
@@ -192,7 +193,7 @@ class ContextMenu extends React.Component {
|
|||||||
|
|
||||||
onMenuItemClick = (event) => {
|
onMenuItemClick = (event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
let operation = event.target.dataset.operation;
|
let operation = Utils.getEventData(event, 'operation');
|
||||||
let currentObject = this.state.currentObject;
|
let currentObject = this.state.currentObject;
|
||||||
this.props.onMenuItemClick(operation, currentObject, event);
|
this.props.onMenuItemClick(operation, currentObject, event);
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import { Link } from '@reach/router';
|
|||||||
import { UncontrolledTooltip } from 'reactstrap';
|
import { UncontrolledTooltip } from 'reactstrap';
|
||||||
import { siteRoot, gettext } from '../../utils/constants';
|
import { siteRoot, gettext } from '../../utils/constants';
|
||||||
import InternalLinkDialog from '../dialog/internal-link-dialog';
|
import InternalLinkDialog from '../dialog/internal-link-dialog';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoName: PropTypes.string.isRequired,
|
repoName: PropTypes.string.isRequired,
|
||||||
@@ -19,7 +20,7 @@ const propTypes = {
|
|||||||
class DirPath extends React.Component {
|
class DirPath extends React.Component {
|
||||||
|
|
||||||
onPathClick = (e) => {
|
onPathClick = (e) => {
|
||||||
let path = e.target.dataset.path;
|
let path = Utils.getEventData(e, 'path');
|
||||||
this.props.onPathClick(path);
|
this.props.onPathClick(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -346,32 +346,49 @@ class DirentListItem extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onItemDragStart = (e) => {
|
onItemDragStart = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let nodeRootPath = '';
|
let nodeRootPath = '';
|
||||||
nodeRootPath = this.props.path === '/' ? `${this.props.path}${this.props.dirent.name}` : `${this.props.path}/${this.props.dirent.name}`;
|
nodeRootPath = this.props.path === '/' ? `${this.props.path}${this.props.dirent.name}` : `${this.props.path}/${this.props.dirent.name}`;
|
||||||
let dragStartItemData = {nodeDirent: this.props.dirent, nodeParentPath: this.props.path, nodeRootPath: nodeRootPath};
|
let dragStartItemData = {nodeDirent: this.props.dirent, nodeParentPath: this.props.path, nodeRootPath: nodeRootPath};
|
||||||
dragStartItemData = JSON.stringify(dragStartItemData);
|
dragStartItemData = JSON.stringify(dragStartItemData);
|
||||||
|
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
if (e.dataTransfer && e.dataTransfer.setDragImage) {
|
||||||
e.dataTransfer.setDragImage(this.refs.drag_icon, 15, 15);
|
e.dataTransfer.setDragImage(this.refs.drag_icon, 15, 15);
|
||||||
|
}
|
||||||
e.dataTransfer.setData('applicaiton/drag-item-info', dragStartItemData);
|
e.dataTransfer.setData('applicaiton/drag-item-info', dragStartItemData);
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemDragEnter = () => {
|
onItemDragEnter = () => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (this.props.dirent.type === 'dir') {
|
if (this.props.dirent.type === 'dir') {
|
||||||
this.setState({isDropTipshow: true});
|
this.setState({isDropTipshow: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemDragOver = (e) => {
|
onItemDragOver = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.dataTransfer.dropEffect = 'move';
|
e.dataTransfer.dropEffect = 'move';
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemDragLeave = () => {
|
onItemDragLeave = () => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.setState({isDropTipshow: false});
|
this.setState({isDropTipshow: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemDragDrop = (e) => {
|
onItemDragDrop = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
this.setState({isDropTipshow: false});
|
this.setState({isDropTipshow: false});
|
||||||
if (e.dataTransfer.files.length) { // uploaded files
|
if (e.dataTransfer.files.length) { // uploaded files
|
||||||
return;
|
return;
|
||||||
|
@@ -537,23 +537,35 @@ class DirentListView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTableDragEnter = (e) => {
|
onTableDragEnter = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (e.target.className === 'table-container ') {
|
if (e.target.className === 'table-container ') {
|
||||||
this.setState({isListDropTipShow: true});
|
this.setState({isListDropTipShow: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTableDragOver = (e) => {
|
onTableDragOver = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.dataTransfer.dropEffect = 'move';
|
e.dataTransfer.dropEffect = 'move';
|
||||||
}
|
}
|
||||||
|
|
||||||
onTableDragLeave = (e) => {
|
onTableDragLeave = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (e.target.className === 'table-container table-drop-active') {
|
if (e.target.className === 'table-container table-drop-active') {
|
||||||
this.setState({isListDropTipShow: false});
|
this.setState({isListDropTipShow: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tableDrop = (e) => {
|
tableDrop = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
e.persist();
|
e.persist();
|
||||||
this.setState({isListDropTipShow: false});
|
this.setState({isListDropTipShow: false});
|
||||||
if (e.dataTransfer.files.length) { // uploaded files
|
if (e.dataTransfer.files.length) { // uploaded files
|
||||||
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import listener from '../context-menu/globalEventListener';
|
import listener from '../context-menu/globalEventListener';
|
||||||
import { Dropdown, ButtonDropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
import { Dropdown, ButtonDropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
tagName: PropTypes.string,
|
tagName: PropTypes.string,
|
||||||
@@ -87,7 +88,7 @@ class ItemDropdownMenu extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMenuItemClick = (event) => {
|
onMenuItemClick = (event) => {
|
||||||
let operation = event.target.dataset.toggle;
|
let operation = Utils.getEventData(event, 'toggle');
|
||||||
let item = this.props.item;
|
let item = this.props.item;
|
||||||
this.props.onMenuItemClick(operation, event, item);
|
this.props.onMenuItemClick(operation, event, item);
|
||||||
}
|
}
|
||||||
|
@@ -120,7 +120,8 @@ class RepoListItem extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleClick = () => {
|
onToggleClick = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
this.setState({isShowChildren: !this.state.isShowChildren});
|
this.setState({isShowChildren: !this.state.isShowChildren});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +130,11 @@ class RepoListItem extends React.Component {
|
|||||||
this.props.onDirentItemClick(repo, filePath, dirent);
|
this.props.onDirentItemClick(repo, filePath, dirent);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRepoItemClick = () => {
|
onRepoItemClick = (e) => {
|
||||||
if (!this.isCurrentRepo() || this.props.selectedPath !== '') {
|
if (!this.isCurrentRepo() || this.props.selectedPath !== '') {
|
||||||
this.props.onRepoItemClick(this.props.repo);
|
this.props.onRepoItemClick(this.props.repo);
|
||||||
} else {
|
} else {
|
||||||
this.onToggleClick();
|
this.onToggleClick(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,12 +151,18 @@ class RepoListItem extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="file-chooser-item">
|
<li>
|
||||||
<span className={`item-toggle fa ${this.state.isShowChildren ? 'fa-caret-down' : 'fa-caret-right'}`} onClick={this.onToggleClick}></span>
|
<div className={`${repoActive ? 'item-active' : ''} item-info`} onClick={this.onRepoItemClick}>
|
||||||
<span className={`item-info ${repoActive ? 'item-active' : ''}`} onClick={this.onRepoItemClick}>
|
<div className="item-text">
|
||||||
<span className="icon far fa-folder"></span>
|
|
||||||
<span className="name user-select-none ellipsis">{this.props.repo.repo_name}</span>
|
<span className="name user-select-none ellipsis">{this.props.repo.repo_name}</span>
|
||||||
</span>
|
</div>
|
||||||
|
<div className="item-left-icon">
|
||||||
|
<span className={`item-toggle icon fa ${this.state.isShowChildren ? 'fa-caret-down' : 'fa-caret-right'}`} onClick={this.onToggleClick}></span>
|
||||||
|
<i className="tree-node-icon">
|
||||||
|
<span className="icon far fa-folder tree-node-icon"></span>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{this.state.isShowChildren && (
|
{this.state.isShowChildren && (
|
||||||
<TreeListView
|
<TreeListView
|
||||||
repo={this.props.repo}
|
repo={this.props.repo}
|
||||||
|
@@ -89,14 +89,20 @@ class TreeViewItem extends React.Component {
|
|||||||
return(
|
return(
|
||||||
<div className="file-chooser-item">
|
<div className="file-chooser-item">
|
||||||
<div className={`${node.path === '/'? 'hide': ''}`}>
|
<div className={`${node.path === '/'? 'hide': ''}`}>
|
||||||
|
<div className={`${(isCurrentRepo && isCurrentPath) ? 'item-active' : ''} item-info`} onClick={this.onItemClick}>
|
||||||
|
<div className="item-text">
|
||||||
|
<span className="name user-select-none ellipsis">{node.object && node.object.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className="item-left-icon">
|
||||||
{
|
{
|
||||||
node.object.type !== 'file' &&
|
node.object.type !== 'file' &&
|
||||||
<span className={`item-toggle fa ${node.isExpanded ? 'fa-caret-down' : 'fa-caret-right'}`} onClick={this.onToggleClick}></span>
|
<span className={`icon item-toggle fa ${node.isExpanded ? 'fa-caret-down' : 'fa-caret-right'}`} onClick={this.onToggleClick}></span>
|
||||||
}
|
}
|
||||||
<span className={`item-info ${(isCurrentRepo && isCurrentPath) ? 'item-active' : ''}`} onClick={this.onItemClick}>
|
<i className="tree-node-icon">
|
||||||
<span className={`icon far ${node.object.type === 'dir' ? 'fa-folder' : 'fa-file'}`}></span>
|
<span className={`icon far ${node.object.type === 'dir' ? 'fa-folder' : 'fa-file'}`}></span>
|
||||||
<span className="name user-select-none ellipsis">{node.object && node.object.name}</span>
|
</i>
|
||||||
</span>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{node.isExpanded && this.renderChildren()}
|
{node.isExpanded && this.renderChildren()}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -414,19 +414,19 @@ class FileUploader extends React.Component {
|
|||||||
|
|
||||||
onFileUpload = () => {
|
onFileUpload = () => {
|
||||||
this.uploadInput.current.removeAttribute('webkitdirectory');
|
this.uploadInput.current.removeAttribute('webkitdirectory');
|
||||||
this.uploadInput.current.click();
|
|
||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
seafileAPI.getUploadLink(repoID, this.props.path).then(res => {
|
seafileAPI.getUploadLink(repoID, this.props.path).then(res => {
|
||||||
this.resumable.opts.target = res.data;
|
this.resumable.opts.target = res.data;
|
||||||
|
this.uploadInput.current.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onFolderUpload = () => {
|
onFolderUpload = () => {
|
||||||
this.uploadInput.current.setAttribute('webkitdirectory', 'webkitdirectory');
|
this.uploadInput.current.setAttribute('webkitdirectory', 'webkitdirectory');
|
||||||
this.uploadInput.current.click();
|
|
||||||
let repoID = this.props.repoID;
|
let repoID = this.props.repoID;
|
||||||
seafileAPI.getUploadLink(repoID, this.props.path).then(res => {
|
seafileAPI.getUploadLink(repoID, this.props.path).then(res => {
|
||||||
this.resumable.opts.target = res.data;
|
this.resumable.opts.target = res.data;
|
||||||
|
this.uploadInput.current.click();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ class UploadListItem extends React.Component {
|
|||||||
<tr className="file-upload-item">
|
<tr className="file-upload-item">
|
||||||
<td className="upload-name">
|
<td className="upload-name">
|
||||||
<div className="ellipsis">{item.resumableFile.relativePath}</div>
|
<div className="ellipsis">{item.resumableFile.relativePath}</div>
|
||||||
<div className="message err-message ml-0">{error}</div>
|
<div className="message err-message ml-0" dangerouslySetInnerHTML={{__html: error}}></div>
|
||||||
</td>
|
</td>
|
||||||
<td className="upload-progress">
|
<td className="upload-progress">
|
||||||
<span className="file-size">{this.formatFileSize(item.resumableFile.size)}</span>
|
<span className="file-size">{this.formatFileSize(item.resumableFile.size)}</span>
|
||||||
|
@@ -55,9 +55,9 @@ class DirOperationToolbar extends React.Component {
|
|||||||
|
|
||||||
toggleOperationMenu = (e) => {
|
toggleOperationMenu = (e) => {
|
||||||
e.nativeEvent.stopImmediatePropagation();
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
let targetRect = e.target.getClientRects()[0];
|
let targetRect = e.target.getBoundingClientRect();
|
||||||
let left = targetRect.x;
|
let left = targetRect.left;
|
||||||
let top = targetRect.y + targetRect.height;
|
let top = targetRect.bottom;
|
||||||
let style = {position: 'fixed', display: 'block', left: left, top: top};
|
let style = {position: 'fixed', display: 'block', left: left, top: top};
|
||||||
this.setState({operationMenuStyle: style});
|
this.setState({operationMenuStyle: style});
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import TextTranslation from '../../utils/text-translation';
|
|||||||
import TreeNodeView from './tree-node-view';
|
import TreeNodeView from './tree-node-view';
|
||||||
import ContextMenu from '../context-menu/context-menu';
|
import ContextMenu from '../context-menu/context-menu';
|
||||||
import { hideMenu, showMenu } from '../context-menu/actions';
|
import { hideMenu, showMenu } from '../context-menu/actions';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoPermission: PropTypes.bool,
|
repoPermission: PropTypes.bool,
|
||||||
@@ -36,6 +37,9 @@ class TreeView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onNodeDragStart = (e, node) => {
|
onNodeDragStart = (e, node) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let dragStartNodeData = {nodeDirent: node.object, nodeParentPath: node.parentNode.path, nodeRootPath: node.path};
|
let dragStartNodeData = {nodeDirent: node.object, nodeParentPath: node.parentNode.path, nodeRootPath: node.path};
|
||||||
dragStartNodeData = JSON.stringify(dragStartNodeData);
|
dragStartNodeData = JSON.stringify(dragStartNodeData);
|
||||||
|
|
||||||
@@ -44,6 +48,9 @@ class TreeView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onNodeDragEnter = (e, node) => {
|
onNodeDragEnter = (e, node) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
e.persist();
|
e.persist();
|
||||||
if (e.target.className === 'tree-view tree ') {
|
if (e.target.className === 'tree-view tree ') {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -53,11 +60,17 @@ class TreeView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onNodeDragMove = (e) => {
|
onNodeDragMove = (e) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.dataTransfer.dropEffect = 'move';
|
e.dataTransfer.dropEffect = 'move';
|
||||||
}
|
}
|
||||||
|
|
||||||
onNodeDragLeave = (e, node) => {
|
onNodeDragLeave = (e, node) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (e.target.className === 'tree-view tree tree-view-drop') {
|
if (e.target.className === 'tree-view tree tree-view-drop') {
|
||||||
this.setState({
|
this.setState({
|
||||||
isTreeViewDropTipShow: false,
|
isTreeViewDropTipShow: false,
|
||||||
@@ -66,6 +79,9 @@ class TreeView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onNodeDrop = (e, node) => {
|
onNodeDrop = (e, node) => {
|
||||||
|
if (Utils.isIEBrower()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (e.dataTransfer.files.length) { // uploaded files
|
if (e.dataTransfer.files.length) { // uploaded files
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -42,36 +42,27 @@
|
|||||||
|
|
||||||
.file-chooser-item {
|
.file-chooser-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 1.5rem;
|
padding-left: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-chooser-item .item-info {
|
.file-chooser-item .item-info {
|
||||||
display: flex;
|
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
position: relative;
|
||||||
}
|
line-height: 1.625;
|
||||||
|
|
||||||
.file-chooser-item .item-info:hover {
|
|
||||||
background: #FDEFB9;
|
|
||||||
border-radius: 2px;
|
|
||||||
box-shadow: inset 0 0 1px #999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-chooser-item .item-active {
|
.file-chooser-item .item-active {
|
||||||
background: #F3AF7D !important;
|
background: #F3AF7D !important;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-shadow: inset 0 0 1px #999;
|
box-shadow: inset 0 0 1px #999;
|
||||||
color: #fff
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-chooser-item .item-info .icon {
|
.file-chooser-item .item-info:hover {
|
||||||
display: flex;
|
background: #FDEFB9;
|
||||||
justify-content: center;
|
border-radius: 2px;
|
||||||
align-items: center;
|
box-shadow: inset 0 0 1px #999;
|
||||||
color: #b0b0b0;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-chooser-item .item-info .name {
|
.file-chooser-item .item-info .name {
|
||||||
@@ -132,6 +123,24 @@
|
|||||||
border-bottom: 1px solid rgba(0, 0, 0, 0);
|
border-bottom: 1px solid rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-text {
|
||||||
|
padding-left: 2.8rem;
|
||||||
|
font-size: 15px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-left-icon {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import { gettext, PER_PAGE, filePath } from '../../utils/constants';
|
|||||||
import editUtilties from '../../utils/editor-utilties';
|
import editUtilties from '../../utils/editor-utilties';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import HistoryListView from '../../components/history-list-view/history-list-view';
|
import HistoryListView from '../../components/history-list-view/history-list-view';
|
||||||
|
import toaster from '../../components/toast';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
onItemClick: PropTypes.func.isRequired,
|
onItemClick: PropTypes.func.isRequired,
|
||||||
@@ -88,6 +89,8 @@ class SidePanel extends React.Component {
|
|||||||
this.setState({isLoading: true});
|
this.setState({isLoading: true});
|
||||||
this.refershFileList();
|
this.refershFileList();
|
||||||
}
|
}
|
||||||
|
let message = gettext('Successfully restored.');
|
||||||
|
toaster.success(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -773,9 +773,6 @@ class LibContentView extends React.Component {
|
|||||||
if (isDir) {
|
if (isDir) {
|
||||||
seafileAPI.renameDir(repoID, path, newName).then(() => {
|
seafileAPI.renameDir(repoID, path, newName).then(() => {
|
||||||
this.renameItemAjaxCallback(path, newName);
|
this.renameItemAjaxCallback(path, newName);
|
||||||
let name = Utils.getFileName(path);
|
|
||||||
var msg = gettext('Rename {name} successfully').replace('{name}', name);
|
|
||||||
toaster.success(msg);
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
let name = Utils.getFileName(path);
|
let name = Utils.getFileName(path);
|
||||||
var msg = gettext('Renaming {name} failed').replace('{name}', name);
|
var msg = gettext('Renaming {name} failed').replace('{name}', name);
|
||||||
@@ -784,9 +781,6 @@ class LibContentView extends React.Component {
|
|||||||
} else {
|
} else {
|
||||||
seafileAPI.renameFile(repoID, path, newName).then(() => {
|
seafileAPI.renameFile(repoID, path, newName).then(() => {
|
||||||
this.renameItemAjaxCallback(path, newName);
|
this.renameItemAjaxCallback(path, newName);
|
||||||
let name = Utils.getFileName(path);
|
|
||||||
var msg = gettext('Rename {name} successfully').replace('{name}', name);
|
|
||||||
toaster.success(msg);
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
let name = Utils.getFileName(path);
|
let name = Utils.getFileName(path);
|
||||||
var msg = gettext('Renaming {name} failed').replace('{name}', name);
|
var msg = gettext('Renaming {name} failed').replace('{name}', name);
|
||||||
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||||
import { gettext, folderPermEnabled, enableRepoSnapshotLabel, enableResetEncryptedRepoPassword, isEmailConfigured } from '../../utils/constants';
|
import { gettext, folderPermEnabled, enableRepoSnapshotLabel, enableResetEncryptedRepoPassword, isEmailConfigured } from '../../utils/constants';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
isPC: PropTypes.bool,
|
isPC: PropTypes.bool,
|
||||||
@@ -21,7 +22,7 @@ class MylibRepoMenu extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMenuItemClick = (e) => {
|
onMenuItemClick = (e) => {
|
||||||
let operation = e.target.dataset.toggle;
|
let operation = Utils.getEventData(e, 'toggle');
|
||||||
this.props.onMenuItemClick(operation);
|
this.props.onMenuItemClick(operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ import CommonToolbar from '../../components/toolbar/common-toolbar';
|
|||||||
import WikiMarkdownViewer from '../../components/wiki-markdown-viewer';
|
import WikiMarkdownViewer from '../../components/wiki-markdown-viewer';
|
||||||
import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view';
|
import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
@@ -37,7 +38,8 @@ class MainPanel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMainNavBarClick = (e) => {
|
onMainNavBarClick = (e) => {
|
||||||
this.props.onMainNavBarClick(e.target.dataset.path);
|
let path = Utils.getEventData(e, 'path');
|
||||||
|
this.props.onMainNavBarClick(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNavPath = () => {
|
renderNavPath = () => {
|
||||||
|
@@ -229,6 +229,13 @@ export const Utils = {
|
|||||||
navigator.userAgent.indexOf('Chrome') > -1;
|
navigator.userAgent.indexOf('Chrome') > -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isIEBrower: function() { // is ie <= ie11 not include Edge
|
||||||
|
var userAgent = navigator.userAgent;
|
||||||
|
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1;
|
||||||
|
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
|
||||||
|
return isIE || isIE11;
|
||||||
|
},
|
||||||
|
|
||||||
getDefaultLibIconUrl: function(isBig) {
|
getDefaultLibIconUrl: function(isBig) {
|
||||||
let size = Utils.isHiDPI() ? 48 : 24;
|
let size = Utils.isHiDPI() ? 48 : 24;
|
||||||
size = isBig ? 256 : size;
|
size = isBig ? 256 : size;
|
||||||
@@ -871,6 +878,14 @@ export const Utils = {
|
|||||||
password += possible.charAt(Math.floor(Math.random() * possible.length));
|
password += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return password;
|
return password;
|
||||||
|
},
|
||||||
|
|
||||||
|
getEventData: function(event, data) {
|
||||||
|
if (event.target.dataset) {
|
||||||
|
return event.target.dataset[data];
|
||||||
|
}
|
||||||
|
return event.target.getAttribute('data-' + data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -371,19 +371,12 @@ class RepoView(APIView):
|
|||||||
if is_org_context(request):
|
if is_org_context(request):
|
||||||
org_id = request.user.org.org_id
|
org_id = request.user.org.org_id
|
||||||
|
|
||||||
try:
|
|
||||||
related_users = get_related_users_by_repo(repo_id, org_id)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
related_users = []
|
|
||||||
|
|
||||||
# remove repo
|
# remove repo
|
||||||
seafile_api.remove_repo(repo_id)
|
seafile_api.remove_repo(repo_id)
|
||||||
|
|
||||||
repo_deleted.send(sender=None,
|
repo_deleted.send(sender=None,
|
||||||
org_id=org_id,
|
org_id=org_id,
|
||||||
operator=username,
|
operator=username,
|
||||||
usernames=related_users,
|
|
||||||
repo_owner=repo_owner,
|
repo_owner=repo_owner,
|
||||||
repo_id=repo_id,
|
repo_id=repo_id,
|
||||||
repo_name=repo.name)
|
repo_name=repo.name)
|
||||||
|
@@ -66,14 +66,19 @@ try:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
org_id = kwargs['org_id']
|
org_id = kwargs['org_id']
|
||||||
related_users = kwargs['usernames']
|
|
||||||
operator = kwargs['operator']
|
operator = kwargs['operator']
|
||||||
|
|
||||||
repo_owner = kwargs['repo_owner']
|
repo_owner = kwargs['repo_owner']
|
||||||
repo_id = kwargs['repo_id']
|
repo_id = kwargs['repo_id']
|
||||||
repo_name = kwargs['repo_name']
|
repo_name = kwargs['repo_name']
|
||||||
related_users.append(repo_owner)
|
|
||||||
|
|
||||||
|
if org_id > 0:
|
||||||
|
related_users = seafile_api.org_get_shared_users_by_repo(org_id, repo_id)
|
||||||
|
else:
|
||||||
|
related_users = seafile_api.get_shared_users_by_repo(repo_id)
|
||||||
|
org_id = -1
|
||||||
|
|
||||||
|
related_users.append(repo_owner)
|
||||||
|
|
||||||
record = {
|
record = {
|
||||||
'op_type':'delete',
|
'op_type':'delete',
|
||||||
|
@@ -3,7 +3,7 @@ import django.dispatch
|
|||||||
|
|
||||||
# Use org_id = -1 if it's not an org repo
|
# Use org_id = -1 if it's not an org repo
|
||||||
repo_created = django.dispatch.Signal(providing_args=["org_id", "creator", "repo_id", "repo_name", "library_template"])
|
repo_created = django.dispatch.Signal(providing_args=["org_id", "creator", "repo_id", "repo_name", "library_template"])
|
||||||
repo_deleted = django.dispatch.Signal(providing_args=["org_id", "operator", "usernames", "repo_owner", "repo_id", "repo_name"])
|
repo_deleted = django.dispatch.Signal(providing_args=["org_id", "operator", "repo_owner", "repo_id", "repo_name"])
|
||||||
repo_transfer = django.dispatch.Signal(providing_args=["org_id", "repo_owner", "to_user", "repo_id", "repo_name"])
|
repo_transfer = django.dispatch.Signal(providing_args=["org_id", "repo_owner", "to_user", "repo_id", "repo_name"])
|
||||||
clean_up_repo_trash = django.dispatch.Signal(providing_args=["org_id", "operator", "repo_id", "repo_name", "repo_owner", "days"])
|
clean_up_repo_trash = django.dispatch.Signal(providing_args=["org_id", "operator", "repo_id", "repo_name", "repo_owner", "days"])
|
||||||
repo_restored = django.dispatch.Signal(providing_args=["repo_id", "operator"])
|
repo_restored = django.dispatch.Signal(providing_args=["repo_id", "operator"])
|
||||||
|
Reference in New Issue
Block a user