Skip to content

Commit

Permalink
Add wsl left panel (#160)
Browse files Browse the repository at this point in the history
* ADDED: WSL Linux distribution list on left panel (win only)
* FIXED: infinite loop in favoriteState
* FIXED: leftpanel selection on Linux distributions fixes #149
* FIXED: isRoot special case for WSL paths fixes #151
* FIXED: incorrect error message when renaming, fixes #156
* ADDED: new FsWsl filesystem for WSL on Windows
* ADDED: new util to decode WSL files with special chars
* FIXED: circular dep Fs <-> FsLocal, fixes tests
  • Loading branch information
warpdesign authored Jul 11, 2020
1 parent 6f4f086 commit 9b32cec
Show file tree
Hide file tree
Showing 12 changed files with 13,497 additions and 13,995 deletions.
27,141 changes: 13,188 additions & 13,953 deletions package-lock.json

Large diffs are not rendered by default.

75 changes: 65 additions & 10 deletions src/components/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import classNames from "classnames";
import { IReactionDisposer, reaction, toJS } from "mobx";
import i18next from 'i18next';
import { USERNAME, isMac } from "../utils/platform";
import { hasWSL } from "../utils/wsl";
import Icons from "../constants/icons";
import { FavoritesState, Favorite } from "../state/favoritesState";
import { AppState } from "../state/appState";
import { AppAlert } from "./AppAlert";
import CONFIG from '../config/appConfig';

declare var ENV: any;

require("../css/favoritesPanel.css");

interface LeftPanelState {
Expand All @@ -32,10 +35,13 @@ interface InjectedProps extends IProps {
export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
favoritesState: FavoritesState;
disposers:Array<IReactionDisposer> = new Array();
// we have to make an async call to check for WSL
// so we first set it to false
showDistributions: boolean = false;

constructor(props:IProps) {
super(props);

const { t } = props;

this.state = {
Expand All @@ -60,8 +66,32 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {

this.favoritesState = this.injected.appState.favoritesState;

this.installReaction();
this.installReactions();
this.bindLanguageChange();
if (!ENV.CY) {
this.checkForWSL();
}
}

private checkForWSL = async (): Promise<boolean> => {
console.log('checking for WSL');
this.showDistributions = await hasWSL();
if (this.showDistributions) {
console.log('WSL detected');
const { t } = this.props;
const { nodes } = this.state;

nodes.push({
id: 2,
hasCaret: true,
isExpanded: true,
label: t('FAVORITES_PANEL.LINUX'),
childNodes: []
});

this.setState({ nodes });
}
return this.showDistributions;
}

private bindLanguageChange = () => {
Expand All @@ -76,7 +106,7 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
public onLanguageChanged = (lang: string) => {
console.log('building nodes', lang);
this.buildNodes(this.favoritesState);
}
}

private get injected() {
return this.props as InjectedProps;
Expand All @@ -87,7 +117,7 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
this.unbindLanguageChange();
}

private installReaction() {
private installReactions() {
this.disposers.push(reaction(
() => toJS(this.favoritesState.places),
(_: Favorite[]) => {
Expand All @@ -97,6 +127,16 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
}
})
);

this.disposers.push(reaction(
() => toJS(this.favoritesState.distributions),
(_: Favorite[]) => {
if (!this.props.hide) {
console.log('distributions updated: need to rebuild nodes');
this.buildNodes(this.favoritesState);
}
})
);
}

/**
Expand All @@ -108,14 +148,16 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
getNodeFromPath(path:string):ITreeNode<string> {
const { nodes } = this.state;
const shortcuts = nodes[0].childNodes;
const places = nodes[1].childNodes;

const found = shortcuts.find(node => node.nodeData === path);
const found = shortcuts.find(node => node.nodeData === path) || places.find(node => node.nodeData === path);

if (found) {
if (found || !this.showDistributions) {
return found;
} else {
const places = nodes[1].childNodes;
return places.find(node => node.nodeData === path);

const distribs = nodes[2].childNodes;
return distribs.find(node => node.nodeData === path);
}
}

Expand Down Expand Up @@ -148,7 +190,7 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
if (sameView) {
const activeCache = appState.getActiveCache();
if (activeCache && activeCache.status === 'ok') {
activeCache.cd(path)
activeCache.cd(path);
}
} else {
const winState = appState.winStates[0];
Expand Down Expand Up @@ -186,6 +228,7 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
const { nodes } = this.state;
const shortcuts = nodes[0];
const places = nodes[1];
const distributions = nodes[2];

shortcuts.childNodes = favorites.shortcuts.map((shortcut, i) => ({
id: `s_${shortcut.path}`,
Expand All @@ -205,15 +248,27 @@ export class LeftPanelClass extends React.Component<IProps, LeftPanelState> {
nodeData: place.path
}));

if (this.showDistributions && favorites.distributions) {
distributions.childNodes = favorites.distributions.map((distrib) => ({
id: `p_${distrib.path}`,
key: `p_${distrib.path}`,
label: <span title={distrib.path}>{distrib.label}</span>,
icon: distrib.icon,
nodeData: distrib.path
}));
}

// update root nodes label too
places.label = t('FAVORITES_PANEL.PLACES');
shortcuts.label = t('FAVORITES_PANEL.SHORTCUTS');
if (distributions) {
distributions.label = t('FAVORITES_PANEL.LINUX');
}

this.setState(this.state);
}

render() {
console.log('LeftPanel.render');
const path = this.getActiveCachePath();
this.setActiveNode(path);
const { nodes } = this.state;
Expand Down
12 changes: 6 additions & 6 deletions src/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ const ElectronApp = {

settings.manage(this.mainWindow);

if (!settings.getCustom()) {
settings.setCustom({
if (!settings.custom) {
settings.custom = {
splitView: false
});
};
}

console.log(settings.getCustom());
console.log(settings.custom);

this.mainWindow.initialSettings = settings.getCustom();
this.mainWindow.initialSettings = settings.custom;

// this.mainWindow.loadURL(HTML_PATH);
this.mainWindow.loadFile(HTML_PATH);
Expand Down Expand Up @@ -202,7 +202,7 @@ const ElectronApp = {
const { id, settings } = data;
const state = WindowSettings.getSettings(id);
console.log('got state', state);
state.setCustom(settings);
state.custom = settings;
});
},

Expand Down
26 changes: 24 additions & 2 deletions src/gui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,35 @@ import { Provider } from "mobx-react";
import { DndProvider } from "react-dnd";
import HTML5Backend from "react-dnd-html5-backend";
import { remote } from "electron";
// register Fs that will be available in React-Explorer
// I guess there is a better place to do that
import { FsGeneric } from '../services/plugins/FsGeneric';
import { FsWsl } from '../services/plugins/FsWsl';
import { FsLocal } from '../services/plugins/FsLocal';
import { registerFs } from '../services/Fs';

declare var ENV: any;

function initFS() {
if ((process && process.env && process.env.NODE_ENV === 'test') || ENV.CY) {
// console.log('**register generic', FsGeneric);
registerFs(FsGeneric);
} else {
registerFs(FsWsl);
registerFs(FsLocal);
}
}

class App {
settingsState: SettingsState;

constructor() {
this.settingsState = new SettingsState(ENV.VERSION);
if (ENV.NODE_ENV !== "production") {
this.createTestFolder().then(this.renderApp);
this.createTestFolder()
.then(this.init);
} else {
this.renderApp();
this.init();
}
}

Expand All @@ -44,6 +61,11 @@ class App {
return window && window.initialSettings || {};
}

init = () => {
initFS();
this.renderApp();
}

renderApp = () => {
const initialSettings = this.getInitialSettings();
document.body.classList.add("loaded");
Expand Down
3 changes: 2 additions & 1 deletion src/locale/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"UNKNOWN": "An error has occured",
"GENERIC": "{{error.message}} (code {{error.code}})",
"BAD_FILENAME": "File or directory name not valid: '{{entry}}'",
"WIN_VALID_FILENAME": "All characters except *:<>\\?| can be used",
"WIN_VALID_FILENAME": "All characters except *:<>\\?|\" can be used",
"UNIX_VALID_FILENAME": "All characters except / can be used",
"DELETE": "Error deleting files: {{message}}",
"DELETE_WARN": "Some files could not be deleted",
Expand Down Expand Up @@ -218,6 +218,7 @@
"FAVORITES_PANEL": {
"SHORTCUTS": "Shortcuts",
"PLACES": "Places",
"LINUX": "Linux",
"DOWNLOADS_DIR": "Downloads",
"MUSIC_DIR": "Music",
"PICTURES_DIR": "Images",
Expand Down
3 changes: 2 additions & 1 deletion src/locale/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"UNKNOWN": "Une erreur est survenue",
"GENERIC": "{{error.message}} (code {{error.code}})",
"BAD_FILENAME": "Nom de fichier ou dossier non valide: '{{entry}}'",
"WIN_VALID_FILENAME": "Tous les caractères sauf *:<>\\?| sont acceptés",
"WIN_VALID_FILENAME": "Tous les caractères sauf *:<>\\?|\" sont acceptés",
"UNIX_VALID_FILENAME": "Tous les caractères sauf / sont acceptés",
"DELETE": "Erreur lors de la suppression des fichiers: {{message}}",
"DELETE_WARN": "Certains fichiers n'ont pu être supprimés",
Expand Down Expand Up @@ -218,6 +218,7 @@
"FAVORITES_PANEL": {
"SHORTCUTS": "Raccourcis",
"PLACES": "Emplacements",
"LINUX": "Linux",
"DOWNLOADS_DIR": "Téléchargements",
"MUSIC_DIR": "Musique",
"PICTURES_DIR": "Images",
Expand Down
11 changes: 1 addition & 10 deletions src/services/Fs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { FsGeneric } from './plugins/FsGeneric';
import { FsLocal } from './plugins/FsLocal';
import { Readable } from 'stream';
import { isWin } from '../utils/platform';

Expand All @@ -18,13 +16,6 @@ export function registerFs(fs: Fs): void {
interfaces.push(fs);
};

if ((process && process.env && process.env.NODE_ENV === 'test') || ENV.CY) {
// console.log('**register generic', FsGeneric);
registerFs(FsGeneric);
} else {
registerFs(FsLocal);
}

declare var ENV: any;

export interface FileID {
Expand Down Expand Up @@ -152,7 +143,7 @@ export interface FsApi {

export function getFS(path: string): Fs {
let newfs = interfaces.find((filesystem) => filesystem.canread(path));

console.log('got FS', newfs);
// if (!newfs) {
// newfs = FsGeneric;
// }
Expand Down
6 changes: 6 additions & 0 deletions src/services/plugins/FsLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,22 @@ export class LocalApi implements FsApi {

async makedir(source: string, dirName: string, transferId = -1): Promise<string> {
return new Promise((resolve, reject) => {
console.log('makedir, source:', source, 'dirName:', dirName);
const unixPath = path.join(source, dirName).replace(/\\/g, "/");
console.log('unixPath', unixPath);
try {
console.log('calling mkdir');
mkdir(unixPath, (err: any) => {
if (err) {
console.log('error creating dir', err);
reject(err);
} else {
console.log('successfully created dir', err);
resolve(path.join(source, dirName));
}
});
} catch (err) {
console.log('error execing mkdir()', err);
reject(err);
}
});
Expand Down
Loading

0 comments on commit 9b32cec

Please sign in to comment.