(() => location.pathname.split("/")[2]);
useEffect(() => {
diff --git a/ui/src/pages/settings/SettingsAbout.tsx b/ui/src/pages/settings/SettingsAbout.tsx
new file mode 100644
index 00000000..b4d86e8c
--- /dev/null
+++ b/ui/src/pages/settings/SettingsAbout.tsx
@@ -0,0 +1,88 @@
+import { useTranslation } from "react-i18next";
+import { IconBook, IconBrandGithub, IconBrandTelegram, IconCoin, IconMessageChatbot } from "@tabler/icons-react";
+import { Badge, Button, Divider, List, Tooltip, Typography } from "antd";
+
+import { APP_DOCUMENT_URL, APP_DOWNLOAD_URL, APP_REPO_URL, APP_VERSION } from "@/domain/app";
+import { useVersionChecker } from "@/hooks";
+
+const SettingsAbout = () => {
+ const { t } = useTranslation();
+
+ const { hasUpdate } = useVersionChecker();
+
+ const handleDownloadClick = () => {
+ window.open(APP_DOWNLOAD_URL, "_blank");
+ };
+
+ const handleDocumentClick = () => {
+ window.open(APP_DOCUMENT_URL, "_blank");
+ };
+
+ const handleGithubClick = () => {
+ window.open(APP_REPO_URL, "_blank");
+ };
+
+ const handleTelegramClick = () => {
+ window.open("https://t.me/+ZXphsppxUg41YmVl", "_blank");
+ };
+
+ const handleDonateClick = () => {
+ window.open("https://profile.ikit.fun/sponsors/", "_blank");
+ };
+
+ const handleFeedbackClick = () => {
+ window.open(APP_REPO_URL + "/issues", "_blank");
+ };
+
+ return (
+ <>
+ Certimate
+
+
+ Version: {APP_VERSION}
+
+
+
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+ } />
+
+
+
+
+
+ {t("settings.about.contributors.title")}
+
+ {t("settings.about.contributors.tips")}
+
+
+

+
+
+
+
+
+
+ {t("settings.about.feedback.button")}}>
+ }
+ title={t("settings.about.feedback.title")}
+ description={t("settings.about.feedback.subtitle")}
+ />
+
+
+
+ >
+ );
+};
+
+export default SettingsAbout;
diff --git a/ui/src/pages/settings/SettingsDiagnostics.tsx b/ui/src/pages/settings/SettingsDiagnostics.tsx
index b693d131..c1157e8c 100644
--- a/ui/src/pages/settings/SettingsDiagnostics.tsx
+++ b/ui/src/pages/settings/SettingsDiagnostics.tsx
@@ -306,7 +306,7 @@ const SettingsDiagnosticsWorkflowDispatcher = ({ className, style }: { className
type Statistics = Awaited>["data"];
const [statistics, setStatistics] = useState();
- const { loading } = useRequest(
+ const { loading, cancel } = useRequest(
() => {
return getWorkflowStats();
},
@@ -318,6 +318,11 @@ const SettingsDiagnosticsWorkflowDispatcher = ({ className, style }: { className
onSuccess: (res) => {
setStatistics(res.data);
},
+ onError: () => {
+ if (!statistics) {
+ cancel();
+ }
+ },
}
);
diff --git a/ui/src/routers/index.tsx b/ui/src/routers/index.tsx
index be671ebc..cabf6278 100644
--- a/ui/src/routers/index.tsx
+++ b/ui/src/routers/index.tsx
@@ -9,6 +9,7 @@ import Dashboard from "@/pages/dashboard/Dashboard";
import ErrorLayout from "@/pages/ErrorLayout";
import Login from "@/pages/login/Login";
import Settings from "@/pages/settings/Settings";
+import SettingsAbout from "@/pages/settings/SettingsAbout";
import SettingsAccount from "@/pages/settings/SettingsAccount";
import SettingsAppearance from "@/pages/settings/SettingsAppearance";
import SettingsDiagnostics from "@/pages/settings/SettingsDiagnostics";
@@ -87,6 +88,10 @@ export const router = createHashRouter([
path: "/settings/diagnostics",
element: ,
},
+ {
+ path: "/settings/about",
+ element: ,
+ },
],
},
],