fix: clear cache permission in windows

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-11-11 23:10:32 +08:00
parent 6eed2c4170
commit 0ce6546d7f
6 changed files with 62 additions and 17 deletions

View File

@ -69,7 +69,9 @@ export const getCacheSize = async () => {
const cachePath = path.join(app.getPath("userData"), "cache")
// Size is in bytes
const sizeInBytes = await fastFolderSizeAsync(cachePath)
const sizeInBytes = await fastFolderSizeAsync(cachePath).catch((error) => {
logger.error(error)
})
return sizeInBytes || 0
}

View File

@ -5,7 +5,7 @@ import path from "node:path"
import { getRendererHandlers } from "@egoist/tipc/main"
import { callWindowExpose } from "@follow/shared/bridge"
import type { BrowserWindow } from "electron"
import { app, clipboard, dialog, screen } from "electron"
import { app, clipboard, dialog, screen, shell } from "electron"
import { registerMenuAndContextMenu } from "~/init"
import { clearAllData, getCacheSize } from "~/lib/cleaner"
@ -275,13 +275,34 @@ ${content}
getCacheSize: t.procedure.action(async () => {
return getCacheSize()
}),
openCacheFolder: t.procedure.action(async () => {
const dir = path.join(app.getPath("userData"), "cache")
shell.openPath(dir)
}),
getCacheLimit: t.procedure.action(async () => {
return store.get(StoreKey.CacheSizeLimit)
}),
clearCache: t.procedure.action(async () => {
const cachePath = path.join(app.getPath("userData"), "cache")
await fsp.rm(cachePath, { recursive: true, force: true })
const cachePath = path.join(app.getPath("userData"), "cache", "Cache_Data")
if (process.platform === "win32") {
// Request elevation on Windows
try {
// Create a bat file to delete cache with elevated privileges
const batPath = path.join(app.getPath("temp"), "clear_cache.bat")
await fsp.writeFile(batPath, `@echo off\nrd /s /q "${cachePath}"\ndel "%~f0"`, "utf-8")
// Execute the bat file with admin privileges
await shell.openPath(batPath)
return
} catch (err) {
logger.error("Failed to clear cache with elevation", { error: err })
}
}
await fsp.rm(cachePath, { recursive: true, force: true }).catch(() => {
logger.error("Failed to clear cache")
})
}),
limitCacheSize: t.procedure.input<number>().action(async ({ input }) => {

View File

@ -63,7 +63,7 @@
<body>
<div id="root"></div>
<div id="app-skeleton">
<div id="app-skeleton" class="drag-region">
<!-- Skeleton -->
<style>
html,

View File

@ -120,7 +120,7 @@ export const SettingActionItem = ({
action,
buttonText,
}: {
label: string
label: ReactNode
action: () => void
buttonText: string
}) => (

View File

@ -1,5 +1,5 @@
import { CarbonInfinitySymbol } from "@follow/components/icons/infinify.jsx"
import { Button } from "@follow/components/ui/button/index.js"
import { Button, MotionButtonBase } from "@follow/components/ui/button/index.js"
import { Label } from "@follow/components/ui/label/index.jsx"
import { Slider } from "@follow/components/ui/slider/index.js"
import { env } from "@follow/shared/env"
@ -15,7 +15,7 @@ import { tipcClient } from "~/lib/client"
import { queryClient } from "~/lib/query-client"
import { clearLocalPersistStoreData } from "~/store/utils/clear"
import { SettingDescription } from "../control"
import { SettingActionItem, SettingDescription } from "../control"
import { createSetting } from "../helper/builder"
import { SettingItemGroup } from "../section"
@ -111,20 +111,41 @@ export const SettingDataControl = () => {
value: t("general.cache"),
},
isElectronBuild && AppCacheLimit,
isElectronBuild && {
label: t("data_control.clean_cache.button"),
description: t("data_control.clean_cache.description"),
buttonText: t("data_control.clean_cache.button"),
action: async () => {
await tipcClient?.clearCache()
queryClient.invalidateQueries({ queryKey: ["app", "cache", "size"] })
},
},
isElectronBuild && CleanCache,
]}
/>
</div>
)
}
const CleanCache = () => {
const { t } = useTranslation("settings")
return (
<SettingItemGroup>
<SettingActionItem
label={
<span className="flex items-center gap-1">
{t("data_control.clean_cache.button")}
<MotionButtonBase
onClick={() => {
tipcClient?.openCacheFolder()
}}
className="center flex"
>
<i className="i-mgc-folder-open-cute-re" />
</MotionButtonBase>
</span>
}
action={async () => {
await tipcClient?.clearCache()
queryClient.setQueryData(["app", "cache", "size"], 0)
}}
buttonText={t("data_control.clean_cache.button")}
/>
<SettingDescription>{t("data_control.clean_cache.description")}</SettingDescription>
</SettingItemGroup>
)
}
const AppCacheLimit = () => {
const { t } = useTranslation("settings")
const { data: cacheSize, isLoading: isLoadingCacheSize } = useQuery({

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="#fff" fill-opacity=".01" d="M24 0v24H0V0z"/><path stroke="#10161F" stroke-linecap="round" stroke-width="2" d="M17 20H7c-1.886 0-2.828 0-3.414-.586C3 18.828 3 17.886 3 16V9c0-2.357 0-3.536.732-4.268C4.464 4 5.643 4 8 4h.4c.626 0 .94 0 1.226.088a2 2 0 0 1 .539.26c.248.168.444.413.835.902v0c.391.49.587.734.835.903a2 2 0 0 0 .539.259c.287.088.6.088 1.227.088H17.5c.464 0 .697 0 .892.026a3 3 0 0 1 2.582 2.582C21 9.303 21 9.536 21 10v0M8.381 20h7.155c2.15 0 3.226 0 4.023-.593.797-.593 1.106-1.623 1.724-3.683l.172-.575c.708-2.358 1.061-3.537.462-4.343-.6-.806-1.831-.806-4.293-.806h-7.155c-2.153 0-3.23 0-4.027.594-.797.594-1.105 1.625-1.722 3.687l-.171.573c-.705 2.357-1.057 3.535-.458 4.34.6.806 1.83.806 4.29.806Z"/></svg>

After

Width:  |  Height:  |  Size: 810 B