feat(fe/files panel): enable download URL QR code
This commit is contained in:
parent
f46d492d44
commit
1ff7cfc141
7 changed files with 93 additions and 34 deletions
|
@ -498,3 +498,7 @@
|
||||||
.bold {
|
.bold {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fix {
|
||||||
|
clear: both;
|
||||||
|
}
|
|
@ -196,6 +196,29 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-default #item-rows .column {
|
||||||
|
width: 50%;
|
||||||
|
max-width: 100%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default #browser .info {
|
||||||
|
border: dashed 1px #95a5a6;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
padding: 1rem;
|
||||||
|
color: #697384;
|
||||||
|
margin: 1rem 0 0 0;
|
||||||
|
background-color: #ecf0f1;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-default .qrcode {
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: #ecf0f1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-default .item-cell {
|
.theme-default .item-cell {
|
||||||
height: 5rem;
|
height: 5rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
"react-copy-to-clipboard": "^5.0.1",
|
"react-copy-to-clipboard": "^5.0.1",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-icons": "4.3.1",
|
"react-icons": "4.3.1",
|
||||||
|
"react-qr-code": "^2.0.3",
|
||||||
"react-svg": "^8.0.6",
|
"react-svg": "^8.0.6",
|
||||||
"throttle-debounce": "^2.1.0",
|
"throttle-debounce": "^2.1.0",
|
||||||
"webpack-bundle-analyzer": "^4.4.2",
|
"webpack-bundle-analyzer": "^4.4.2",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
import { List, Map, Set } from "immutable";
|
import { List, Map, Set } from "immutable";
|
||||||
import FileSize from "filesize";
|
import FileSize from "filesize";
|
||||||
|
import QRCode from "react-qr-code";
|
||||||
|
|
||||||
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
import { RiFolder2Fill } from "@react-icons/all-files/ri/RiFolder2Fill";
|
||||||
import { RiArchiveDrawerFill } from "@react-icons/all-files/ri/RiArchiveDrawerFill";
|
import { RiArchiveDrawerFill } from "@react-icons/all-files/ri/RiArchiveDrawerFill";
|
||||||
|
@ -11,6 +12,7 @@ import { RiCheckboxFill } from "@react-icons/all-files/ri/RiCheckboxFill";
|
||||||
import { RiInformationFill } from "@react-icons/all-files/ri/RiInformationFill";
|
import { RiInformationFill } from "@react-icons/all-files/ri/RiInformationFill";
|
||||||
import { BiTable } from "@react-icons/all-files/bi/BiTable";
|
import { BiTable } from "@react-icons/all-files/bi/BiTable";
|
||||||
import { BiListUl } from "@react-icons/all-files/bi/BiListUl";
|
import { BiListUl } from "@react-icons/all-files/bi/BiListUl";
|
||||||
|
import { RiRefreshLine } from "@react-icons/all-files/ri/RiRefreshLine";
|
||||||
|
|
||||||
import { ErrorLogger } from "../common/log_error";
|
import { ErrorLogger } from "../common/log_error";
|
||||||
import { alertMsg, confirmMsg } from "../common/env";
|
import { alertMsg, confirmMsg } from "../common/env";
|
||||||
|
@ -465,17 +467,17 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
>
|
>
|
||||||
<Flexbox
|
<Flexbox
|
||||||
children={List([
|
children={List([
|
||||||
<span>
|
<div className="label">{`SHA1: `}</div>,
|
||||||
<div className="label">{`SHA1: `}</div>
|
<RiRefreshLine
|
||||||
<input type="text" readOnly={true} value={`${item.sha1}`} />
|
onClick={() => this.generateHash(itemPath)}
|
||||||
</span>,
|
size={"2rem"}
|
||||||
<button onClick={() => this.generateHash(itemPath)}>
|
className="black-font"
|
||||||
{this.props.msg.pkg.get("refresh")}
|
/>,
|
||||||
</button>,
|
|
||||||
])}
|
])}
|
||||||
className="item-info"
|
className="item-info"
|
||||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||||
/>
|
/>
|
||||||
|
<div className="info">{item.sha1}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -582,16 +584,13 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
? this.props.msg.pkg.get("item.type.folder")
|
? this.props.msg.pkg.get("item.type.folder")
|
||||||
: this.props.msg.pkg.get("item.type.file");
|
: this.props.msg.pkg.get("item.type.file");
|
||||||
|
|
||||||
|
const downloadPath = `/v1/fs/files?fp=${itemPath}`;
|
||||||
const name = item.isDir ? (
|
const name = item.isDir ? (
|
||||||
<span className="clickable" onClick={() => this.gotoChild(item.name)}>
|
<span className="clickable" onClick={() => this.gotoChild(item.name)}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<a
|
<a className="title-m clickable" href={downloadPath} target="_blank">
|
||||||
className="title-m clickable"
|
|
||||||
href={`/v1/fs/files?fp=${itemPath}`}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
{item.name}
|
{item.name}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
@ -620,7 +619,8 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const pathTitle = this.props.msg.pkg.get("item.path");
|
const absDownloadURL = `${document.location.protocol}//${document.location.hostname}${downloadPath}`;
|
||||||
|
const pathTitle = this.props.msg.pkg.get("item.downloadURL");
|
||||||
const modTimeTitle = this.props.msg.pkg.get("item.modTime");
|
const modTimeTitle = this.props.msg.pkg.get("item.modTime");
|
||||||
const sizeTitle = this.props.msg.pkg.get("item.size");
|
const sizeTitle = this.props.msg.pkg.get("item.size");
|
||||||
const fileTypeTitle = this.props.msg.pkg.get("item.type");
|
const fileTypeTitle = this.props.msg.pkg.get("item.type");
|
||||||
|
@ -631,6 +631,7 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
: `${pathTitle}: ${itemPath} | ${modTimeTitle}: ${item.modTime} | ${sizeTitle}: ${itemSize} | sha1: ${item.sha1}`;
|
: `${pathTitle}: ${itemPath} | ${modTimeTitle}: ${item.modTime} | ${sizeTitle}: ${itemSize} | sha1: ${item.sha1}`;
|
||||||
const details = (
|
const details = (
|
||||||
<div>
|
<div>
|
||||||
|
<div className="column">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<span className="title-m black-font">{pathTitle}</span>
|
<span className="title-m black-font">{pathTitle}</span>
|
||||||
<span>{itemPath}</span>
|
<span>{itemPath}</span>
|
||||||
|
@ -643,17 +644,32 @@ export class FilesPanel extends React.Component<Props, State, {}> {
|
||||||
<span className="title-m black-font">{sizeTitle}</span>
|
<span className="title-m black-font">{sizeTitle}</span>
|
||||||
<span>{itemSize}</span>
|
<span>{itemSize}</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="column">
|
||||||
|
<div className="card">
|
||||||
|
<span className="title-m black-font">{pathTitle}</span>
|
||||||
|
<div className="qrcode">
|
||||||
|
<QRCode value={absDownloadURL} size={128} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="fix">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<span className="title-m black-font">SHA1</span>
|
|
||||||
<Flexbox
|
<Flexbox
|
||||||
children={List([
|
children={List([
|
||||||
<input type="text" readOnly={true} value={`${item.sha1}`} />,
|
<span className="title-m black-font">SHA1</span>,
|
||||||
<button onClick={() => this.generateHash(itemPath)}>
|
<RiRefreshLine
|
||||||
{this.props.msg.pkg.get("refresh")}
|
onClick={() => this.generateHash(itemPath)}
|
||||||
</button>,
|
size={"2rem"}
|
||||||
|
className="black-font"
|
||||||
|
/>,
|
||||||
])}
|
])}
|
||||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||||
/>
|
/>
|
||||||
|
<div className="info">{item.sha1}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -126,6 +126,7 @@ export const msgs: Map<string, string> = Map({
|
||||||
"item.modTime": "Mod Time",
|
"item.modTime": "Mod Time",
|
||||||
"item.size": "Size",
|
"item.size": "Size",
|
||||||
"item.progress": "Progress",
|
"item.progress": "Progress",
|
||||||
|
"item.downloadURL": "Download URL",
|
||||||
"error.report.title": "Error Report",
|
"error.report.title": "Error Report",
|
||||||
"op.truncate": "Truncate",
|
"op.truncate": "Truncate",
|
||||||
"op.submit": "Submit",
|
"op.submit": "Submit",
|
||||||
|
|
|
@ -123,6 +123,7 @@ export const msgs: Map<string, string> = Map({
|
||||||
"item.modTime": "修改时间",
|
"item.modTime": "修改时间",
|
||||||
"item.size": "大小",
|
"item.size": "大小",
|
||||||
"item.progress": "进度",
|
"item.progress": "进度",
|
||||||
|
"item.downloadURL": "下载链接",
|
||||||
"error.report.title": "报告错误",
|
"error.report.title": "报告错误",
|
||||||
"op.truncate": "清空",
|
"op.truncate": "清空",
|
||||||
"op.submit": "提交",
|
"op.submit": "提交",
|
||||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -4047,6 +4047,11 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||||
|
|
||||||
|
qr.js@0.0.0:
|
||||||
|
version "0.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
|
||||||
|
integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=
|
||||||
|
|
||||||
randombytes@^2.1.0:
|
randombytes@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
|
@ -4087,6 +4092,14 @@ react-is@^17.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||||
|
|
||||||
|
react-qr-code@^2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-qr-code/-/react-qr-code-2.0.3.tgz#cc80785e08f817d1ab066ca4035262f77d049648"
|
||||||
|
integrity sha512-6GDH0l53lksf2JgZwwcoS0D60a1OAal/GQRyNFkMBW19HjSqvtD5S20scmSQsKl+BgWM85Wd5DCcUYoHd+PZnQ==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
qr.js "0.0.0"
|
||||||
|
|
||||||
react-svg@*:
|
react-svg@*:
|
||||||
version "14.0.13"
|
version "14.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-14.0.13.tgz#fd458d52884efcd8c8a6fb2dc20cc7c603b64b45"
|
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-14.0.13.tgz#fd458d52884efcd8c8a6fb2dc20cc7c603b64b45"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue