feat: support refreshing hash
This commit is contained in:
parent
f8bb187c89
commit
ec1bb36c21
11 changed files with 99 additions and 36 deletions
|
@ -731,3 +731,11 @@ div.hr {
|
|||
color: #e74c3c;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.detail {
|
||||
font-size: 1.2rem;
|
||||
line-height: 2rem;
|
||||
margin: 0 1rem 1rem 1rem;
|
||||
padding: 1rem;
|
||||
border-top: dashed 1px #7f8c8d;
|
||||
}
|
||||
|
|
|
@ -205,3 +205,12 @@ func (cl *FilesClient) ListSharings() (*http.Response, *fileshdr.SharingResp, []
|
|||
}
|
||||
return resp, shResp, nil
|
||||
}
|
||||
|
||||
func (cl *FilesClient) GenerateHash(filepath string) (*http.Response, string, []error) {
|
||||
return cl.r.Post(cl.url("/v1/fs/hashes/sha1")).
|
||||
AddCookie(cl.token).
|
||||
Send(fileshdr.GenerateHashReq{
|
||||
FilePath: filepath,
|
||||
}).
|
||||
End()
|
||||
}
|
||||
|
|
|
@ -198,4 +198,14 @@ export class FilesClient extends BaseClient {
|
|||
url: `${this.url}/v1/fs/sharings`,
|
||||
});
|
||||
};
|
||||
|
||||
generateHash = (filePath: string): Promise<Response> => {
|
||||
return this.do({
|
||||
method: "post",
|
||||
url: `${this.url}/v1/fs/hashes/sha1`,
|
||||
data: {
|
||||
filePath: filePath,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ export interface FilesClientResps {
|
|||
deleteSharingMockResp?: Response;
|
||||
listSharingsMockResp?: Response<ListSharingsResp>;
|
||||
isSharingMockResp?: Response;
|
||||
generateHashMockResp?: Response;
|
||||
}
|
||||
|
||||
export const resps = {
|
||||
|
@ -130,7 +131,9 @@ export const resps = {
|
|||
},
|
||||
},
|
||||
isSharingMockResp: { status: 200, statusText: "", data: {} },
|
||||
generateHashMockResp: { status: 200, statusText: "", data: {} },
|
||||
};
|
||||
|
||||
export class MockFilesClient {
|
||||
private url: string;
|
||||
private resps: FilesClientResps;
|
||||
|
@ -213,4 +216,8 @@ export class MockFilesClient {
|
|||
isSharing = (dirPath: string): Promise<Response> => {
|
||||
return this.wrapPromise(this.resps.isSharingMockResp);
|
||||
};
|
||||
|
||||
generateHash = (filePath: string): Promise<Response> => {
|
||||
return this.wrapPromise(this.resps.generateHashMockResp);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ export interface IFilesClient {
|
|||
deleteSharing: (dirPath: string) => Promise<Response>;
|
||||
isSharing: (dirPath: string) => Promise<Response>;
|
||||
listSharings: () => Promise<Response<ListSharingsResp>>;
|
||||
generateHash: (filePath: string) => Promise<Response>;
|
||||
}
|
||||
|
||||
export interface Response<T = any> {
|
||||
|
|
|
@ -2,6 +2,7 @@ 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";
|
||||
|
@ -318,10 +319,17 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
};
|
||||
|
||||
toggleDetail = (name: string) => {
|
||||
const showDetail = this.state.showDetail.has(name) ? this.state.showDetail.delete(name) : this.state.showDetail.add(name);
|
||||
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" : "";
|
||||
|
||||
|
@ -341,7 +349,8 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
}
|
||||
);
|
||||
|
||||
const nameCellClass = `item-name item-name-${this.props.browser.isVertical ? "vertical" : "horizontal"
|
||||
const nameCellClass = `item-name item-name-${
|
||||
this.props.browser.isVertical ? "vertical" : "horizontal"
|
||||
} pointer`;
|
||||
const sizeCellClass = this.props.browser.isVertical
|
||||
? `hidden margin-s`
|
||||
|
@ -434,7 +443,8 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
<span className={`padding-m ${showOp}`}>
|
||||
<button
|
||||
onClick={() => this.select(item.name)}
|
||||
className={`${isSelected ? "blue0-bg white-font" : "grey2-bg grey3-font"
|
||||
className={`${
|
||||
isSelected ? "blue0-bg white-font" : "grey2-bg grey3-font"
|
||||
}`}
|
||||
style={{ width: "8rem", display: "inline-block" }}
|
||||
>
|
||||
|
@ -442,26 +452,21 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
? this.props.msg.pkg.get("browser.deselect")
|
||||
: this.props.msg.pkg.get("browser.select")}
|
||||
</button>
|
||||
{/* <button
|
||||
onClick={() => this.toggleDetail(item.name)}
|
||||
className="grey2-bg grey3-font"
|
||||
style={{ width: "8rem", display: "inline-block" }}
|
||||
>
|
||||
{this.props.msg.pkg.get("detail")}
|
||||
</button> */}
|
||||
</span>,
|
||||
])}
|
||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
/>
|
||||
) : (
|
||||
<div key={item.name}>
|
||||
|
||||
<Flexbox
|
||||
children={List([
|
||||
<span className="padding-m">
|
||||
<Flexbox
|
||||
children={List([
|
||||
<RiFile2Fill size="3rem" className="cyan0-font margin-r-m" />,
|
||||
<RiFile2Fill
|
||||
size="3rem"
|
||||
className="cyan0-font margin-r-m"
|
||||
/>,
|
||||
|
||||
<span className={`${nameCellClass}`}>
|
||||
<a
|
||||
|
@ -486,7 +491,7 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
<span className={`item-op padding-m ${showOp}`}>
|
||||
<button
|
||||
onClick={() => this.toggleDetail(item.name)}
|
||||
className="grey2-bg grey3-font"
|
||||
className="grey2-bg grey3-font margin-r-m"
|
||||
style={{ width: "8rem", display: "inline-block" }}
|
||||
>
|
||||
{this.props.msg.pkg.get("detail")}
|
||||
|
@ -495,7 +500,8 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => this.select(item.name)}
|
||||
className={`${isSelected ? "blue0-bg white-font" : "grey2-bg grey3-font"
|
||||
className={`${
|
||||
isSelected ? "blue0-bg white-font" : "grey2-bg grey3-font"
|
||||
}`}
|
||||
style={{ width: "8rem", display: "inline-block" }}
|
||||
>
|
||||
|
@ -508,9 +514,27 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
/>
|
||||
<div
|
||||
className={`grey2-bg grey3-font margin-l ${this.state.showDetail.has(item.name) ? "" : "hidden"}`}
|
||||
className={`${
|
||||
this.state.showDetail.has(item.name) ? "" : "hidden"
|
||||
}`}
|
||||
>
|
||||
<span className="margin-l">{`SHA1: ${item.sha1}`}</span>
|
||||
<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>
|
||||
);
|
||||
|
@ -672,9 +696,7 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
/>
|
||||
{uploading.err.trim() === "" ? null : (
|
||||
<div className="alert-red margin-s">
|
||||
<span className="padding-m">
|
||||
{uploading.err.trim()}
|
||||
</span>
|
||||
<span className="padding-m">{uploading.err.trim()}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -761,7 +783,8 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
type="text"
|
||||
readOnly
|
||||
className="margin-r-m"
|
||||
value={`${document.location.href.split("?")[0]
|
||||
value={`${
|
||||
document.location.href.split("?")[0]
|
||||
}?dir=${encodeURIComponent(dirPath)}`}
|
||||
/>
|
||||
<button
|
||||
|
@ -902,12 +925,8 @@ export class Browser extends React.Component<Props, State, {}> {
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{sharingListPane}
|
||||
</div>
|
||||
<div>
|
||||
{uploadingListPane}
|
||||
</div>
|
||||
<div>{sharingListPane}</div>
|
||||
<div>{uploadingListPane}</div>
|
||||
{itemListPane}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -548,6 +548,11 @@ export class Updater {
|
|||
}
|
||||
};
|
||||
|
||||
generateHash = async (filePath: string): Promise<boolean> => {
|
||||
const resp = await this.filesClient.generateHash(filePath);
|
||||
return resp.status === 200;
|
||||
};
|
||||
|
||||
updateBrowser = (prevState: ICoreState): ICoreState => {
|
||||
return {
|
||||
...prevState,
|
||||
|
|
|
@ -75,4 +75,6 @@ export const msgs: Map<string, string> = Map({
|
|||
"upload.404.title": "No uploading is in the progress",
|
||||
"upload.404.desc": "You can upload a file in the items tab",
|
||||
"detail": "Detail",
|
||||
"refresh": "Refresh",
|
||||
"refresh-hint": "Please refresh later to see the result",
|
||||
});
|
||||
|
|
|
@ -73,4 +73,6 @@ export const msgs: Map<string, string> = Map({
|
|||
"upload.404.title": "没有正在上传的文件",
|
||||
"upload.404.desc": "在列表面板可以上传文件",
|
||||
"detail": "详细",
|
||||
"refresh": "刷新",
|
||||
"refresh-hint": "请稍后刷新查看结果",
|
||||
});
|
||||
|
|
|
@ -903,12 +903,12 @@ func (h *FileHandlers) ListSharings(c *gin.Context) {
|
|||
c.JSON(200, &SharingResp{SharingDirs: dirs})
|
||||
}
|
||||
|
||||
type HashBody struct {
|
||||
type GenerateHashReq struct {
|
||||
FilePath string `json:"filePath"`
|
||||
}
|
||||
|
||||
func (h *FileHandlers) GenerateHash(c *gin.Context) {
|
||||
req := &HashBody{}
|
||||
req := &GenerateHashReq{}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(q.ErrResp(c, 400, err))
|
||||
return
|
||||
|
|
|
@ -69,7 +69,7 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
|
|||
apiRuleCname(userstore.AdminRole, "DELETE", "/v1/fs/sharings"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/v1/fs/sharings"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/v1/fs/sharings/exist"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/hashes/sha1"): true,
|
||||
apiRuleCname(userstore.AdminRole, "POST", "/v1/fs/hashes/sha1"): true,
|
||||
|
||||
// user rules
|
||||
apiRuleCname(userstore.UserRole, "GET", "/"): true,
|
||||
|
@ -99,7 +99,7 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
|
|||
apiRuleCname(userstore.UserRole, "DELETE", "/v1/fs/sharings"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", "/v1/fs/sharings"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", "/v1/fs/sharings/exist"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/hashes/sha1"): true,
|
||||
apiRuleCname(userstore.AdminRole, "POST", "/v1/fs/hashes/sha1"): true,
|
||||
// visitor rules
|
||||
apiRuleCname(userstore.VisitorRole, "GET", "/"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "GET", publicPath): true,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue