support clean orogress
This commit is contained in:
@@ -2,8 +2,11 @@ use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::backend::fast_clean::clean_directory_contents;
|
||||
use crate::backend::models::{BrowserProfile, BrowserScanResult, BrowserType, CleanResult};
|
||||
use crate::backend::models::{
|
||||
BrowserProfile, BrowserScanResult, BrowserType, CleanResult, ProjectCleanProgress,
|
||||
};
|
||||
use crate::backend::utils::{format_size, get_dir_size_simple};
|
||||
use tauri::Emitter;
|
||||
|
||||
const BROWSER_CACHE_DIRS: &[&str] = &[
|
||||
"Cache",
|
||||
@@ -80,18 +83,23 @@ pub async fn run_browser_scan(browser: BrowserType) -> Result<BrowserScanResult,
|
||||
pub async fn run_browser_clean(
|
||||
browser: BrowserType,
|
||||
profile_paths: Vec<String>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<CleanResult, String> {
|
||||
let user_data_path = browser.get_user_data_path()?;
|
||||
let mut total_freed = 0;
|
||||
let mut success_count = 0;
|
||||
let mut fail_count = 0;
|
||||
let mut approx_completed_bytes = 0;
|
||||
let total_items = profile_paths.len() as u32;
|
||||
|
||||
for profile_dir in profile_paths {
|
||||
for (index, profile_dir) in profile_paths.into_iter().enumerate() {
|
||||
let profile_path = user_data_path.join(&profile_dir);
|
||||
let mut profile_estimated_size = 0;
|
||||
if profile_path.exists() {
|
||||
for sub_dir in BROWSER_CACHE_DIRS {
|
||||
let target = profile_path.join(sub_dir);
|
||||
if target.exists() {
|
||||
profile_estimated_size += get_dir_size_simple(&target);
|
||||
let (freed, success, fail) = clean_directory_contents(&target, None);
|
||||
total_freed += freed;
|
||||
success_count += success;
|
||||
@@ -99,6 +107,17 @@ pub async fn run_browser_clean(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
approx_completed_bytes += profile_estimated_size;
|
||||
let _ = app_handle.emit(
|
||||
"browser-clean-progress",
|
||||
ProjectCleanProgress {
|
||||
completed_items: (index + 1) as u32,
|
||||
total_items,
|
||||
current_item: profile_dir,
|
||||
approx_completed_bytes,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(CleanResult {
|
||||
|
||||
@@ -2,7 +2,9 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use crate::backend::models::{CleanResult, CleaningConfig, FastScanResult, ScanItem};
|
||||
use tauri::Emitter;
|
||||
|
||||
use crate::backend::models::{CleanResult, CleaningConfig, FastScanResult, ProjectCleanProgress, ScanItem};
|
||||
use crate::backend::utils::format_size;
|
||||
|
||||
fn get_fast_cleaning_configs() -> Vec<CleaningConfig> {
|
||||
@@ -89,22 +91,42 @@ fn get_dir_stats(path: &Path, filter_days: Option<u64>) -> (u64, u32) {
|
||||
(size, count)
|
||||
}
|
||||
|
||||
pub async fn run_fast_clean(selected_paths: Vec<String>) -> Result<CleanResult, String> {
|
||||
let configs = get_fast_cleaning_configs();
|
||||
pub async fn run_fast_clean(
|
||||
selected_paths: Vec<String>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<CleanResult, String> {
|
||||
let selected_configs: Vec<CleaningConfig> = get_fast_cleaning_configs()
|
||||
.into_iter()
|
||||
.filter(|config| selected_paths.contains(&config.path))
|
||||
.collect();
|
||||
|
||||
let mut success_count = 0;
|
||||
let mut fail_count = 0;
|
||||
let mut total_freed = 0;
|
||||
let mut approx_completed_bytes = 0;
|
||||
let total_items = selected_configs.len() as u32;
|
||||
|
||||
for config in configs {
|
||||
if selected_paths.contains(&config.path) {
|
||||
let path = Path::new(&config.path);
|
||||
if path.exists() {
|
||||
let (freed, success, fail) = clean_directory_contents(path, config.filter_days);
|
||||
total_freed += freed;
|
||||
success_count += success;
|
||||
fail_count += fail;
|
||||
}
|
||||
for (index, config) in selected_configs.into_iter().enumerate() {
|
||||
let path = Path::new(&config.path);
|
||||
let item_size = get_dir_stats(path, config.filter_days).0;
|
||||
|
||||
if path.exists() {
|
||||
let (freed, success, fail) = clean_directory_contents(path, config.filter_days);
|
||||
total_freed += freed;
|
||||
success_count += success;
|
||||
fail_count += fail;
|
||||
}
|
||||
|
||||
approx_completed_bytes += item_size;
|
||||
let _ = app_handle.emit(
|
||||
"fast-clean-progress",
|
||||
ProjectCleanProgress {
|
||||
completed_items: (index + 1) as u32,
|
||||
total_items,
|
||||
current_item: config.name,
|
||||
approx_completed_bytes,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(CleanResult {
|
||||
|
||||
@@ -18,6 +18,14 @@ pub struct ScanProgress {
|
||||
pub current_path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct ProjectCleanProgress {
|
||||
pub completed_items: u32,
|
||||
pub total_items: u32,
|
||||
pub current_item: String,
|
||||
pub approx_completed_bytes: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CleaningConfig {
|
||||
pub name: String,
|
||||
|
||||
@@ -10,8 +10,11 @@ async fn start_fast_scan() -> backend::models::FastScanResult {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn start_fast_clean(selected_paths: Vec<String>) -> Result<backend::models::CleanResult, String> {
|
||||
backend::fast_clean::run_fast_clean(selected_paths).await
|
||||
async fn start_fast_clean(
|
||||
selected_paths: Vec<String>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<backend::models::CleanResult, String> {
|
||||
backend::fast_clean::run_fast_clean(selected_paths, app_handle).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -66,6 +69,7 @@ async fn start_browser_scan(browser: String) -> Result<backend::models::BrowserS
|
||||
async fn start_browser_clean(
|
||||
browser: String,
|
||||
profiles: Vec<String>,
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<backend::models::CleanResult, String> {
|
||||
let browser_type = if browser == "chrome" {
|
||||
backend::models::BrowserType::Chrome
|
||||
@@ -73,7 +77,7 @@ async fn start_browser_clean(
|
||||
backend::models::BrowserType::Edge
|
||||
};
|
||||
|
||||
backend::browser_clean::run_browser_clean(browser_type, profiles).await
|
||||
backend::browser_clean::run_browser_clean(browser_type, profiles, app_handle).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -2,12 +2,14 @@ import { computed, ref } from "vue";
|
||||
import {
|
||||
startBrowserClean as runBrowserCleanCommand,
|
||||
startBrowserScan as runBrowserScanCommand,
|
||||
subscribeBrowserCleanProgress,
|
||||
} from "../services/tauri/cleaner";
|
||||
import type {
|
||||
AlertOptions,
|
||||
BrowserScanResult,
|
||||
CleanResult,
|
||||
ConfirmOptions,
|
||||
ProjectCleanProgressPayload,
|
||||
} from "../types/cleaner";
|
||||
import { formatItemSize } from "../utils/format";
|
||||
|
||||
@@ -19,6 +21,13 @@ interface BrowserState {
|
||||
cleanResult: CleanResult | null;
|
||||
}
|
||||
|
||||
interface BrowserCleanProgressState {
|
||||
completedItems: number;
|
||||
totalItems: number;
|
||||
currentItem: string;
|
||||
approxCompletedBytes: number;
|
||||
}
|
||||
|
||||
export function useBrowserClean(
|
||||
browser: "chrome" | "edge",
|
||||
showAlert: (options: AlertOptions) => void,
|
||||
@@ -31,20 +40,50 @@ export function useBrowserClean(
|
||||
scanResult: null,
|
||||
cleanResult: null,
|
||||
});
|
||||
const cleanProgress = ref<BrowserCleanProgressState>({
|
||||
completedItems: 0,
|
||||
totalItems: 0,
|
||||
currentItem: "",
|
||||
approxCompletedBytes: 0,
|
||||
});
|
||||
|
||||
const selectedStats = computed(() => {
|
||||
const scanResult = state.value.scanResult;
|
||||
if (!scanResult) return { sizeStr: "0 B", count: 0, hasSelection: false };
|
||||
if (!scanResult) return { totalBytes: 0, sizeStr: "0 B", count: 0, hasSelection: false };
|
||||
|
||||
const enabledProfiles = scanResult.profiles.filter((profile) => profile.enabled);
|
||||
const totalBytes = enabledProfiles.reduce((acc, profile) => acc + profile.cache_size, 0);
|
||||
|
||||
return {
|
||||
totalBytes,
|
||||
sizeStr: formatItemSize(totalBytes),
|
||||
count: enabledProfiles.length,
|
||||
hasSelection: enabledProfiles.length > 0,
|
||||
};
|
||||
});
|
||||
const cleanProgressSizeStr = computed(() => formatSizeValue(cleanProgress.value.approxCompletedBytes));
|
||||
|
||||
function formatSizeValue(bytes: number) {
|
||||
return formatItemSize(bytes);
|
||||
}
|
||||
|
||||
function resetCleanProgress() {
|
||||
cleanProgress.value = {
|
||||
completedItems: 0,
|
||||
totalItems: 0,
|
||||
currentItem: "",
|
||||
approxCompletedBytes: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function handleCleanProgress(payload: ProjectCleanProgressPayload) {
|
||||
cleanProgress.value = {
|
||||
completedItems: payload.completed_items,
|
||||
totalItems: payload.total_items,
|
||||
currentItem: payload.current_item,
|
||||
approxCompletedBytes: payload.approx_completed_bytes,
|
||||
};
|
||||
}
|
||||
|
||||
async function startScan() {
|
||||
const current = state.value;
|
||||
@@ -102,7 +141,9 @@ export function useBrowserClean(
|
||||
return;
|
||||
}
|
||||
|
||||
resetCleanProgress();
|
||||
current.isCleaning = true;
|
||||
const unlisten = await subscribeBrowserCleanProgress(handleCleanProgress);
|
||||
try {
|
||||
current.cleanResult = await runBrowserCleanCommand(browser, selectedProfiles);
|
||||
current.isDone = true;
|
||||
@@ -114,6 +155,7 @@ export function useBrowserClean(
|
||||
type: "error",
|
||||
});
|
||||
} finally {
|
||||
unlisten();
|
||||
current.isCleaning = false;
|
||||
}
|
||||
}
|
||||
@@ -138,11 +180,14 @@ export function useBrowserClean(
|
||||
scanResult: null,
|
||||
cleanResult: null,
|
||||
};
|
||||
resetCleanProgress();
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
selectedStats,
|
||||
cleanProgress,
|
||||
cleanProgressSizeStr,
|
||||
startScan,
|
||||
startClean,
|
||||
toggleAllProfiles,
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { computed, ref } from "vue";
|
||||
import { startFastClean as runFastCleanCommand, startFastScan as runFastScanCommand } from "../services/tauri/cleaner";
|
||||
import {
|
||||
startFastClean as runFastCleanCommand,
|
||||
startFastScan as runFastScanCommand,
|
||||
subscribeFastCleanProgress,
|
||||
} from "../services/tauri/cleaner";
|
||||
import type {
|
||||
AlertOptions,
|
||||
CleanResult,
|
||||
ConfirmOptions,
|
||||
FastScanResult,
|
||||
ProjectCleanProgressPayload,
|
||||
} from "../types/cleaner";
|
||||
import { formatItemSize } from "../utils/format";
|
||||
|
||||
@@ -17,6 +22,13 @@ interface FastState {
|
||||
cleanResult: CleanResult | null;
|
||||
}
|
||||
|
||||
interface FastCleanProgressState {
|
||||
completedItems: number;
|
||||
totalItems: number;
|
||||
currentItem: string;
|
||||
approxCompletedBytes: number;
|
||||
}
|
||||
|
||||
export function useFastClean(
|
||||
showAlert: (options: AlertOptions) => void,
|
||||
requestConfirm: (options: ConfirmOptions) => Promise<boolean>,
|
||||
@@ -29,21 +41,47 @@ export function useFastClean(
|
||||
scanResult: null,
|
||||
cleanResult: null,
|
||||
});
|
||||
const cleanProgress = ref<FastCleanProgressState>({
|
||||
completedItems: 0,
|
||||
totalItems: 0,
|
||||
currentItem: "",
|
||||
approxCompletedBytes: 0,
|
||||
});
|
||||
|
||||
const selectedStats = computed(() => {
|
||||
const scanResult = state.value.scanResult;
|
||||
if (!scanResult) return { sizeStr: "0 B", count: 0, hasSelection: false };
|
||||
if (!scanResult) return { totalBytes: 0, sizeStr: "0 B", count: 0, hasSelection: false };
|
||||
|
||||
const enabledItems = scanResult.items.filter((item) => item.enabled);
|
||||
const totalBytes = enabledItems.reduce((acc, item) => acc + item.size, 0);
|
||||
const totalCount = enabledItems.reduce((acc, item) => acc + item.count, 0);
|
||||
|
||||
return {
|
||||
totalBytes,
|
||||
sizeStr: formatItemSize(totalBytes),
|
||||
count: totalCount,
|
||||
hasSelection: enabledItems.length > 0,
|
||||
};
|
||||
});
|
||||
const cleanProgressSizeStr = computed(() => formatItemSize(cleanProgress.value.approxCompletedBytes));
|
||||
|
||||
function resetCleanProgress() {
|
||||
cleanProgress.value = {
|
||||
completedItems: 0,
|
||||
totalItems: 0,
|
||||
currentItem: "",
|
||||
approxCompletedBytes: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function handleCleanProgress(payload: ProjectCleanProgressPayload) {
|
||||
cleanProgress.value = {
|
||||
completedItems: payload.completed_items,
|
||||
totalItems: payload.total_items,
|
||||
currentItem: payload.current_item,
|
||||
approxCompletedBytes: payload.approx_completed_bytes,
|
||||
};
|
||||
}
|
||||
|
||||
async function startScan() {
|
||||
const current = state.value;
|
||||
@@ -104,7 +142,9 @@ export function useFastClean(
|
||||
}
|
||||
}
|
||||
|
||||
resetCleanProgress();
|
||||
current.isCleaning = true;
|
||||
const unlisten = await subscribeFastCleanProgress(handleCleanProgress);
|
||||
try {
|
||||
current.cleanResult = await runFastCleanCommand(selectedPaths);
|
||||
current.isDone = true;
|
||||
@@ -116,6 +156,7 @@ export function useFastClean(
|
||||
type: "error",
|
||||
});
|
||||
} finally {
|
||||
unlisten();
|
||||
current.isCleaning = false;
|
||||
}
|
||||
}
|
||||
@@ -129,11 +170,14 @@ export function useFastClean(
|
||||
scanResult: null,
|
||||
cleanResult: null,
|
||||
};
|
||||
resetCleanProgress();
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
selectedStats,
|
||||
cleanProgress,
|
||||
cleanProgressSizeStr,
|
||||
startScan,
|
||||
startClean,
|
||||
reset,
|
||||
|
||||
@@ -9,7 +9,7 @@ const props = defineProps<{
|
||||
requestConfirm: (options: ConfirmOptions) => Promise<boolean>;
|
||||
}>();
|
||||
|
||||
const { state, selectedStats, startScan, startClean, toggleAllProfiles, invertProfiles, reset } =
|
||||
const { state, selectedStats, cleanProgress, cleanProgressSizeStr, startScan, startClean, toggleAllProfiles, invertProfiles, reset } =
|
||||
useBrowserClean(props.browser, props.showAlert, props.requestConfirm);
|
||||
|
||||
const browserName = props.browser === "chrome" ? "谷歌浏览器" : "微软浏览器";
|
||||
@@ -36,23 +36,26 @@ const browserName = props.browser === "chrome" ? "谷歌浏览器" : "微软浏
|
||||
|
||||
<div v-else-if="state.scanResult && !state.isDone" class="result-card">
|
||||
<div class="result-header">
|
||||
<span class="result-icon">🌍</span>
|
||||
<h2>扫描完成</h2>
|
||||
<span class="result-icon">{{ state.isCleaning ? "🧹" : "🌍" }}</span>
|
||||
<h2>{{ state.isCleaning ? "正在清理" : "扫描完成" }}</h2>
|
||||
</div>
|
||||
<div class="result-stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-value">
|
||||
{{ splitSize(selectedStats.sizeStr).value }}
|
||||
<span class="unit">{{ splitSize(selectedStats.sizeStr).unit }}</span>
|
||||
{{ splitSize(state.isCleaning ? cleanProgressSizeStr : selectedStats.sizeStr).value }}
|
||||
<span class="unit">{{ splitSize(state.isCleaning ? cleanProgressSizeStr : selectedStats.sizeStr).unit }}</span>
|
||||
</span>
|
||||
<span class="stat-label">预计释放</span>
|
||||
<span class="stat-label">{{ state.isCleaning ? "已处理约" : "预计释放" }}</span>
|
||||
</div>
|
||||
<div class="stat-divider"></div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-value">{{ selectedStats.count }}</span>
|
||||
<span class="stat-label">用户资料数量</span>
|
||||
<span class="stat-value">{{ state.isCleaning ? `${cleanProgress.completedItems}/${cleanProgress.totalItems}` : selectedStats.count }}</span>
|
||||
<span class="stat-label">{{ state.isCleaning ? "已完成资料" : "用户资料数量" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="state.isCleaning" class="cleaning-note">
|
||||
正在清理:{{ cleanProgress.currentItem || "准备开始..." }},建议保持浏览器关闭以减少文件占用。
|
||||
</p>
|
||||
<button class="btn-primary main-btn" :disabled="state.isCleaning || !selectedStats.hasSelection" @click="startClean">
|
||||
{{ state.isCleaning ? "正在清理..." : "立即清理" }}
|
||||
</button>
|
||||
@@ -86,7 +89,7 @@ const browserName = props.browser === "chrome" ? "谷歌浏览器" : "微软浏
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="(state.isScanning || state.scanResult) && !state.isDone" class="detail-list">
|
||||
<div v-if="(state.isScanning || state.scanResult) && !state.isDone && !state.isCleaning" class="detail-list">
|
||||
<div class="list-header">
|
||||
<h3>用户资料列表</h3>
|
||||
<div class="list-actions">
|
||||
|
||||
@@ -8,7 +8,7 @@ const props = defineProps<{
|
||||
requestConfirm: (options: ConfirmOptions) => Promise<boolean>;
|
||||
}>();
|
||||
|
||||
const { state, selectedStats, startScan, startClean, reset } = useFastClean(
|
||||
const { state, selectedStats, cleanProgress, cleanProgressSizeStr, startScan, startClean, reset } = useFastClean(
|
||||
props.showAlert,
|
||||
props.requestConfirm,
|
||||
);
|
||||
@@ -35,24 +35,28 @@ const { state, selectedStats, startScan, startClean, reset } = useFastClean(
|
||||
|
||||
<div v-else-if="state.scanResult && !state.isDone" class="result-card">
|
||||
<div class="result-header">
|
||||
<span class="result-icon">📋</span>
|
||||
<h2>扫描完成</h2>
|
||||
<span class="result-icon">{{ state.isCleaning ? "🧹" : "📋" }}</span>
|
||||
<h2>{{ state.isCleaning ? "正在清理" : "扫描完成" }}</h2>
|
||||
</div>
|
||||
<div class="result-stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-value">
|
||||
{{ splitSize(selectedStats.sizeStr).value }}
|
||||
<span class="unit">{{ splitSize(selectedStats.sizeStr).unit }}</span>
|
||||
{{ splitSize(state.isCleaning ? cleanProgressSizeStr : selectedStats.sizeStr).value }}
|
||||
<span class="unit">{{ splitSize(state.isCleaning ? cleanProgressSizeStr : selectedStats.sizeStr).unit }}</span>
|
||||
</span>
|
||||
<span class="stat-label">预计释放</span>
|
||||
<span class="stat-label">{{ state.isCleaning ? "已处理约" : "预计释放" }}</span>
|
||||
</div>
|
||||
<div class="stat-divider"></div>
|
||||
<div class="stat-item">
|
||||
<span class="stat-value">{{ selectedStats.count }}</span>
|
||||
<span class="stat-label">文件数量</span>
|
||||
<span class="stat-value">{{ state.isCleaning ? `${cleanProgress.completedItems}/${cleanProgress.totalItems}` : selectedStats.count }}</span>
|
||||
<span class="stat-label">{{ state.isCleaning ? "已完成项目" : "文件数量" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="state.isCleaning" class="cleaning-note">
|
||||
正在清理:{{ cleanProgress.currentItem || "准备开始..." }},请稍候,不要关闭程序。
|
||||
</p>
|
||||
|
||||
<button class="btn-primary main-btn" :disabled="state.isCleaning || !selectedStats.hasSelection" @click="startClean">
|
||||
{{ state.isCleaning ? "正在清理..." : "立即清理" }}
|
||||
</button>
|
||||
@@ -87,7 +91,7 @@ const { state, selectedStats, startScan, startClean, reset } = useFastClean(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="(state.isScanning || state.scanResult) && !state.isDone" class="detail-list">
|
||||
<div v-if="(state.isScanning || state.scanResult) && !state.isDone && !state.isCleaning" class="detail-list">
|
||||
<h3>清理项详情</h3>
|
||||
<div
|
||||
v-for="item in state.scanResult?.items || []"
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
FastScanResult,
|
||||
FileNode,
|
||||
MemoryStats,
|
||||
ProjectCleanProgressPayload,
|
||||
ScanProgressPayload,
|
||||
} from "../../types/cleaner";
|
||||
|
||||
@@ -54,6 +55,22 @@ export function subscribeScanProgress(
|
||||
});
|
||||
}
|
||||
|
||||
export function subscribeFastCleanProgress(
|
||||
handler: (payload: ProjectCleanProgressPayload) => void,
|
||||
) {
|
||||
return listen<ProjectCleanProgressPayload>("fast-clean-progress", (event) => {
|
||||
handler(event.payload);
|
||||
});
|
||||
}
|
||||
|
||||
export function subscribeBrowserCleanProgress(
|
||||
handler: (payload: ProjectCleanProgressPayload) => void,
|
||||
) {
|
||||
return listen<ProjectCleanProgressPayload>("browser-clean-progress", (event) => {
|
||||
handler(event.payload);
|
||||
});
|
||||
}
|
||||
|
||||
export function openInExplorer(path: string) {
|
||||
return invoke("open_in_explorer", { path });
|
||||
}
|
||||
|
||||
@@ -136,6 +136,13 @@
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.cleaning-note {
|
||||
margin: -8px 0 24px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-sec);
|
||||
}
|
||||
|
||||
.scan-circle-container {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
|
||||
@@ -64,6 +64,13 @@ export interface ScanProgressPayload {
|
||||
current_path: string;
|
||||
}
|
||||
|
||||
export interface ProjectCleanProgressPayload {
|
||||
completed_items: number;
|
||||
total_items: number;
|
||||
current_item: string;
|
||||
approx_completed_bytes: number;
|
||||
}
|
||||
|
||||
export type ModalType = "info" | "success" | "error";
|
||||
export type ModalMode = "alert" | "confirm";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user