mirror of
https://github.com/usememos/memos.git
synced 2025-02-15 10:50:47 +01:00
chore: update data initial requests (#538)
This commit is contained in:
parent
362306a9cb
commit
a0667abec8
@ -3,9 +3,9 @@ package api
|
||||
import "github.com/usememos/memos/server/profile"
|
||||
|
||||
type SystemStatus struct {
|
||||
Host *User `json:"host"`
|
||||
Profile *profile.Profile `json:"profile"`
|
||||
DBSize int64 `json:"dbSize"`
|
||||
Host *User `json:"host"`
|
||||
Profile profile.Profile `json:"profile"`
|
||||
DBSize int64 `json:"dbSize"`
|
||||
|
||||
// System settings
|
||||
// Allow sign up.
|
||||
|
@ -41,7 +41,7 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
|
||||
|
||||
systemStatus := api.SystemStatus{
|
||||
Host: hostUser,
|
||||
Profile: s.Profile,
|
||||
Profile: *s.Profile,
|
||||
DBSize: 0,
|
||||
AllowSignUp: false,
|
||||
AdditionalStyle: "",
|
||||
|
@ -2,49 +2,43 @@ import { CssVarsProvider } from "@mui/joy/styles";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
import { globalService, locationService } from "./services";
|
||||
import { locationService } from "./services";
|
||||
import { useAppSelector } from "./store";
|
||||
import router from "./router";
|
||||
import * as api from "./helpers/api";
|
||||
import * as storage from "./helpers/storage";
|
||||
|
||||
function App() {
|
||||
const { i18n } = useTranslation();
|
||||
const global = useAppSelector((state) => state.global);
|
||||
const { locale, systemStatus } = useAppSelector((state) => state.global);
|
||||
|
||||
useEffect(() => {
|
||||
locationService.updateStateWithLocation();
|
||||
window.onpopstate = () => {
|
||||
locationService.updateStateWithLocation();
|
||||
};
|
||||
|
||||
globalService.initialState();
|
||||
}, []);
|
||||
|
||||
// Inject additional style and script codes.
|
||||
useEffect(() => {
|
||||
api.getSystemStatus().then(({ data }) => {
|
||||
const { data: status } = data;
|
||||
if (status.additionalStyle) {
|
||||
const styleEl = document.createElement("style");
|
||||
styleEl.innerHTML = status.additionalStyle;
|
||||
styleEl.setAttribute("type", "text/css");
|
||||
document.head.appendChild(styleEl);
|
||||
}
|
||||
if (status.additionalScript) {
|
||||
const scriptEl = document.createElement("script");
|
||||
scriptEl.innerHTML = status.additionalScript;
|
||||
document.head.appendChild(scriptEl);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
if (systemStatus.additionalStyle) {
|
||||
const styleEl = document.createElement("style");
|
||||
styleEl.innerHTML = systemStatus.additionalStyle;
|
||||
styleEl.setAttribute("type", "text/css");
|
||||
document.head.appendChild(styleEl);
|
||||
}
|
||||
if (systemStatus.additionalScript) {
|
||||
const scriptEl = document.createElement("script");
|
||||
scriptEl.innerHTML = systemStatus.additionalScript;
|
||||
document.head.appendChild(scriptEl);
|
||||
}
|
||||
}, [systemStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
i18n.changeLanguage(global.locale);
|
||||
i18n.changeLanguage(locale);
|
||||
storage.set({
|
||||
locale: global.locale,
|
||||
locale: locale,
|
||||
});
|
||||
}, [global.locale]);
|
||||
}, [locale]);
|
||||
|
||||
return (
|
||||
<CssVarsProvider>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as api from "../helpers/api";
|
||||
import { useAppSelector } from "../store";
|
||||
import Icon from "./Icon";
|
||||
import { generateDialog } from "./Dialog";
|
||||
import GitHubBadge from "./GitHubBadge";
|
||||
@ -10,23 +9,7 @@ type Props = DialogProps;
|
||||
|
||||
const AboutSiteDialog: React.FC<Props> = ({ destroy }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [profile, setProfile] = useState<Profile>();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
api.getSystemStatus().then(({ data }) => {
|
||||
const {
|
||||
data: { profile },
|
||||
} = data;
|
||||
setProfile(profile);
|
||||
});
|
||||
} catch (error) {
|
||||
setProfile({
|
||||
mode: "dev",
|
||||
version: "0.0.0",
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
const profile = useAppSelector((state) => state.global.systemStatus.profile);
|
||||
|
||||
const handleCloseBtnClick = () => {
|
||||
destroy();
|
||||
@ -49,15 +32,13 @@ const AboutSiteDialog: React.FC<Props> = ({ destroy }: Props) => {
|
||||
<br />
|
||||
<div className="addtion-info-container">
|
||||
<GitHubBadge />
|
||||
{profile !== undefined && (
|
||||
<>
|
||||
{t("common.version")}:
|
||||
<span className="pre-text">
|
||||
{profile?.version}-{profile?.mode}
|
||||
</span>
|
||||
🎉
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
{t("common.version")}:
|
||||
<span className="pre-text">
|
||||
{profile.version}-{profile.mode}
|
||||
</span>
|
||||
🎉
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@ -8,6 +8,7 @@ import "../less/memo-filter.less";
|
||||
|
||||
const MemoFilter = () => {
|
||||
const { t } = useTranslation();
|
||||
useAppSelector((state) => state.shortcut.shortcuts);
|
||||
const query = useAppSelector((state) => state.location.query);
|
||||
const { tag: tagQuery, duration, type: memoType, text: textQuery, shortcutId, visibility } = query;
|
||||
const shortcut = shortcutId ? shortcutService.getShortcutById(shortcutId) : null;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAppSelector } from "../store";
|
||||
import * as api from "../helpers/api";
|
||||
import * as storage from "../helpers/storage";
|
||||
import Icon from "./Icon";
|
||||
@ -10,35 +11,23 @@ interface State {
|
||||
}
|
||||
|
||||
const UpdateVersionBanner: React.FC = () => {
|
||||
const profile = useAppSelector((state) => state.global.systemStatus.profile);
|
||||
const [state, setState] = useState<State>({
|
||||
latestVersion: "",
|
||||
show: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([api.getRepoLatestTag(), api.getSystemStatus()])
|
||||
.then(
|
||||
([
|
||||
latestTag,
|
||||
{
|
||||
data: {
|
||||
data: { profile },
|
||||
},
|
||||
},
|
||||
]) => {
|
||||
const { skippedVersion } = storage.get(["skippedVersion"]);
|
||||
const latestVersion = latestTag.slice(1) || "0.0.0";
|
||||
const currentVersion = profile.version;
|
||||
const skipped = skippedVersion ? skippedVersion === latestVersion : false;
|
||||
setState({
|
||||
latestVersion,
|
||||
show: !skipped && currentVersion < latestVersion,
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(() => {
|
||||
// do nth
|
||||
api.getRepoLatestTag().then((latestTag) => {
|
||||
const { skippedVersion } = storage.get(["skippedVersion"]);
|
||||
const latestVersion = latestTag.slice(1) || "0.0.0";
|
||||
const currentVersion = profile.version;
|
||||
const skipped = skippedVersion ? skippedVersion === latestVersion : false;
|
||||
setState({
|
||||
latestVersion,
|
||||
show: !skipped && currentVersion < latestVersion,
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onSkip = () => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAppSelector } from "../store";
|
||||
import * as api from "../helpers/api";
|
||||
import { validate, ValidatorConfig } from "../helpers/validator";
|
||||
import useLoading from "../hooks/useLoading";
|
||||
@ -19,23 +20,11 @@ const validateConfig: ValidatorConfig = {
|
||||
const Auth = () => {
|
||||
const { t, i18n } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const pageLoadingState = useLoading(true);
|
||||
const [systemStatus, setSystemStatus] = useState<SystemStatus>();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const systemStatus = useAppSelector((state) => state.global.systemStatus);
|
||||
const actionBtnLoadingState = useLoading(false);
|
||||
|
||||
useEffect(() => {
|
||||
api.getSystemStatus().then(({ data }) => {
|
||||
const { data: status } = data;
|
||||
setSystemStatus(status);
|
||||
if (status.profile.mode === "dev") {
|
||||
setEmail("demo@usememos.com");
|
||||
setPassword("secret");
|
||||
}
|
||||
pageLoadingState.setFinish();
|
||||
});
|
||||
}, []);
|
||||
const mode = systemStatus.profile.mode;
|
||||
const [email, setEmail] = useState(mode === "dev" ? "demo@usememos.com" : "");
|
||||
const [password, setPassword] = useState(mode === "dev" ? "secret" : "");
|
||||
|
||||
const handleEmailInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const text = e.target.value as string;
|
||||
@ -138,39 +127,32 @@ const Auth = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="action-btns-container">
|
||||
{!pageLoadingState.isLoading && (
|
||||
{systemStatus?.host ? (
|
||||
<>
|
||||
{systemStatus?.host ? (
|
||||
<>
|
||||
{actionBtnLoadingState.isLoading && <Icon.Loader className="w-4 h-auto animate-spin" />}
|
||||
{systemStatus?.allowSignUp && (
|
||||
<>
|
||||
<button
|
||||
className={`btn signup-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSignUpBtnsClick("USER")}
|
||||
>
|
||||
{t("common.sign-up")}
|
||||
</button>
|
||||
<span className="mr-2 font-mono text-gray-200">/</span>
|
||||
</>
|
||||
)}
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={handleSigninBtnsClick}
|
||||
>
|
||||
{t("common.sign-in")}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
{actionBtnLoadingState.isLoading && <Icon.Loader className="w-4 h-auto animate-spin" />}
|
||||
{systemStatus?.allowSignUp && (
|
||||
<>
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSignUpBtnsClick("HOST")}
|
||||
className={`btn signup-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSignUpBtnsClick("USER")}
|
||||
>
|
||||
{t("auth.signup-as-host")}
|
||||
{t("common.sign-up")}
|
||||
</button>
|
||||
<span className="mr-2 font-mono text-gray-200">/</span>
|
||||
</>
|
||||
)}
|
||||
<button className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`} onClick={handleSigninBtnsClick}>
|
||||
{t("common.sign-in")}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSignUpBtnsClick("HOST")}
|
||||
>
|
||||
{t("auth.signup-as-host")}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createBrowserRouter, redirect } from "react-router-dom";
|
||||
import { isNullorUndefined } from "../helpers/utils";
|
||||
import { userService } from "../services";
|
||||
import { globalService, userService } from "../services";
|
||||
import Auth from "../pages/Auth";
|
||||
import Explore from "../pages/Explore";
|
||||
import Home from "../pages/Home";
|
||||
@ -10,12 +10,20 @@ const router = createBrowserRouter([
|
||||
{
|
||||
path: "/auth",
|
||||
element: <Auth />,
|
||||
loader: async () => {
|
||||
try {
|
||||
await globalService.initialState();
|
||||
} catch (error) {
|
||||
// do nth
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
element: <Home />,
|
||||
loader: async () => {
|
||||
try {
|
||||
await globalService.initialState();
|
||||
await userService.initialState();
|
||||
} catch (error) {
|
||||
// do nth
|
||||
@ -34,6 +42,7 @@ const router = createBrowserRouter([
|
||||
element: <Home />,
|
||||
loader: async () => {
|
||||
try {
|
||||
await globalService.initialState();
|
||||
await userService.initialState();
|
||||
} catch (error) {
|
||||
// do nth
|
||||
@ -50,6 +59,7 @@ const router = createBrowserRouter([
|
||||
element: <Explore />,
|
||||
loader: async () => {
|
||||
try {
|
||||
await globalService.initialState();
|
||||
await userService.initialState();
|
||||
} catch (error) {
|
||||
// do nth
|
||||
@ -66,6 +76,7 @@ const router = createBrowserRouter([
|
||||
element: <MemoDetail />,
|
||||
loader: async () => {
|
||||
try {
|
||||
await globalService.initialState();
|
||||
await userService.initialState();
|
||||
} catch (error) {
|
||||
// do nth
|
||||
|
@ -2,7 +2,6 @@ import store from "../store";
|
||||
import * as api from "../helpers/api";
|
||||
import * as storage from "../helpers/storage";
|
||||
import { setGlobalState, setLocale } from "../store/modules/global";
|
||||
import { convertResponseModelUser } from "./userService";
|
||||
|
||||
const globalService = {
|
||||
getState: () => {
|
||||
@ -12,19 +11,22 @@ const globalService = {
|
||||
initialState: async () => {
|
||||
const defaultGlobalState = {
|
||||
locale: "en" as Locale,
|
||||
systemStatus: {
|
||||
allowSignUp: false,
|
||||
additionalStyle: "",
|
||||
additionalScript: "",
|
||||
} as SystemStatus,
|
||||
};
|
||||
|
||||
const { locale: storageLocale } = storage.get(["locale"]);
|
||||
if (storageLocale) {
|
||||
defaultGlobalState.locale = storageLocale;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = (await api.getMyselfUser()).data;
|
||||
const { data } = (await api.getSystemStatus()).data;
|
||||
if (data) {
|
||||
const user = convertResponseModelUser(data);
|
||||
if (user.setting.locale) {
|
||||
defaultGlobalState.locale = user.setting.locale;
|
||||
}
|
||||
defaultGlobalState.systemStatus = data;
|
||||
}
|
||||
} catch (error) {
|
||||
// do nth
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { locationService } from ".";
|
||||
import { globalService, locationService } from ".";
|
||||
import * as api from "../helpers/api";
|
||||
import { UNKNOWN_ID } from "../helpers/consts";
|
||||
import store from "../store";
|
||||
import { setLocale } from "../store/modules/global";
|
||||
import { setUser, patchUser, setHost, setOwner } from "../store/modules/user";
|
||||
|
||||
const defauleSetting: Setting = {
|
||||
@ -35,11 +36,9 @@ const userService = {
|
||||
},
|
||||
|
||||
initialState: async () => {
|
||||
const {
|
||||
data: { host },
|
||||
} = (await api.getSystemStatus()).data;
|
||||
if (host) {
|
||||
store.dispatch(setHost(convertResponseModelUser(host)));
|
||||
const { systemStatus } = globalService.getState();
|
||||
if (systemStatus.host) {
|
||||
store.dispatch(setHost(convertResponseModelUser(systemStatus.host)));
|
||||
}
|
||||
|
||||
const ownerUserId = userService.getUserIdFromPath();
|
||||
@ -53,6 +52,9 @@ const userService = {
|
||||
const { data: user } = (await api.getMyselfUser()).data;
|
||||
if (user) {
|
||||
store.dispatch(setUser(convertResponseModelUser(user)));
|
||||
if (user.setting.locale) {
|
||||
store.dispatch(setLocale(user.setting.locale));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2,11 +2,25 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface State {
|
||||
locale: Locale;
|
||||
systemStatus: SystemStatus;
|
||||
}
|
||||
|
||||
const globalSlice = createSlice({
|
||||
name: "global",
|
||||
initialState: {} as State,
|
||||
initialState: {
|
||||
locale: "en",
|
||||
systemStatus: {
|
||||
host: undefined,
|
||||
profile: {
|
||||
mode: "dev",
|
||||
version: "",
|
||||
},
|
||||
dbSize: 0,
|
||||
allowSignUp: false,
|
||||
additionalStyle: "",
|
||||
additionalScript: "",
|
||||
},
|
||||
} as State,
|
||||
reducers: {
|
||||
setGlobalState: (_, action: PayloadAction<State>) => {
|
||||
return action.payload;
|
||||
|
2
web/src/types/modules/system.d.ts
vendored
2
web/src/types/modules/system.d.ts
vendored
@ -4,7 +4,7 @@ interface Profile {
|
||||
}
|
||||
|
||||
interface SystemStatus {
|
||||
host: User;
|
||||
host?: User;
|
||||
profile: Profile;
|
||||
dbSize: number;
|
||||
// System settings
|
||||
|
Loading…
x
Reference in New Issue
Block a user