feat(fe/loading): introduce loading layer

This commit is contained in:
hexxa 2022-01-22 11:46:16 +08:00 committed by Hexxa
parent f06c5f5a7d
commit 2904d03bdb
7 changed files with 82 additions and 44 deletions

View file

@ -70,6 +70,7 @@
.theme-default #layers { .theme-default #layers {
height: 0; height: 0;
z-index: 3;
} }
.theme-default #panes .container { .theme-default #panes .container {
@ -499,12 +500,28 @@
bottom: 0; bottom: 0;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
overflow: scroll; overflow: scroll;
z-index: 100;
} }
.theme-default #login-layer { .theme-default #login-layer {
z-index: 200; z-index: 200;
} }
.theme-default #loading-layer {
z-index: 201;
}
.theme-default #loading-container {
background-color: rgba(255, 255, 255, 1);
border-radius: 0.6rem;
padding: 0.5rem;
position: fixed;
right: 2rem;
bottom: 2rem;
height: 3rem;
z-index: 201;
}
.theme-default #settings-layer { .theme-default #settings-layer {
z-index: 100; z-index: 100;
} }

View file

@ -4,4 +4,5 @@ export const sharingCtrl = "sharingCtrl";
export const filesViewCtrl = "filesView"; export const filesViewCtrl = "filesView";
export const ctrlHidden = "hidden"; export const ctrlHidden = "hidden";
export const ctrlOn = "on"; export const ctrlOn = "on";
export const ctrlOff = "off"; export const ctrlOff = "off";
export const loadingCtrl = "loading";

View file

@ -17,6 +17,7 @@ import {
import { NewMockSettingsClient } from "../../client/settings_mock"; import { NewMockSettingsClient } from "../../client/settings_mock";
import { controlName as panelTabs } from "../root_frame"; import { controlName as panelTabs } from "../root_frame";
import { import {
loadingCtrl,
sharingCtrl, sharingCtrl,
ctrlOn, ctrlOn,
ctrlOff, ctrlOff,
@ -131,6 +132,7 @@ describe("Login", () => {
[settingsTabsCtrl]: "preferencePane", [settingsTabsCtrl]: "preferencePane",
[sharingCtrl]: ctrlOff, [sharingCtrl]: ctrlOff,
[filesViewCtrl]: "rows", [filesViewCtrl]: "rows",
[loadingCtrl]: ctrlOff,
}), }),
options: Map<string, Set<string>>({ options: Map<string, Set<string>>({
[panelTabs]: Set<string>([ [panelTabs]: Set<string>([
@ -142,6 +144,7 @@ describe("Login", () => {
[settingsTabsCtrl]: Set<string>(["preferencePane", "managementPane"]), [settingsTabsCtrl]: Set<string>(["preferencePane", "managementPane"]),
[sharingCtrl]: Set<string>([ctrlOn, ctrlOff]), [sharingCtrl]: Set<string>([ctrlOn, ctrlOff]),
[filesViewCtrl]: Set<string>(["rows", "table"]), [filesViewCtrl]: Set<string>(["rows", "table"]),
[loadingCtrl]: Set<string>([ctrlOn, ctrlOff]),
}), }),
}, },
}); });

View file

@ -14,6 +14,7 @@ import {
sharingCtrl, sharingCtrl,
ctrlOn, ctrlOn,
ctrlOff, ctrlOff,
loadingCtrl,
} from "../common/controls"; } from "../common/controls";
import { LoginProps } from "./pane_login"; import { LoginProps } from "./pane_login";
import { AdminProps } from "./pane_admin"; import { AdminProps } from "./pane_admin";
@ -117,6 +118,7 @@ export function initState(): ICoreState {
[settingsTabsCtrl]: "preferencePane", [settingsTabsCtrl]: "preferencePane",
[sharingCtrl]: ctrlOff, [sharingCtrl]: ctrlOff,
[filesViewCtrl]: "rows", [filesViewCtrl]: "rows",
[loadingCtrl]: ctrlOff,
}), }),
options: Map<string, Set<string>>({ options: Map<string, Set<string>>({
[panelTabs]: Set<string>([ [panelTabs]: Set<string>([
@ -128,6 +130,7 @@ export function initState(): ICoreState {
[settingsTabsCtrl]: Set<string>(["preferencePane", "managementPane"]), [settingsTabsCtrl]: Set<string>(["preferencePane", "managementPane"]),
[sharingCtrl]: Set<string>([ctrlOn, ctrlOff]), [sharingCtrl]: Set<string>([ctrlOn, ctrlOff]),
[filesViewCtrl]: Set<string>(["rows", "table"]), [filesViewCtrl]: Set<string>(["rows", "table"]),
[loadingCtrl]: Set<string>([ctrlOn, ctrlOff]),
}), }),
}, },
}, },

View file

@ -1,6 +1,8 @@
import * as React from "react"; import * as React from "react";
import { List } from "immutable"; import { List } from "immutable";
import { RiTimer2Line } from "@react-icons/all-files/ri/RiTimer2Line";
import { updater } from "./state_updater"; import { updater } from "./state_updater";
import { ICoreState, MsgProps, UIProps } from "./core_state"; import { ICoreState, MsgProps, UIProps } from "./core_state";
import { AdminProps } from "./pane_admin"; import { AdminProps } from "./pane_admin";
@ -10,7 +12,7 @@ import { AuthPane, LoginProps } from "./pane_login";
import { FilesProps } from "./panel_files"; import { FilesProps } from "./panel_files";
import { Flexbox } from "./layout/flexbox"; import { Flexbox } from "./layout/flexbox";
import { Container } from "./layout/container"; import { Container } from "./layout/container";
import { sharingCtrl, ctrlOn } from "../common/controls"; import { sharingCtrl, loadingCtrl, ctrlOn } from "../common/controls";
export interface Props { export interface Props {
filesInfo: FilesProps; filesInfo: FilesProps;
@ -40,9 +42,11 @@ export class Layers extends React.Component<Props, State, {}> {
? "hidden" ? "hidden"
: ""; : "";
const showSettings = const showSettings =
this.props.ui.control.controls.get("settingsDialog") === "on" this.props.ui.control.controls.get("settingsDialog") === ctrlOn
? "" ? ""
: "hidden"; : "hidden";
const showLoading =
this.props.ui.control.controls.get(loadingCtrl) == ctrlOn ? "" : "hidden";
return ( return (
<div id="layers"> <div id="layers">
@ -56,6 +60,12 @@ export class Layers extends React.Component<Props, State, {}> {
</div> </div>
</div> </div>
<div id="loading-layer" className={showLoading}>
<div id="loading-container">
<RiTimer2Line size="3rem" className="cyan1-font anm-rotate" />
</div>
</div>
<div id="settings-layer" className={`layer ${showSettings}`}> <div id="settings-layer" className={`layer ${showSettings}`}>
<div id="root-container"> <div id="root-container">
<Container> <Container>

View file

@ -7,6 +7,7 @@ import { updater } from "./state_updater";
import { alertMsg } from "../common/env"; import { alertMsg } from "../common/env";
import { Quota, Preferences } from "../client"; import { Quota, Preferences } from "../client";
import { getErrMsg } from "../common/utils"; import { getErrMsg } from "../common/utils";
import { ctrlOn, ctrlOff, loadingCtrl } from "../common/controls";
export interface ExtInfo { export interface ExtInfo {
usedSpace: string; usedSpace: string;
@ -59,46 +60,47 @@ export class AuthPane extends React.Component<Props, State, {}> {
}; };
login = async () => { login = async () => {
return updater() updater().setControlOption(loadingCtrl, ctrlOn);
.login( this.props.update(updater().updateUI);
try {
const loginStatus = await updater().login(
this.state.user, this.state.user,
this.state.pwd, this.state.pwd,
this.props.login.captchaID, this.props.login.captchaID,
this.state.captchaInput this.state.captchaInput
) );
.then((status: string): Promise<any> => { if (loginStatus !== "") {
this.setState({ captchaInput: "" }); alertMsg(
if (status === "") { getErrMsg(this.props.msg.pkg, "op.fail", loginStatus.toString())
const params = new URLSearchParams( );
document.location.search.substring(1) return;
); }
return updater().initAll(params);
} else { const params = new URLSearchParams(document.location.search.substring(1));
throw status; const initStatus = await updater().initAll(params);
} if (initStatus !== "") {
}) alertMsg(
.then((status: string) => { getErrMsg(this.props.msg.pkg, "op.fail", initStatus.toString())
if (status !== "") { );
throw status; }
}
this.update(updater().updateAll); this.setState({ user: "", pwd: "" });
}) } finally {
.catch((status: Error) => { this.setState({ pwd: "", captchaInput: "" });
alertMsg(getErrMsg(this.props.msg.pkg, "op.fail", status.toString())); updater().setControlOption(loadingCtrl, ctrlOff);
return updater().getCaptchaID(); await this.refreshCaptcha();
}); this.props.update(updater().updateAll);
}
}; };
refreshCaptcha = async () => { refreshCaptcha = async () => {
return updater() const status = await updater().getCaptchaID();
.getCaptchaID() if (status !== "") {
.then((status: string) => { alertMsg(getErrMsg(this.props.msg.pkg, "op.fail", status));
if (status !== "") { } else {
alertMsg(getErrMsg(this.props.msg.pkg, "op.fail", status)); this.props.update(updater().updateLogin);
} else { }
this.props.update(updater().updateLogin);
}
});
}; };
render() { render() {

View file

@ -13,6 +13,7 @@ import { FilesClient } from "../client/files";
import { UsersClient } from "../client/users"; import { UsersClient } from "../client/users";
import { SettingsClient } from "../client/settings"; import { SettingsClient } from "../client/settings";
import { IUsersClient, IFilesClient, ISettingsClient } from "../client"; import { IUsersClient, IFilesClient, ISettingsClient } from "../client";
import { loadingCtrl, ctrlOn, ctrlOff } from "../common/controls";
export interface Props {} export interface Props {}
export interface State extends ICoreState {} export interface State extends ICoreState {}
@ -49,6 +50,9 @@ export class StateMgr extends React.Component<Props, State, {}> {
query: URLSearchParams query: URLSearchParams
): Promise<void> => { ): Promise<void> => {
updater().init(state); updater().init(state);
updater().setControlOption(loadingCtrl, ctrlOn);
this.update(updater().updateUI);
if ( if (
this.usersClient == null || this.usersClient == null ||
this.filesClient == null || this.filesClient == null ||
@ -63,14 +67,12 @@ export class StateMgr extends React.Component<Props, State, {}> {
this.settingsClient this.settingsClient
); );
return updater() const status = await updater().initAll(query);
.initAll(query) if (status !== "") {
.then((status: string) => { alertMsg(getErrMsg(state.msg.pkg, "op.fail", status));
if (status !== "") { }
alertMsg(getErrMsg(state.msg.pkg, "op.fail", status)); updater().setControlOption(loadingCtrl, ctrlOff);
} this.update(updater().updateAll);
this.update(updater().updateAll);
});
}; };
update = (update: (prevState: ICoreState) => ICoreState): void => { update = (update: (prevState: ICoreState) => ICoreState): void => {