feat(pane_admin): enable some site settings in fe
This commit is contained in:
parent
1694e9026b
commit
f55581efb8
11 changed files with 191 additions and 85 deletions
|
@ -93,10 +93,16 @@ export interface GetSharingDirResp {
|
|||
sharingDir: string;
|
||||
}
|
||||
|
||||
export interface ClientConfigMsg {
|
||||
export interface ClientConfig {
|
||||
siteName: string;
|
||||
siteDesc: string;
|
||||
bg: BgConfig;
|
||||
allowSetBg: boolean;
|
||||
autoTheme: boolean;
|
||||
}
|
||||
|
||||
export interface ClientConfigMsg {
|
||||
clientCfg: ClientConfig;
|
||||
captchaEnabled?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@ export const resps = {
|
|||
status: 200,
|
||||
statusText: "",
|
||||
data: {
|
||||
clientCfg: {
|
||||
siteName: "",
|
||||
siteDesc: "",
|
||||
captchaEnabled: true,
|
||||
bg: {
|
||||
url: "clientCfg_bg_url",
|
||||
repeat: "clientCfg_bg_repeat",
|
||||
|
@ -25,6 +25,10 @@ export const resps = {
|
|||
align: "clientCfg_bg_align",
|
||||
bgColor: "clientCfg_bg_bg_Color"
|
||||
},
|
||||
allowSetBg: true,
|
||||
autoTheme: true,
|
||||
},
|
||||
captchaEnabled: true,
|
||||
},
|
||||
},
|
||||
reportErrorsMockResp: {
|
||||
|
|
|
@ -123,9 +123,9 @@ describe("Login", () => {
|
|||
// ui
|
||||
expect(coreState.ui).toEqual({
|
||||
isVertical: false,
|
||||
clientCfg: {
|
||||
siteName: "",
|
||||
siteDesc: "",
|
||||
captchaEnabled: true,
|
||||
bg: {
|
||||
url: "clientCfg_bg_url",
|
||||
repeat: "clientCfg_bg_repeat",
|
||||
|
@ -133,6 +133,10 @@ describe("Login", () => {
|
|||
align: "clientCfg_bg_align",
|
||||
bgColor: "clientCfg_bg_bg_Color",
|
||||
},
|
||||
allowSetBg: true,
|
||||
autoTheme: true,
|
||||
},
|
||||
captchaEnabled: true,
|
||||
control: {
|
||||
controls: Map<string, string>({
|
||||
[panelTabs]: "filesPanel",
|
||||
|
|
|
@ -142,7 +142,7 @@ describe("State Manager", () => {
|
|||
expect(coreState.msg.pkg).toEqual(MsgPackage.get("en_US"));
|
||||
|
||||
// ui
|
||||
expect(coreState.ui.bg).toEqual(settingsResps.getClientCfgMockResp.data.bg);
|
||||
expect(coreState.ui.clientCfg.bg).toEqual(settingsResps.getClientCfgMockResp.data.clientCfg.bg);
|
||||
});
|
||||
|
||||
test("initUpdater for visitor in sharing mode", async () => {
|
||||
|
@ -257,7 +257,7 @@ describe("State Manager", () => {
|
|||
expect(coreState.msg.pkg).toEqual(MsgPackage.get("en_US"));
|
||||
|
||||
// ui
|
||||
expect(coreState.ui.bg).toEqual(settingsResps.getClientCfgMockResp.data.bg);
|
||||
expect(coreState.ui.clientCfg.bg).toEqual(settingsResps.getClientCfgMockResp.data.clientCfg.bg);
|
||||
});
|
||||
|
||||
test("initUpdater for visitor", async () => {
|
||||
|
@ -352,7 +352,7 @@ describe("State Manager", () => {
|
|||
expect(coreState.msg.pkg).toEqual(MsgPackage.get("en_US"));
|
||||
|
||||
// ui
|
||||
expect(coreState.ui.bg).toEqual({
|
||||
expect(coreState.ui.clientCfg.bg).toEqual({
|
||||
align: "clientCfg_bg_align",
|
||||
position: "clientCfg_bg_position",
|
||||
repeat: "clientCfg_bg_repeat",
|
||||
|
|
|
@ -2,7 +2,7 @@ import { List, Set, Map } from "immutable";
|
|||
|
||||
import { UploadEntry } from "../worker/interface";
|
||||
import { MsgPackage } from "../i18n/msger";
|
||||
import { User, MetadataResp } from "../client";
|
||||
import { User, MetadataResp, ClientConfig } from "../client";
|
||||
import { FilesProps } from "./panel_files";
|
||||
import { UploadingsProps } from "./panel_uploadings";
|
||||
import { SharingsProps } from "./panel_sharings";
|
||||
|
@ -25,17 +25,9 @@ export interface MsgProps {
|
|||
}
|
||||
|
||||
export interface UIProps {
|
||||
isVertical: boolean;
|
||||
siteName: string;
|
||||
siteDesc: string;
|
||||
clientCfg: ClientConfig;
|
||||
captchaEnabled: boolean;
|
||||
bg: {
|
||||
url: string;
|
||||
repeat: string;
|
||||
position: string;
|
||||
align: string;
|
||||
bgColor: string;
|
||||
};
|
||||
isVertical: boolean;
|
||||
control: {
|
||||
controls: Map<string, string>;
|
||||
options: Map<string, Set<string>>;
|
||||
|
@ -120,6 +112,7 @@ export function initState(): ICoreState {
|
|||
},
|
||||
ui: {
|
||||
isVertical: isVertical(),
|
||||
clientCfg: {
|
||||
siteName: "",
|
||||
siteDesc: "",
|
||||
bg: {
|
||||
|
@ -129,6 +122,9 @@ export function initState(): ICoreState {
|
|||
align: "",
|
||||
bgColor: "",
|
||||
},
|
||||
allowSetBg: false,
|
||||
autoTheme: true,
|
||||
},
|
||||
captchaEnabled: true,
|
||||
control: {
|
||||
controls: Map<string, string>({
|
||||
|
|
|
@ -575,6 +575,19 @@ export class AdminPane extends React.Component<Props, State, {}> {
|
|||
|
||||
return (
|
||||
<div className="font-m">
|
||||
<Container>
|
||||
<Flexbox
|
||||
children={List([
|
||||
<h5 className="title-m">{this.props.msg.pkg.get("siteSettings")}</h5>,
|
||||
<button onClick={this.addUser} className="button-default">
|
||||
{this.props.msg.pkg.get("update")}
|
||||
</button>,
|
||||
])}
|
||||
childrenStyles={List([{}, { justifyContent: "flex-end" }])}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
|
||||
<Container>
|
||||
<BgCfg
|
||||
ui={this.props.ui}
|
||||
|
@ -713,51 +726,58 @@ interface BgProps {
|
|||
|
||||
interface BgState { }
|
||||
export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
||||
changeSiteName = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui, siteName: ev.target.value });
|
||||
onChangeSiteName = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui.clientCfg, siteName: ev.target.value });
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
|
||||
changeSiteDesc = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui, siteDesc: ev.target.value });
|
||||
onChangeSiteDesc = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({ ...this.props.ui.clientCfg, siteDesc: ev.target.value });
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
onChangeAllowSetBg = (enabled: boolean) => {
|
||||
updater().setClientCfg({ ...this.props.ui.clientCfg, allowSetBg: enabled });
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
onChangeAutoTheme = (enabled: boolean) => {
|
||||
updater().setClientCfg({ ...this.props.ui.clientCfg, autoTheme: enabled });
|
||||
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.ui.clientCfg,
|
||||
bg: { ...this.props.ui.clientCfg.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.ui.clientCfg,
|
||||
bg: { ...this.props.ui.clientCfg.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.ui.clientCfg,
|
||||
bg: { ...this.props.ui.clientCfg.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.ui.clientCfg,
|
||||
bg: { ...this.props.ui.clientCfg.bg, align: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
changeBgBgColor = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updater().setClientCfg({
|
||||
...this.props.ui,
|
||||
bg: { ...this.props.ui.bg, bgColor: ev.target.value },
|
||||
...this.props.ui.clientCfg,
|
||||
bg: { ...this.props.ui.clientCfg.bg, bgColor: ev.target.value },
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
|
@ -772,13 +792,13 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
};
|
||||
|
||||
setClientCfg = async () => {
|
||||
const bgURL = this.props.ui.bg.url;
|
||||
const bgURL = this.props.ui.clientCfg.bg.url;
|
||||
if (bgURL.length >= 4096) {
|
||||
Env().alertMsg(this.props.msg.pkg.get("bg.url.alert"));
|
||||
return;
|
||||
}
|
||||
|
||||
const bgRepeat = this.props.ui.bg.repeat;
|
||||
const bgRepeat = this.props.ui.clientCfg.bg.repeat;
|
||||
if (
|
||||
bgRepeat !== "repeat-x" &&
|
||||
bgRepeat !== "repeat-y" &&
|
||||
|
@ -791,7 +811,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
return;
|
||||
}
|
||||
|
||||
const bgPos = this.props.ui.bg.position;
|
||||
const bgPos = this.props.ui.clientCfg.bg.position;
|
||||
if (
|
||||
bgPos !== "top" &&
|
||||
bgPos !== "bottom" &&
|
||||
|
@ -803,7 +823,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
return;
|
||||
}
|
||||
|
||||
const bgAlign = this.props.ui.bg.align;
|
||||
const bgAlign = this.props.ui.clientCfg.bg.align;
|
||||
if (bgAlign !== "scroll" && bgAlign !== "fixed" && bgAlign !== "local") {
|
||||
Env().alertMsg(this.props.msg.pkg.get("bg.align.alert"));
|
||||
return;
|
||||
|
@ -813,9 +833,8 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
|
||||
try {
|
||||
const status = await updater().setClientCfgRemote({
|
||||
siteName: this.props.ui.siteName,
|
||||
siteDesc: this.props.ui.siteDesc,
|
||||
bg: this.props.ui.bg,
|
||||
clientCfg: this.props.ui.clientCfg,
|
||||
// captchaEnabled is omitted
|
||||
});
|
||||
if (status !== "") {
|
||||
Env().alertMsg(this.props.msg.pkg.get("update.fail"));
|
||||
|
@ -840,6 +859,8 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
align: "fixed",
|
||||
bgColor: "",
|
||||
},
|
||||
allowSetBg: false,
|
||||
autoTheme: true,
|
||||
});
|
||||
this.props.update(updater().updateUI);
|
||||
};
|
||||
|
@ -871,6 +892,68 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
|
||||
<div className="hr"></div>
|
||||
|
||||
<span className="inline-block margin-r-m">
|
||||
<div className="label">{this.props.msg.pkg.get("siteName")}</div>
|
||||
<input
|
||||
type="text"
|
||||
onChange={this.onChangeSiteName}
|
||||
value={this.props.ui.clientCfg.siteName}
|
||||
placeholder={this.props.msg.pkg.get("siteName")}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span className="inline-block margin-r-m">
|
||||
<div className="label">{this.props.msg.pkg.get("siteDesc")}</div>
|
||||
<input
|
||||
type="text"
|
||||
onChange={this.onChangeSiteDesc}
|
||||
value={this.props.ui.clientCfg.siteDesc}
|
||||
placeholder={this.props.msg.pkg.get("siteDesc")}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<div>
|
||||
<div className="label">{this.props.msg.pkg.get("allowSetBg")}</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
this.onChangeAllowSetBg(true);
|
||||
}}
|
||||
className="button-default inline-block margin-r-m"
|
||||
>
|
||||
{this.props.msg.pkg.get("term.enabled")}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
this.onChangeAllowSetBg(false);
|
||||
}}
|
||||
className="button-default inline-block margin-r-m"
|
||||
>
|
||||
{this.props.msg.pkg.get("term.disabled")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="label">{this.props.msg.pkg.get("autoTheme")}</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
this.onChangeAutoTheme(true);
|
||||
}}
|
||||
className="button-default inline-block margin-r-m"
|
||||
>
|
||||
{this.props.msg.pkg.get("term.enabled")}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
this.onChangeAutoTheme(false);
|
||||
}}
|
||||
className="button-default inline-block margin-r-m"
|
||||
>
|
||||
{this.props.msg.pkg.get("term.disabled")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="hr"></div>
|
||||
|
||||
<div>
|
||||
<div className="inline-block margin-r-m">
|
||||
<div className="label">{this.props.msg.pkg.get("cfg.bg.url")}</div>
|
||||
|
@ -878,7 +961,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
name="bg_url"
|
||||
type="text"
|
||||
onChange={this.changeBgUrl}
|
||||
value={this.props.ui.bg.url}
|
||||
value={this.props.ui.clientCfg.bg.url}
|
||||
style={{ width: "20rem" }}
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.url")}
|
||||
/>
|
||||
|
@ -892,7 +975,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
name="bg_repeat"
|
||||
type="text"
|
||||
onChange={this.changeBgRepeat}
|
||||
value={this.props.ui.bg.repeat}
|
||||
value={this.props.ui.clientCfg.bg.repeat}
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.repeat")}
|
||||
/>
|
||||
</div>
|
||||
|
@ -903,7 +986,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
name="bg_pos"
|
||||
type="text"
|
||||
onChange={this.changeBgPos}
|
||||
value={this.props.ui.bg.position}
|
||||
value={this.props.ui.clientCfg.bg.position}
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.pos")}
|
||||
/>
|
||||
</div>
|
||||
|
@ -916,7 +999,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
name="bg_align"
|
||||
type="text"
|
||||
onChange={this.changeBgAlign}
|
||||
value={this.props.ui.bg.align}
|
||||
value={this.props.ui.clientCfg.bg.align}
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.align")}
|
||||
/>
|
||||
</div>
|
||||
|
@ -929,7 +1012,7 @@ export class BgCfg extends React.Component<BgProps, BgState, {}> {
|
|||
name="bg_bgColor"
|
||||
type="text"
|
||||
onChange={this.changeBgBgColor}
|
||||
value={this.props.ui.bg.bgColor}
|
||||
value={this.props.ui.clientCfg.bg.bgColor}
|
||||
placeholder={this.props.msg.pkg.get("cfg.bg.bgColor")}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -47,15 +47,15 @@ export class RootFrame extends React.Component<Props, State, {}> {
|
|||
};
|
||||
}
|
||||
|
||||
if (this.props.ui.bg.url !== "") {
|
||||
if (this.props.ui.clientCfg.bg.url !== "") {
|
||||
return {
|
||||
background: `url("${this.props.ui.bg.url}") ${this.props.ui.bg.repeat} ${this.props.ui.bg.position} ${this.props.ui.bg.align}`,
|
||||
background: `url("${this.props.ui.clientCfg.bg.url}") ${this.props.ui.clientCfg.bg.repeat} ${this.props.ui.clientCfg.bg.position} ${this.props.ui.clientCfg.bg.align}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (this.props.ui.bg.bgColor !== "") {
|
||||
if (this.props.ui.clientCfg.bg.bgColor !== "") {
|
||||
return {
|
||||
backgroundColor: this.props.ui.bg.bgColor,
|
||||
backgroundColor: this.props.ui.clientCfg.bg.bgColor,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
roleAdmin,
|
||||
visitorID,
|
||||
ClientConfigMsg,
|
||||
ClientConfig,
|
||||
Preferences,
|
||||
} from "../client";
|
||||
import { FilesClient, shareIDQuery, shareDirQuery } from "../client/files";
|
||||
|
@ -561,6 +562,8 @@ export class Updater {
|
|||
return initClientCfgStatus;
|
||||
}
|
||||
|
||||
console.log(this.props.ui.control.controls.toJSON());
|
||||
|
||||
this.initControls(paramMap);
|
||||
this.initUITree();
|
||||
|
||||
|
@ -816,12 +819,10 @@ export class Updater {
|
|||
return resp.status === 200 ? "" : errServer;
|
||||
};
|
||||
|
||||
setClientCfg = (cfg: ClientConfigMsg) => {
|
||||
setClientCfg = (cfg: ClientConfig) => {
|
||||
this.props.ui = {
|
||||
...this.props.ui,
|
||||
siteName: cfg.siteName,
|
||||
siteDesc: cfg.siteDesc,
|
||||
bg: cfg.bg,
|
||||
clientCfg: cfg,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -841,11 +842,9 @@ export class Updater {
|
|||
if (resp.status !== 200) {
|
||||
return errServer;
|
||||
}
|
||||
const clientCfg = resp.data as ClientConfigMsg;
|
||||
this.props.ui.siteName = clientCfg.siteName;
|
||||
this.props.ui.siteDesc = clientCfg.siteDesc;
|
||||
this.props.ui.bg = clientCfg.bg;
|
||||
this.props.ui.captchaEnabled = clientCfg.captchaEnabled;
|
||||
const clientCfgMsg = resp.data as ClientConfigMsg;
|
||||
this.props.ui.clientCfg = clientCfgMsg.clientCfg;
|
||||
this.props.ui.captchaEnabled = clientCfgMsg.captchaEnabled;
|
||||
return "";
|
||||
};
|
||||
|
||||
|
|
|
@ -146,4 +146,11 @@ export const msgs: Map<string, string> = Map({
|
|||
theme: "Theme",
|
||||
"theme.light": "Light",
|
||||
"theme.dark": "Dark",
|
||||
"siteSettings": "Site Settings",
|
||||
"siteName": "Site Name",
|
||||
"siteDesc": "Site Description",
|
||||
"allowSetBg": "Allow user to customize background",
|
||||
"autoTheme": "Enable auto theme switching",
|
||||
"term.enabled": "Enabled",
|
||||
"term.disabled": "Disabled",
|
||||
});
|
||||
|
|
|
@ -143,4 +143,11 @@ export const msgs: Map<string, string> = Map({
|
|||
theme: "主题",
|
||||
"theme.light": "光白",
|
||||
"theme.dark": "暗黑",
|
||||
"siteSettings": "网站设置",
|
||||
"siteName": "网站名",
|
||||
"siteDesc": "网站描述",
|
||||
"allowSetBg": "允许用户自定义背景",
|
||||
"autoTheme": "自动切换主题",
|
||||
"term.enabled": "启用",
|
||||
"term.disabled": "关闭",
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ func (h *SettingsSvc) Health(c *gin.Context) {
|
|||
}
|
||||
|
||||
type ClientCfgMsg struct {
|
||||
ClientCfg *db.ClientConfig `json:"cfg"`
|
||||
ClientCfg *db.ClientConfig `json:"clientCfg"`
|
||||
CaptchaEnabled bool `json:"captchaEnabled"`
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue