From d2f1a76cd2e421904918aa23f48ad088cecef072 Mon Sep 17 00:00:00 2001 From: mHost Developer Date: Tue, 29 Sep 2026 13:35:11 +0800 Subject: [PATCH] chore(frontend): remove 6 unmounted components + 3 orphaned CSS modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deleting -1309 lines of code that no route or component can reach. #230 item 7 (P-F6, ApplyStatus) already proposed this. Items 4 and the underlying finding are broader than that, and both need reclassifying: - Item 4 (P-F7) claimed ProfileEdit "silently discards unsaved name/description edits" and asked for it to outrank the rest of the perf batch. ProfileEdit has had zero importers since 1bfe932 (the #55 sidebar/drawer redesign) — no route, no import, no test, no dynamic import. The live editing components are not affected: HostsProfileView already seeds draft rules on `[profile?.id]` (not `[profile]`) and seeds draftInfo on-demand in handleEditInfo rather than in an effect, and DnsProfileView has no useEffect at all. There was no user-facing data loss to fix. The underlying cause is an audit-process gap, not a code defect: both the #90 review and the 2026-09-28 review scanned files rather than reachability, so each produced findings against code that never runs. Deleting the code removes the false positives rather than patching them. Removed: pages/ProfileEdit.tsx orphaned by 1bfe932 (#55 redesign) components/BasicInfoForm.tsx only importer was ProfileEdit components/RuleList.tsx existed only to import ProfileEdit's CSS components/ProfileCard.tsx superseded by DrawerProfileCard components/CreateProfileForm.tsx components/ApplyStatus.tsx unmounted; see #230 item 7 __tests__/ApplyStatus.test.tsx 283 lines covering a never-rendered component, which is why the dead component kept looking maintained CSS modules orphaned by the above: pages/ProfileEdit.module.css only ProfileEdit + RuleList pages/ProfileList.module.css only ProfileCard + CreateProfileForm components/ApplyStatus.module.css Not removed: the global `.toggle` / `.toggle-slider` classes. The comment credited ProfileCard, but AdBlock is the live consumer (pages/AdBlock.tsx :326, :597, :790), so only the comment is corrected. Verification: pnpm test 353 passed / 26 files, pnpm build (tsc + vite) clean. No Rust touched. --- src/components/ApplyStatus.module.css | 122 -------- src/components/ApplyStatus.tsx | 141 --------- src/components/BasicInfoForm.tsx | 58 ---- src/components/CreateProfileForm.tsx | 53 ---- src/components/ProfileCard.tsx | 120 -------- src/components/RuleList.tsx | 56 ---- src/components/__tests__/ApplyStatus.test.tsx | 283 ------------------ src/pages/ProfileEdit.module.css | 103 ------- src/pages/ProfileEdit.tsx | 153 ---------- src/pages/ProfileList.module.css | 218 -------------- src/stores/profiles/actions.ts | 2 +- src/styles/global.css | 2 +- 12 files changed, 2 insertions(+), 1309 deletions(-) delete mode 100644 src/components/ApplyStatus.module.css delete mode 100644 src/components/ApplyStatus.tsx delete mode 100644 src/components/BasicInfoForm.tsx delete mode 100644 src/components/CreateProfileForm.tsx delete mode 100644 src/components/ProfileCard.tsx delete mode 100644 src/components/RuleList.tsx delete mode 100644 src/components/__tests__/ApplyStatus.test.tsx delete mode 100644 src/pages/ProfileEdit.module.css delete mode 100644 src/pages/ProfileEdit.tsx delete mode 100644 src/pages/ProfileList.module.css diff --git a/src/components/ApplyStatus.module.css b/src/components/ApplyStatus.module.css deleted file mode 100644 index 42bee85..0000000 --- a/src/components/ApplyStatus.module.css +++ /dev/null @@ -1,122 +0,0 @@ -.applyStatusSection { - margin-bottom: 16px; -} - -.profileName { - font-size: 16px; - font-weight: 600; - color: var(--color-primary); - margin-bottom: 8px; -} - -.noProfile { - color: var(--color-text-muted); - font-size: 14px; -} - -.rulesList { - margin-bottom: 16px; -} - -.ruleItem { - display: flex; - gap: 12px; - padding: 6px 0; - border-bottom: 1px solid var(--color-border); - font-size: 13px; -} - -.ruleItem:last-child { - border-bottom: none; -} - -.ruleIp { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; - font-weight: 500; - color: var(--color-text); - min-width: 140px; -} - -.ruleDomains { - color: var(--color-text-secondary); -} - -/* ---- Managed Block ---- */ - -.managedBlockContent { - background: var(--color-bg); - border: 1px solid var(--color-border); - border-radius: var(--radius-sm); - padding: 12px; - font-size: 12px; - line-height: 1.6; - overflow: auto; - max-height: 200px; - white-space: pre-wrap; - word-break: break-word; - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; -} - -.managedBlockEmpty { - color: var(--color-text-muted); - font-size: 13px; -} - -/* ---- Last Applied ---- */ - -.lastAppliedRow { - display: flex; - align-items: center; - gap: 8px; - font-size: 13px; - color: var(--color-text-secondary); - margin-bottom: 12px; -} - -.lastAppliedLabel { - font-weight: 500; -} - -/* ---- Pending Changes ---- */ - -.pendingChanges { - display: flex; - align-items: center; - gap: 6px; - padding: 8px 12px; - background: var(--color-warning-bg); - border: 1px solid var(--color-warning-border); - border-radius: var(--radius-sm); - font-size: 13px; - color: var(--color-warning); - font-weight: 500; -} - -/* ---- Conflicts ---- */ - -.conflictWarning { - display: flex; - align-items: center; - gap: 6px; - padding: 8px 12px; - background: var(--color-error-bg); - border: 1px solid var(--color-error-border); - border-radius: var(--radius-sm); - font-size: 13px; - color: var(--color-danger); - margin-bottom: 12px; -} - -.conflictDomain { - font-weight: 600; - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; -} - -/* ---- Loading ---- */ - -.loading { - padding: 20px; - text-align: center; - color: var(--color-text-muted); - font-size: 13px; -} diff --git a/src/components/ApplyStatus.tsx b/src/components/ApplyStatus.tsx deleted file mode 100644 index 0d66723..0000000 --- a/src/components/ApplyStatus.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { useEffect, useState } from "react"; -import { useAtomValue } from "jotai"; -import { enabledProfileAtom } from "../stores/profiles"; -import { - getManagedBlockContent, - getLastApplied, - generateApplyPlan, -} from "../lib/tauri"; -import type { ApplyPlan } from "../types"; -import styles from "./ApplyStatus.module.css"; - -function ApplyStatus() { - const enabledProfile = useAtomValue(enabledProfileAtom); - const [managedContent, setManagedContent] = useState(null); - const [lastApplied, setLastApplied] = useState(null); - const [applyPlan, setApplyPlan] = useState(null); - const [planFailed, setPlanFailed] = useState(false); - const [loading, setLoading] = useState(true); - - useEffect(() => { - let cancelled = false; - - async function fetchData() { - setLoading(true); - try { - const [content, applied, plan] = await Promise.all([ - getManagedBlockContent(), - getLastApplied(), - generateApplyPlan().catch(() => null), - ]); - - if (cancelled) return; - - setManagedContent(content); - setLastApplied(applied); - - if (plan) { - setApplyPlan(plan); - setPlanFailed(false); - } else { - setPlanFailed(true); - } - } finally { - if (!cancelled) { - setLoading(false); - } - } - } - - fetchData(); - return () => { - cancelled = true; - }; - }, [enabledProfile]); - - if (loading) { - return
Loading status...
; - } - - const hasPendingChanges = - applyPlan !== null && - (applyPlan.diff.added.length > 0 || applyPlan.diff.removed.length > 0); - - return ( -
- {/* Active Profile */} -
-

Current Active Profile

- {enabledProfile ? ( - <> -
{enabledProfile.name}
- {enabledProfile.rules.length > 0 && ( -
- {enabledProfile.rules - .filter((r) => r.enabled && r.ip !== null) - .map((rule) => ( -
- {rule.ip ?? ""} - - {rule.domains.join(", ")} - -
- ))} -
- )} - - ) : ( -
No active profile
- )} -
- - {/* Managed Block Content */} -
-

Managed Block in Hosts

- {managedContent ? ( -
{managedContent}
- ) : ( -
- No managed block found in system hosts. -
- )} -
- - {/* Last Applied */} -
-

Apply History

-
- Last Applied: - - {lastApplied - ? new Date(lastApplied).toLocaleString() - : "Never"} - -
- - {/* Pending Changes */} - {!planFailed && hasPendingChanges && ( -
- Pending Changes: {applyPlan.diff.added.length} added,{" "} - {applyPlan.diff.removed.length} removed -
- )} - - {/* Conflicts */} - {applyPlan && - applyPlan.conflicts.length > 0 && - applyPlan.conflicts.map((conflict) => ( -
- Conflict on{" "} - - {conflict.domain} - - : {conflict.rules.length} profiles claim this domain -
- ))} -
-
- ); -} - -export default ApplyStatus; diff --git a/src/components/BasicInfoForm.tsx b/src/components/BasicInfoForm.tsx deleted file mode 100644 index 626f132..0000000 --- a/src/components/BasicInfoForm.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import type { Profile } from "../types"; - -interface BasicInfoFormProps { - draft: Profile; - onChange: (field: keyof Profile, value: unknown) => void; -} - -function BasicInfoForm({ draft, onChange }: BasicInfoFormProps) { - const handleTagsChange = (value: string) => { - const tags = value - .split(",") - .map((t) => t.trim()) - .filter(Boolean); - onChange("tags", tags); - }; - - return ( -
-

Basic Info

-
- - onChange("name", e.target.value)} - /> -
-
- -