mirror of
https://github.com/aleksey-hoffman/sigma-file-manager.git
synced 2026-10-18 17:20:21 -05:00
Refine: virtual locations
- Refactor: Make drive list change reactively
This commit is contained in:
1 parent
a6289a9d53
commit
0aa3d58dbc
3 files changed
+123
-15
No files matched your search
+20
-12
@@ -33,6 +33,9 @@ import {
|
||||
getNavigableParentPath,
|
||||
isVirtualLocationPath,
|
||||
resolveDirectoryContents,
|
||||
buildLocationsDirectoryFromDrives,
|
||||
getLocationsDriveListDisplaySignature,
|
||||
getLocationsEntriesDisplaySignature,
|
||||
} from '@/utils/virtual-locations';
|
||||
import { sharedDrives } from '@/modules/home/composables/use-drives';
|
||||
import { shouldIncludeItemCountsForSort } from '@/modules/navigator/components/file-browser/utils/file-browser-sort-columns';
|
||||
@@ -46,13 +49,6 @@ interface DirChangePayload {
|
||||
const DIRECTORY_DWELL_TIME_MS = 3000;
|
||||
const WATCHER_DEBOUNCE_MS = 500;
|
||||
|
||||
function getDrivePathListSignature(paths: string[]): string {
|
||||
return paths
|
||||
.map(path => normalizePath(path))
|
||||
.sort()
|
||||
.join('\0');
|
||||
}
|
||||
|
||||
function dirWatcherDiagEnabled(): boolean {
|
||||
return import.meta.env.DEV && localStorage.getItem('SFM_DIR_WATCHER_DIAG') === '1';
|
||||
}
|
||||
@@ -266,10 +262,10 @@ export function useFileBrowserNavigation(
|
||||
return;
|
||||
}
|
||||
|
||||
const displayedDrivePaths = dirContents.value.entries.map(entry => entry.path);
|
||||
const liveDrivePaths = sharedDrives.value.map(drive => drive.path);
|
||||
const displayedSignature = getLocationsEntriesDisplaySignature(dirContents.value.entries);
|
||||
const liveSignature = getLocationsDriveListDisplaySignature(sharedDrives.value);
|
||||
|
||||
if (getDrivePathListSignature(displayedDrivePaths) === getDrivePathListSignature(liveDrivePaths)) {
|
||||
if (displayedSignature === liveSignature) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -290,14 +286,22 @@ export function useFileBrowserNavigation(
|
||||
const canGoForward = computed(() => historyIndex.value < history.value.length - 1);
|
||||
|
||||
async function silentRefresh(): Promise<void> {
|
||||
if (!currentPath.value) {
|
||||
const refreshPath = currentPath.value;
|
||||
|
||||
if (!refreshPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
isRefreshing.value = true;
|
||||
|
||||
try {
|
||||
const result = await loadDirectoryContents(currentPath.value, createReadDirOptions());
|
||||
const result = isVirtualLocationPath(refreshPath)
|
||||
? buildLocationsDirectoryFromDrives(sharedDrives.value)
|
||||
: await loadDirectoryContents(refreshPath, createReadDirOptions());
|
||||
|
||||
if (currentPath.value !== refreshPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
dirContents.value = result;
|
||||
invalidateDirectoryLinkMetadata(result);
|
||||
@@ -319,6 +323,10 @@ export function useFileBrowserNavigation(
|
||||
}
|
||||
}
|
||||
catch {
|
||||
if (currentPath.value !== refreshPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
await navigateToNearestExistingAncestor();
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
LOCATIONS_VIRTUAL_PATH,
|
||||
buildLocationsDirectoryFromDrives,
|
||||
createLocationsDirEntry,
|
||||
driveInfoToDirEntry,
|
||||
getLocationsDriveListDisplaySignature,
|
||||
getLocationsEntriesDisplaySignature,
|
||||
getNavigableParentPath,
|
||||
getVirtualLocationDisplayName,
|
||||
isVirtualLocationPath,
|
||||
@@ -60,6 +63,57 @@ describe('virtual-locations', () => {
|
||||
expect(driveEntry.item_count).toBeNull();
|
||||
});
|
||||
|
||||
it('builds locations directory contents from drive snapshots', () => {
|
||||
const drivePayload: DriveInfo = {
|
||||
name: 'Local Disk (C:)',
|
||||
path: 'C:/',
|
||||
mount_point: 'C:\\',
|
||||
file_system: 'NTFS',
|
||||
drive_type: 'SSD',
|
||||
total_space: 1000,
|
||||
available_space: 500,
|
||||
used_space: 500,
|
||||
percent_used: 50,
|
||||
is_removable: false,
|
||||
is_read_only: false,
|
||||
is_mounted: true,
|
||||
device_path: '\\\\.\\C:',
|
||||
};
|
||||
|
||||
const contents = buildLocationsDirectoryFromDrives([drivePayload]);
|
||||
|
||||
expect(contents.path).toBe(LOCATIONS_VIRTUAL_PATH);
|
||||
expect(contents.entries).toHaveLength(1);
|
||||
expect(contents.entries[0]?.path).toBe('C:/');
|
||||
});
|
||||
|
||||
it('detects drive metadata changes in locations display signatures', () => {
|
||||
const baseDrive: DriveInfo = {
|
||||
name: 'Local Disk (C:)',
|
||||
path: 'C:/',
|
||||
mount_point: 'C:\\',
|
||||
file_system: 'NTFS',
|
||||
drive_type: 'SSD',
|
||||
total_space: 1000,
|
||||
available_space: 500,
|
||||
used_space: 500,
|
||||
percent_used: 50,
|
||||
is_removable: false,
|
||||
is_read_only: false,
|
||||
is_mounted: true,
|
||||
device_path: '\\\\.\\C:',
|
||||
};
|
||||
|
||||
const renamedDrive = { ...baseDrive, name: 'System (C:)' };
|
||||
const resizedDrive = { ...baseDrive, total_space: 2000 };
|
||||
const entries = buildLocationsDirectoryFromDrives([baseDrive]).entries;
|
||||
const baseSignature = getLocationsDriveListDisplaySignature([baseDrive]);
|
||||
|
||||
expect(getLocationsEntriesDisplaySignature(entries)).toBe(baseSignature);
|
||||
expect(getLocationsDriveListDisplaySignature([renamedDrive])).not.toBe(baseSignature);
|
||||
expect(getLocationsDriveListDisplaySignature([resizedDrive])).not.toBe(baseSignature);
|
||||
});
|
||||
|
||||
describe('getNavigableParentPath', () => {
|
||||
it('returns null for the virtual locations path', () => {
|
||||
expect(getNavigableParentPath('sfm://locations', 'windows')).toBeNull();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { DirContents, DirEntry, ReadDirOptions } from '@/types/dir-entry';
|
||||
import type { DriveInfo } from '@/types/drive-info';
|
||||
import type { DriveEntryMetadata, DriveInfo } from '@/types/drive-info';
|
||||
import normalizePath, {
|
||||
getParentPath,
|
||||
getPathDisplayName,
|
||||
@@ -74,8 +74,7 @@ export function createLocationsDirEntry(): DirEntry {
|
||||
};
|
||||
}
|
||||
|
||||
export async function readLocationsDirectory(): Promise<DirContents> {
|
||||
const drives = await invoke<DriveInfo[]>('get_system_drives');
|
||||
export function buildLocationsDirectoryFromDrives(drives: DriveInfo[]): DirContents {
|
||||
const entries = drives.map(drive => driveInfoToDirEntry(drive));
|
||||
const directoryCount = entries.length;
|
||||
|
||||
@@ -93,6 +92,53 @@ export async function readLocationsDirectory(): Promise<DirContents> {
|
||||
};
|
||||
}
|
||||
|
||||
function formatLocationsDriveDisplaySignaturePart(
|
||||
path: string,
|
||||
name: string,
|
||||
size: number,
|
||||
driveMetadata: DriveEntryMetadata | undefined,
|
||||
): string {
|
||||
return [
|
||||
normalizePath(path),
|
||||
name,
|
||||
String(size),
|
||||
driveMetadata?.drive_type ?? '',
|
||||
driveMetadata?.is_removable ? '1' : '0',
|
||||
].join('\x1f');
|
||||
}
|
||||
|
||||
export function getLocationsDriveListDisplaySignature(drives: DriveInfo[]): string {
|
||||
return drives
|
||||
.map((drive) => {
|
||||
const entry = driveInfoToDirEntry(drive);
|
||||
return formatLocationsDriveDisplaySignaturePart(
|
||||
entry.path,
|
||||
entry.name,
|
||||
entry.size,
|
||||
entry.drive_metadata,
|
||||
);
|
||||
})
|
||||
.sort()
|
||||
.join('\0');
|
||||
}
|
||||
|
||||
export function getLocationsEntriesDisplaySignature(entries: DirEntry[]): string {
|
||||
return entries
|
||||
.map(entry => formatLocationsDriveDisplaySignaturePart(
|
||||
entry.path,
|
||||
entry.name,
|
||||
entry.size,
|
||||
entry.drive_metadata,
|
||||
))
|
||||
.sort()
|
||||
.join('\0');
|
||||
}
|
||||
|
||||
export async function readLocationsDirectory(): Promise<DirContents> {
|
||||
const drives = await invoke<DriveInfo[]>('get_system_drives');
|
||||
return buildLocationsDirectoryFromDrives(drives);
|
||||
}
|
||||
|
||||
export async function resolveDirectoryContents(
|
||||
path: string,
|
||||
options?: ReadDirOptions,
|
||||
|
||||
Reference in new issue
Block a user