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 { UploadEntry } from "../worker/interface";
export const uploadCheckCycle = 1000;
export interface Item {
name: string;
size: number;
@ -28,8 +26,10 @@ export interface Item {
export interface Props {
dirPath: List<string>;
isSharing: boolean;
items: List<MetadataResp>;
uploadings: List<UploadInfo>;
sharings: List<string>;
uploadFiles: List<File>;
uploadValue: string;
@ -191,6 +191,12 @@ export class Browser extends React.Component<Props, State, {}> {
updater()
.setItems(dirPath)
.then(() => {
updater().listSharings();
})
.then(() => {
updater().setSharing(dirPath.join("/"));
})
.then(() => {
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() {
const breadcrumb = this.props.dirPath.map(
(pathPart: string, key: number) => {
@ -308,10 +348,29 @@ export class Browser extends React.Component<Props, State, {}> {
<button
type="button"
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
</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>
);
@ -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 (
<div>
<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)",
padding: "0.8rem 1rem",
fontWeight: "bold",
borderRadius: "0.5rem"
borderRadius: "0.5rem",
}}
>
Location:
@ -453,6 +530,19 @@ export class Browser extends React.Component<Props, State, {}> {
</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="flex-list-container bold">
<span className="flex-list-item-l">

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,6 +43,8 @@ export class RootFrame extends React.Component<Props, State, {}> {
render() {
const update = this.props.update;
console.log("rootframe", this.props.browser.isSharing);
return (
<div className="theme-white desktop">
<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}
items={this.props.browser.items}
uploadings={this.props.browser.uploadings}
sharings={this.props.browser.sharings}
isSharing={this.props.browser.isSharing}
update={update}
uploadFiles={this.props.browser.uploadFiles}
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.setClient(new UsersClient(""));
LoginPaneUpdater.getCaptchaID()
.then((ok: boolean) => {
if (!ok) {
alert("failed to get captcha id");
} else {
this.update(LoginPaneUpdater.setAuthPane);
console.log(LoginPaneUpdater)
}
});
LoginPaneUpdater.getCaptchaID().then((ok: boolean) => {
if (!ok) {
alert("failed to get captcha id");
} else {
this.update(LoginPaneUpdater.setAuthPane);
}
});
BrowserUpdater()
.setHomeItems()
@ -42,28 +40,42 @@ export class StateMgr extends React.Component<Props, State, {}> {
.then((_: boolean) => {
BrowserUpdater().initUploads();
})
.then(() => {
BrowserUpdater().setSharing(BrowserUpdater().props.dirPath.join("/"));
})
.then(() => {
BrowserUpdater().listSharings();
})
.then(() => {
this.update(BrowserUpdater().setBrowser);
console.log("0", this.state, BrowserUpdater().props);
})
.then(() => {
return PanesUpdater.self();
PanesUpdater.self();
console.log("1", this.state);
})
.then(() => {
return PanesUpdater.listRoles();
PanesUpdater.listRoles();
console.log("2", this.state);
})
.then((_: boolean) => {
return PanesUpdater.listUsers();
.then(() => {
PanesUpdater.listUsers();
console.log("3", this.state);
})
.then((_: boolean) => {
.then(() => {
this.update(PanesUpdater.updateState);
console.log("final", this.state);
});
};
update = (apply: (prevState: ICoreState) => ICoreState): void => {
this.setState(apply(this.state));
console.log("core", this.state);
};
render() {
console.log("state_mgr", this.state.panel.browser.isSharing);
return (
<RootFrame
authPane={this.state.panel.authPane}