feat: adjust profiles page ui
This commit is contained in:
parent
8bb4803ff9
commit
7338838b0e
@ -26,7 +26,7 @@ interface Props {
|
|||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileEditor = (props: Props) => {
|
export const EditorViewer = (props: Props) => {
|
||||||
const { uid, open, mode, onClose, onChange } = props;
|
const { uid, open, mode, onClose, onChange } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
@ -1,44 +1,29 @@
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { Grid } from "@mui/material";
|
||||||
import { Box, Grid, IconButton, Stack } from "@mui/material";
|
|
||||||
import { RestartAltRounded } from "@mui/icons-material";
|
|
||||||
import {
|
import {
|
||||||
getProfiles,
|
getProfiles,
|
||||||
deleteProfile,
|
deleteProfile,
|
||||||
enhanceProfiles,
|
|
||||||
patchProfilesConfig,
|
patchProfilesConfig,
|
||||||
getRuntimeLogs,
|
getRuntimeLogs,
|
||||||
} from "@/services/cmds";
|
} from "@/services/cmds";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
import ProfileMore from "./profile-more";
|
import { ProfileMore } from "./profile-more";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
items: IProfileItem[];
|
items: IProfileItem[];
|
||||||
chain: string[];
|
chain: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnhancedMode = (props: Props) => {
|
export const EnhancedMode = (props: Props) => {
|
||||||
const { items, chain } = props;
|
const { items, chain } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { mutate: mutateProfiles } = useSWR("getProfiles", getProfiles);
|
const { mutate: mutateProfiles } = useSWR("getProfiles", getProfiles);
|
||||||
const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
|
const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
|
||||||
"getRuntimeLogs",
|
"getRuntimeLogs",
|
||||||
getRuntimeLogs
|
getRuntimeLogs
|
||||||
);
|
);
|
||||||
|
|
||||||
// handler
|
|
||||||
const onEnhance = useLockFn(async () => {
|
|
||||||
try {
|
|
||||||
await enhanceProfiles();
|
|
||||||
mutateLogs();
|
|
||||||
// Notice.success("Refresh clash config", 1000);
|
|
||||||
} catch (err: any) {
|
|
||||||
Notice.error(err.message || err.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const onEnhanceEnable = useLockFn(async (uid: string) => {
|
const onEnhanceEnable = useLockFn(async (uid: string) => {
|
||||||
if (chain.includes(uid)) return;
|
if (chain.includes(uid)) return;
|
||||||
|
|
||||||
@ -87,43 +72,22 @@ const EnhancedMode = (props: Props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ mt: 2 }}>
|
<Grid container spacing={{ xs: 2, lg: 3 }}>
|
||||||
<Stack
|
{items.map((item) => (
|
||||||
spacing={1}
|
<Grid item xs={12} sm={6} md={4} lg={3} key={item.file}>
|
||||||
direction="row"
|
<ProfileMore
|
||||||
alignItems="center"
|
selected={!!chain.includes(item.uid)}
|
||||||
justifyContent="flex-end"
|
itemData={item}
|
||||||
sx={{ mb: 0.5 }}
|
enableNum={chain.length}
|
||||||
>
|
logInfo={chainLogs[item.uid]}
|
||||||
<IconButton
|
onEnable={() => onEnhanceEnable(item.uid)}
|
||||||
size="small"
|
onDisable={() => onEnhanceDisable(item.uid)}
|
||||||
color="inherit"
|
onDelete={() => onEnhanceDelete(item.uid)}
|
||||||
title={t("Refresh profiles")}
|
onMoveTop={() => onMoveTop(item.uid)}
|
||||||
onClick={onEnhance}
|
onMoveEnd={() => onMoveEnd(item.uid)}
|
||||||
>
|
/>
|
||||||
<RestartAltRounded />
|
</Grid>
|
||||||
</IconButton>
|
))}
|
||||||
</Stack>
|
</Grid>
|
||||||
|
|
||||||
<Grid container spacing={2}>
|
|
||||||
{items.map((item) => (
|
|
||||||
<Grid item xs={12} sm={6} key={item.file}>
|
|
||||||
<ProfileMore
|
|
||||||
selected={!!chain.includes(item.uid)}
|
|
||||||
itemData={item}
|
|
||||||
enableNum={chain.length}
|
|
||||||
logInfo={chainLogs[item.uid]}
|
|
||||||
onEnable={() => onEnhanceEnable(item.uid)}
|
|
||||||
onDisable={() => onEnhanceDisable(item.uid)}
|
|
||||||
onDelete={() => onEnhanceDelete(item.uid)}
|
|
||||||
onMoveTop={() => onMoveTop(item.uid)}
|
|
||||||
onMoveEnd={() => onMoveEnd(item.uid)}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EnhancedMode;
|
|
||||||
|
@ -7,7 +7,7 @@ interface Props {
|
|||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileInput = (props: Props) => {
|
export const FileInput = (props: Props) => {
|
||||||
const { onChange } = props;
|
const { onChange } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -59,5 +59,3 @@ const FileInput = (props: Props) => {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FileInput;
|
|
||||||
|
@ -27,7 +27,7 @@ interface Props {
|
|||||||
|
|
||||||
// edit the profile item
|
// edit the profile item
|
||||||
// remote / local file / merge / script
|
// remote / local file / merge / script
|
||||||
const InfoEditor = (props: Props) => {
|
export const InfoViewer = (props: Props) => {
|
||||||
const { open, itemData, onClose } = props;
|
const { open, itemData, onClose } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -209,5 +209,3 @@ const InfoEditor = (props: Props) => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default InfoEditor;
|
|
@ -18,7 +18,7 @@ interface Props {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LogViewer = (props: Props) => {
|
export const LogViewer = (props: Props) => {
|
||||||
const { open, logInfo, onClose } = props;
|
const { open, logInfo, onClose } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -67,5 +67,3 @@ const LogViewer = (props: Props) => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LogViewer;
|
|
||||||
|
@ -1,43 +1,43 @@
|
|||||||
import { alpha, Box, styled } from "@mui/material";
|
import { alpha, Box, styled } from "@mui/material";
|
||||||
|
|
||||||
const ProfileBox = styled(Box)(({ theme, "aria-selected": selected }) => {
|
export const ProfileBox = styled(Box)(
|
||||||
const { mode, primary, text, grey, background } = theme.palette;
|
({ theme, "aria-selected": selected }) => {
|
||||||
const key = `${mode}-${!!selected}`;
|
const { mode, primary, text, grey, background } = theme.palette;
|
||||||
|
const key = `${mode}-${!!selected}`;
|
||||||
|
|
||||||
const backgroundColor = {
|
const backgroundColor = {
|
||||||
"light-true": alpha(primary.main, 0.2),
|
"light-true": alpha(primary.main, 0.2),
|
||||||
"light-false": alpha(background.paper, 0.75),
|
"light-false": alpha(background.paper, 0.75),
|
||||||
"dark-true": alpha(primary.main, 0.45),
|
"dark-true": alpha(primary.main, 0.45),
|
||||||
"dark-false": alpha(grey[700], 0.45),
|
"dark-false": alpha(grey[700], 0.45),
|
||||||
}[key]!;
|
}[key]!;
|
||||||
|
|
||||||
const color = {
|
const color = {
|
||||||
"light-true": text.secondary,
|
"light-true": text.secondary,
|
||||||
"light-false": text.secondary,
|
"light-false": text.secondary,
|
||||||
"dark-true": alpha(text.secondary, 0.85),
|
"dark-true": alpha(text.secondary, 0.85),
|
||||||
"dark-false": alpha(text.secondary, 0.65),
|
"dark-false": alpha(text.secondary, 0.65),
|
||||||
}[key]!;
|
}[key]!;
|
||||||
|
|
||||||
const h2color = {
|
const h2color = {
|
||||||
"light-true": primary.main,
|
"light-true": primary.main,
|
||||||
"light-false": text.primary,
|
"light-false": text.primary,
|
||||||
"dark-true": primary.light,
|
"dark-true": primary.light,
|
||||||
"dark-false": text.primary,
|
"dark-false": text.primary,
|
||||||
}[key]!;
|
}[key]!;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
display: "block",
|
display: "block",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadius,
|
||||||
boxShadow: theme.shadows[2],
|
boxShadow: theme.shadows[2],
|
||||||
padding: "8px 16px",
|
padding: "8px 16px",
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
color,
|
color,
|
||||||
"& h2": { color: h2color },
|
"& h2": { color: h2color },
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
export default ProfileBox;
|
|
||||||
|
@ -17,10 +17,10 @@ import { RefreshRounded } from "@mui/icons-material";
|
|||||||
import { atomLoadingCache } from "@/services/states";
|
import { atomLoadingCache } from "@/services/states";
|
||||||
import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
|
import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
|
import { InfoViewer } from "./info-viewer";
|
||||||
|
import { EditorViewer } from "./editor-viewer";
|
||||||
|
import { ProfileBox } from "./profile-box";
|
||||||
import parseTraffic from "@/utils/parse-traffic";
|
import parseTraffic from "@/utils/parse-traffic";
|
||||||
import ProfileBox from "./profile-box";
|
|
||||||
import InfoEditor from "./info-editor";
|
|
||||||
import { FileEditor } from "./file-editor";
|
|
||||||
|
|
||||||
const round = keyframes`
|
const round = keyframes`
|
||||||
from { transform: rotate(0deg); }
|
from { transform: rotate(0deg); }
|
||||||
@ -33,7 +33,7 @@ interface Props {
|
|||||||
onSelect: (force: boolean) => void;
|
onSelect: (force: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProfileItem = (props: Props) => {
|
export const ProfileItem = (props: Props) => {
|
||||||
const { selected, itemData, onSelect } = props;
|
const { selected, itemData, onSelect } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -298,13 +298,13 @@ const ProfileItem = (props: Props) => {
|
|||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<InfoEditor
|
<InfoViewer
|
||||||
open={editOpen}
|
open={editOpen}
|
||||||
itemData={itemData}
|
itemData={itemData}
|
||||||
onClose={() => setEditOpen(false)}
|
onClose={() => setEditOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FileEditor
|
<EditorViewer
|
||||||
uid={uid}
|
uid={uid}
|
||||||
open={fileOpen}
|
open={fileOpen}
|
||||||
mode="yaml"
|
mode="yaml"
|
||||||
@ -325,5 +325,3 @@ function parseExpire(expire?: number) {
|
|||||||
if (!expire) return "-";
|
if (!expire) return "-";
|
||||||
return dayjs(expire * 1000).format("YYYY-MM-DD");
|
return dayjs(expire * 1000).format("YYYY-MM-DD");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProfileItem;
|
|
||||||
|
@ -14,10 +14,10 @@ import {
|
|||||||
import { FeaturedPlayListRounded } from "@mui/icons-material";
|
import { FeaturedPlayListRounded } from "@mui/icons-material";
|
||||||
import { viewProfile } from "@/services/cmds";
|
import { viewProfile } from "@/services/cmds";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
import InfoEditor from "./info-editor";
|
import { InfoViewer } from "./info-viewer";
|
||||||
import { FileEditor } from "./file-editor";
|
import { EditorViewer } from "./editor-viewer";
|
||||||
import ProfileBox from "./profile-box";
|
import { ProfileBox } from "./profile-box";
|
||||||
import LogViewer from "./log-viewer";
|
import { LogViewer } from "./log-viewer";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
@ -32,7 +32,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// profile enhanced item
|
// profile enhanced item
|
||||||
const ProfileMore = (props: Props) => {
|
export const ProfileMore = (props: Props) => {
|
||||||
const {
|
const {
|
||||||
selected,
|
selected,
|
||||||
itemData,
|
itemData,
|
||||||
@ -219,13 +219,13 @@ const ProfileMore = (props: Props) => {
|
|||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<InfoEditor
|
<InfoViewer
|
||||||
open={editOpen}
|
open={editOpen}
|
||||||
itemData={itemData}
|
itemData={itemData}
|
||||||
onClose={() => setEditOpen(false)}
|
onClose={() => setEditOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FileEditor
|
<EditorViewer
|
||||||
uid={uid}
|
uid={uid}
|
||||||
open={fileOpen}
|
open={fileOpen}
|
||||||
mode={type === "merge" ? "yaml" : "javascript"}
|
mode={type === "merge" ? "yaml" : "javascript"}
|
||||||
@ -247,5 +247,3 @@ function parseExpire(expire?: number) {
|
|||||||
if (!expire) return "-";
|
if (!expire) return "-";
|
||||||
return dayjs(expire * 1000).format("YYYY-MM-DD");
|
return dayjs(expire * 1000).format("YYYY-MM-DD");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProfileMore;
|
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
import { Settings } from "@mui/icons-material";
|
import { Settings } from "@mui/icons-material";
|
||||||
import { createProfile } from "@/services/cmds";
|
import { createProfile } from "@/services/cmds";
|
||||||
import { Notice } from "@/components/base";
|
import { Notice } from "@/components/base";
|
||||||
import FileInput from "./file-input";
|
import { FileInput } from "./file-input";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -30,7 +30,7 @@ interface Props {
|
|||||||
|
|
||||||
// create a new profile
|
// create a new profile
|
||||||
// remote / local file / merge / script
|
// remote / local file / merge / script
|
||||||
const ProfileNew = (props: Props) => {
|
export const ProfileNew = (props: Props) => {
|
||||||
const { open, onClose } = props;
|
const { open, onClose } = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -210,5 +210,3 @@ const ProfileNew = (props: Props) => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProfileNew;
|
|
||||||
|
@ -2,20 +2,22 @@ import useSWR, { mutate } from "swr";
|
|||||||
import { useLockFn } from "ahooks";
|
import { useLockFn } from "ahooks";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useSetRecoilState } from "recoil";
|
import { useSetRecoilState } from "recoil";
|
||||||
import { Button, Grid, Stack, TextField } from "@mui/material";
|
import { Box, Button, Grid, IconButton, Stack, TextField } from "@mui/material";
|
||||||
|
import { CachedRounded } from "@mui/icons-material";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
getProfiles,
|
getProfiles,
|
||||||
patchProfile,
|
patchProfile,
|
||||||
patchProfilesConfig,
|
patchProfilesConfig,
|
||||||
importProfile,
|
importProfile,
|
||||||
|
enhanceProfiles,
|
||||||
} from "@/services/cmds";
|
} from "@/services/cmds";
|
||||||
import { getProxies, updateProxy } from "@/services/api";
|
import { getProxies, updateProxy } from "@/services/api";
|
||||||
import { atomCurrentProfile } from "@/services/states";
|
import { atomCurrentProfile } from "@/services/states";
|
||||||
import { BasePage, Notice } from "@/components/base";
|
import { BasePage, Notice } from "@/components/base";
|
||||||
import ProfileNew from "@/components/profile/profile-new";
|
import { ProfileNew } from "@/components/profile/profile-new";
|
||||||
import ProfileItem from "@/components/profile/profile-item";
|
import { ProfileItem } from "@/components/profile/profile-item";
|
||||||
import EnhancedMode from "@/components/profile/enhanced";
|
import { EnhancedMode } from "@/components/profile/enhanced";
|
||||||
|
|
||||||
const ProfilePage = () => {
|
const ProfilePage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -138,8 +140,32 @@ const ProfilePage = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onEnhance = useLockFn(async () => {
|
||||||
|
try {
|
||||||
|
await enhanceProfiles();
|
||||||
|
mutate("getRuntimeLogs");
|
||||||
|
// Notice.success("Refresh clash config", 1000);
|
||||||
|
} catch (err: any) {
|
||||||
|
Notice.error(err.message || err.toString(), 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePage title={t("Profiles")}>
|
<BasePage
|
||||||
|
title={t("Profiles")}
|
||||||
|
header={
|
||||||
|
<Box sx={{ mt: 1, display: "flex", alignItems: "center" }}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
color="inherit"
|
||||||
|
title={t("Refresh profiles")}
|
||||||
|
onClick={onEnhance}
|
||||||
|
>
|
||||||
|
<CachedRounded />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Stack direction="row" spacing={1} sx={{ mb: 2 }}>
|
<Stack direction="row" spacing={1} sx={{ mb: 2 }}>
|
||||||
<TextField
|
<TextField
|
||||||
hiddenLabel
|
hiddenLabel
|
||||||
@ -170,17 +196,19 @@ const ProfilePage = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Grid container spacing={2}>
|
<Box sx={{ mb: 4.5 }}>
|
||||||
{regularItems.map((item) => (
|
<Grid container spacing={{ xs: 2, lg: 3 }}>
|
||||||
<Grid item xs={12} sm={6} key={item.file}>
|
{regularItems.map((item) => (
|
||||||
<ProfileItem
|
<Grid item xs={12} sm={6} md={4} lg={3} key={item.file}>
|
||||||
selected={profiles.current === item.uid}
|
<ProfileItem
|
||||||
itemData={item}
|
selected={profiles.current === item.uid}
|
||||||
onSelect={(f) => onSelect(item.uid, f)}
|
itemData={item}
|
||||||
/>
|
onSelect={(f) => onSelect(item.uid, f)}
|
||||||
</Grid>
|
/>
|
||||||
))}
|
</Grid>
|
||||||
</Grid>
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{enhanceItems.length > 0 && (
|
{enhanceItems.length > 0 && (
|
||||||
<EnhancedMode items={enhanceItems} chain={profiles.chain || []} />
|
<EnhancedMode items={enhanceItems} chain={profiles.chain || []} />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user