Coder Social home page Coder Social logo

file-explorer's People

Contributors

emmesbef avatar pkerschbaum avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

file-explorer's Issues

[Bug]: If a folder is moved or deleted while it is opened in a explorer tab, the explorer tab gets into a broken state

Current Behavior

If a folder is moved or deleted while it is opened in a explorer tab, the explorer tab gets into a broken state.

Example

A explorer tab has this directory opened: home\test-directory\sub-directory.
If home, test-subdirectory or sub-directory is moved (because it is renamed in a second tab; it is renamed using the native file explorer; it is deleted; etc.), then the tab remains present but almost every action performed in this tab will throw an error.
It is possible to get into a healthy state again if the user navigates up the directory hierarchy or changes the CWD (current working directory) using the change CWD form (behind the Breadcrumbs menu). It is also possible to just close the tab.

Reason for the bug

Explorer tabs do not react to their CWD getting invalid/detached.

Suggested Solution

The Windows file explorer seems to navigate up the file hierarchy until it finds an ancestor which is valid. In case no ancestor is valid (e.g. the path F:\test was open, and the device having the drive letter F got detached), the file explorer just closes.

I think it is sufficient for our file explorer if it just removes explorer tabs which CWD got detached.

Implementation Notes

A single explorer tab does already register a file system watcher for each of its CWD segments. For example, if the CWD is home\test-directory\sub-directory, three file system watchers are active:

  • home
  • home\test-directory
  • home\test-directory\sub-directory

This is done by creating a CwdSegmentContextProvider for each CWD segment...

{cwdSegments.map((segment, idx) => {
const isLastSegment = idx === cwdSegments.length - 1;
return (
<CwdSegmentContextProvider
key={uriHelper.getComparisonKey(segment.uri)}
segmentIdx={idx}
>
<ActionsBarAndResourcesView
isLastSegment={isLastSegment}
activeAnimationVariant={activeAnimationVariant}
/>
</CwdSegmentContextProvider>
);
})}

...and this CwdSegmentContextProvider "listens" for the resources in its directory:

const { resources } = useResourcesOfDirectory(uri);

useResourcesOfDirectory returns a property error. We could check if that error is set and if so, remove not just the CWD segment but the entire explorer panel from the global state.

[Enhancement]: Resources Gallery View: Respect orientation embedded in image files

Current Behavior

Image thumbnails shown in the Resources Gallery View are shown in the orientation as read from the disk.

Desired Behavior

Image files might contain a orientation in their EXIF metadata. Read the orientation from that metadata an display the image thumbnail rotated accordingly.
There are many options for an EXIF image parser library to choose from: https://www.npmjs.com/search?ranking=optimal&q=exif

Implementation Notes

  • The image thumbnails are retrieved by the UI via a custom electron protocol. I think we just should read and rotate the image thumbnail here:
    const THUMBNAIL_RESIZE_BLOCKLIST = ['image/svg+xml'];
    async function getThumbnail(request: electron.ProtocolRequest): Promise<ProtocolStreamResponse> {
    const parsed = new URL(request.url);
    // property "pathname" has a leading slash --> remove that (https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname)
    const path = parsed.pathname.substring(1);
    const uri = URI.parse(decodeURIComponent(path));
    const requestedHeight = parsed.searchParams.get('height');
    const parsedHeight = numbers.convert(requestedHeight);
    invariant(parsedHeight !== undefined);
    const mimeTypeBasedOnContent = (await FileType.fromFile(uri.fsPath))?.mime;
    const extension = uriHelper.extractExtension(uri);
    const mimeTypeBasedOnExtension = check.isNullishOrEmptyString(extension)
    ? undefined
    : mime.getType(extension);
    const finalMimeType = mimeTypeBasedOnContent ?? mimeTypeBasedOnExtension ?? undefined;
    let thumbnailStream;
    if (finalMimeType === undefined || THUMBNAIL_RESIZE_BLOCKLIST.includes(finalMimeType)) {
    thumbnailStream = fs.createReadStream(uri.fsPath);
    } else {
    thumbnailStream = fs
    .createReadStream(uri.fsPath)
    .pipe(sharp().resize({ height: parsedHeight }));
    }
    return {
    data: thumbnailStream,
    mimeType: finalMimeType,
    headers: {
    'cache-control': `max-age=${60 * 60 * 24}`, // cache for 1 day
    },
    };
    }

[Enhancement]: Resources Gallery View: Show thumbnails for PDF (and perhaps MS Office) files

Current Behavior

Thumbnails in the Resources Gallery View are shown only for images and SVG files:

const THUMBNAIL_AVAILABLE_FOR_MIME_TYPE = ['image/png', 'image/jpeg', 'image/svg+xml'];

Desired Behavior

Add support for additional file types:

  • PDF files
  • maybe also MS Office files:
    • Word (docx)
    • Excel (xlsx)
    • Powerpoint (pptx)

Implementation Notes

  • The image thumbnails are retrieved by the UI via a custom electron protocol. The implementation of the custom electron protocol is in the main process. We should generate the thumbnail there. NodeJS APIs are available in the main process, so we could use e.g. GraphicsMagick like this approach: https://gist.github.com/jamilnyc/71bb717c95835bcc1d848b5158e90abb.
    Here is the implementation of the custom protocol:
    const THUMBNAIL_RESIZE_BLOCKLIST = ['image/svg+xml'];
    async function getThumbnail(request: electron.ProtocolRequest): Promise<ProtocolStreamResponse> {
    const parsed = new URL(request.url);
    // property "pathname" has a leading slash --> remove that (https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname)
    const path = parsed.pathname.substring(1);
    const uri = URI.parse(decodeURIComponent(path));
    const requestedHeight = parsed.searchParams.get('height');
    const parsedHeight = numbers.convert(requestedHeight);
    invariant(parsedHeight !== undefined);
    const mimeTypeBasedOnContent = (await FileType.fromFile(uri.fsPath))?.mime;
    const extension = uriHelper.extractExtension(uri);
    const mimeTypeBasedOnExtension = check.isNullishOrEmptyString(extension)
    ? undefined
    : mime.getType(extension);
    const finalMimeType = mimeTypeBasedOnContent ?? mimeTypeBasedOnExtension ?? undefined;
    let thumbnailStream;
    if (finalMimeType === undefined || THUMBNAIL_RESIZE_BLOCKLIST.includes(finalMimeType)) {
    thumbnailStream = fs.createReadStream(uri.fsPath);
    } else {
    thumbnailStream = fs
    .createReadStream(uri.fsPath)
    .pipe(sharp().resize({ height: parsedHeight }));
    }
    return {
    data: thumbnailStream,
    mimeType: finalMimeType,
    headers: {
    'cache-control': `max-age=${60 * 60 * 24}`, // cache for 1 day
    },
    };
    }

[Enhancement]: Title Bar Mac OS

Current Behavior

A default electron title bar is rendered in Mac OS, not adapted to the file explorer in any way (not even background color or something).

Desired Behavior

Improve style of the title bar for Mac OS.

[Enhancement]: Show disk partitions and devices

Current Behavior

  • There is no way to see disk partitions, devices, network drives, ...
  • Switching to another disk partition/devices/network drive is, at least in Windows, only possible by
    • opening the dropdown menu in the breadcrumbs row
    • then click on "Change Directory"
    • and type the drive letter into the input field (e.g. "f:" to switch to a drive with the drive letter F)

Desired Behavior

  • Show disk partitions, devices, and network drives somewhere
  • Provide an intuitive way to switch to another disk partition/device/network drive.

[Enhancement]: Extract/Compress archive files

Motivation

The file explorer should be able to extract archives (.tar.gz, .zip, .rar files) and also to create such archives based on the currently selected files.

Ideas

Extraction

  • New button in ActionBar: "Extract Archive"
  • The button would only be enabled if exactly one archive file (.zip, .tar.gz, .rar) is selected.
  • After click on "Extract Archive", a popover containing a form appears which asks for the name of the resulting folder (similar to the button "New Folder").
  • After confirming the form, an "extraction" process is added to the processes area (lower left corner) which extracts the selected archive file into the folder entered by the user, in the currently opened folder.

Compression

  • New button in ActionBar: "Compress to ZIP file"
  • After click on "Compress to ZIP file", a popover containing a form appears which asks for the name of the ZIP file (similar to the button "New Folder").
  • After confirming the form, a "compression" process is added to the processes area (lower left corner) which compresses all selected files&folders into a ZIP file with the given name, in the currently opened folder.

See this annotated screenshot (using the "New Folder" popover just for demonstration purposes):
compression_annotated_img

[Enhancement]: Allow Drag&Drop of files/folders into another folder

Motivation

As other file explorers can do, it should be able to select multiple files/folders and move them into another folder via Drag&Drop.
It would be even better if this file explorer could "react" to files/folders dropped into it from the outside, e.g. from the MacOS Finder or Windows File Explorer.

See this screenshot for illustration purposes:
2022-01-17 13_36_04-New Issue · pkerschbaum_file-explorer - Brave

Implementation Notes

There is already a onDragStart handler on resource rows / resource tiles which allows to drag the selected resource outside of the file explorer into other applications. E.g. if a .pdf file is dragged from the file explorer to a web browser, the browser opens the PDF file.
See these lines of code:

onDragStart: (e: React.DragEvent<HTMLTableRowElement>) => {
e.preventDefault();
startNativeDnDForSelectedResources();
},

The implementation of startNativeFileDnD is based on the Electron native file drag & drop API (https://www.electronjs.org/docs/latest/tutorial/native-file-drag-drop). It runs in the main process here:

import { ipcMain, IpcMainEvent, Item } from 'electron';
import invariant from 'tiny-invariant';
import {
IpcFileDragStart,
FILEDRAGSTART_CHANNEL,
} from '@app/platform/electron/ipc/common/file-drag-start';
import { OUTLINE_INSERT_DRIVE_FILE_ICON_PATH } from '@app/static-resources-main';
export function registerListeners(): void {
ipcMain.on(FILEDRAGSTART_CHANNEL, fileDragStartHandler);
}
function fileDragStartHandler(
e: IpcMainEvent,
{ fsPaths }: IpcFileDragStart.Args,
): IpcFileDragStart.ReturnValue {
invariant(fsPaths.length > 0);
const startDragArg: Omit<Item, 'file'> = {
files: fsPaths,
icon: OUTLINE_INSERT_DRIVE_FILE_ICON_PATH,
};
// @ts-expect-error -- electron typings have the property "file" defined as required, although that is actually not necessary (https://www.electronjs.org/docs/latest/api/web-contents#contentsstartdragitem)
e.sender.startDrag(startDragArg);
}

[Bug]: Option+T shortcut to open a new tab is not working

Current Behavior

Option+T shortcut is not working in Mac OS.
The equivalent shortcut is working in Windows and Ubuntu (WSLg).

Reason

Option+T produces a special character †. But the shortcut is expecting the character "t" to be produced.

Proposed solution

Check for multiple characters if a shortcut is invoked.

[Tech]: Perform schema validation when reading from persistent storage

Current Behavior

The persistent storage is implemented with electron-store. This module just writes the data into a config.json (put somewhere on the users machine). When this data is read, it is currently just typed as StorageState. But if the data of the JSON file does not match the expected shape, the file explorer can crash.
This already happened during development if the shape was changed but config.json contained data with the old shape.

Desired Behavior

When data is read from the persistent storage, validate that data according to a schema resembling StorageState before continuing. Either using https://github.com/colinhacks/zod or https://github.com/sinclairzx81/typebox + https://github.com/ajv-validator/ajv.
If a validation error occurs, continue with a "blank" state (as if the file explorer started for the first time). This means that any stored data on the user's machine is lost. At the moment, only the explorer tabs are persisted, so no meaningful data should be lost. However, in the future there might be some meaningful data stored in the persistent storage (e.g. tags for files&folders).
In general, changes of the shape of StorageState (and thus, effectively, config.json) should be done in a backwards-compatible manner.

Implementation Notes

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.