feat(settings): enable background settings
This commit is contained in:
parent
b151c1b56e
commit
f151f47581
13 changed files with 229 additions and 17 deletions
|
@ -25,7 +25,9 @@ export class SettingsClient extends BaseClient {
|
|||
return this.do({
|
||||
method: "patch",
|
||||
url: `${this.url}/v1/settings/client`,
|
||||
data: cfg,
|
||||
data: {
|
||||
clientCfg: cfg,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,10 +3,11 @@ import { List, Map, Set } from "immutable";
|
|||
import FileSize from "filesize";
|
||||
|
||||
import { alertMsg, confirmMsg } from "../common/env";
|
||||
import { ICoreState, MsgProps } from "./core_state";
|
||||
import { ICoreState, MsgProps, UIProps } from "./core_state";
|
||||
import { User, Quota } from "../client";
|
||||
import { updater } from "./state_updater";
|
||||
import { Flexbox } from "./layout/flexbox";
|
||||
import { Flowgrid } from "./layout/flowgrid";
|
||||
|
||||
export interface AdminProps {
|
||||
users: Map<string, User>;
|
||||
|
@ -15,6 +16,7 @@ export interface AdminProps {
|
|||
|
||||
export interface Props {
|
||||
admin: AdminProps;
|
||||
ui: UIProps;
|
||||
msg: MsgProps;
|
||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
}
|
||||
|
@ -458,6 +460,14 @@ export class AdminPane extends React.Component<Props, State, {}> {
|
|||
|
||||
return (
|
||||
<div className="font-size-m">
|
||||
<div className="container padding-l">
|
||||
<BgCfg
|
||||
ui={this.props.ui}
|
||||
msg={this.props.msg}
|
||||
update={this.props.update}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="container padding-l">
|
||||
<Flexbox
|
||||
children={List([
|
||||
|
@ -581,3 +591,160 @@ export class AdminPane extends React.Component<Props, State, {}> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface BgProps {
|
||||
msg: MsgProps;
|
||||
ui: UIProps;
|
||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
}
|
||||
|
||||
interface BgState {}
|
||||
export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
||||
changeSiteName = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui, siteName: ev.target.value });
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeSiteDesc = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui, siteDesc: ev.target.value });
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeBgUrl = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({
|
||||
...this.props.ui,
|
||||
bg: { ...this.props.ui.bg, url: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeBgRepeat = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({
|
||||
...this.props.ui,
|
||||
bg: { ...this.props.ui.bg, repeat: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeBgPos = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({
|
||||
...this.props.ui,
|
||||
bg: { ...this.props.ui.bg, position: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeBgAlign = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({
|
||||
...this.props.ui,
|
||||
bg: { ...this.props.ui.bg, align: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
|
||||
constructor(p: BgProps) {
|
||||
super(p);
|
||||
}
|
||||
|
||||
setClientCfg = async () => {
|
||||
return updater().setClientCfgRemote({
|
||||
siteName: this.props.ui.siteName,
|
||||
siteDesc: this.props.ui.siteDesc,
|
||||
bg: this.props.ui.bg,
|
||||
});
|
||||
};
|
||||
|
||||
resetClientCfg = () => {
|
||||
// TODO: move this to backend
|
||||
updater().setClientCfg({
|
||||
siteName: "Quickshare",
|
||||
siteDesc: "Quickshare",
|
||||
bg: {
|
||||
url: "/static/img/textured_paper.png",
|
||||
repeat: "repeat",
|
||||
position: "fixed",
|
||||
align: "center",
|
||||
},
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Flexbox
|
||||
children={List([
|
||||
<span className="title-m bold">
|
||||
{this.props.msg.pkg.get("cfg.bg")}
|
||||
</span>,
|
||||
|
||||
<span>
|
||||
<button onClick={this.resetClientCfg} className="margin-r-m">
|
||||
{this.props.msg.pkg.get("reset")}
|
||||
</button>
|
||||
<button onClick={this.setClientCfg}>
|
||||
{this.props.msg.pkg.get("update")}
|
||||
</button>
|
||||
</span>,
|
||||
])}
|
||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
/>
|
||||
|
||||
<Flowgrid
|
||||
grids={List([
|
||||
<div className="padding-t-m padding-b-m padding-r-m">
|
||||
<div className="font-size-s grey1-font">
|
||||
{this.props.msg.pkg.get("cfg.bg.url")}
|
||||
</div>
|
||||
<input
|
||||
name="bg_url"
|
||||
type="text"
|
||||
onChange={this.changeBgUrl}
|
||||
value={this.props.ui.bg.url}
|
||||
className="black0-font"
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.url")}
|
||||
/>
|
||||
</div>,
|
||||
|
||||
<div className="padding-t-m padding-b-m padding-r-m">
|
||||
<div className="font-size-s grey1-font">
|
||||
{this.props.msg.pkg.get("cfg.bg.repeat")}
|
||||
</div>
|
||||
<input
|
||||
name="bg_repeat"
|
||||
type="text"
|
||||
onChange={this.changeBgRepeat}
|
||||
value={this.props.ui.bg.repeat}
|
||||
className="black0-font"
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.repeat")}
|
||||
/>
|
||||
</div>,
|
||||
|
||||
<div className="padding-t-m padding-b-m padding-r-m">
|
||||
<div className="font-size-s grey1-font">
|
||||
{this.props.msg.pkg.get("cfg.bg.pos")}
|
||||
</div>
|
||||
<input
|
||||
name="bg_pos"
|
||||
type="text"
|
||||
onChange={this.changeBgPos}
|
||||
value={this.props.ui.bg.position}
|
||||
className="black0-font"
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.pos")}
|
||||
/>
|
||||
</div>,
|
||||
|
||||
<div className="padding-t-m padding-b-m padding-r-m">
|
||||
<div className="font-size-s grey1-font">
|
||||
{this.props.msg.pkg.get("cfg.bg.align")}
|
||||
</div>
|
||||
<input
|
||||
name="bg_align"
|
||||
type="text"
|
||||
onChange={this.changeBgAlign}
|
||||
value={this.props.ui.bg.align}
|
||||
className="black0-font"
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.align")}
|
||||
/>
|
||||
</div>,
|
||||
])}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ export class AuthPane extends React.Component<Props, State, {}> {
|
|||
this.update(updater().updateLogin);
|
||||
this.update(updater().updatePanes);
|
||||
this.update(updater().updateAdmin);
|
||||
this.update(updater().updateUI);
|
||||
|
||||
updater().initLan();
|
||||
this.update(updater().updateMsg);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import * as React from "react";
|
||||
import FileSize from "filesize";
|
||||
import { List } from "immutable";
|
||||
|
||||
import { ICoreState, MsgProps } from "./core_state";
|
||||
import { LoginProps } from "./pane_login";
|
||||
import { Flexbox } from "./layout/flexbox";
|
||||
import { updater } from "./state_updater";
|
||||
import { alertMsg } from "../common/env";
|
||||
import { List } from "immutable";
|
||||
export interface Props {
|
||||
login: LoginProps;
|
||||
msg: MsgProps;
|
||||
|
||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
}
|
||||
|
||||
|
@ -20,7 +21,6 @@ export interface State {
|
|||
}
|
||||
|
||||
export class PaneSettings extends React.Component<Props, State, {}> {
|
||||
private update: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
changeOldPwd = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ oldPwd: ev.target.value });
|
||||
};
|
||||
|
@ -33,7 +33,6 @@ export class PaneSettings extends React.Component<Props, State, {}> {
|
|||
|
||||
constructor(p: Props) {
|
||||
super(p);
|
||||
this.update = p.update;
|
||||
this.state = {
|
||||
oldPwd: "",
|
||||
newPwd1: "",
|
||||
|
@ -130,9 +129,7 @@ export class PaneSettings extends React.Component<Props, State, {}> {
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="hr white0-bg margin-t-m margin-b-m"></div>
|
||||
|
||||
<div>
|
||||
<Flexbox
|
||||
children={List([
|
||||
|
@ -188,9 +185,7 @@ export class PaneSettings extends React.Component<Props, State, {}> {
|
|||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="hr white0-bg margin-t-m margin-b-m"></div>
|
||||
|
||||
<div className="margin-b-m">
|
||||
<Flexbox
|
||||
children={List([
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Set, List } from "immutable";
|
|||
|
||||
import { updater } from "./state_updater";
|
||||
import { Flexbox } from "./layout/flexbox";
|
||||
import { ICoreState, MsgProps } from "./core_state";
|
||||
import { ICoreState, MsgProps, UIProps } from "./core_state";
|
||||
import { PaneSettings } from "./pane_settings";
|
||||
import { AdminPane, AdminProps } from "./pane_admin";
|
||||
import { AuthPane, LoginProps } from "./pane_login";
|
||||
|
@ -16,6 +16,7 @@ export interface Props {
|
|||
panes: PanesProps;
|
||||
login: LoginProps;
|
||||
admin: AdminProps;
|
||||
ui: UIProps;
|
||||
msg: MsgProps;
|
||||
update?: (updater: (prevState: ICoreState) => ICoreState) => void;
|
||||
}
|
||||
|
@ -88,6 +89,7 @@ export class Panes extends React.Component<Props, State, {}> {
|
|||
<div className={`${showAdmin}`}>
|
||||
<AdminPane
|
||||
admin={this.props.admin}
|
||||
ui={this.props.ui}
|
||||
msg={this.props.msg}
|
||||
update={this.props.update}
|
||||
/>
|
||||
|
|
|
@ -44,6 +44,7 @@ export class RootFrame extends React.Component<Props, State, {}> {
|
|||
panes={this.props.panes}
|
||||
login={this.props.login}
|
||||
admin={this.props.admin}
|
||||
ui={this.props.ui}
|
||||
msg={this.props.msg}
|
||||
update={this.props.update}
|
||||
/>
|
||||
|
|
|
@ -64,6 +64,7 @@ export class StateMgr extends React.Component<Props, State, {}> {
|
|||
this.update(updater().updateLogin);
|
||||
this.update(updater().updatePanes);
|
||||
this.update(updater().updateAdmin);
|
||||
this.update(updater().updateUI);
|
||||
|
||||
updater().initLan();
|
||||
this.update(updater().updateMsg);
|
||||
|
|
|
@ -350,6 +350,10 @@ export class Updater {
|
|||
.then(() => {
|
||||
return this.isSharing(this.props.browser.dirPath.join("/"));
|
||||
})
|
||||
.then(() => {
|
||||
// init settings
|
||||
return this.getClientCfg();
|
||||
})
|
||||
.then(() => {
|
||||
// init panes
|
||||
return this.initPanes();
|
||||
|
@ -561,11 +565,20 @@ export class Updater {
|
|||
return resp.status === 200;
|
||||
};
|
||||
|
||||
setClientCfg = async (cfg: ClientConfig): Promise<number> => {
|
||||
setClientCfgRemote = async (cfg: ClientConfig): Promise<number> => {
|
||||
const resp = await this.settingsClient.setClientCfg(cfg);
|
||||
return resp.status;
|
||||
};
|
||||
|
||||
setClientCfg = async (cfg: ClientConfig): Promise<void> => {
|
||||
this.props.ui = {
|
||||
...this.props.ui,
|
||||
siteName: cfg.siteName,
|
||||
siteDesc: cfg.siteDesc,
|
||||
bg: cfg.bg,
|
||||
};
|
||||
};
|
||||
|
||||
getClientCfg = async (): Promise<number> => {
|
||||
const resp = await this.settingsClient.getClientCfg();
|
||||
if (resp.status === 200) {
|
||||
|
@ -612,6 +625,13 @@ export class Updater {
|
|||
msg: { ...prevState.msg, ...this.props.msg },
|
||||
};
|
||||
};
|
||||
|
||||
updateUI = (prevState: ICoreState): ICoreState => {
|
||||
return {
|
||||
...prevState,
|
||||
ui: { ...prevState.ui, ...this.props.ui },
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export let coreUpdater = new Updater();
|
||||
|
|
|
@ -8,7 +8,7 @@ import { PanesProps } from "./panes";
|
|||
import { updater } from "./state_updater";
|
||||
import { Flexbox } from "./layout/flexbox";
|
||||
|
||||
export interface State { }
|
||||
export interface State {}
|
||||
export interface Props {
|
||||
login: LoginProps;
|
||||
panes: PanesProps;
|
||||
|
@ -51,7 +51,9 @@ export class TopBar extends React.Component<Props, State, {}> {
|
|||
.logout()
|
||||
.then((ok: boolean) => {
|
||||
if (ok) {
|
||||
const params = new URLSearchParams(document.location.search.substring(1));
|
||||
const params = new URLSearchParams(
|
||||
document.location.search.substring(1)
|
||||
);
|
||||
return updater().initAll(params);
|
||||
} else {
|
||||
alertMsg(this.props.msg.pkg.get("login.logout.fail"));
|
||||
|
@ -65,6 +67,7 @@ export class TopBar extends React.Component<Props, State, {}> {
|
|||
this.props.update(updater().updateLogin);
|
||||
this.props.update(updater().updatePanes);
|
||||
this.props.update(updater().updateAdmin);
|
||||
this.props.update(updater().updateUI);
|
||||
|
||||
updater().initLan();
|
||||
this.props.update(updater().updateMsg);
|
||||
|
@ -82,7 +85,9 @@ export class TopBar extends React.Component<Props, State, {}> {
|
|||
render() {
|
||||
const showUserInfo = this.props.login.authed ? "" : "hidden";
|
||||
const showLogin = this.props.login.authed ? "" : "hidden";
|
||||
const showSettings = this.props.panes.paneNames.get("settings") ? "" : "hidden";
|
||||
const showSettings = this.props.panes.paneNames.get("settings")
|
||||
? ""
|
||||
: "hidden";
|
||||
const showAdmin = this.props.panes.paneNames.get("admin") ? "" : "hidden";
|
||||
|
||||
return (
|
||||
|
|
|
@ -87,4 +87,12 @@ export const msgs: Map<string, string> = Map({
|
|||
"user.downLimit": "Download Speed Limit",
|
||||
"user.upLimit": "Upload Speed Limit",
|
||||
"user.spaceLimit": "Space Limit",
|
||||
"cfg.siteName": "Site Name",
|
||||
"cfg.siteDesc": "Site Description",
|
||||
"cfg.bg": "Background",
|
||||
"cfg.bg.url": "Background URL",
|
||||
"cfg.bg.repeat": "Repeat",
|
||||
"cfg.bg.pos": "Position",
|
||||
"cfg.bg.align": "Align",
|
||||
reset: "Reset",
|
||||
});
|
||||
|
|
|
@ -79,11 +79,19 @@ export const msgs: Map<string, string> = Map({
|
|||
"pane.admin": "管理",
|
||||
"pane.settings": "设置",
|
||||
"logout.confirm": "确定登出吗?",
|
||||
"unauthed": "未授权动作",
|
||||
unauthed: "未授权动作",
|
||||
"err.tooManyUploads": "不可同时上传超过1000个文件",
|
||||
"login.role": "角色",
|
||||
"user.profile": "用户信息",
|
||||
"user.downLimit": "下载速度限制",
|
||||
"user.upLimit": "上传速度限制",
|
||||
"user.spaceLimit": "空间限制",
|
||||
"cfg.siteName": "站点名字",
|
||||
"cfg.siteDesc": "站点描述",
|
||||
"cfg.bg": "背景设置",
|
||||
"cfg.bg.url": "图片链接",
|
||||
"cfg.bg.repeat": "重复",
|
||||
"cfg.bg.pos": "位置",
|
||||
"cfg.bg.align": "对齐",
|
||||
reset: "重置",
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ func (h *SettingsSvc) Health(c *gin.Context) {
|
|||
}
|
||||
|
||||
type ClientCfgMsg struct {
|
||||
ClientCfg *sitestore.ClientConfig
|
||||
ClientCfg *sitestore.ClientConfig `json:"clientCfg"`
|
||||
}
|
||||
|
||||
func (h *SettingsSvc) GetClientCfg(c *gin.Context) {
|
||||
|
@ -51,6 +51,8 @@ func (h *SettingsSvc) SetClientCfg(c *gin.Context) {
|
|||
c.JSON(q.ErrResp(c, 400, err))
|
||||
return
|
||||
}
|
||||
h.deps.Log().Info(req.ClientCfg)
|
||||
|
||||
if err = validateClientCfg(req.ClientCfg); err != nil {
|
||||
c.JSON(q.ErrResp(c, 400, err))
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue