feat(ui): support sharing

This commit is contained in:
hexxa 2021-08-18 15:05:50 +08:00 committed by Hexxa
parent 86474e044f
commit 752768a916
8 changed files with 187 additions and 46 deletions

View file

@ -16,8 +16,6 @@ import {
import { Up } from "../worker/upload_mgr"; import { Up } from "../worker/upload_mgr";
import { UploadEntry } from "../worker/interface"; import { UploadEntry } from "../worker/interface";
export const uploadCheckCycle = 1000;
export interface Item { export interface Item {
name: string; name: string;
size: number; size: number;
@ -28,8 +26,10 @@ export interface Item {
export interface Props { export interface Props {
dirPath: List<string>; dirPath: List<string>;
isSharing: boolean;
items: List<MetadataResp>; items: List<MetadataResp>;
uploadings: List<UploadInfo>; uploadings: List<UploadInfo>;
sharings: List<string>;
uploadFiles: List<File>; uploadFiles: List<File>;
uploadValue: string; uploadValue: string;
@ -191,6 +191,12 @@ export class Browser extends React.Component<Props, State, {}> {
updater() updater()
.setItems(dirPath) .setItems(dirPath)
.then(() => {
updater().listSharings();
})
.then(() => {
updater().setSharing(dirPath.join("/"));
})
.then(() => { .then(() => {
this.update(updater().setBrowser); this.update(updater().setBrowser);
}); });
@ -235,6 +241,40 @@ export class Browser extends React.Component<Props, State, {}> {
}); });
}; };
addSharing = () => {
updater()
.addSharing()
.then((ok) => {
if (!ok) {
alert("failed to enable sharing");
} else {
this.listSharings();
}
});
};
deleteSharing = (dirPath: string) => {
updater()
.deleteSharing(dirPath)
.then((ok) => {
if (!ok) {
alert("failed to disable sharing");
} else {
this.listSharings();
}
});
};
listSharings = () => {
updater()
.listSharings()
.then((ok) => {
if (ok) {
this.update(updater().setBrowser);
}
});
};
render() { render() {
const breadcrumb = this.props.dirPath.map( const breadcrumb = this.props.dirPath.map(
(pathPart: string, key: number) => { (pathPart: string, key: number) => {
@ -308,10 +348,29 @@ export class Browser extends React.Component<Props, State, {}> {
<button <button
type="button" type="button"
onClick={() => this.moveHere()} onClick={() => this.moveHere()}
className="grey1-bg white-font margin-t-m margin-b-m" className="grey1-bg white-font margin-t-m margin-b-m margin-r-m"
> >
Paste Paste
</button> </button>
{this.props.isSharing ? (
<button
type="button"
onClick={() => {
this.deleteSharing(this.props.dirPath.join("/"));
}}
className="red0-bg white-font margin-t-m margin-b-m"
>
Stop Sharing
</button>
) : (
<button
type="button"
onClick={this.addSharing}
className="green0-bg white-font margin-t-m margin-b-m"
>
Share Folder
</button>
)}
</div> </div>
</div> </div>
); );
@ -418,6 +477,24 @@ export class Browser extends React.Component<Props, State, {}> {
); );
}); });
const sharingList = this.props.sharings.map((dirPath: string) => {
<div key={dirPath} className="flex-list-container">
<span className="flex-list-item-l">{dirPath}</span>
<span className="flex-list-item-r">
<button
onClick={() => {
this.deleteSharing(dirPath);
}}
className="grey1-bg white-font"
>
Delete
</button>
</span>
</div>;
});
console.log("browser", this.props.sharings, this.props.isSharing);
return ( return (
<div> <div>
<div id="op-bar" className="op-bar"> <div id="op-bar" className="op-bar">
@ -432,7 +509,7 @@ export class Browser extends React.Component<Props, State, {}> {
backgroundColor: "rgba(0, 0, 0, 0.7)", backgroundColor: "rgba(0, 0, 0, 0.7)",
padding: "0.8rem 1rem", padding: "0.8rem 1rem",
fontWeight: "bold", fontWeight: "bold",
borderRadius: "0.5rem" borderRadius: "0.5rem",
}} }}
> >
Location: Location:
@ -453,6 +530,19 @@ export class Browser extends React.Component<Props, State, {}> {
</div> </div>
)} )}
{this.props.sharings.size === 0 ? null : (
<div className="container">
<div className="flex-list-container bold">
<span className="flex-list-item-l">
<span className="dot black-bg"></span>
<span>Uploading Files</span>
</span>
<span className="flex-list-item-r padding-r-m"></span>
</div>
{sharingList}
</div>
)}
<div className="container"> <div className="container">
<div className="flex-list-container bold"> <div className="flex-list-container bold">
<span className="flex-list-item-l"> <span className="flex-list-item-l">

View file

@ -25,21 +25,18 @@ export class Updater {
} }
initUploads = () => { initUploads = () => {
this.props.uploadings.forEach(entry => { this.props.uploadings.forEach((entry) => {
Up().addStopped(entry.realFilePath, entry.uploaded, entry.size); Up().addStopped(entry.realFilePath, entry.uploaded, entry.size);
}) });
// this.setUploadings(Up().list()); // this.setUploadings(Up().list());
}; };
addUploads = (fileList: List<File>) => { addUploads = (fileList: List<File>) => {
fileList.forEach(file => { fileList.forEach((file) => {
const filePath = getItemPath( const filePath = getItemPath(this.props.dirPath.join("/"), file.name);
this.props.dirPath.join("/"),
file.name
);
// do not wait for the promise // do not wait for the promise
Up().add(file, filePath); Up().add(file, filePath);
}) });
this.setUploadings(Up().list()); this.setUploadings(Up().list());
}; };
@ -51,18 +48,42 @@ export class Updater {
setUploadings = (infos: Map<string, UploadEntry>) => { setUploadings = (infos: Map<string, UploadEntry>) => {
this.props.uploadings = List<UploadInfo>( this.props.uploadings = List<UploadInfo>(
infos.valueSeq().map( infos.valueSeq().map((v: UploadEntry): UploadInfo => {
(v: UploadEntry): UploadInfo => { return {
return { realFilePath: v.filePath,
realFilePath: v.filePath, size: v.size,
size: v.size, uploaded: v.uploaded,
uploaded: v.uploaded, };
}; })
}
)
); );
}; };
addSharing = async (): Promise<boolean> => {
const dirPath = this.props.dirPath.join("/");
const resp = await this.filesClient.addSharing(dirPath);
return resp.status === 200;
};
deleteSharing = async (dirPath: string): Promise<boolean> => {
const resp = await this.filesClient.addSharing(dirPath);
return resp.status === 200;
};
setSharing = async (dirPath: string): Promise<boolean> => {
const resp = await this.filesClient.isSharing(dirPath);
this.props.isSharing = resp.status === 200;
return resp.status === 200; // TODO: differentiate 404 and error
};
listSharings = async (): Promise<boolean> => {
const resp = await this.filesClient.listSharings();
this.props.sharings =
resp.status === 200
? List<string>(resp.data.sharingDirs)
: this.props.sharings;
return resp.status === 200;
};
refreshUploadings = async (): Promise<boolean> => { refreshUploadings = async (): Promise<boolean> => {
const luResp = await this.filesClient.listUploadings(); const luResp = await this.filesClient.listUploadings();
@ -93,13 +114,11 @@ export class Updater {
.filter((item) => { .filter((item) => {
return selectedItems.has(item.name); return selectedItems.has(item.name);
}) })
.map( .map(async (selectedItem: MetadataResp): Promise<string> => {
async (selectedItem: MetadataResp): Promise<string> => { const itemPath = getItemPath(dirParts.join("/"), selectedItem.name);
const itemPath = getItemPath(dirParts.join("/"), selectedItem.name); const resp = await this.filesClient.delete(itemPath);
const resp = await this.filesClient.delete(itemPath); return resp.status === 200 ? "" : selectedItem.name;
return resp.status === 200 ? "" : selectedItem.name; });
}
);
const failedFiles = await Promise.all(delRequests); const failedFiles = await Promise.all(delRequests);
failedFiles.forEach((failedFile) => { failedFiles.forEach((failedFile) => {
@ -156,8 +175,13 @@ export class Updater {
}; };
setBrowser = (prevState: ICoreState): ICoreState => { setBrowser = (prevState: ICoreState): ICoreState => {
prevState.panel.browser = { ...prevState.panel, ...this.props }; return {
return prevState; ...prevState,
panel: {
...prevState.panel,
browser: { ...this.props }, // TODO: use spread
},
};
}; };
} }

View file

@ -56,6 +56,8 @@ export function initState(): ICoreState {
isVertical: isVertical(), isVertical: isVertical(),
dirPath: List<string>(["."]), dirPath: List<string>(["."]),
items: List<Item>([]), items: List<Item>([]),
sharings: List<string>([]),
isSharing: false,
uploadings: List<UploadInfo>([]), uploadings: List<UploadInfo>([]),
uploadValue: "", uploadValue: "",
uploadFiles: List<File>([]), uploadFiles: List<File>([]),
@ -91,6 +93,8 @@ export function mockState(): ICoreState {
isVertical: false, isVertical: false,
dirPath: List<string>(["."]), dirPath: List<string>(["."]),
items: List<Item>([]), items: List<Item>([]),
sharings: List<string>([]),
isSharing: false,
uploadings: List<UploadInfo>([]), uploadings: List<UploadInfo>([]),
uploadValue: "", uploadValue: "",
uploadFiles: List<File>([]), uploadFiles: List<File>([]),

View file

@ -377,7 +377,7 @@ export class AdminPane extends React.Component<Props, State, {}> {
render() { render() {
const userList = this.props.users.valueSeq().map((user: User) => { const userList = this.props.users.valueSeq().map((user: User) => {
return ( return (
<div className="margin-t-m"> <div key={user.id} className="margin-t-m">
<UserForm <UserForm
key={user.id} key={user.id}
id={user.id} id={user.id}

View file

@ -139,6 +139,14 @@ export class AuthPane extends React.Component<Props, State, {}> {
.then(() => { .then(() => {
return BrowserUpdater().refreshUploadings(); return BrowserUpdater().refreshUploadings();
}) })
.then(() => {
return BrowserUpdater().setSharing(
BrowserUpdater().props.dirPath.join("/")
);
})
.then(() => {
return BrowserUpdater().listSharings();
})
.then((_: boolean) => { .then((_: boolean) => {
this.update(BrowserUpdater().setBrowser); this.update(BrowserUpdater().setBrowser);
}); });

View file

@ -117,7 +117,6 @@ export class Updater {
}; };
static updateState = (prevState: ICoreState): ICoreState => { static updateState = (prevState: ICoreState): ICoreState => {
console.log(prevState, Updater.props);
return { return {
...prevState, ...prevState,
panel: { panel: {

View file

@ -43,6 +43,8 @@ export class RootFrame extends React.Component<Props, State, {}> {
render() { render() {
const update = this.props.update; const update = this.props.update;
console.log("rootframe", this.props.browser.isSharing);
return ( return (
<div className="theme-white desktop"> <div className="theme-white desktop">
<div id="bg" className="bg bg-img font-m"> <div id="bg" className="bg bg-img font-m">
@ -88,6 +90,8 @@ export class RootFrame extends React.Component<Props, State, {}> {
dirPath={this.props.browser.dirPath} dirPath={this.props.browser.dirPath}
items={this.props.browser.items} items={this.props.browser.items}
uploadings={this.props.browser.uploadings} uploadings={this.props.browser.uploadings}
sharings={this.props.browser.sharings}
isSharing={this.props.browser.isSharing}
update={update} update={update}
uploadFiles={this.props.browser.uploadFiles} uploadFiles={this.props.browser.uploadFiles}
uploadValue={this.props.browser.uploadValue} uploadValue={this.props.browser.uploadValue}

View file

@ -24,15 +24,13 @@ export class StateMgr extends React.Component<Props, State, {}> {
LoginPaneUpdater.init(state.panel.authPane); LoginPaneUpdater.init(state.panel.authPane);
LoginPaneUpdater.setClient(new UsersClient("")); LoginPaneUpdater.setClient(new UsersClient(""));
LoginPaneUpdater.getCaptchaID() LoginPaneUpdater.getCaptchaID().then((ok: boolean) => {
.then((ok: boolean) => { if (!ok) {
if (!ok) { alert("failed to get captcha id");
alert("failed to get captcha id"); } else {
} else { this.update(LoginPaneUpdater.setAuthPane);
this.update(LoginPaneUpdater.setAuthPane); }
console.log(LoginPaneUpdater) });
}
});
BrowserUpdater() BrowserUpdater()
.setHomeItems() .setHomeItems()
@ -42,28 +40,42 @@ export class StateMgr extends React.Component<Props, State, {}> {
.then((_: boolean) => { .then((_: boolean) => {
BrowserUpdater().initUploads(); BrowserUpdater().initUploads();
}) })
.then(() => {
BrowserUpdater().setSharing(BrowserUpdater().props.dirPath.join("/"));
})
.then(() => {
BrowserUpdater().listSharings();
})
.then(() => { .then(() => {
this.update(BrowserUpdater().setBrowser); this.update(BrowserUpdater().setBrowser);
console.log("0", this.state, BrowserUpdater().props);
}) })
.then(() => { .then(() => {
return PanesUpdater.self(); PanesUpdater.self();
console.log("1", this.state);
}) })
.then(() => { .then(() => {
return PanesUpdater.listRoles(); PanesUpdater.listRoles();
console.log("2", this.state);
}) })
.then((_: boolean) => { .then(() => {
return PanesUpdater.listUsers(); PanesUpdater.listUsers();
console.log("3", this.state);
}) })
.then((_: boolean) => { .then(() => {
this.update(PanesUpdater.updateState); this.update(PanesUpdater.updateState);
console.log("final", this.state);
}); });
}; };
update = (apply: (prevState: ICoreState) => ICoreState): void => { update = (apply: (prevState: ICoreState) => ICoreState): void => {
this.setState(apply(this.state)); this.setState(apply(this.state));
console.log("core", this.state);
}; };
render() { render() {
console.log("state_mgr", this.state.panel.browser.isSharing);
return ( return (
<RootFrame <RootFrame
authPane={this.state.panel.authPane} authPane={this.state.panel.authPane}