diff --git a/src/client/web/src/client/index.ts b/src/client/web/src/client/index.ts index 99963f3..7ca7267 100644 --- a/src/client/web/src/client/index.ts +++ b/src/client/web/src/client/index.ts @@ -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; } diff --git a/src/client/web/src/client/settings_mock.ts b/src/client/web/src/client/settings_mock.ts index e7ec787..6326503 100644 --- a/src/client/web/src/client/settings_mock.ts +++ b/src/client/web/src/client/settings_mock.ts @@ -15,16 +15,20 @@ export const resps = { status: 200, statusText: "", data: { - siteName: "", - siteDesc: "", - captchaEnabled: true, - bg: { - url: "clientCfg_bg_url", - repeat: "clientCfg_bg_repeat", - position: "clientCfg_bg_position", - align: "clientCfg_bg_align", - bgColor: "clientCfg_bg_bg_Color" + clientCfg: { + siteName: "", + siteDesc: "", + bg: { + url: "clientCfg_bg_url", + repeat: "clientCfg_bg_repeat", + position: "clientCfg_bg_position", + align: "clientCfg_bg_align", + bgColor: "clientCfg_bg_bg_Color" + }, + allowSetBg: true, + autoTheme: true, }, + captchaEnabled: true, }, }, reportErrorsMockResp: { diff --git a/src/client/web/src/components/__test__/pane_login.test.tsx b/src/client/web/src/components/__test__/pane_login.test.tsx index d846e60..8521bd7 100644 --- a/src/client/web/src/components/__test__/pane_login.test.tsx +++ b/src/client/web/src/components/__test__/pane_login.test.tsx @@ -123,16 +123,20 @@ describe("Login", () => { // ui expect(coreState.ui).toEqual({ isVertical: false, - siteName: "", - siteDesc: "", - captchaEnabled: true, - bg: { - url: "clientCfg_bg_url", - repeat: "clientCfg_bg_repeat", - position: "clientCfg_bg_position", - align: "clientCfg_bg_align", - bgColor: "clientCfg_bg_bg_Color", + clientCfg: { + siteName: "", + siteDesc: "", + bg: { + url: "clientCfg_bg_url", + repeat: "clientCfg_bg_repeat", + position: "clientCfg_bg_position", + align: "clientCfg_bg_align", + bgColor: "clientCfg_bg_bg_Color", + }, + allowSetBg: true, + autoTheme: true, }, + captchaEnabled: true, control: { controls: Map({ [panelTabs]: "filesPanel", diff --git a/src/client/web/src/components/__test__/state_mgr.test.tsx b/src/client/web/src/components/__test__/state_mgr.test.tsx index 0829987..7686b09 100644 --- a/src/client/web/src/components/__test__/state_mgr.test.tsx +++ b/src/client/web/src/components/__test__/state_mgr.test.tsx @@ -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", diff --git a/src/client/web/src/components/core_state.ts b/src/client/web/src/components/core_state.ts index f938ef3..b730692 100644 --- a/src/client/web/src/components/core_state.ts +++ b/src/client/web/src/components/core_state.ts @@ -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; options: Map>; @@ -120,14 +112,18 @@ export function initState(): ICoreState { }, ui: { isVertical: isVertical(), - siteName: "", - siteDesc: "", - bg: { - url: "", - repeat: "", - position: "", - align: "", - bgColor: "", + clientCfg: { + siteName: "", + siteDesc: "", + bg: { + url: "", + repeat: "", + position: "", + align: "", + bgColor: "", + }, + allowSetBg: false, + autoTheme: true, }, captchaEnabled: true, control: { diff --git a/src/client/web/src/components/pane_admin.tsx b/src/client/web/src/components/pane_admin.tsx index f987505..3109382 100644 --- a/src/client/web/src/components/pane_admin.tsx +++ b/src/client/web/src/components/pane_admin.tsx @@ -575,6 +575,19 @@ export class AdminPane extends React.Component { return (
+ + {this.props.msg.pkg.get("siteSettings")}, + , + ])} + childrenStyles={List([{}, { justifyContent: "flex-end" }])} + /> + + + ICoreState) => void; } -interface BgState {} +interface BgState { } export class BgCfg extends React.Component { - changeSiteName = (ev: React.ChangeEvent) => { - updater().setClientCfg({ ...this.props.ui, siteName: ev.target.value }); + onChangeSiteName = (ev: React.ChangeEvent) => { + updater().setClientCfg({ ...this.props.ui.clientCfg, siteName: ev.target.value }); this.props.update(updater().updateUI); }; - - changeSiteDesc = (ev: React.ChangeEvent) => { - updater().setClientCfg({ ...this.props.ui, siteDesc: ev.target.value }); + onChangeSiteDesc = (ev: React.ChangeEvent) => { + 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) => { 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) => { 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) => { 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) => { 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) => { 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 { }; 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 { 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 { 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 { 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 { align: "fixed", bgColor: "", }, + allowSetBg: false, + autoTheme: true, }); this.props.update(updater().updateUI); }; @@ -871,6 +892,68 @@ export class BgCfg extends React.Component {
+ +
{this.props.msg.pkg.get("siteName")}
+ +
+ + +
{this.props.msg.pkg.get("siteDesc")}
+ +
+ +
+
{this.props.msg.pkg.get("allowSetBg")}
+ + +
+ +
+
{this.props.msg.pkg.get("autoTheme")}
+ + +
+ +
+
{this.props.msg.pkg.get("cfg.bg.url")}
@@ -878,7 +961,7 @@ export class BgCfg extends React.Component { 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 { 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")} />
@@ -903,7 +986,7 @@ export class BgCfg extends React.Component { 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")} />
@@ -916,7 +999,7 @@ export class BgCfg extends React.Component { 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")} />
@@ -929,12 +1012,12 @@ export class BgCfg extends React.Component { 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")} /> - + ); } } diff --git a/src/client/web/src/components/root_frame.tsx b/src/client/web/src/components/root_frame.tsx index 7ac136f..befaaa0 100644 --- a/src/client/web/src/components/root_frame.tsx +++ b/src/client/web/src/components/root_frame.tsx @@ -24,7 +24,7 @@ export interface Props { update?: (updater: (prevState: ICoreState) => ICoreState) => void; } -export interface State {} +export interface State { } export class RootFrame extends React.Component { constructor(p: Props) { super(p); @@ -47,15 +47,15 @@ export class RootFrame extends React.Component { }; } - 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, }; } diff --git a/src/client/web/src/components/state_updater.ts b/src/client/web/src/components/state_updater.ts index 7e06bbd..ea4430a 100644 --- a/src/client/web/src/components/state_updater.ts +++ b/src/client/web/src/components/state_updater.ts @@ -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 ""; }; diff --git a/src/client/web/src/i18n/en_US.ts b/src/client/web/src/i18n/en_US.ts index e07efe6..8bca28e 100644 --- a/src/client/web/src/i18n/en_US.ts +++ b/src/client/web/src/i18n/en_US.ts @@ -146,4 +146,11 @@ export const msgs: Map = 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", }); diff --git a/src/client/web/src/i18n/zh_CN.ts b/src/client/web/src/i18n/zh_CN.ts index 864adc4..278a76c 100644 --- a/src/client/web/src/i18n/zh_CN.ts +++ b/src/client/web/src/i18n/zh_CN.ts @@ -143,4 +143,11 @@ export const msgs: Map = Map({ theme: "主题", "theme.light": "光白", "theme.dark": "暗黑", + "siteSettings": "网站设置", + "siteName": "网站名", + "siteDesc": "网站描述", + "allowSetBg": "允许用户自定义背景", + "autoTheme": "自动切换主题", + "term.enabled": "启用", + "term.disabled": "关闭", }); diff --git a/src/handlers/settings/handlers.go b/src/handlers/settings/handlers.go index 02c4669..4df163b 100644 --- a/src/handlers/settings/handlers.go +++ b/src/handlers/settings/handlers.go @@ -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"` }