feat(ui): support sharing
This commit is contained in:
parent
86474e044f
commit
752768a916
8 changed files with 187 additions and 46 deletions
|
@ -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">
|
||||||
|
|
|
@ -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
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>([]),
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue