fix(fe/errors): introduce errors and make functions return status
This commit is contained in:
parent
9bf30f9677
commit
e23fc0a2d9
8 changed files with 67 additions and 1070 deletions
|
@ -1,964 +0,0 @@
|
|||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { List, Map, Set } from "immutable";
|
||||
import FileSize from "filesize";
|
||||
|
||||
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
||||
import { RiHomeSmileFill } from "@react-icons/all-files/ri/RiHomeSmileFill";
|
||||
import { RiFile2Fill } from "@react-icons/all-files/ri/RiFile2Fill";
|
||||
import { RiShareBoxLine } from "@react-icons/all-files/ri/RiShareBoxLine";
|
||||
import { RiFolderSharedFill } from "@react-icons/all-files/ri/RiFolderSharedFill";
|
||||
import { RiUploadCloudFill } from "@react-icons/all-files/ri/RiUploadCloudFill";
|
||||
import { RiUploadCloudLine } from "@react-icons/all-files/ri/RiUploadCloudLine";
|
||||
import { RiEmotionSadLine } from "@react-icons/all-files/ri/RiEmotionSadLine";
|
||||
|
||||
import { alertMsg, confirmMsg } from "../common/env";
|
||||
import { updater } from "./state_updater";
|
||||
import { ICoreState, MsgProps, UIProps } from "./core_state";
|
||||
import { LoginProps } from "./pane_login";
|
||||
import { MetadataResp, roleVisitor, roleAdmin } from "../client";
|
||||
import { Up } from "../worker/upload_mgr";
|
||||
import { UploadEntry, UploadState } from "../worker/interface";
|
||||
import { Flexbox } from "./layout/flexbox";
|
||||
|
||||
// export interface Item {
|
||||
// name: string;
|
||||
// size: number;
|
||||
// modTime: string;
|
||||
// isDir: boolean;
|
||||
// selected: boolean;
|
||||
// sha1: string;
|
||||
// }
|
||||
|
||||
// export interface BrowserProps {
|
||||
// tab: string;
|
||||
|
||||
// dirPath: List<string>;
|
||||
// isSharing: boolean;
|
||||
// items: List<MetadataResp>;
|
||||
|
||||
// uploadings: List<UploadEntry>;
|
||||
// uploadFiles: List<File>;
|
||||
// uploadValue: string;
|
||||
|
||||
// sharings: List<string>;
|
||||
// }
|
||||
|
||||
// export interface Props {
|
||||
// browser: BrowserProps;
|
||||
// msg: MsgProps;
|
||||
// login: LoginProps;
|
||||
// ui: UIProps;
|
||||
// update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
// }
|
||||
|
||||
export function getItemPath(dirPath: string, itemName: string): string {
|
||||
return dirPath.endsWith("/")
|
||||
? `${dirPath}${itemName}`
|
||||
: `${dirPath}/${itemName}`;
|
||||
}
|
||||
|
||||
// export interface State {
|
||||
// newFolderName: string;
|
||||
// selectedSrc: string;
|
||||
// selectedItems: Map<string, boolean>;
|
||||
// showDetail: Set<string>;
|
||||
// }
|
||||
|
||||
// export class Browser extends React.Component<Props, State, {}> {
|
||||
// private uploadInput: Element | Text;
|
||||
// private assignInput: (input: Element) => void;
|
||||
// private onClickUpload: () => void;
|
||||
|
||||
// constructor(p: Props) {
|
||||
// super(p);
|
||||
// this.state = {
|
||||
// newFolderName: "",
|
||||
// selectedSrc: "",
|
||||
// selectedItems: Map<string, boolean>(),
|
||||
// showDetail: Set<string>(),
|
||||
// };
|
||||
|
||||
// Up().setStatusCb(this.updateProgress);
|
||||
// this.uploadInput = undefined;
|
||||
// this.assignInput = (input) => {
|
||||
// this.uploadInput = ReactDOM.findDOMNode(input);
|
||||
// };
|
||||
// this.onClickUpload = () => {
|
||||
// const uploadInput = this.uploadInput as HTMLButtonElement;
|
||||
// uploadInput.click();
|
||||
// };
|
||||
// }
|
||||
|
||||
// onNewFolderNameChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// this.setState({ newFolderName: ev.target.value });
|
||||
// };
|
||||
|
||||
// addUploads = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// if (event.target.files.length > 1000) {
|
||||
// alertMsg(this.props.msg.pkg.get("err.tooManyUploads"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let fileList = List<File>();
|
||||
// for (let i = 0; i < event.target.files.length; i++) {
|
||||
// fileList = fileList.push(event.target.files[i]);
|
||||
// }
|
||||
// updater().addUploads(fileList);
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// };
|
||||
|
||||
// deleteUpload = (filePath: string): Promise<void> => {
|
||||
// return updater()
|
||||
// .deleteUpload(filePath)
|
||||
// .then((ok: boolean) => {
|
||||
// if (!ok) {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.upload.del.fail"));
|
||||
// }
|
||||
// return updater().refreshUploadings();
|
||||
// })
|
||||
// .then(() => {
|
||||
// return updater().self();
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// this.props.update(updater().updateLogin);
|
||||
// });
|
||||
// };
|
||||
|
||||
// stopUploading = (filePath: string) => {
|
||||
// updater().stopUploading(filePath);
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// };
|
||||
|
||||
// onMkDir = () => {
|
||||
// if (this.state.newFolderName === "") {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.folder.add.fail"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const dirPath = getItemPath(
|
||||
// this.props.browser.dirPath.join("/"),
|
||||
// this.state.newFolderName
|
||||
// );
|
||||
// updater()
|
||||
// .mkDir(dirPath)
|
||||
// .then(() => {
|
||||
// this.setState({ newFolderName: "" });
|
||||
// return updater().setItems(this.props.browser.dirPath);
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// });
|
||||
// };
|
||||
|
||||
// delete = () => {
|
||||
// // TODO: selected should be cleaned after change the cwd
|
||||
// if (this.props.browser.dirPath.join("/") !== this.state.selectedSrc) {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.del.fail"));
|
||||
// this.setState({
|
||||
// selectedSrc: this.props.browser.dirPath.join("/"),
|
||||
// selectedItems: Map<string, boolean>(),
|
||||
// });
|
||||
// return;
|
||||
// } else {
|
||||
// const filesToDel = this.state.selectedItems.keySeq().join(", ");
|
||||
// if (!confirmMsg(`${this.props.msg.pkg.get("op.confirm")} [${this.state.selectedItems.size}]: ${filesToDel}`)) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// updater()
|
||||
// .delete(
|
||||
// this.props.browser.dirPath,
|
||||
// this.props.browser.items,
|
||||
// this.state.selectedItems
|
||||
// )
|
||||
// .then(() => {
|
||||
// return updater().self();
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// this.props.update(updater().updateLogin);
|
||||
// this.setState({
|
||||
// selectedSrc: "",
|
||||
// selectedItems: Map<string, boolean>(),
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
// moveHere = () => {
|
||||
// const oldDir = this.state.selectedSrc;
|
||||
// const newDir = this.props.browser.dirPath.join("/");
|
||||
// if (oldDir === newDir) {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.move.fail"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// updater()
|
||||
// .moveHere(
|
||||
// this.state.selectedSrc,
|
||||
// this.props.browser.dirPath.join("/"),
|
||||
// this.state.selectedItems
|
||||
// )
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// this.setState({
|
||||
// selectedSrc: "",
|
||||
// selectedItems: Map<string, boolean>(),
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
// gotoChild = async (childDirName: string) => {
|
||||
// return this.chdir(this.props.browser.dirPath.push(childDirName));
|
||||
// };
|
||||
|
||||
// chdir = async (dirPath: List<string>) => {
|
||||
// if (dirPath === this.props.browser.dirPath) {
|
||||
// return;
|
||||
// } else if (this.props.login.userRole !== roleAdmin && dirPath.size <= 1) {
|
||||
// alertMsg(this.props.msg.pkg.get("unauthed"));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// return updater()
|
||||
// .setItems(dirPath)
|
||||
// .then(() => {
|
||||
// return updater().listSharings();
|
||||
// })
|
||||
// .then(() => {
|
||||
// return updater().isSharing(dirPath.join("/"));
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// });
|
||||
// };
|
||||
|
||||
// updateProgress = async (
|
||||
// infos: Map<string, UploadEntry>,
|
||||
// refresh: boolean
|
||||
// ) => {
|
||||
// updater().setUploadings(infos);
|
||||
// let errCount = 0;
|
||||
// infos.valueSeq().forEach((entry: UploadEntry) => {
|
||||
// errCount += entry.state === UploadState.Error ? 1 : 0;
|
||||
// });
|
||||
|
||||
// if (infos.size === 0 || infos.size === errCount) {
|
||||
// // refresh used space
|
||||
// updater()
|
||||
// .self()
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateLogin);
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (refresh) {
|
||||
// updater()
|
||||
// .setItems(this.props.browser.dirPath)
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// });
|
||||
// } else {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// }
|
||||
// };
|
||||
|
||||
// select = (itemName: string) => {
|
||||
// const selectedItems = this.state.selectedItems.has(itemName)
|
||||
// ? this.state.selectedItems.delete(itemName)
|
||||
// : this.state.selectedItems.set(itemName, true);
|
||||
|
||||
// this.setState({
|
||||
// selectedSrc: this.props.browser.dirPath.join("/"),
|
||||
// selectedItems: selectedItems,
|
||||
// });
|
||||
// };
|
||||
|
||||
// selectAll = () => {
|
||||
// let newSelected = Map<string, boolean>();
|
||||
// const someSelected = this.state.selectedItems.size === 0 ? true : false;
|
||||
// if (someSelected) {
|
||||
// this.props.browser.items.forEach((item) => {
|
||||
// newSelected = newSelected.set(item.name, true);
|
||||
// });
|
||||
// } else {
|
||||
// this.props.browser.items.forEach((item) => {
|
||||
// newSelected = newSelected.delete(item.name);
|
||||
// });
|
||||
// }
|
||||
|
||||
// this.setState({
|
||||
// selectedSrc: this.props.browser.dirPath.join("/"),
|
||||
// selectedItems: newSelected,
|
||||
// });
|
||||
// };
|
||||
|
||||
// addSharing = async () => {
|
||||
// return updater()
|
||||
// .addSharing()
|
||||
// .then((ok) => {
|
||||
// if (!ok) {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.share.add.fail"));
|
||||
// } else {
|
||||
// updater().setSharing(true);
|
||||
// return this.listSharings();
|
||||
// }
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// });
|
||||
// };
|
||||
|
||||
// deleteSharing = async (dirPath: string) => {
|
||||
// return updater()
|
||||
// .deleteSharing(dirPath)
|
||||
// .then((ok) => {
|
||||
// if (!ok) {
|
||||
// alertMsg(this.props.msg.pkg.get("browser.share.del.fail"));
|
||||
// } else {
|
||||
// updater().setSharing(false);
|
||||
// return this.listSharings();
|
||||
// }
|
||||
// })
|
||||
// .then(() => {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// });
|
||||
// };
|
||||
|
||||
// listSharings = async () => {
|
||||
// return updater()
|
||||
// .listSharings()
|
||||
// .then((ok) => {
|
||||
// if (ok) {
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
// setTab = (tabName: string) => {
|
||||
// updater().setTab(tabName);
|
||||
// this.props.update(updater().updateBrowser);
|
||||
// };
|
||||
|
||||
// toggleDetail = (name: string) => {
|
||||
// const showDetail = this.state.showDetail.has(name)
|
||||
// ? this.state.showDetail.delete(name)
|
||||
// : this.state.showDetail.add(name);
|
||||
// this.setState({ showDetail });
|
||||
// };
|
||||
|
||||
// generateHash = async (filePath: string): Promise<boolean> => {
|
||||
// alertMsg(this.props.msg.pkg.get("refresh-hint"));
|
||||
// return updater().generateHash(filePath);
|
||||
// };
|
||||
|
||||
// render() {
|
||||
// const showOp = this.props.login.userRole === roleVisitor ? "hidden" : "";
|
||||
// const breadcrumb = this.props.browser.dirPath.map(
|
||||
// (pathPart: string, key: number) => {
|
||||
// return (
|
||||
// <button
|
||||
// key={pathPart}
|
||||
// onClick={() =>
|
||||
// this.chdir(this.props.browser.dirPath.slice(0, key + 1))
|
||||
// }
|
||||
// className="item"
|
||||
// >
|
||||
// {pathPart}
|
||||
// </button>
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
|
||||
// const nameWidthClass = `item-name item-name-${
|
||||
// this.props.ui.isVertical ? "vertical" : "horizontal"
|
||||
// } pointer`;
|
||||
|
||||
// const ops = (
|
||||
// <div id="upload-op">
|
||||
// <div className="float">
|
||||
// <input
|
||||
// type="text"
|
||||
// onChange={this.onNewFolderNameChange}
|
||||
// value={this.state.newFolderName}
|
||||
// placeholder={this.props.msg.pkg.get("browser.folder.name")}
|
||||
// className="float"
|
||||
// />
|
||||
// <button onClick={this.onMkDir} className="float">
|
||||
// {this.props.msg.pkg.get("browser.folder.add")}
|
||||
// </button>
|
||||
// </div>
|
||||
|
||||
// <div className="float">
|
||||
// <button onClick={this.onClickUpload}>
|
||||
// {this.props.msg.pkg.get("browser.upload")}
|
||||
// </button>
|
||||
// <input
|
||||
// type="file"
|
||||
// onChange={this.addUploads}
|
||||
// multiple={true}
|
||||
// value={this.props.browser.uploadValue}
|
||||
// ref={this.assignInput}
|
||||
// className="hidden"
|
||||
// />
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
|
||||
// const sortedItems = this.props.browser.items.sort(
|
||||
// (item1: MetadataResp, item2: MetadataResp) => {
|
||||
// if (item1.isDir && !item2.isDir) {
|
||||
// return -1;
|
||||
// } else if (!item1.isDir && item2.isDir) {
|
||||
// return 1;
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
// );
|
||||
|
||||
// const itemList = sortedItems.map((item: MetadataResp) => {
|
||||
// const isSelected = this.state.selectedItems.has(item.name);
|
||||
// const dirPath = this.props.browser.dirPath.join("/");
|
||||
// const itemPath = dirPath.endsWith("/")
|
||||
// ? `${dirPath}${item.name}`
|
||||
// : `${dirPath}/${item.name}`;
|
||||
|
||||
// return item.isDir ? (
|
||||
// <Flexbox
|
||||
// key={item.name}
|
||||
// children={List([
|
||||
// <span className="padding-m">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiFolder2Fill
|
||||
// size="3rem"
|
||||
// className="yellow0-font margin-r-m"
|
||||
// />,
|
||||
|
||||
// <span className={`${nameWidthClass}`}>
|
||||
// <span
|
||||
// className="title-m"
|
||||
// onClick={() => this.gotoChild(item.name)}
|
||||
// >
|
||||
// {item.name}
|
||||
// </span>
|
||||
// <div className="desc-m grey0-font">
|
||||
// <span>
|
||||
// {item.modTime.slice(0, item.modTime.indexOf("T"))}
|
||||
// </span>
|
||||
// </div>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto" },
|
||||
// { flex: "0 0 auto" },
|
||||
// ])}
|
||||
// />
|
||||
// </span>,
|
||||
|
||||
// <span className={`item-op padding-m ${showOp}`}>
|
||||
// <button
|
||||
// onClick={() => this.select(item.name)}
|
||||
// className={`${
|
||||
// isSelected ? "cyan0-bg white-font" : "grey2-bg grey3-font"
|
||||
// }`}
|
||||
// style={{ width: "8rem", display: "inline-block" }}
|
||||
// >
|
||||
// {isSelected
|
||||
// ? this.props.msg.pkg.get("browser.deselect")
|
||||
// : this.props.msg.pkg.get("browser.select")}
|
||||
// </button>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto", width: "60%" },
|
||||
// { flex: "0 0 auto", justifyContent: "flex-end", width: "40%" },
|
||||
// ])}
|
||||
// />
|
||||
// ) : (
|
||||
// <div key={item.name}>
|
||||
// <Flexbox
|
||||
// key={item.name}
|
||||
// children={List([
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiFile2Fill
|
||||
// size="3rem"
|
||||
// className="cyan0-font margin-l-m margin-r-m"
|
||||
// />,
|
||||
|
||||
// <span className={`${nameWidthClass}`}>
|
||||
// <a
|
||||
// className="title-m"
|
||||
// href={`/v1/fs/files?fp=${itemPath}`}
|
||||
// target="_blank"
|
||||
// >
|
||||
// {item.name}
|
||||
// </a>
|
||||
// <div className="desc-m grey0-font">
|
||||
// <span>
|
||||
// {item.modTime.slice(0, item.modTime.indexOf("T"))}
|
||||
// </span>
|
||||
// /
|
||||
// <span>{FileSize(item.size, { round: 0 })}</span>
|
||||
// </div>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto" },
|
||||
// { flex: "0 0 auto" },
|
||||
// ])}
|
||||
// />,
|
||||
|
||||
// <span className={`item-op padding-m ${showOp}`}>
|
||||
// <button
|
||||
// onClick={() => this.toggleDetail(item.name)}
|
||||
// style={{ width: "8rem" }}
|
||||
// className="float-input"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("detail")}
|
||||
// </button>
|
||||
|
||||
// <button
|
||||
// type="button"
|
||||
// onClick={() => this.select(item.name)}
|
||||
// className={`float-input ${
|
||||
// isSelected ? "cyan0-bg white-font " : "grey2-bg grey3-font "
|
||||
// }`}
|
||||
// style={{ width: "8rem" }}
|
||||
// >
|
||||
// {isSelected
|
||||
// ? this.props.msg.pkg.get("browser.deselect")
|
||||
// : this.props.msg.pkg.get("browser.select")}
|
||||
// </button>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto", width: "60%" },
|
||||
// { flex: "0 0 auto", justifyContent: "flex-end", width: "40%" },
|
||||
// ])}
|
||||
// />
|
||||
|
||||
// <div
|
||||
// className={`${
|
||||
// this.state.showDetail.has(item.name) ? "" : "hidden"
|
||||
// }`}
|
||||
// >
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span>
|
||||
// <b>SHA1:</b>
|
||||
// {` ${item.sha1}`}
|
||||
// </span>,
|
||||
// <button
|
||||
// onClick={() => this.generateHash(itemPath)}
|
||||
// className="black-bg white-font margin-l-m"
|
||||
// style={{ display: "inline-block" }}
|
||||
// >
|
||||
// {this.props.msg.pkg.get("refresh")}
|
||||
// </button>,
|
||||
// ])}
|
||||
// className={`grey2-bg grey3-font detail margin-r-m`}
|
||||
// childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
// />
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// });
|
||||
|
||||
// const usedSpace = FileSize(parseInt(this.props.login.usedSpace, 10), {
|
||||
// round: 0,
|
||||
// });
|
||||
// const spaceLimit = FileSize(
|
||||
// parseInt(this.props.login.quota.spaceLimit, 10),
|
||||
// {
|
||||
// round: 0,
|
||||
// }
|
||||
// );
|
||||
|
||||
// const itemListPane =
|
||||
// this.props.browser.tab === "" || this.props.browser.tab === "item" ? (
|
||||
// <div id="item-list">
|
||||
// <div className={`container ${showOp}`}>{ops}</div>
|
||||
|
||||
// <div className="container">
|
||||
// <div id="browser-op" className={`${showOp}`}>
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span>
|
||||
// {this.props.browser.isSharing ? (
|
||||
// <button
|
||||
// type="button"
|
||||
// onClick={() => {
|
||||
// this.deleteSharing(
|
||||
// this.props.browser.dirPath.join("/")
|
||||
// );
|
||||
// }}
|
||||
// className="red-btn"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.share.del")}
|
||||
// </button>
|
||||
// ) : (
|
||||
// <button
|
||||
// type="button"
|
||||
// onClick={this.addSharing}
|
||||
// className="cyan-btn"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.share.add")}
|
||||
// </button>
|
||||
// )}
|
||||
// </span>,
|
||||
|
||||
// <span>
|
||||
// {this.state.selectedItems.size > 0 ? (
|
||||
// <span>
|
||||
// <button
|
||||
// type="button"
|
||||
// onClick={() => this.delete()}
|
||||
// className="red-btn"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.delete")}
|
||||
// </button>
|
||||
|
||||
// <button type="button" onClick={() => this.moveHere()}>
|
||||
// {this.props.msg.pkg.get("browser.paste")}
|
||||
// </button>
|
||||
// </span>
|
||||
// ) : null}
|
||||
// </span>,
|
||||
|
||||
// <span>
|
||||
// <span
|
||||
// id="space-used"
|
||||
// className="desc-m grey0-font"
|
||||
// >{`${this.props.msg.pkg.get(
|
||||
// "browser.used"
|
||||
// )} ${usedSpace} / ${spaceLimit}`}</span>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto" },
|
||||
// { flex: "0 0 auto" },
|
||||
// { justifyContent: "flex-end" },
|
||||
// ])}
|
||||
// />
|
||||
// </div>
|
||||
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span id="breadcrumb">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiHomeSmileFill size="3rem" id="icon-home" />,
|
||||
// <Flexbox children={breadcrumb} />,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "0 0 auto" },
|
||||
// { flex: "0 0 auto" },
|
||||
// ])}
|
||||
// />
|
||||
// </span>,
|
||||
|
||||
// <span className={`${showOp}`}>
|
||||
// <button
|
||||
// onClick={() => this.selectAll()}
|
||||
// className="select-btn"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.selectAll")}
|
||||
// </button>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
// />
|
||||
|
||||
// {itemList}
|
||||
// </div>
|
||||
// </div>
|
||||
// ) : null;
|
||||
|
||||
// const uploadingList = this.props.browser.uploadings.map(
|
||||
// (uploading: UploadEntry) => {
|
||||
// const pathParts = uploading.filePath.split("/");
|
||||
// const fileName = pathParts[pathParts.length - 1];
|
||||
|
||||
// return (
|
||||
// <div key={uploading.filePath}>
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span className="padding-m">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiUploadCloudLine
|
||||
// size="3rem"
|
||||
// id="icon-upload"
|
||||
// className="margin-r-m blue0-font"
|
||||
// />,
|
||||
|
||||
// <div className={`${nameWidthClass}`}>
|
||||
// <span className="title-m">{fileName}</span>
|
||||
// <div className="desc-m grey0-font">
|
||||
// {FileSize(uploading.uploaded, { round: 0 })}
|
||||
// / {FileSize(uploading.size, { round: 0 })}
|
||||
// </div>
|
||||
// </div>,
|
||||
// ])}
|
||||
// />
|
||||
// </span>,
|
||||
|
||||
// <div className="item-op">
|
||||
// <button
|
||||
// onClick={() => this.stopUploading(uploading.filePath)}
|
||||
// className="float-input"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.stop")}
|
||||
// </button>
|
||||
// <button
|
||||
// onClick={() => this.deleteUpload(uploading.filePath)}
|
||||
// className="float-input"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.delete")}
|
||||
// </button>
|
||||
// </div>,
|
||||
// ])}
|
||||
// childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
// />
|
||||
// {uploading.err.trim() === "" ? null : (
|
||||
// <div className="error">{uploading.err.trim()}</div>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
|
||||
// const uploadingListPane =
|
||||
// this.props.browser.tab === "uploading" ? (
|
||||
// this.props.browser.uploadings.size === 0 ? (
|
||||
// <div className="container">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiEmotionSadLine
|
||||
// size="4rem"
|
||||
// className="margin-r-m red0-font"
|
||||
// />,
|
||||
// <span>
|
||||
// <h3 className="title-l">
|
||||
// {this.props.msg.pkg.get("upload.404.title")}
|
||||
// </h3>
|
||||
// <span className="desc-l grey0-font">
|
||||
// {this.props.msg.pkg.get("upload.404.desc")}
|
||||
// </span>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "auto", justifyContent: "flex-end" },
|
||||
// { flex: "auto" },
|
||||
// ])}
|
||||
// className="padding-l"
|
||||
// />
|
||||
// </div>
|
||||
// ) : (
|
||||
// <div className="container">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span className="upload-item">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiUploadCloudFill
|
||||
// size="3rem"
|
||||
// className="margin-r-m black-font"
|
||||
// />,
|
||||
|
||||
// <span>
|
||||
// <span className="title-m bold">
|
||||
// {this.props.msg.pkg.get("browser.upload.title")}
|
||||
// </span>
|
||||
// <span className="desc-m grey0-font">
|
||||
// {this.props.msg.pkg.get("browser.upload.desc")}
|
||||
// </span>
|
||||
// </span>,
|
||||
// ])}
|
||||
// />
|
||||
// </span>,
|
||||
|
||||
// <span></span>,
|
||||
// ])}
|
||||
// />
|
||||
|
||||
// {uploadingList}
|
||||
// </div>
|
||||
// )
|
||||
// ) : null;
|
||||
|
||||
// const sharingList = this.props.browser.sharings.map((dirPath: string) => {
|
||||
// return (
|
||||
// <div id="share-list" key={dirPath}>
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiFolderSharedFill
|
||||
// size="3rem"
|
||||
// className="purple0-font margin-r-m"
|
||||
// />,
|
||||
// <span>{dirPath}</span>,
|
||||
// ])}
|
||||
// />,
|
||||
|
||||
// <span>
|
||||
// <input
|
||||
// type="text"
|
||||
// readOnly
|
||||
// className="float-input"
|
||||
// value={`${
|
||||
// document.location.href.split("?")[0]
|
||||
// }?dir=${encodeURIComponent(dirPath)}`}
|
||||
// />
|
||||
// <button
|
||||
// onClick={() => {
|
||||
// this.deleteSharing(dirPath);
|
||||
// }}
|
||||
// className="float-input"
|
||||
// >
|
||||
// {this.props.msg.pkg.get("browser.share.del")}
|
||||
// </button>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// });
|
||||
|
||||
// const sharingListPane =
|
||||
// this.props.browser.tab === "sharing" ? (
|
||||
// this.props.browser.sharings.size === 0 ? (
|
||||
// <div className="container">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiEmotionSadLine
|
||||
// size="4rem"
|
||||
// className="margin-r-m red0-font"
|
||||
// />,
|
||||
// <span>
|
||||
// <h3 className="title-l">
|
||||
// {this.props.msg.pkg.get("share.404.title")}
|
||||
// </h3>
|
||||
// <span className="desc-l grey0-font">
|
||||
// {this.props.msg.pkg.get("share.404.desc")}
|
||||
// </span>
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([
|
||||
// { flex: "auto", justifyContent: "flex-end" },
|
||||
// { flex: "auto" },
|
||||
// ])}
|
||||
// className="padding-l"
|
||||
// />
|
||||
// </div>
|
||||
// ) : (
|
||||
// <div className="container">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <span className="padding-m">
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiShareBoxLine
|
||||
// size="3rem"
|
||||
// className="margin-r-m black-font"
|
||||
// />,
|
||||
|
||||
// <span>
|
||||
// <span className="title-m bold">
|
||||
// {this.props.msg.pkg.get("browser.share.title")}
|
||||
// </span>
|
||||
// <span className="desc-m grey0-font">
|
||||
// {this.props.msg.pkg.get("browser.share.desc")}
|
||||
// </span>
|
||||
// </span>,
|
||||
// ])}
|
||||
// />
|
||||
// </span>,
|
||||
|
||||
// <span></span>,
|
||||
// ])}
|
||||
// />
|
||||
|
||||
// {sharingList}
|
||||
// </div>
|
||||
// )
|
||||
// ) : null;
|
||||
|
||||
// const showTabs = this.props.login.userRole === roleVisitor ? "hidden" : "";
|
||||
// return (
|
||||
// <div>
|
||||
// <div id="browser">
|
||||
// <div className={`container ${showTabs}`}>
|
||||
// <div id="tabs">
|
||||
// <button
|
||||
// onClick={() => {
|
||||
// this.setTab("item");
|
||||
// }}
|
||||
// className="float"
|
||||
// >
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiFolder2Fill
|
||||
// size="1.6rem"
|
||||
// className="margin-r-s cyan0-font"
|
||||
// />,
|
||||
// <span>{this.props.msg.pkg.get("browser.item.title")}</span>,
|
||||
// ])}
|
||||
// childrenStyles={List([{ flex: "30%" }, { flex: "70%" }])}
|
||||
// />
|
||||
// </button>
|
||||
// <button
|
||||
// onClick={() => {
|
||||
// this.setTab("uploading");
|
||||
// }}
|
||||
// className="float"
|
||||
// >
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiUploadCloudFill
|
||||
// size="1.6rem"
|
||||
// className="margin-r-s blue0-font"
|
||||
// />,
|
||||
// <span>
|
||||
// {this.props.msg.pkg.get("browser.upload.title")}
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([{ flex: "30%" }, { flex: "70%" }])}
|
||||
// />
|
||||
// </button>
|
||||
// <button
|
||||
// onClick={() => {
|
||||
// this.setTab("sharing");
|
||||
// }}
|
||||
// className="float"
|
||||
// >
|
||||
// <Flexbox
|
||||
// children={List([
|
||||
// <RiShareBoxLine
|
||||
// size="1.6rem"
|
||||
// className="margin-r-s purple0-font"
|
||||
// />,
|
||||
// <span>
|
||||
// {this.props.msg.pkg.get("browser.share.title")}
|
||||
// </span>,
|
||||
// ])}
|
||||
// childrenStyles={List([{ flex: "30%" }, { flex: "70%" }])}
|
||||
// />
|
||||
// </button>
|
||||
// </div>
|
||||
// </div>
|
||||
|
||||
// <div>{sharingListPane}</div>
|
||||
// <div>{uploadingListPane}</div>
|
||||
// {itemListPane}
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// }
|
|
@ -1,16 +1,13 @@
|
|||
import * as React from "react";
|
||||
import { List } from "immutable";
|
||||
|
||||
import { updater } from "../state_updater";
|
||||
|
||||
export interface Cell {
|
||||
elem: React.ReactNode;
|
||||
elem: React.ReactNode; // element to display
|
||||
val: string; // original cell value
|
||||
// sortVal: string; // this value is for sorting
|
||||
}
|
||||
|
||||
export interface Row {
|
||||
cells: List<Cell>;
|
||||
cells: List<Cell>; // columns of arow
|
||||
val: Object; // original object value
|
||||
}
|
||||
|
||||
|
@ -27,8 +24,8 @@ export interface Props {
|
|||
id?: string;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
originalVals?: List<Object>;
|
||||
updateRows?: (rows: Object) => void;
|
||||
originalVals?: List<Object>; // these are original values which will be updated to the state after re-sorting
|
||||
updateRows?: (rows: Object) => void; // this is a callback which update state with re-sorted rows
|
||||
}
|
||||
|
||||
export interface State {
|
||||
|
@ -151,51 +148,3 @@ export class Table extends React.Component<Props, State, {}> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// export const Table = (props: Props) => {
|
||||
// const headCols = props.head.map((head: Head, i: number): React.ReactNode => {
|
||||
// const style = props.colStyles != null ? props.colStyles.get(i) : {};
|
||||
// return (
|
||||
// <th key={`h-${i}`} className="title-xs clickable" style={style}>
|
||||
// {head.elem}
|
||||
// </th>
|
||||
// );
|
||||
// });
|
||||
|
||||
// const bodyRows = props.rows.map(
|
||||
// (row: List<Cell>, i: number): React.ReactNode => {
|
||||
// const tds = row.map((cell: Cell, j: number) => {
|
||||
// const style = props.colStyles != null ? props.colStyles.get(j) : {};
|
||||
// return (
|
||||
// <td key={`rc-${i}-${j}`} style={style}>
|
||||
// {cell.elem}
|
||||
// </td>
|
||||
// );
|
||||
// });
|
||||
// return <tr key={`r-${i}`}>{tds}</tr>;
|
||||
// }
|
||||
// );
|
||||
|
||||
// const footCols = props.foot.map(
|
||||
// (elem: React.ReactNode, i: number): React.ReactNode => {
|
||||
// const style = props.colStyles != null ? props.colStyles.get(i) : {};
|
||||
// return (
|
||||
// <th key={`f-${i}`} style={style}>
|
||||
// {elem}
|
||||
// </th>
|
||||
// );
|
||||
// }
|
||||
// );
|
||||
|
||||
// return (
|
||||
// <table id={props.id} style={props.style} className={props.className}>
|
||||
// <thead>
|
||||
// <tr>{headCols}</tr>
|
||||
// </thead>
|
||||
// <tbody>{bodyRows}</tbody>
|
||||
// <tfoot>
|
||||
// <tr>{footCols}</tr>
|
||||
// </tfoot>
|
||||
// </table>
|
||||
// );
|
||||
// };
|
||||
|
|
|
@ -87,7 +87,7 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
|||
infos: Map<string, UploadEntry>,
|
||||
refresh: boolean
|
||||
) => {
|
||||
updater().setUploadings(infos);
|
||||
updater().setUploads(infos);
|
||||
let errCount = 0;
|
||||
infos.valueSeq().forEach((entry: UploadEntry) => {
|
||||
errCount += entry.state === UploadState.Error ? 1 : 0;
|
||||
|
@ -126,7 +126,11 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
|||
for (let i = 0; i < event.target.files.length; i++) {
|
||||
fileList = fileList.push(event.target.files[i]);
|
||||
}
|
||||
updater().addUploads(fileList);
|
||||
|
||||
const status = updater().addUploads(fileList);
|
||||
if (status !== "") {
|
||||
alertMsg(this.props.msg.pkg.get("upload.add.fail"));
|
||||
}
|
||||
this.props.update(updater().updateUploadingsInfo);
|
||||
};
|
||||
|
||||
|
|
|
@ -35,26 +35,16 @@ export class UploadingsPanel extends React.Component<Props, State, {}> {
|
|||
this.state = {};
|
||||
}
|
||||
|
||||
addUploads = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files.length > 1000) {
|
||||
alertMsg(this.props.msg.pkg.get("err.tooManyUploads"));
|
||||
return;
|
||||
}
|
||||
|
||||
let fileList = List<File>();
|
||||
for (let i = 0; i < event.target.files.length; i++) {
|
||||
fileList = fileList.push(event.target.files[i]);
|
||||
}
|
||||
updater().addUploads(fileList);
|
||||
this.props.update(updater().updateUploadingsInfo);
|
||||
};
|
||||
|
||||
deleteUpload = (filePath: string): Promise<void> => {
|
||||
return updater()
|
||||
.deleteUpload(filePath)
|
||||
.then((ok: boolean) => {
|
||||
if (!ok) {
|
||||
alertMsg(this.props.msg.pkg.get("browser.upload.del.fail"));
|
||||
.then((status: string) => {
|
||||
if (status !== "") {
|
||||
alertMsg(
|
||||
`${this.props.msg.pkg.get(
|
||||
"browser.upload.del.fail"
|
||||
)}: ${this.props.msg.pkg.get(status)}`
|
||||
);
|
||||
}
|
||||
return updater().refreshUploadings();
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
ctrlOff,
|
||||
ctrlHidden,
|
||||
} from "./core_state";
|
||||
import { getItemPath } from "./browser";
|
||||
import { getItemPath } from "../common/utils";
|
||||
import {
|
||||
User,
|
||||
ListUsersResp,
|
||||
|
@ -38,10 +38,6 @@ import { settingsDialogCtrl } from "./layers";
|
|||
|
||||
import { MsgPackage, isValidLanPack } from "../i18n/msger";
|
||||
|
||||
function getCookieLanKey(user: string) {
|
||||
return `qs_${user}_lan`;
|
||||
}
|
||||
|
||||
export class Updater {
|
||||
props: ICoreState;
|
||||
private usersClient: IUsersClient = new UsersClient("");
|
||||
|
@ -59,31 +55,41 @@ export class Updater {
|
|||
this.settingsClient = settingsClient;
|
||||
}
|
||||
|
||||
initUploads = () => {
|
||||
initUploads = (): string => {
|
||||
this.props.uploadingsInfo.uploadings.forEach((entry) => {
|
||||
Up().addStopped(entry.filePath, entry.uploaded, entry.size);
|
||||
});
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
addUploads = (fileList: List<File>) => {
|
||||
addUploads = (fileList: List<File>): string => {
|
||||
fileList.forEach((file) => {
|
||||
const filePath = getItemPath(
|
||||
this.props.filesInfo.dirPath.join("/"),
|
||||
file.name
|
||||
);
|
||||
// do not wait for the promise
|
||||
Up().add(file, filePath);
|
||||
const status = Up().add(file, filePath);
|
||||
if (status !== ""){
|
||||
return status;
|
||||
}
|
||||
});
|
||||
this.setUploadings(Up().list());
|
||||
|
||||
this.setUploads(Up().list());
|
||||
return "";
|
||||
};
|
||||
|
||||
deleteUpload = async (filePath: string): Promise<boolean> => {
|
||||
Up().delete(filePath);
|
||||
deleteUpload = async (filePath: string): Promise<string> => {
|
||||
const status = Up().delete(filePath);
|
||||
if (status !== "") {
|
||||
return status;
|
||||
}
|
||||
|
||||
const resp = await this.filesClient.deleteUploading(filePath);
|
||||
return resp.status === 200;
|
||||
return resp.status === 200 ? "" : "server.fail";
|
||||
};
|
||||
|
||||
setUploadings = (infos: Map<string, UploadEntry>) => {
|
||||
setUploads = (infos: Map<string, UploadEntry>) => {
|
||||
this.props.uploadingsInfo.uploadings = List<UploadEntry>(
|
||||
infos.valueSeq().map((entry: UploadEntry): UploadEntry => {
|
||||
return entry;
|
||||
|
@ -369,11 +375,8 @@ export class Updater {
|
|||
|
||||
initStateForAuthedUser = async (): Promise<any> => {
|
||||
// TOOD: status is ignored, should return alert
|
||||
return Promise.all([
|
||||
this.refreshUploadings(),
|
||||
this.initUploads(),
|
||||
this.listSharings(),
|
||||
]);
|
||||
this.initUploads(); // ignore return because it always succeed
|
||||
return Promise.all([this.refreshUploadings(), this.listSharings()]);
|
||||
};
|
||||
|
||||
initStateForAdmin = async (): Promise<any> => {
|
||||
|
|
|
@ -111,4 +111,6 @@ export const msgs: Map<string, string> = Map({
|
|||
"control.panelTabs.sharingsPanel": "Sharings",
|
||||
"control.settingsTabs.managementPane": "Management",
|
||||
"control.settingsTabs.preferencePane": "Preference",
|
||||
"upload.add.fail": "Some files conflict with uploading files, please check.",
|
||||
"server.fail": "The operation failed in the server",
|
||||
});
|
||||
|
|
|
@ -110,4 +110,6 @@ export const msgs: Map<string, string> = Map({
|
|||
"control.panelTabs.sharingsPanel": "共享",
|
||||
"control.settingsTabs.managementPane": "管理",
|
||||
"control.settingsTabs.preferencePane": "设置",
|
||||
"upload.add.fail": "有些文件与上传任务冲突,请检查",
|
||||
"server.fail": "操作在服务器端失败",
|
||||
});
|
||||
|
|
|
@ -98,7 +98,7 @@ export class UploadMgr {
|
|||
this.statusCb = cb;
|
||||
};
|
||||
|
||||
// addStopped is for initializing uploading list in the UploadMgr
|
||||
// addStopped is for initializing uploading list in the UploadMgr, when page is loaded
|
||||
// notice even uploading list are shown in the UI, it may not inited in the UploadMgr
|
||||
addStopped = (filePath: string, uploaded: number, fileSize: number) => {
|
||||
this.infos = this.infos.set(filePath, {
|
||||
|
@ -111,8 +111,10 @@ export class UploadMgr {
|
|||
});
|
||||
};
|
||||
|
||||
add = (file: File, filePath: string) => {
|
||||
add = (file: File, filePath: string): string => {
|
||||
const entry = this.infos.get(filePath);
|
||||
let status = "";
|
||||
|
||||
if (entry == null) {
|
||||
// new uploading
|
||||
this.infos = this.infos.set(filePath, {
|
||||
|
@ -124,46 +126,55 @@ export class UploadMgr {
|
|||
err: "",
|
||||
});
|
||||
} else {
|
||||
// restart the uploading
|
||||
// the uploading task exists, restart the uploading
|
||||
if (
|
||||
entry.state === UploadState.Stopped &&
|
||||
filePath === entry.filePath &&
|
||||
file.size === entry.size
|
||||
) {
|
||||
// try to upload a file with same name but actually with different content.
|
||||
// it still can not resolve one case: names and sizes are same, but contents are different
|
||||
// TODO: showing file SHA will avoid above case
|
||||
// try to upload a file with same name
|
||||
// the file may be a totally different file.
|
||||
// TODO: checking file SHA will avoid above case
|
||||
this.infos = this.infos.set(filePath, {
|
||||
...entry,
|
||||
file: file,
|
||||
state: UploadState.Ready,
|
||||
});
|
||||
} else {
|
||||
alert(
|
||||
`(${filePath}) seems not same file with uploading item, please check.`
|
||||
);
|
||||
status = "op.fail";
|
||||
}
|
||||
}
|
||||
|
||||
this.statusCb(this.infos.toMap(), false);
|
||||
return status;
|
||||
};
|
||||
|
||||
stop = (filePath: string) => {
|
||||
stop = (filePath: string): string => {
|
||||
const entry = this.infos.get(filePath);
|
||||
let status = "";
|
||||
|
||||
if (entry != null) {
|
||||
this.infos = this.infos.set(filePath, {
|
||||
...entry,
|
||||
state: UploadState.Stopped,
|
||||
});
|
||||
} else {
|
||||
alert(`failed to stop uploading ${filePath}: not found`);
|
||||
status = "op.fail";
|
||||
}
|
||||
|
||||
this.statusCb(this.infos.toMap(), false);
|
||||
return status;
|
||||
};
|
||||
|
||||
delete = (filePath: string) => {
|
||||
this.stop(filePath);
|
||||
delete = (filePath: string): string => {
|
||||
const status = this.stop(filePath);
|
||||
if (status !== "") {
|
||||
return status;
|
||||
}
|
||||
|
||||
this.infos = this.infos.delete(filePath);
|
||||
this.statusCb(this.infos.toMap(), false);
|
||||
return "";
|
||||
};
|
||||
|
||||
list = (): OrderedMap<string, UploadEntry> => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue