feat: reactive after save when profile content changes

This commit is contained in:
dongchengjie
2024-06-29 09:21:50 +08:00
parent 6ee5e560cc
commit 80d3c9e96f
12 changed files with 157 additions and 71 deletions

View File

@@ -27,10 +27,10 @@ export const ConfirmViewer = (props: Props) => {
return (
<Dialog open={open} onClose={onClose} maxWidth="xs" fullWidth>
<DialogTitle>{t(title)}</DialogTitle>
<DialogTitle>{title}</DialogTitle>
<DialogContent sx={{ pb: 1, userSelect: "text" }}>
{t(message)}
{message}
</DialogContent>
<DialogActions>

View File

@@ -32,7 +32,7 @@ interface Props {
language: "yaml" | "javascript" | "css";
schema?: "clash" | "merge";
onClose: () => void;
onChange?: (content?: string) => void;
onChange?: (prev?: string, curr?: string) => void;
}
// yaml worker
@@ -90,6 +90,7 @@ export const EditorViewer = (props: Props) => {
const editorRef = useRef<any>();
const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const themeMode = useThemeMode();
const prevData = useRef<string>();
useEffect(() => {
if (!open) return;
@@ -136,6 +137,8 @@ export const EditorViewer = (props: Props) => {
fontLigatures: true, // 连字符
smoothScrolling: true, // 平滑滚动
});
prevData.current = data;
});
return () => {
@@ -147,15 +150,15 @@ export const EditorViewer = (props: Props) => {
}, [open]);
const onSave = useLockFn(async () => {
const value = instanceRef.current?.getValue();
const currData = instanceRef.current?.getValue();
if (value == null) return;
if (currData == null) return;
try {
if (mode === "profile") {
await saveProfileFile(property, value);
await saveProfileFile(property, currData);
}
onChange?.(value);
onChange?.(prevData.current, currData);
onClose();
} catch (err: any) {
Notice.error(err.message || err.toString());

View File

@@ -17,7 +17,7 @@ import {
} from "@mui/material";
import { RefreshRounded, DragIndicator } from "@mui/icons-material";
import { useLoadingCache, useSetLoadingCache } from "@/services/states";
import { updateProfile, deleteProfile, viewProfile } from "@/services/cmds";
import { updateProfile, viewProfile } from "@/services/cmds";
import { Notice } from "@/components/base";
import { EditorViewer } from "@/components/profile/editor-viewer";
import { ProfileBox } from "./profile-box";
@@ -36,10 +36,20 @@ interface Props {
itemData: IProfileItem;
onSelect: (force: boolean) => void;
onEdit: () => void;
onChange?: (prev?: string, curr?: string) => void;
onDelete: () => void;
}
export const ProfileItem = (props: Props) => {
const { selected, activating, itemData, onSelect, onEdit } = props;
const {
selected,
activating,
itemData,
onSelect,
onEdit,
onChange,
onDelete,
} = props;
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: props.id });
@@ -53,6 +63,7 @@ export const ProfileItem = (props: Props) => {
// local file mode
// remote file mode
// remote file mode
const hasUrl = !!itemData.url;
const hasExtra = !!extra; // only subscription url has extra info
const hasHome = !!itemData.home; // only subscription url has home page
@@ -162,16 +173,6 @@ export const ProfileItem = (props: Props) => {
}
});
const onDelete = useLockFn(async () => {
setAnchorEl(null);
try {
await deleteProfile(itemData.uid);
mutate("getProfiles");
} catch (err: any) {
Notice.error(err?.message || err.toString());
}
});
const urlModeMenu = (
hasHome ? [{ label: "Home", handler: onOpenHome }] : []
).concat([
@@ -242,7 +243,7 @@ export const ProfileItem = (props: Props) => {
backdropFilter: "blur(2px)",
}}
>
<CircularProgress size={20} />
<CircularProgress color="inherit" size={20} />
</Box>
)}
<Box position="relative">
@@ -312,7 +313,7 @@ export const ProfileItem = (props: Props) => {
</Typography>
) : (
hasUrl && (
<Typography noWrap title={`From ${from}`}>
<Typography noWrap title={`${t("From")} ${from}`}>
{from}
</Typography>
)
@@ -323,7 +324,7 @@ export const ProfileItem = (props: Props) => {
flex="1 0 auto"
fontSize={14}
textAlign="right"
title={`Updated Time: ${parseExpire(updated)}`}
title={`${t("Update Time")}: ${parseExpire(updated)}`}
>
{updated > 0 ? dayjs(updated * 1000).fromNow() : ""}
</Typography>
@@ -334,17 +335,21 @@ export const ProfileItem = (props: Props) => {
{/* the third line show extra info or last updated time */}
{hasExtra ? (
<Box sx={{ ...boxStyle, fontSize: 14 }}>
<span title="Used / Total">
<span title={t("Used / Total")}>
{parseTraffic(upload + download)} / {parseTraffic(total)}
</span>
<span title="Expire Time">{expire}</span>
<span title={t("Expire Time")}>{expire}</span>
</Box>
) : (
<Box sx={{ ...boxStyle, fontSize: 12, justifyContent: "flex-end" }}>
<span title="Updated Time">{parseExpire(updated)}</span>
<span title={t("Update Time")}>{parseExpire(updated)}</span>
</Box>
)}
<LinearProgress variant="determinate" value={progress} />
<LinearProgress
variant="determinate"
value={progress}
style={{ opacity: progress > 0 ? 1 : 0 }}
/>
</ProfileBox>
<Menu
@@ -390,11 +395,12 @@ export const ProfileItem = (props: Props) => {
open={fileOpen}
language="yaml"
schema="clash"
onChange={onChange}
onClose={() => setFileOpen(false)}
/>
<ConfirmViewer
title="Confirm deletion"
message="This operation is not reversible"
title={t("Confirm deletion")}
message={t("This operation is not reversible")}
open={confirmOpen}
onClose={() => setConfirmOpen(false)}
onConfirm={() => {

View File

@@ -9,6 +9,7 @@ import {
MenuItem,
Menu,
IconButton,
CircularProgress,
} from "@mui/material";
import { FeaturedPlayListRounded } from "@mui/icons-material";
import { viewProfile } from "@/services/cmds";
@@ -20,6 +21,7 @@ import { ConfirmViewer } from "./confirm-viewer";
interface Props {
selected: boolean;
activating: boolean;
itemData: IProfileItem;
enableNum: number;
logInfo?: [string, string][];
@@ -27,14 +29,16 @@ interface Props {
onDisable: () => void;
onMoveTop: () => void;
onMoveEnd: () => void;
onDelete: () => void;
onEdit: () => void;
onChange?: (prev?: string, curr?: string) => void;
onDelete: () => void;
}
// profile enhanced item
export const ProfileMore = (props: Props) => {
const {
selected,
activating,
itemData,
enableNum,
logInfo = [],
@@ -44,6 +48,7 @@ export const ProfileMore = (props: Props) => {
onMoveEnd,
onDelete,
onEdit,
onChange,
} = props;
const { uid, type } = itemData;
@@ -132,6 +137,24 @@ export const ProfileMore = (props: Props) => {
event.preventDefault();
}}
>
{activating && (
<Box
sx={{
position: "absolute",
display: "flex",
justifyContent: "center",
alignItems: "center",
top: 10,
left: 10,
right: 10,
bottom: 2,
zIndex: 10,
backdropFilter: "blur(2px)",
}}
>
<CircularProgress color="inherit" size={20} />
</Box>
)}
<Box
display="flex"
justifyContent="space-between"
@@ -237,11 +260,12 @@ export const ProfileMore = (props: Props) => {
open={fileOpen}
language={type === "merge" ? "yaml" : "javascript"}
schema={type === "merge" ? "merge" : undefined}
onChange={onChange}
onClose={() => setFileOpen(false)}
/>
<ConfirmViewer
title="Confirm deletion"
message="This operation is not reversible"
title={t("Confirm deletion")}
message={t("This operation is not reversible")}
open={confirmOpen}
onClose={() => setConfirmOpen(false)}
onConfirm={() => {

View File

@@ -249,10 +249,10 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
property={value.pac_content ?? ""}
open={editorOpen}
language="javascript"
onChange={(content) => {
onChange={(_prev, curr) => {
let pac = DEFAULT_PAC;
if (content && content.trim().length > 0) {
pac = content;
if (curr && curr.trim().length > 0) {
pac = curr;
}
setValue((v) => ({ ...v, pac_content: pac }));
}}

View File

@@ -129,8 +129,8 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
property={theme.css_injection ?? ""}
open={editorOpen}
language="css"
onChange={(content) => {
theme.css_injection = content;
onChange={(_prev, curr) => {
theme.css_injection = curr;
handleChange("css_injection");
}}
onClose={() => {