diff --git a/fabfile/locale.py b/fabfile/locale.py index c4dcc49a10..1f31206ff5 100644 --- a/fabfile/locale.py +++ b/fabfile/locale.py @@ -37,6 +37,11 @@ def make(default=True, lang='en'): local('django-admin.py makemessages -l %s -d djangojs -i "thirdpart" -i "node_modules" -i "media" -i "static/scripts/dist" -i "static/scripts/lib" -i "tests" -i "tools" -i "tagging" -i "static/scripts/i18n" --verbosity 2' % lang) +@task +def makejs(default=True, lang='en'): + + local('django-admin.py makemessages -l %s -d djangojs -i "thirdpart" -i "node_modules" -i "media" -i "static/scripts/dist" -i "static/scripts/lib" -i "tests" -i "tools" -i "tagging" -i "static/scripts/i18n" -i "frontend/build" -i "frontend/config" -i "frontend/scripts" --verbosity 2' % lang) + @task def push(): """Push source file to Transifex. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f9d63795b3..3b53dd11d2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -35,7 +35,7 @@ "promise": "8.0.1", "prop-types": "15.6.2", "raf": "3.4.0", - "react": "16.2.0", + "react": "16.4.2", "react-dev-utils": "5.0.0", "react-dom": "16.2.0", "react-s-alert": "1.4.1", @@ -9517,9 +9517,9 @@ } }, "react": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.2.0.tgz", - "integrity": "sha512-ZmIomM7EE1DvPEnSFAHZn9Vs9zJl5A9H7el0EGTE6ZbW9FKe/14IYAlPbC8iH25YarEQxZL+E8VW7Mi7kfQrDQ==", + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz", + "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==", "requires": { "fbjs": "0.8.16", "loose-envify": "1.3.1", @@ -10296,9 +10296,9 @@ } }, "seafile-ui": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/seafile-ui/-/seafile-ui-0.1.4.tgz", - "integrity": "sha512-pV7jq4tuBGBCECNEyJxGeKyehFb2nqyvnmLZZY71LCFX4sFNI8j40KSWoKkLHrBUTW4SoP6keabzfuPBxPLQVg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/seafile-ui/-/seafile-ui-0.1.8.tgz", + "integrity": "sha512-k5HL8WMgHnptCBDjSDSJZzU3ZG+X60NDLXty9CQn68w5Ar0mHyDK6Ev1rvWIx3FdR0G+PIE23iTgjWXMMw31mQ==", "requires": { "bootstrap": "4.1.3" } diff --git a/frontend/package.json b/frontend/package.json index 3c8446f11a..60d476884e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,11 +28,11 @@ "prismjs": "^1.15.0", "promise": "8.0.1", "raf": "3.4.0", - "react": "^16.2.0", + "react": "^16.4.2", "react-cookies": "^0.1.0", "react-dom": "^16.2.0", "react-s-alert": "^1.4.1", - "reactstrap": "^5.0.0-beta.3", + "reactstrap": "^6.4.0", "rehype-format": "^2.2.0", "rehype-raw": "^2.0.0", "rehype-stringify": "^3.0.0", @@ -42,7 +42,7 @@ "remark-rehype": "^3.0.0", "remark-slug": "^5.0.0", "seafile-js": "^0.2.7", - "seafile-ui": "^0.1.4", + "seafile-ui": "^0.1.8", "sw-precache-webpack-plugin": "0.11.4", "unified": "^6.1.6", "url-loader": "0.6.2", diff --git a/frontend/src/components/MainPanel.js b/frontend/src/components/MainPanel.js index 5f31ce845b..cc18f31e5c 100644 --- a/frontend/src/components/MainPanel.js +++ b/frontend/src/components/MainPanel.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import Search from './search'; import MarkdownViewer from './markdown-viewer'; import Account from './account'; -import { repoID, serviceUrl, slug, siteRoot } from './constance'; +import { gettext, repoID, serviceUrl, slug, siteRoot } from './constance'; class MainPanel extends Component { @@ -33,7 +33,7 @@ class MainPanel extends Component {
- Edit Page + {gettext("Edit Page")}
@@ -43,7 +43,7 @@ class MainPanel extends Component {
- Wikis + {gettext("Wikis")} / {slug} {pathElem} diff --git a/frontend/src/components/SidePanel.js b/frontend/src/components/SidePanel.js index e7e022e4a8..7813daca40 100644 --- a/frontend/src/components/SidePanel.js +++ b/frontend/src/components/SidePanel.js @@ -1,16 +1,219 @@ import React, { Component } from 'react'; import TreeView from './tree-view/tree-view'; import { siteRoot, logoPath, mediaUrl, siteTitle, logoWidth, logoHeight } from './constance'; +import Tree from './tree-view/tree'; +import Node from './tree-view/node' +import NodeMenu from './menu-component/node-menu'; +import MenuControl from './menu-component/node-menu-control'; +const gettext = window.gettext; class SidePanel extends Component { + + constructor(props) { + super(props); + this.state = { + tree_data: new Tree(), + currentNode: null, + isNodeItemFrezee: false, + isShowMenu: false, + menuPosition: { + left: 0, + top: 0 + }, + isLoadFailed: false, + isMenuIconShow: false + } + } + closeSide = () => { this.props.onCloseSide(); } - onFileClick = (e, node) => { + onMouseEnter = () => { + this.setState({ + isMenuIconShow: true + }) + } + + onMouseLeave = () => { + this.setState({ + isMenuIconShow: false + }) + } + + onNodeClick = (e, node) => { + this.setState({ + currentNode: node + }) this.props.onFileClick(e, node) } + onShowContextMenu = (e, node) => { + let left = e.clientX - 8*16; + let top = e.clientY + 10; + let position = Object.assign({},this.state.menuPosition, {left: left, top: top}); + this.setState({ + isShowMenu: !this.state.isShowMenu, + currentNode: node, + menuPosition: position, + isNodeItemFrezee: true + }) + } + + onHeadingMenuClick = (e) => { + e.nativeEvent.stopImmediatePropagation(); + let node = this.state.tree_data.root; + let left = e.clientX - 8*16; + let top = e.clientY + 10; + let position = Object.assign({},this.state.menuPosition, {left: left, top: top}); + this.setState({ + isShowMenu: !this.state.isShowMenu, + currentNode: node, + menuPosition: position + }) + } + + onHideContextMenu = () => { + this.setState({ + isShowMenu: false, + isNodeItemFrezee: false + }) + } + + onAddFolderNode = (dirPath) => { + this.props.editorUtilities.createDir(dirPath).then(res => { + this.initializeTreeData() + }) + } + + onAddFileNode = (filePath) => { + this.props.editorUtilities.createFile(filePath).then(res => { + this.initializeTreeData() + }) + } + + onRenameNode = (newName) => { + var node = this.state.currentNode; + let type = node.type; + let filePath = node.path; + if (type === 'file') { + this.props.editorUtilities.renameFile(filePath, newName).then(res => { + this.initializeTreeData() + if (this.isModifyCurrentFile()) { + node.name = newName; + this.props.onFileClick(null, node); + } + }) + } + + if (type === 'dir') { + this.props.editorUtilities.renameDir(filePath, newName).then(res => { + this.initializeTreeData(); + if (this.isModifyContainsCurrentFile()) { + let currentNode = this.state.currentNode; + let nodePath = encodeURI(currentNode.path); + let pathname = window.location.pathname; + let start = pathname.indexOf(nodePath); + let node = currentNode.getNodeByPath(decodeURI(pathname.slice(start))); + if(node){ + currentNode.name = newName; + this.props.onFileClick(null, node); + } + } + }) + } + } + + onDeleteNode = () => { + var currentNode = this.state.currentNode; + let filePath = currentNode.path; + let type = currentNode.type; + if (type === 'file') { + this.props.editorUtilities.deleteFile(filePath).then(res => { + this.initializeTreeData(); + }) + } + + if (type === 'dir') { + this.props.editorUtilities.deleteDir(filePath).then(res => { + this.initializeTreeData(); + }) + } + + let isCurrentFile = false; + if (this.state.currentNode.type === "dir") { + isCurrentFile = this.isModifyContainsCurrentFile(); + } else { + isCurrentFile = this.isModifyCurrentFile(); + } + + if (isCurrentFile) { + let homeNode = this.getHomeNode(); + this.props.onFileClick(null, homeNode); + } + } + + isModifyCurrentFile() { + let name = this.state.currentNode.name; + let pathname = window.location.pathname; + let currentName = pathname.slice(pathname.lastIndexOf("/") + 1); + return name === currentName; + } + + isModifyContainsCurrentFile() { + let pathname = window.location.pathname; + let nodePath = this.state.currentNode.path; + if (pathname.indexOf(nodePath)) { + return true; + } + return false; + } + + initializeTreeData() { + this.props.editorUtilities.getFiles().then((files) => { + // construct the tree object + var rootObj = { + name: '/', + type: 'dir', + isExpanded: true + } + var treeData = new Tree(); + treeData.parseFromList(rootObj, files); + let homeNode = this.getHomeNode(treeData); + this.setState({ + tree_data: treeData, + currentNode: homeNode + }) + }, () => { + console.log("failed to load files"); + this.setState({ + isLoadFailed: true + }) + }) + } + + getHomeNode(treeData) { + let root = null; + if (treeData) { + root = treeData.root; + } else { + root = this.state.tree_data.root; + } + let homeNode = root.getNodeByPath(decodeURI("/home.md")); + return homeNode; + } + + componentDidMount() { + //init treeview data + this.initializeTreeData(); + + document.addEventListener('click', this.onHideContextMenu); + } + + componentWillUnmount() { + document.removeEventListener('click', this.onHideContextMenu); + } + render() { return (
@@ -21,11 +224,39 @@ class SidePanel extends Component {
diff --git a/frontend/src/components/account.js b/frontend/src/components/account.js index 5975885096..bca8548dfc 100644 --- a/frontend/src/components/account.js +++ b/frontend/src/components/account.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import cookie from 'react-cookies'; import { keyCodes, bytesToSize } from './utils'; -import { siteRoot, avatarInfo } from './constance'; +import { siteRoot, avatarInfo, gettext } from './constance'; class Account extends Component { @@ -88,7 +88,7 @@ class Account extends Component { renderMenu = () => { if(this.state.isStaff){ return ( - System Admin + {gettext("System Admin")} ) } } @@ -124,15 +124,15 @@ class Account extends Component {
-

Used: {this.state.quotaUsage} / {this.state.quotaTotal}

+

{gettext("Used")}: {this.state.quotaUsage} / {this.state.quotaTotal}

- Settings + {gettext("Settings")} {this.renderMenu()} - Log out + {gettext("Log out")}
diff --git a/frontend/src/components/constance.js b/frontend/src/components/constance.js index 829393a3ce..096a223c6d 100644 --- a/frontend/src/components/constance.js +++ b/frontend/src/components/constance.js @@ -1,4 +1,5 @@ export const dirPath = '/'; +export const gettext = window.gettext; export const siteRoot = window.app.config.siteRoot; export const avatarInfo = window.app.config.avatarInfo; diff --git a/frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js b/frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js new file mode 100644 index 0000000000..1a754cb5c4 --- /dev/null +++ b/frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js @@ -0,0 +1,100 @@ +import React from 'react'; +import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Col, FormText } from 'reactstrap'; +const gettext = window.gettext; + +class CreateFileForder extends React.Component { + constructor(props) { + super(props); + this.state = { + parentPath: '', + childName: '' + }; + this.newInput = React.createRef() + } + + handleChange = (e) => { + this.setState({ + childName: e.target.value, + }) + } + + handleSubmit = () => { + let path = this.state.parentPath + this.state.childName + if (this.props.isFile) { + this.props.onAddFile(path); + } else { + this.props.onAddFolder(path); + } + } + + toggle = () => { + if (this.props.isFile) { + this.props.addFileCancel(); + } else { + this.props.addFolderCancel(); + } + } + + componentWillMount() { + this.changeState(this.props.isFile); + } + + componentDidMount() { + if (this.props.currentNode.path === "/") { + this.setState({parentPath: this.props.currentNode.path}); + } else { + this.setState({parentPath: this.props.currentNode.path + "/"}); + } + this.newInput.focus(); + this.newInput.setSelectionRange(0,0); + } + + changeState(isFile) { + if (isFile) { + this.setState({childName: '.md'}); + } else{ + this.setState({childName: ""}); + } + } + + componentWillReceiveProps(nextProps) { + this.changeState(nextProps.isFile); + } + + changeState(isFile) { + if (isFile) { + this.setState({childName: '.md'}); + } else{ + this.setState({childName: ""}); + } + } + + + render() { + return ( + + {this.props.isFile ? gettext("New File") : gettext("New Folder")} + +
+ + + {this.state.parentPath} + + + + + {this.newInput = input}} id="fileName" placeholder={gettext("newName")} value={this.state.childName} onChange={this.handleChange}/> + + +
+
+ + + + +
+ ) + } +} + +export default CreateFileForder; diff --git a/frontend/src/components/menu-component/menu-dialog/delete-dialog.js b/frontend/src/components/menu-component/menu-dialog/delete-dialog.js new file mode 100644 index 0000000000..d2c3fe872f --- /dev/null +++ b/frontend/src/components/menu-component/menu-dialog/delete-dialog.js @@ -0,0 +1,29 @@ +import React from 'react'; +import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; + +const gettext = window.gettext; + +class Delete extends React.Component { + + toggle = () => { + this.props.toggleCancel(); + } + + render() { + let name = this.props.currentNode.name; + return ( + + {gettext("Delete")} + +

{gettext("Are you sure to delete")}{' '}{name} ?

+
+ + + + +
+ ) + } +} + +export default Delete; diff --git a/frontend/src/components/menu-component/menu-dialog/rename-dialog.js b/frontend/src/components/menu-component/menu-dialog/rename-dialog.js new file mode 100644 index 0000000000..06b01b258d --- /dev/null +++ b/frontend/src/components/menu-component/menu-dialog/rename-dialog.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter } from 'reactstrap'; +const gettext = window.gettext; + +class Rename extends React.Component { + constructor(props) { + super(props); + this.state = { + newName: '', + }; + this.newInput = React.createRef(); + } + + handleChange = (e) => { + this.setState({ + newName: e.target.value, + }); + } + + handleSubmit = () => { + this.props.onRename(this.state.newName); + } + + toggle = () => { + this.props.toggleCancel(); + } + + componentWillMount() { + this.setState({ + newName: this.props.currentNode.name + }) + } + + componentDidMount() { + this.changeState(this.props.currentNode); + this.newInput.focus(); + let type = this.props.currentNode.type; + if (type === "file") { + var endIndex = this.props.currentNode.name.lastIndexOf(".md"); + this.newInput.setSelectionRange(0, endIndex, "forward"); + } else { + this.newInput.setSelectionRange(0, -1); + } + } + + componentWillReceiveProps(nextProps) { + this.changeState(nextProps.currentNode); + } + + changeState(currentNode) { + this.setState({newName: currentNode.name}); + } + + render() { + let type = this.props.currentNode.type; + let preName = this.props.currentNode.name; + return ( + + {type === 'file' ? gettext("Rename File") : gettext("Rename Folder") } + +

{type === 'file' ? gettext("Enter the new file name:"): gettext("Enter the new folder name:")}

+ {this.newInput = input}} placeholder="newName" value={this.state.newName} onChange={this.handleChange} /> +
+ + + + +
+ ) + } +} + +export default Rename; diff --git a/frontend/src/components/menu-component/node-menu-control.js b/frontend/src/components/menu-component/node-menu-control.js new file mode 100644 index 0000000000..97442f91e8 --- /dev/null +++ b/frontend/src/components/menu-component/node-menu-control.js @@ -0,0 +1,21 @@ +import React from 'react'; + +class NodeMenuControl extends React.Component { + + onClick = (e) => { + let node = this.props.currentNode; + this.props.onClick(e, node); + } + + render() { + return ( + + + ) + } +} + +export default NodeMenuControl; \ No newline at end of file diff --git a/frontend/src/components/menu-component/node-menu.js b/frontend/src/components/menu-component/node-menu.js new file mode 100644 index 0000000000..9df628bba1 --- /dev/null +++ b/frontend/src/components/menu-component/node-menu.js @@ -0,0 +1,166 @@ +import React from 'react' +import Delete from './menu-dialog/delete-dialog'; +import CreateFlieFolder from './menu-dialog/create-fileforder-dialog'; +import Rename from './menu-dialog/rename-dialog'; + +const gettext = window.gettext; + +class NodeMenu extends React.Component { + + constructor(props) { + super(props); + this.state = { + showDelete: false, + showAddFileFolder: false, + showRename: false, + isFile: false + }; + } + + toggleDelete = () => { + this.setState({showDelete: !this.state.showDelete}); + this.props.onHideContextMenu(); + } + + toggleAddFileFolder = (ev, flag) => { + if(flag){ + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: true + }); + } else { + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: false + }) + } + this.props.onHideContextMenu(); + } + + toggleRename = () => { + this.setState({showRename: !this.state.showRename}); + this.props.onHideContextMenu(); + } + + onDelete = () => { + this.setState({showDelete: !this.state.showDelete}); + this.props.onDeleteNode(); + } + + deleteCancel = () => { + this.setState({showDelete: !this.state.showDelete}); + } + + onAddFile = (filePath) => { + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: false + }); + this.props.onAddFileNode(filePath); + } + + addFileCancel = () => { + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: false + }); + } + + onAddFolder = (dirPath) => { + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: false + }); + this.props.onAddFolderNode(dirPath); + } + + addFolderCancel = () => { + this.setState({ + showAddFileFolder: !this.state.showAddFileFolder, + isFile: false + }); + } + + onRename = (newName) => { + this.setState({showRename: !this.state.showRename}); + this.props.onRenameNode(newName); + } + + renameCancel = () => { + this.setState({showRename: !this.state.showRename}); + } + + renderNodeMenu() { + let style = null; + let position = this.props.menuPosition; + if (this.props.isShowMenu) { + style = {position: "fixed",left: position.left, top: position.top, display: 'block'}; + } + + if (this.props.currentNode.type === "dir") { + + if (this.props.currentNode.name === "/") { + return ( + + ) + } + + return ( + + ) + } + + return ( + + ) + + } + + render() { + if (!this.props.currentNode) { + return (
) + } + return ( +
+ {this.renderNodeMenu()} + {this.state.showDelete && + + } + {this.state.showAddFileFolder && + + } + {this.state.showRename && + + } +
+ ) + } +} + +export default NodeMenu; diff --git a/frontend/src/components/search.js b/frontend/src/components/search.js index 38d74cbe1b..b8251a3152 100644 --- a/frontend/src/components/search.js +++ b/frontend/src/components/search.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { repoID } from './constance'; +import { gettext, repoID } from './constance'; import SearchResultItem from './SearchResultItem'; class Search extends Component { @@ -195,7 +195,7 @@ class Search extends Component { type="text" className="search-input" name="query" - placeholder="Search files in this wiki" + placeholder={gettext("Search files in this wiki")} style={style} value={this.state.value} onFocus={this.onFocusHandler} diff --git a/frontend/src/components/tree-view/node.js b/frontend/src/components/tree-view/node.js index 1456e3376f..155c2e479c 100644 --- a/frontend/src/components/tree-view/node.js +++ b/frontend/src/components/tree-view/node.js @@ -100,6 +100,33 @@ class Node { return this.type == "dir"; } + getleafPaths() { + let paths = new Map(); + function getleafPath(node){ + if (node.hasChildren()) { + let children = node.children; + children.forEach(child => { + if (child.hasChildren()) { + getleafPath(child); + } else { + let path = child.path; + paths.set(path,child); + } + }); + } + } + getleafPath(this); + return paths; + } + + getNodeByPath(path) { + let paths = this.getleafPaths(); + if (paths.has(path)) { + return paths.get(path); + } + return null; + } + /** * Return a JSON representation of the node. * diff --git a/frontend/src/components/tree-view/tree-node-view.js b/frontend/src/components/tree-view/tree-node-view.js index ef8e81ccb0..e4eda3bc2f 100644 --- a/frontend/src/components/tree-view/tree-node-view.js +++ b/frontend/src/components/tree-view/tree-node-view.js @@ -1,4 +1,5 @@ import React from 'react'; +import MenuControl from '../menu-component/node-menu-control' function sortByType(a, b) { if (a.type == "dir" && b.type != "dir") { @@ -12,6 +13,69 @@ function sortByType(a, b) { class TreeNodeView extends React.Component { + constructor(props) { + super(props); + this.state = { + isMenuIconShow: false + } + } + + onClick = (e) => { + // e.nativeEvent.stopImmediatePropagation(); + let { node } = this.props; + this.props.treeView.onNodeClick(e, node); + } + + onMouseEnter = () => { + if (!this.props.isNodeItemFrezee) { + this.setState({ + isMenuIconShow: true + }) + } + } + + onMouseLeave = () => { + if (!this.props.isNodeItemFrezee) { + this.setState({ + isMenuIconShow: false + }) + } + } + + handleCollapse = (e) => { + e.stopPropagation(); + const { node } = this.props; + if (this.props.treeView.toggleCollapse) { + this.props.treeView.toggleCollapse(node); + } + } + + onDragStart = (e) => { + const { node } = this.props; + this.props.treeView.onDragStart(e, node); + } + + onMenuControlClick = (e) => { + e.stopPropagation(); + e.nativeEvent.stopImmediatePropagation(); + const { node } = this.props; + this.props.treeView.onShowContextMenu(e, node); + } + + hideMenuIcon = () => { + this.setState({ + isMenuIconShow: false + }); + } + + componentDidMount() { + document.addEventListener('click', this.hideMenuIcon); + } + + componentWillUnmount() { + document.removeEventListener('click', this.hideMenuIcon); + } + renderCollapse = () => { const { node } = this.props; @@ -50,6 +114,8 @@ class TreeNodeView extends React.Component { key={child.path} paddingLeft={this.props.paddingLeft} treeView={this.props.treeView} + isNodeItemFrezee={this.props.isNodeItemFrezee} + permission={this.props.permission} /> ); })} @@ -60,16 +126,30 @@ class TreeNodeView extends React.Component { return null; } - render() { - const { node } = this.props; - const styles = {}; - var icon, type; - if (node.type === "dir") { + renderMenuController() { + if (this.props.permission === "rw") { + return ( +
+ +
+ ) + } + return; + } + + getNodeTypeAndIcon() { + const node = this.props.node; + let icon = ''; + let type = ''; + if (node.type === 'dir') { icon = ; type = 'dir'; - } else { + } else { let index = node.name.lastIndexOf("."); - if (index === -1) { + if (index === -1) { icon = ; type = 'file'; } else { @@ -84,52 +164,37 @@ class TreeNodeView extends React.Component { } } + return { type, icon }; + + + } + + render() { + const styles = {}; + let node = this.props.node; + let { type, icon } = this.getNodeTypeAndIcon(); + return ( -
-
+
- {this.renderCollapse()} - - {icon} - - {node.name} + type={type} + className={`tree-node-inner text-nowrap ${node.name === '/'? 'hide': ''}`} + > +
{node.name}
+
+ {this.renderCollapse()} + {icon} +
+ {this.renderMenuController()}
{node.isExpanded ? this.renderChildren() : null}
); } - onClick = e => { - let { node } = this.props; - this.props.treeView.onClick(e, node); - } - - onMouseEnter = e => { - let { node } = this.props; - this.props.treeView.showImagePreview(e, node); - } - - onMouseLeave = e => { - this.props.treeView.hideImagePreview(e); - } - - handleCollapse = e => { - e.stopPropagation(); - const { node } = this.props; - if (this.props.treeView.toggleCollapse) { - this.props.treeView.toggleCollapse(node); - } - } - - onDragStart = e => { - const { node } = this.props; - this.props.treeView.onDragStart(e, node); - } - } export default TreeNodeView; diff --git a/frontend/src/components/tree-view/tree-view.js b/frontend/src/components/tree-view/tree-view.js index 1d9b5c796c..22e8aa13fc 100644 --- a/frontend/src/components/tree-view/tree-view.js +++ b/frontend/src/components/tree-view/tree-view.js @@ -1,110 +1,8 @@ import React from 'react'; import TreeNodeView from './tree-node-view'; -import Tree from './tree'; class TreeView extends React.PureComponent { - static defaultProps = { - paddingLeft: 20 - }; - - imagePreviewTimeout = null - - state = { - tree: new Tree(), - loadingFailed: false, - imagePreviewPosition: { - left: 10+'px', - top: 10+'px' - }, - isShowImagePreview: false, - imagePreviewLoading: false, - imageSrc: '', - } - - showImagePreview = (e, node) => { - e.persist(); - - let type = e.target.getAttribute('type'); - if (type === 'image') { - this.imagePreviewTimeout = setTimeout(() => { - let X = e.clientX + 20; - let Y = e.clientY - 55; - if (e.view.innerHeight < e.clientY + 150) { - Y = e.clientY - 219; - } - this.setState({ - isShowImagePreview: true, - imagePreviewLoading: true, - imageSrc: this.props.editorUtilities.getFileURL(node), - imagePreviewPosition: { - left: X + 'px', - top: Y + 'px' - } - }); - }, 1000) - } - } - - hideImagePreview = (e) => { - clearTimeout(this.imagePreviewTimeout); - this.setState({ - isShowImagePreview: false, - imagePreviewLoading: false, - }); - } - - imageLoaded = () => { - this.setState({ - imagePreviewLoading: false, - }); - } - - componentDidMount() { - this.props.editorUtilities.getFiles().then((files) => { - // construct the tree object - var rootObj = { - name: '/', - type: 'dir', - isExpanded: true - } - var treeData = new Tree(); - treeData.parseFromList(rootObj, files); - this.setState({ - tree: treeData - }) - }, () => { - console.log("failed to load files"); - this.setState({ - loadingFailed: true - }) - }) - } - - - render() { - const tree = this.state.tree; - if (!tree.root) { - return
Loading...
- } - - return ( -
- - { this.state.isShowImagePreview && -
- { this.state.imagePreviewLoading && } - -
- } -
- ); - } - change = (tree) => { /* this._updated = true; @@ -113,7 +11,7 @@ class TreeView extends React.PureComponent { } toggleCollapse = (node) => { - const tree = this.state.tree; + const tree = this.props.treeData; node.isExpanded = !node.isExpanded; // copy the tree to make PureComponent work @@ -130,12 +28,35 @@ class TreeView extends React.PureComponent { e.dataTransfer.setData("text/plain", url); } - onClick = (e, node) => { + onNodeClick = (e, node) => { if (node.isDir()) { this.toggleCollapse(node); return; } - this.props.onClick(e, node); + this.props.onNodeClick(e, node); + } + + onShowContextMenu = (e, node) => { + this.props.onShowContextMenu(e, node); + } + + render() { + if (!this.props.treeData.root) { + return
Loading...
+ } + + return ( +
+ +
+ ); } } diff --git a/frontend/src/css/side-panel.css b/frontend/src/css/side-panel.css index a9422beed0..67d2801310 100644 --- a/frontend/src/css/side-panel.css +++ b/frontend/src/css/side-panel.css @@ -1,38 +1,8 @@ -/*tree view */ -.tree-node:not([type = 'dir']):hover { - background-color: rgb(255,239,178); -} - -.tree-node { - min-width: -moz-max-content; - min-width: -webkit-max-content; - min-width: max-content; -} - -.tree-node-inner { - position: relative; - padding-left: 12px; -} - /* the main reason to icon can not be align is that .folder has a real width it take the place of .tree-node-inner causing tree-node-icon not aligned , use absolute can make sure .tree-node-icon is always at the far left of .tree-node-inner */ -.folder-toggle-icon { - position: absolute; - left: 0; - line-height: 1.5; -} - -.tree-node-icon { - margin-right: 0.4rem; - margin-left: 0.1rem; - display: inline-block; - width: 1rem; - text-align: center; -} - .side-panel { user-select: none; height:100%; @@ -119,7 +89,89 @@ .outline-h3:hover { color: #eb8205; } + +/*tree view */ +.tree-node:not([type = 'dir']):hover { + background-color: rgb(255,239,178); +} + .tree-view { padding-left: 10px; line-height: 1.5; } + +.tree-node-inner { + position: relative; + padding-left: 12px; + height: 24px; +} + +.tree-node-inner .tree-node-text { + padding-left: 1.2rem; + width: calc(100% - 1.5rem); + font-size: 15px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.tree-node-inner .left-icon { + position: absolute; + display:flex; + justify-content:center; + align-items:center; + top: 0; + left: 0; + padding-left: 0.7rem; +} + +.folder-toggle-icon { + position: absolute; + left: 0; + line-height: 1.5; +} + +.tree-node-icon { + margin-right: 0.4rem; + margin-left: 0.1rem; + display: inline-block; + width: 1rem; + text-align: center; +} + +.tree-node-inner .right-icon { + position: absolute; + top: 0; + right: 0; + width: 1.5rem; + color: #888; + z-index: 2; + font-size: 0.8125rem; + text-align: center; +} + +.tree-node-inner .right-icon i { + width: 100%; + height: 100%; + vertical-align: middle; + font-size: 0.8125rem; + line-height: 1.625 !important; +} + +.dropdown-menu { + min-width: 8rem; +} + +.parent-path { + position: relative; +} + +.parent-path .form-text { + position: absolute; + top: 50%; + transform: translateY(-50%); + margin-top: 0; + margin-left: 0.25rem; + font-size: 0.9375rem; +} + diff --git a/frontend/src/css/wiki.css b/frontend/src/css/wiki.css index a8ce87f572..f28e60c172 100644 --- a/frontend/src/css/wiki.css +++ b/frontend/src/css/wiki.css @@ -8,6 +8,7 @@ } .wiki-pages-heading { + position: relative; font-size: 1rem; font-weight: normal; text-align:center; @@ -16,6 +17,13 @@ line-height: 1.5; height:40px; } +.heading-icon { + position: absolute; + right: 1rem; + top: 25%; + color: #888; + font-size: 0.8125rem; +} .wiki-pages-container { overflow: hidden; padding-bottom: 10px; diff --git a/frontend/src/wiki.js b/frontend/src/wiki.js index dca102938a..2c208b7f80 100644 --- a/frontend/src/wiki.js +++ b/frontend/src/wiki.js @@ -33,6 +33,31 @@ class EditorUtilities { return files; }) } + + createFile(filePath) { + return seafileAPI.createFile(repoID, filePath) + } + + deleteFile(filePath) { + return seafileAPI.deleteFile(repoID, filePath) + } + + renameFile(filePath, newFileName) { + return seafileAPI.renameFile(repoID, filePath, newFileName) + } + + createDir(dirPath) { + return seafileAPI.createDir(repoID, dirPath) + } + + deleteDir(dirPath) { + return seafileAPI.deleteDir(repoID, dirPath) + } + + renameDir(dirPath, newDirName) { + return seafileAPI.renameDir(repoID, dirPath, newDirName) + } + } const editorUtilities = new EditorUtilities(); @@ -115,7 +140,7 @@ class Wiki extends Component { }) }) - let fileUrl = siteRoot + 'wikis/' + slug + filePath; + let fileUrl = serviceUrl + '/wikis/' + slug + filePath; window.history.pushState({urlPath: fileUrl, filePath: filePath}, filePath, fileUrl); } @@ -145,6 +170,7 @@ class Wiki extends Component { closeSideBar={this.state.closeSideBar} onCloseSide ={this.onCloseSide} editorUtilities={editorUtilities} + permission={this.state.permission} /> \n" "Language-Team: LANGUAGE \n" @@ -17,13 +17,120 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#: frontend/src/components/MainPanel.js:36 +msgid "Edit Page" +msgstr "" + +#: frontend/src/components/MainPanel.js:46 +msgid "Wikis" +msgstr "" + +#: frontend/src/components/SidePanel.js:232 +msgid "Pages" +msgstr "" + +#: frontend/src/components/account.js:91 +msgid "System Admin" +msgstr "" + +#: frontend/src/components/account.js:127 +msgid "Used" +msgstr "" + +#: frontend/src/components/account.js:133 +msgid "Settings" +msgstr "" + +#: frontend/src/components/account.js:135 +msgid "Log out" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:76 +#: frontend/src/components/menu-component/node-menu.js:106 +#: frontend/src/components/menu-component/node-menu.js:114 +#: static/scripts/app/views/dir.js:770 +msgid "New File" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:76 +#: frontend/src/components/menu-component/node-menu.js:105 +#: frontend/src/components/menu-component/node-menu.js:113 +msgid "New Folder" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:84 +msgid "Name" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:86 +msgid "newName" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:92 +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:65 +msgid "Submit" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/create-fileforder-dialog.js:93 +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:66 +#: static/scripts/app/views/fileupload.js:21 +msgid "Cancel" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/delete-dialog.js:16 +#: frontend/src/components/menu-component/node-menu.js:116 +#: frontend/src/components/menu-component/node-menu.js:124 +#: static/scripts/app/views/fileupload.js:22 +#: static/scripts/sysadmin-app/views/device-trusted-ipaddress.js:27 +msgid "Delete" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/delete-dialog.js:18 +msgid "Are you sure to delete" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/delete-dialog.js:21 +msgid "YES" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/delete-dialog.js:22 +msgid "NO" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:59 +#: static/scripts/app/views/dialogs/dirent-rename.js:39 +msgid "Rename File" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:59 +#: static/scripts/app/views/dialogs/dirent-rename.js:39 +msgid "Rename Folder" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:61 +msgid "Enter the new file name:" +msgstr "" + +#: frontend/src/components/menu-component/menu-dialog/rename-dialog.js:61 +msgid "Enter the new folder name:" +msgstr "" + +#: frontend/src/components/menu-component/node-menu.js:115 +#: frontend/src/components/menu-component/node-menu.js:123 +msgid "Rename" +msgstr "" + +#: frontend/src/components/search.js:198 +msgid "Search files in this wiki" +msgstr "" + #: static/scripts/app/models/deleted-repo.js:19 -#: static/scripts/app/models/repo.js:59 static/scripts/common.js:333 +#: static/scripts/app/models/repo.js:59 static/scripts/common.js:343 msgid "Encrypted library" msgstr "" #: static/scripts/app/models/deleted-repo.js:21 -#: static/scripts/app/models/repo.js:61 static/scripts/common.js:337 +#: static/scripts/app/models/repo.js:61 static/scripts/common.js:347 #: static/scripts/sysadmin-app/models/trash-repo.js:14 msgid "Read-Write library" msgstr "" @@ -34,7 +141,7 @@ msgstr "" #: static/scripts/app/views/fileupload.js:406 #: static/scripts/app/views/fileupload.js:418 #: static/scripts/app/views/fileupload.js:430 -#: static/scripts/app/views/group.js:63 static/scripts/common.js:611 +#: static/scripts/app/views/group.js:65 static/scripts/common.js:640 msgid "Just now" msgstr "" @@ -45,29 +152,29 @@ msgstr "" #: static/scripts/app/models/repo.js:37 #: static/scripts/app/views/dialogs/dirent-rename.js:65 #: static/scripts/app/views/dir.js:666 static/scripts/app/views/dir.js:726 -#: static/scripts/app/views/dirent.js:501 -#: static/scripts/app/views/group-repo.js:133 -#: static/scripts/app/views/repo.js:181 +#: static/scripts/app/views/dirent.js:511 +#: static/scripts/app/views/group-repo.js:131 +#: static/scripts/app/views/repo.js:187 msgid "Name should not include '/'." msgstr "" -#: static/scripts/app/models/repo.js:41 static/scripts/app/views/share.js:303 +#: static/scripts/app/models/repo.js:41 static/scripts/app/views/share.js:294 msgid "Please enter password" msgstr "" -#: static/scripts/app/models/repo.js:42 static/scripts/app/views/share.js:311 +#: static/scripts/app/models/repo.js:42 static/scripts/app/views/share.js:302 msgid "Please enter the password again" msgstr "" -#: static/scripts/app/models/repo.js:44 static/scripts/app/views/share.js:307 +#: static/scripts/app/models/repo.js:44 static/scripts/app/views/share.js:298 msgid "Password is too short" msgstr "" -#: static/scripts/app/models/repo.js:46 static/scripts/app/views/share.js:315 +#: static/scripts/app/models/repo.js:46 static/scripts/app/views/share.js:306 msgid "Passwords don't match" msgstr "" -#: static/scripts/app/models/repo.js:63 static/scripts/common.js:335 +#: static/scripts/app/models/repo.js:63 static/scripts/common.js:345 msgid "Read-Only library" msgstr "" @@ -81,46 +188,6 @@ msgstr "" msgid "Read-Only" msgstr "" -#: static/scripts/app/views/account.js:58 -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:135 -#: static/scripts/app/views/dialogs/repo-share-link-admin.js:97 -#: static/scripts/app/views/dir.js:476 static/scripts/app/views/dir.js:510 -#: static/scripts/app/views/dirent.js:301 -#: static/scripts/app/views/file-comments.js:120 -#: static/scripts/app/views/group-discussions.js:119 -#: static/scripts/app/views/group-discussions.js:199 -#: static/scripts/app/views/group-discussions.js:242 -#: static/scripts/app/views/group-manage-members.js:121 -#: static/scripts/app/views/group-manage-members.js:150 -#: static/scripts/app/views/group-members.js:80 -#: static/scripts/app/views/group.js:190 static/scripts/app/views/group.js:219 -#: static/scripts/app/views/groups.js:95 -#: static/scripts/app/views/groups.js:149 -#: static/scripts/app/views/invitations.js:126 -#: static/scripts/app/views/my-deleted-repos.js:86 -#: static/scripts/app/views/myhome-repos.js:94 -#: static/scripts/app/views/myhome-shared-repos.js:79 -#: static/scripts/app/views/notifications.js:63 -#: static/scripts/app/views/notifications.js:163 -#: static/scripts/app/views/organization.js:135 -#: static/scripts/app/views/repo-shared-link.js:90 -#: static/scripts/app/views/share-admin-folders.js:96 -#: static/scripts/app/views/share-admin-repos.js:96 -#: static/scripts/app/views/share-admin-share-links.js:147 -#: static/scripts/app/views/share-admin-upload-links.js:61 -#: static/scripts/app/views/share.js:225 static/scripts/app/views/share.js:531 -#: static/scripts/app/views/share.js:680 static/scripts/app/views/share.js:847 -#: static/scripts/sysadmin-app/views/address-book-group.js:143 -#: static/scripts/sysadmin-app/views/address-book-group.js:215 -#: static/scripts/sysadmin-app/views/address-book-group.js:269 -#: static/scripts/sysadmin-app/views/address-book.js:89 -#: static/scripts/sysadmin-app/views/device-trusted-ipaddresses.js:62 -#: static/scripts/sysadmin-app/views/group-members.js:90 -#: static/scripts/sysadmin-app/views/groups.js:100 -#: static/scripts/sysadmin-app/views/repos.js:90 -msgid "Please check the network." -msgstr "" - #: static/scripts/app/views/activity-item.js:25 msgid "Removed all items from trash." msgstr "" @@ -157,78 +224,6 @@ msgstr "" msgid "Deleted directories" msgstr "" -#: static/scripts/app/views/details.js:94 -#: static/scripts/app/views/dialogs/dirent-mvcp.js:144 -#: static/scripts/app/views/dialogs/dirent-mvcp.js:173 -#: static/scripts/app/views/dialogs/dirent-rename.js:96 -#: static/scripts/app/views/dialogs/repo-change-password.js:94 -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:303 -#: static/scripts/app/views/dialogs/repo-history-settings.js:83 -#: static/scripts/app/views/dialogs/repo-history-settings.js:142 -#: static/scripts/app/views/dir.js:1332 static/scripts/app/views/dir.js:1366 -#: static/scripts/app/views/dir.js:1435 -#: static/scripts/app/views/dirent-details.js:160 -#: static/scripts/app/views/dirent-grid.js:354 -#: static/scripts/app/views/dirent-grid.js:395 -#: static/scripts/app/views/dirent.js:519 -#: static/scripts/app/views/dirent.js:649 -#: static/scripts/app/views/dirent.js:690 -#: static/scripts/app/views/file-comment.js:52 -#: static/scripts/app/views/file-comments.js:163 -#: static/scripts/app/views/folder-perm.js:266 -#: static/scripts/app/views/folder-share-item.js:127 -#: static/scripts/app/views/folder-share-item.js:188 -#: static/scripts/app/views/group-discussion.js:94 -#: static/scripts/app/views/group-manage-member.js:79 -#: static/scripts/app/views/group-manage-member.js:105 -#: static/scripts/app/views/group-manage-members.js:184 -#: static/scripts/app/views/group-repo.js:166 -#: static/scripts/app/views/group-repo.js:299 -#: static/scripts/app/views/group-settings.js:134 -#: static/scripts/app/views/group-settings.js:191 -#: static/scripts/app/views/group-settings.js:235 -#: static/scripts/app/views/group-settings.js:292 -#: static/scripts/app/views/group-settings.js:332 -#: static/scripts/app/views/group-settings.js:367 -#: static/scripts/app/views/invitations.js:194 -#: static/scripts/app/views/repo-folder-perm-item.js:96 -#: static/scripts/app/views/repo-folder-perm-item.js:147 -#: static/scripts/app/views/repo.js:206 static/scripts/app/views/repo.js:281 -#: static/scripts/app/views/repo.js:398 static/scripts/app/views/repo.js:440 -#: static/scripts/app/views/share.js:448 static/scripts/app/views/share.js:944 -#: static/scripts/app/views/share.js:1037 static/scripts/common.js:432 -#: static/scripts/common.js:521 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:104 -#: static/scripts/sysadmin-app/views/address-book-group.js:314 -#: static/scripts/sysadmin-app/views/address-book-group.js:339 -#: static/scripts/sysadmin-app/views/address-book.js:129 -#: static/scripts/sysadmin-app/views/admin-login-logs.js:129 -#: static/scripts/sysadmin-app/views/admin-operation-logs.js:129 -#: static/scripts/sysadmin-app/views/dashboard.js:84 -#: static/scripts/sysadmin-app/views/desktop-devices.js:105 -#: static/scripts/sysadmin-app/views/device-errors.js:92 -#: static/scripts/sysadmin-app/views/device-trusted-ipaddresses.js:115 -#: static/scripts/sysadmin-app/views/dir.js:195 -#: static/scripts/sysadmin-app/views/folder-share-item.js:90 -#: static/scripts/sysadmin-app/views/folder-share-item.js:139 -#: static/scripts/sysadmin-app/views/group-member.js:71 -#: static/scripts/sysadmin-app/views/group-members.js:151 -#: static/scripts/sysadmin-app/views/group-repos.js:75 -#: static/scripts/sysadmin-app/views/group.js:108 -#: static/scripts/sysadmin-app/views/groups.js:168 -#: static/scripts/sysadmin-app/views/mobile-devices.js:106 -#: static/scripts/sysadmin-app/views/repo.js:142 -#: static/scripts/sysadmin-app/views/repos.js:163 -#: static/scripts/sysadmin-app/views/search-groups.js:76 -#: static/scripts/sysadmin-app/views/search-repos.js:77 -#: static/scripts/sysadmin-app/views/search-trash-repos.js:113 -#: static/scripts/sysadmin-app/views/share.js:195 -#: static/scripts/sysadmin-app/views/share.js:269 -#: static/scripts/sysadmin-app/views/system-repo.js:59 -#: static/scripts/sysadmin-app/views/trash-repos.js:142 -msgid "Failed. Please check the network." -msgstr "" - #: static/scripts/app/views/device.js:42 #: static/scripts/sysadmin-app/views/device.js:42 msgid "Unlink device" @@ -275,43 +270,35 @@ msgid "Failed." msgstr "" #: static/scripts/app/views/dialogs/dirent-mvcp.js:133 -#: static/scripts/app/views/dialogs/dirent-mvcp.js:164 -#: static/scripts/app/views/dir.js:1426 +#: static/scripts/app/views/dialogs/dirent-mvcp.js:159 +#: static/scripts/app/views/dir.js:1416 msgid "Canceled." msgstr "" -#: static/scripts/app/views/dialogs/dirent-mvcp.js:196 +#: static/scripts/app/views/dialogs/dirent-mvcp.js:186 #: static/scripts/app/views/dir.js:1171 msgid "Invalid destination path" msgstr "" -#: static/scripts/app/views/dialogs/dirent-mvcp.js:215 -#: static/scripts/app/views/dirent.js:292 +#: static/scripts/app/views/dialogs/dirent-mvcp.js:205 +#: static/scripts/app/views/dirent.js:295 msgid "Successfully moved %(name)s" msgstr "" -#: static/scripts/app/views/dialogs/dirent-mvcp.js:218 +#: static/scripts/app/views/dialogs/dirent-mvcp.js:208 msgid "Successfully copied %(name)s" msgstr "" -#: static/scripts/app/views/dialogs/dirent-rename.js:39 -msgid "Rename Folder" -msgstr "" - -#: static/scripts/app/views/dialogs/dirent-rename.js:39 -msgid "Rename File" -msgstr "" - #: static/scripts/app/views/dialogs/dirent-rename.js:59 #: static/scripts/app/views/dir.js:661 static/scripts/app/views/dir.js:721 -#: static/scripts/app/views/dirent.js:495 -#: static/scripts/app/views/group-repo.js:127 -#: static/scripts/app/views/groups.js:127 +#: static/scripts/app/views/dirent.js:505 +#: static/scripts/app/views/group-repo.js:125 +#: static/scripts/app/views/groups.js:118 #: static/scripts/app/views/invitations.js:65 -#: static/scripts/app/views/repo.js:175 static/scripts/app/views/repo.js:411 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:74 -#: static/scripts/sysadmin-app/views/address-book-group.js:174 -#: static/scripts/sysadmin-app/views/address-book-group.js:239 +#: static/scripts/app/views/repo.js:181 static/scripts/app/views/repo.js:406 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:85 +#: static/scripts/sysadmin-app/views/address-book-group.js:181 +#: static/scripts/sysadmin-app/views/address-book-group.js:252 #: static/scripts/sysadmin-app/views/device-trusted-ipaddresses.js:42 #: static/scripts/sysadmin-app/views/dir.js:82 #: static/scripts/sysadmin-app/views/group-members.js:51 @@ -350,13 +337,13 @@ msgstr "" msgid "Successfully changed library password." msgstr "" -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:83 +#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:91 msgid "{placeholder} Folder Permission" msgstr "" -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:102 -#: static/scripts/app/views/group-settings.js:155 -#: static/scripts/app/views/repo.js:245 +#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:110 +#: static/scripts/app/views/group-settings.js:150 +#: static/scripts/app/views/repo.js:247 #: static/scripts/sysadmin-app/views/group.js:74 #: static/scripts/sysadmin-app/views/groups.js:68 #: static/scripts/sysadmin-app/views/repo.js:107 @@ -364,56 +351,15 @@ msgstr "" msgid "Search user or enter email and press Enter" msgstr "" -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:111 +#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:141 msgid "Select a group" msgstr "" -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:113 +#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:143 msgid "You can only select 1 item" msgstr "" -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:130 -#: static/scripts/app/views/dialogs/repo-share-link-admin.js:92 -#: static/scripts/app/views/file-comments.js:115 -#: static/scripts/app/views/group-discussions.js:114 -#: static/scripts/app/views/group-discussions.js:194 -#: static/scripts/app/views/group-manage-members.js:116 -#: static/scripts/app/views/group-members.js:75 -#: static/scripts/app/views/group.js:214 static/scripts/app/views/groups.js:90 -#: static/scripts/app/views/invitations.js:189 -#: static/scripts/app/views/my-deleted-repos.js:81 -#: static/scripts/app/views/myhome-repos.js:89 -#: static/scripts/app/views/myhome-shared-repos.js:74 -#: static/scripts/app/views/organization.js:130 -#: static/scripts/app/views/share-admin-folders.js:91 -#: static/scripts/app/views/share-admin-repos.js:91 -#: static/scripts/app/views/share-admin-share-links.js:142 -#: static/scripts/app/views/share-admin-upload-links.js:56 -#: static/scripts/app/views/share.js:220 static/scripts/app/views/share.js:526 -#: static/scripts/app/views/share.js:675 static/scripts/app/views/share.js:842 -#: static/scripts/sysadmin-app/views/address-book-group.js:309 -#: static/scripts/sysadmin-app/views/address-book-group.js:334 -#: static/scripts/sysadmin-app/views/address-book.js:124 -#: static/scripts/sysadmin-app/views/admin-login-logs.js:124 -#: static/scripts/sysadmin-app/views/admin-operation-logs.js:124 -#: static/scripts/sysadmin-app/views/dashboard.js:79 -#: static/scripts/sysadmin-app/views/desktop-devices.js:100 -#: static/scripts/sysadmin-app/views/device-errors.js:87 -#: static/scripts/sysadmin-app/views/dir.js:190 -#: static/scripts/sysadmin-app/views/group-members.js:146 -#: static/scripts/sysadmin-app/views/group-repos.js:70 -#: static/scripts/sysadmin-app/views/groups.js:163 -#: static/scripts/sysadmin-app/views/mobile-devices.js:101 -#: static/scripts/sysadmin-app/views/repos.js:158 -#: static/scripts/sysadmin-app/views/search-groups.js:71 -#: static/scripts/sysadmin-app/views/search-repos.js:72 -#: static/scripts/sysadmin-app/views/search-trash-repos.js:108 -#: static/scripts/sysadmin-app/views/system-repo.js:54 -#: static/scripts/sysadmin-app/views/trash-repos.js:137 -msgid "Permission error" -msgstr "" - -#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:193 +#: static/scripts/app/views/dialogs/repo-folder-perm-admin.js:222 msgid "Please click and choose a directory." msgstr "" @@ -421,7 +367,7 @@ msgstr "" msgid "{placeholder} History Setting" msgstr "" -#: static/scripts/app/views/dialogs/repo-history-settings.js:135 +#: static/scripts/app/views/dialogs/repo-history-settings.js:130 msgid "Successfully set library history." msgstr "" @@ -468,12 +414,13 @@ msgstr "" msgid "Password is required." msgstr "" -#: static/scripts/app/views/dir.js:732 -msgid "Only an extension there, please input a name." +#: static/scripts/app/views/dir.js:479 +#: static/scripts/app/views/notifications.js:63 static/scripts/common.js:464 +msgid "Please check the network." msgstr "" -#: static/scripts/app/views/dir.js:770 -msgid "New File" +#: static/scripts/app/views/dir.js:732 +msgid "Only an extension there, please input a name." msgstr "" #: static/scripts/app/views/dir.js:778 @@ -536,27 +483,27 @@ msgstr "" msgid "Copy selected item(s) to:" msgstr "" -#: static/scripts/app/views/dir.js:1220 static/scripts/app/views/dir.js:1387 +#: static/scripts/app/views/dir.js:1220 static/scripts/app/views/dir.js:1377 msgid "Successfully moved %(name)s." msgstr "" -#: static/scripts/app/views/dir.js:1222 static/scripts/app/views/dir.js:1389 +#: static/scripts/app/views/dir.js:1222 static/scripts/app/views/dir.js:1379 msgid "Successfully moved %(name)s and 1 other item." msgstr "" -#: static/scripts/app/views/dir.js:1224 static/scripts/app/views/dir.js:1391 +#: static/scripts/app/views/dir.js:1224 static/scripts/app/views/dir.js:1381 msgid "Successfully moved %(name)s and %(amount)s other items." msgstr "" -#: static/scripts/app/views/dir.js:1229 static/scripts/app/views/dir.js:1395 +#: static/scripts/app/views/dir.js:1229 static/scripts/app/views/dir.js:1385 msgid "Successfully copied %(name)s." msgstr "" -#: static/scripts/app/views/dir.js:1231 static/scripts/app/views/dir.js:1397 +#: static/scripts/app/views/dir.js:1231 static/scripts/app/views/dir.js:1387 msgid "Successfully copied %(name)s and 1 other item." msgstr "" -#: static/scripts/app/views/dir.js:1233 static/scripts/app/views/dir.js:1399 +#: static/scripts/app/views/dir.js:1233 static/scripts/app/views/dir.js:1389 msgid "Successfully copied %(name)s and %(amount)s other items." msgstr "" @@ -592,8 +539,8 @@ msgstr "" msgid "Failed to copy %(name)s" msgstr "" -#: static/scripts/app/views/dirent-details.js:95 static/scripts/common.js:662 -#: static/scripts/common.js:733 +#: static/scripts/app/views/dirent-details.js:95 static/scripts/common.js:691 +#: static/scripts/common.js:762 msgid "No matches" msgstr "" @@ -607,7 +554,7 @@ msgid "locked by {placeholder}" msgstr "" #: static/scripts/app/views/dirent-grid.js:186 -#: static/scripts/app/views/dirent.js:403 +#: static/scripts/app/views/dirent.js:412 msgid "Successfully deleted %(name)s" msgstr "" @@ -638,25 +585,10 @@ msgstr "" #: static/scripts/app/views/fileupload.js:17 #: static/scripts/app/views/fileupload.js:225 #: static/scripts/app/views/fileupload.js:265 -#: static/scripts/app/views/group-discussions.js:116 -#: static/scripts/app/views/group-discussions.js:196 -#: static/scripts/app/views/group-manage-members.js:118 -#: static/scripts/app/views/group-manage-members.js:182 -#: static/scripts/app/views/group-members.js:77 -#: static/scripts/app/views/group.js:216 static/scripts/app/views/groups.js:92 -#: static/scripts/app/views/my-deleted-repos.js:83 -#: static/scripts/app/views/myhome-repos.js:91 -#: static/scripts/app/views/myhome-shared-repos.js:76 -#: static/scripts/app/views/organization.js:132 #: static/scripts/app/views/repo-details.js:37 -#: static/scripts/app/views/share-admin-folders.js:93 -#: static/scripts/app/views/share-admin-repos.js:93 -#: static/scripts/app/views/share-admin-share-links.js:144 -#: static/scripts/app/views/share-admin-upload-links.js:58 -#: static/scripts/app/views/share.js:222 static/scripts/app/views/share.js:528 -#: static/scripts/app/views/share.js:677 static/scripts/app/views/share.js:844 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:128 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:135 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:145 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:152 +#: static/scripts/sysadmin-app/views/system-repo.js:52 msgid "Error" msgstr "" @@ -672,15 +604,6 @@ msgstr "" msgid "Start" msgstr "" -#: static/scripts/app/views/fileupload.js:21 -msgid "Cancel" -msgstr "" - -#: static/scripts/app/views/fileupload.js:22 -#: static/scripts/sysadmin-app/views/device-trusted-ipaddress.js:27 -msgid "Delete" -msgstr "" - #: static/scripts/app/views/fileupload.js:46 msgid "File Uploading..." msgstr "" @@ -705,12 +628,16 @@ msgstr "" msgid "File is locked" msgstr "" -#: static/scripts/app/views/folder-perm.js:62 +#: static/scripts/app/views/fileupload.js:440 +msgid "Network error" +msgstr "" + +#: static/scripts/app/views/folder-perm.js:60 msgid "Set {placeholder}'s permission" msgstr "" -#: static/scripts/app/views/folder-perm.js:134 -#: static/scripts/app/views/share.js:827 +#: static/scripts/app/views/folder-perm.js:126 +#: static/scripts/app/views/share.js:763 msgid "Select groups" msgstr "" @@ -718,6 +645,13 @@ msgstr "" msgid "Edit failed" msgstr "" +#: static/scripts/app/views/folder-share-item.js:127 +#: static/scripts/app/views/folder-share-item.js:188 +#: static/scripts/common.js:444 +#: static/scripts/sysadmin-app/views/dashboard.js:84 +msgid "Failed. Please check the network." +msgstr "" + #: static/scripts/app/views/folder-share-item.js:186 msgid "Delete failed" msgstr "" @@ -726,18 +660,18 @@ msgstr "" msgid "{placeholder} Members" msgstr "" -#: static/scripts/app/views/group-repo.js:60 -#: static/scripts/sysadmin-app/views/address-book-group-library.js:44 +#: static/scripts/app/views/group-repo.js:59 +#: static/scripts/sysadmin-app/views/address-book-group-library.js:55 msgid "Successfully deleted library {placeholder}" msgstr "" -#: static/scripts/app/views/group-repo.js:291 +#: static/scripts/app/views/group-repo.js:287 #: static/scripts/app/views/organization-repo.js:50 msgid "Successfully unshared 1 item." msgstr "" -#: static/scripts/app/views/group-settings.js:156 -#: static/scripts/app/views/repo.js:246 +#: static/scripts/app/views/group-settings.js:151 +#: static/scripts/app/views/repo.js:248 #: static/scripts/sysadmin-app/views/group.js:75 #: static/scripts/sysadmin-app/views/groups.js:69 #: static/scripts/sysadmin-app/views/repo.js:108 @@ -745,37 +679,37 @@ msgstr "" msgid "You cannot select any more choices" msgstr "" -#: static/scripts/app/views/group-settings.js:183 +#: static/scripts/app/views/group-settings.js:178 msgid "" "Successfully transferred the group. You are now a normal member of the group." msgstr "" -#: static/scripts/app/views/group-settings.js:253 +#: static/scripts/app/views/group-settings.js:238 msgid "Please choose a CSV file" msgstr "" -#: static/scripts/app/views/group-settings.js:284 +#: static/scripts/app/views/group-settings.js:269 msgid "Successfully imported." msgstr "" -#: static/scripts/app/views/group-settings.js:312 +#: static/scripts/app/views/group-settings.js:292 msgid "Dismiss Group" msgstr "" -#: static/scripts/app/views/group-settings.js:313 +#: static/scripts/app/views/group-settings.js:293 msgid "Really want to dismiss this group?" msgstr "" -#: static/scripts/app/views/group-settings.js:346 +#: static/scripts/app/views/group-settings.js:321 msgid "Quit Group" msgstr "" -#: static/scripts/app/views/group-settings.js:347 +#: static/scripts/app/views/group-settings.js:322 msgid "Are you sure you want to quit this group?" msgstr "" #: static/scripts/app/views/invitation.js:37 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:46 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:57 #: static/scripts/sysadmin-app/views/device-trusted-ipaddress.js:39 #: static/scripts/sysadmin-app/views/group.js:44 msgid "Successfully deleted 1 item." @@ -801,7 +735,7 @@ msgstr "" msgid "Refresh" msgstr "" -#: static/scripts/app/views/repo.js:91 +#: static/scripts/app/views/repo.js:95 #: static/scripts/sysadmin-app/views/address-book-group-library.js:30 #: static/scripts/sysadmin-app/views/admin-operation-log.js:51 #: static/scripts/sysadmin-app/views/repo.js:65 @@ -809,33 +743,33 @@ msgstr "" msgid "Delete Library" msgstr "" -#: static/scripts/app/views/repo.js:92 -#: static/scripts/sysadmin-app/views/address-book-group-item.js:33 +#: static/scripts/app/views/repo.js:96 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:47 #: static/scripts/sysadmin-app/views/address-book-group-library.js:31 #: static/scripts/sysadmin-app/views/device-trusted-ipaddress.js:28 -#: static/scripts/sysadmin-app/views/group-member.js:82 +#: static/scripts/sysadmin-app/views/group-member.js:91 #: static/scripts/sysadmin-app/views/group.js:31 #: static/scripts/sysadmin-app/views/repo.js:66 #, javascript-format msgid "Are you sure you want to delete %s ?" msgstr "" -#: static/scripts/app/views/repo.js:102 +#: static/scripts/app/views/repo.js:106 #: static/scripts/sysadmin-app/views/repo.js:79 msgid "Successfully deleted." msgstr "" -#: static/scripts/app/views/repo.js:235 +#: static/scripts/app/views/repo.js:237 #: static/scripts/sysadmin-app/views/repo.js:97 msgid "Transfer Library {library_name} To" msgstr "" -#: static/scripts/app/views/repo.js:274 +#: static/scripts/app/views/repo.js:276 #: static/scripts/sysadmin-app/views/repo.js:135 msgid "Successfully transferred the library." msgstr "" -#: static/scripts/app/views/repo.js:429 +#: static/scripts/app/views/repo.js:424 msgid "Successfully added label(s) for library {placeholder}" msgstr "" @@ -860,32 +794,32 @@ msgstr "" msgid "Expired" msgstr "" -#: static/scripts/app/views/share.js:248 static/scripts/app/views/share.js:249 -#: static/scripts/app/views/share.js:270 static/scripts/app/views/share.js:271 +#: static/scripts/app/views/share.js:239 static/scripts/app/views/share.js:240 +#: static/scripts/app/views/share.js:261 static/scripts/app/views/share.js:262 msgid "Hide" msgstr "" -#: static/scripts/app/views/share.js:266 static/scripts/app/views/share.js:267 +#: static/scripts/app/views/share.js:257 static/scripts/app/views/share.js:258 msgid "Show" msgstr "" -#: static/scripts/app/views/share.js:325 +#: static/scripts/app/views/share.js:316 msgid "Please enter days." msgstr "" -#: static/scripts/app/views/share.js:329 +#: static/scripts/app/views/share.js:320 msgid "Please enter valid days" msgstr "" -#: static/scripts/app/views/share.js:415 +#: static/scripts/app/views/share.js:406 msgid "Please input at least an email." msgstr "" -#: static/scripts/app/views/share.js:432 +#: static/scripts/app/views/share.js:423 msgid "Successfully sent to {placeholder}" msgstr "" -#: static/scripts/app/views/share.js:436 +#: static/scripts/app/views/share.js:427 msgid "Failed to send to {placeholder}" msgstr "" @@ -902,45 +836,50 @@ msgstr "" msgid "Successfully unstared {placeholder}" msgstr "" -#: static/scripts/common.js:653 -#: static/scripts/sysadmin-app/views/address-book-group.js:165 +#: static/scripts/common.js:458 +#: static/scripts/sysadmin-app/views/dashboard.js:79 +msgid "Permission error" +msgstr "" + +#: static/scripts/common.js:682 +#: static/scripts/sysadmin-app/views/address-book-group.js:172 #: static/scripts/sysadmin-app/views/group-members.js:41 msgid "Search users or enter emails and press Enter" msgstr "" -#: static/scripts/common.js:661 static/scripts/common.js:732 +#: static/scripts/common.js:690 static/scripts/common.js:761 msgid "Please enter 1 or more character" msgstr "" -#: static/scripts/common.js:663 static/scripts/common.js:734 +#: static/scripts/common.js:692 static/scripts/common.js:763 msgid "Searching..." msgstr "" -#: static/scripts/common.js:664 static/scripts/common.js:735 +#: static/scripts/common.js:693 static/scripts/common.js:764 msgid "Loading failed" msgstr "" -#: static/scripts/common.js:724 +#: static/scripts/common.js:753 msgid "Search groups" msgstr "" -#: static/scripts/common.js:1059 +#: static/scripts/common.js:1088 msgid "Packaging..." msgstr "" -#: static/scripts/sysadmin-app/views/address-book-group-item.js:32 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:46 msgid "Delete Department" msgstr "" -#: static/scripts/sysadmin-app/views/address-book-group-item.js:80 +#: static/scripts/sysadmin-app/views/address-book-group-item.js:91 msgid "Invalid quota." msgstr "" -#: static/scripts/sysadmin-app/views/address-book-group.js:99 +#: static/scripts/sysadmin-app/views/address-book-group.js:101 msgid "New Sub-department" msgstr "" -#: static/scripts/sysadmin-app/views/address-book-group.js:111 +#: static/scripts/sysadmin-app/views/address-book-group.js:114 #: static/scripts/sysadmin-app/views/address-book.js:64 #: static/scripts/sysadmin-app/views/groups.js:79 #: static/scripts/sysadmin-app/views/repos.js:69 @@ -1016,11 +955,11 @@ msgstr "" msgid "Successfully clean all errors." msgstr "" -#: static/scripts/sysadmin-app/views/group-member.js:81 +#: static/scripts/sysadmin-app/views/group-member.js:90 msgid "Delete Member" msgstr "" -#: static/scripts/sysadmin-app/views/group-member.js:95 +#: static/scripts/sysadmin-app/views/group-member.js:100 msgid "Successfully deleted member {placeholder}" msgstr "" diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index 8fd4183daa..73edfb3566 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -32,6 +32,7 @@ } }; + {% block extra_script %}{% endblock %}