Skip to content

Commit

Permalink
Merge branch 'master' of https://www.github.com/qusly/qusly
Browse files Browse the repository at this point in the history
  • Loading branch information
xnerhu committed Aug 10, 2019
2 parents ff7b0de + dfd4b33 commit dc41449
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 37 deletions.
24 changes: 2 additions & 22 deletions README.md
Expand Up @@ -2,7 +2,7 @@
<img src="static/app-icons/readme.png">

<h3>
A feature-rich, elegant FTP client
A full-featured, elegant FTP client
</h3>

<br />
Expand All @@ -11,7 +11,7 @@
[![Travis](https://img.shields.io/travis/qusly/qusly.svg?style=flat-square)](https://travis-ci.com/qusly/qusly)
[![Travis](https://img.shields.io/travis/qusly/qusly-core.svg?style=flat-square)](https://travis-ci.org/xnerhu/qusly-core.svg)
[![Downloads](https://img.shields.io/github/downloads/qusly/qusly/total.svg?style=flat-square)](https://github.com/qusly/qusly/releases)
[![Discord](https://img.shields.io/discord/591624973609730059.svg?style=flat-square)](https://discord.gg/rNyNYFn)
[![Discord](https://discordapp.com/api/guilds/307605794680209409/widget.png?style=shield)](https://discord.gg/P7Vn4VX)
[![Github](https://img.shields.io/github/followers/xnerhu.svg?style=social&label=Follow)](https://github.com/xnerhu)

</div>
Expand Down Expand Up @@ -59,26 +59,6 @@ ENABLED=true
You can set the protocol to `sftp`, `ftp` or `ftps`.
Port is usually `21` for FTP(s) and `22` for SFTP.

### Other commands

You can also run other commands, for other tasks like building the app or linting the code, by using the commands described below.

##### Usage:

```bash
$ npm run <command>
```

| Command | Description |
| ---------------- | ------------------------------------------- |
| `build` | Bundles the source code in production mode. |
| `compile-win32` | Compiles binaries for Windows. |
| `compile-darwin` | Compiles binaries for macOS. |
| `compile-linux` | Compiles binaries for Linux. |
| `lint` | Lints the source code. |
| `lint-fix` | Fixes eslint errors |
| `dev` | Starts Qusly in the dev mode |

<a href="https://www.patreon.com/bePatron?u=21429620">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
</a>
10 changes: 9 additions & 1 deletion src/renderer/components/FileMenu/index.tsx
Expand Up @@ -5,6 +5,14 @@ import { ContextMenu, ContextMenuItem } from '../ContextMenu';
import store from '~/renderer/store';
import { resizeTextarea, selectFileName } from '~/renderer/utils';

const onDownload = () => {
const session = store.sessions.current;
const page = store.pages.current;
const path = page.location.relative(page.focusedFile.name);

session.download.add(path, page.focusedFile.name);
};

const onOpen = () => {
const page = store.pages.current;
page.location.push(page.focusedFile.name);
Expand Down Expand Up @@ -65,7 +73,7 @@ export default observer(() => {

return (
<ContextMenu content="file">
<ContextMenuItem disabled>Download</ContextMenuItem>
<ContextMenuItem onClick={onDownload}>Download</ContextMenuItem>
{!containsFile && (
<>
{!mutliple && (
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/components/Menu/index.tsx
Expand Up @@ -6,6 +6,7 @@ import { MenuButton } from '../MenuButton';
import MenuPage from '../MenuPage';
import FileTree from '../FileTree';
import SitesManager from '../SitesManager';
import TransferView from '../TransferView';
import { ButtonsBar } from './styles';

const Buttons = () => {
Expand All @@ -14,7 +15,7 @@ const Buttons = () => {
<MenuButton content="sites" icon={icons.sitesManager} />
<MenuButton content="file-tree" icon={icons.fileTree} />
<MenuButton content="search" icon={icons.search} />
<MenuButton content="transfer" icon={icons.transfer} iconSize={26} />
<MenuButton content="transfers" icon={icons.transfer} iconSize={26} disabled />
</ButtonsBar>
);
};
Expand All @@ -27,9 +28,12 @@ export default () => {
<MenuPage content="file-tree">
<FileTree />
</MenuPage>
<MenuPage content="sites" style={{ overflowX: 'hidden' }}>
<MenuPage content="sites">
<SitesManager />
</MenuPage>
<MenuPage content="transfers">
<TransferView />
</MenuPage>
</Resizable>
</>
);
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/components/MenuButton/index.tsx
Expand Up @@ -14,17 +14,20 @@ export const MenuButton = observer(
content,
icon,
iconSize,
disabled,
}: {
content: MenuContent;
icon: any;
iconSize?: number;
disabled?: boolean;
}) => {
return (
<StyledButton onClick={onClick(content)}>
<StyledButton onClick={onClick(content)} disabled={disabled}>
<Icon
size={iconSize}
icon={icon}
selected={store.menu.content === content}
disabled={disabled}
/>
</StyledButton>
);
Expand Down
24 changes: 15 additions & 9 deletions src/renderer/components/MenuButton/styles.ts
Expand Up @@ -8,6 +8,10 @@ export const StyledButton = styled.div`
height: ${MENU_WIDTH}px;
cursor: pointer;
position: relative;
${({ disabled }: { disabled: boolean }) => css`
pointer-events: ${disabled ? 'none' : 'auto'};
`}
`;

export const Icon = styled.div`
Expand All @@ -19,16 +23,18 @@ export const Icon = styled.div`
}
${({
icon,
selected,
size,
}: {
icon: any;
selected: boolean;
size: number;
}) => css`
icon,
selected,
size,
disabled,
}: {
icon: any;
selected: boolean;
size: number;
disabled: boolean;
}) => css`
background-image: url(${icon});
opacity: ${selected ? 1 : transparency.icons.inactive};
opacity: ${disabled ? transparency.icons.disabled : (selected ? 1 : transparency.icons.inactive)};
${centerIcon(size)};
`}
`;
19 changes: 19 additions & 0 deletions src/renderer/components/TransferItem/index.tsx
@@ -0,0 +1,19 @@
import * as React from 'react';

import { File } from '~/renderer/models';
import store from '~/renderer/store';
import { StyledItem, Icon, Name, Path, Details } from './styles';

export default ({ file }: { file: File }) => {
const { icon, opacity } = store.favicons.get(file);

return (
<StyledItem>
<Icon icon={icon} opacity={opacity} />
<Details>
<Name>name.txt</Name>
<Path>/var/www/</Path>
</Details>
</StyledItem>
);
};
39 changes: 39 additions & 0 deletions src/renderer/components/TransferItem/styles.ts
@@ -0,0 +1,39 @@
import styled, { css } from 'styled-components';
import { centerIcon, transparency } from 'wexond-ui';

export const StyledItem = styled.div`
width: 100%;
height: 36px;
display: flex;
align-items: center;
`;

export const Icon = styled.div`
width: 24px;
height: 24px;
margin-left: 20px;
${centerIcon(24)};
${({ icon, opacity }: { icon: string, opacity: number }) => css`
background-image: url(${icon});
opacity: ${opacity};
`}
`;

export const Details = styled.div`
display: flex;
justify-content: center;
flex-direction: column;
padding-left: 12px;
padding-right: 24px;
`;

export const Name = styled.div`
font-size: 13px;
white-space: nowrap;
`;

export const Path = styled(Name)`
margin-top: 2px;
color: rgba(0, 0, 0, ${transparency.text.medium});
`;
29 changes: 29 additions & 0 deletions src/renderer/components/TransferView/index.tsx
@@ -0,0 +1,29 @@
import * as React from 'react';
import { observer } from 'mobx-react';

import store from '~/renderer/store';
import { Pagebar, PageTitle } from '../MenuPage/styles';
import TransferItem from '../TransferItem';
import { File } from '~/renderer/models';

export default observer(() => {
const file: File = {
date: new Date('2001-06-01T20:05:00.000Z'),
permissions: { user: 6, group: 4 },
name: 'documentation.pdf',
size: 1724303,
user: 'root',
group: 'root',
type: 'file',
ext: '.pdf',
};

return (
<React.Fragment>
<Pagebar>
<PageTitle>File transfer</PageTitle>
</Pagebar>
<TransferItem file={file} />
</React.Fragment>
);
});
4 changes: 4 additions & 0 deletions src/renderer/models/queue-item.ts
@@ -0,0 +1,4 @@
export interface QueueItem {
remotePath: string;
localPath: string;
}
3 changes: 3 additions & 0 deletions src/renderer/models/session.ts
Expand Up @@ -4,6 +4,7 @@ import { Client } from 'qusly-core';
import { Tree } from './tree';
import { Site } from './site';
import store from '../store';
import { TransferManager } from './transfer';

let id = 0;

Expand All @@ -22,6 +23,8 @@ export class Session {

public connecting = false;

public download = new TransferManager(this, 'download');

public async connect(config: Site) {
if (this.connecting) return;

Expand Down
61 changes: 61 additions & 0 deletions src/renderer/models/transfer.ts
@@ -0,0 +1,61 @@
import { createWriteStream, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import { Client } from 'qusly-core';

import { Session } from './session';
import { QueueItem } from './queue-item';
import { getPath } from '../utils';

export class TransferManager {
public client: Client;

public queue: QueueItem[] = [];

public transfering = false;

constructor(public session: Session, public type: 'download' | 'upload') { }

public async connect() {
if (!this.client) {
this.client = new Client();

const config = this.session.site;
const { error } = await this.client.connect(config);

if (error) throw error;
}
}

public async add(remotePath: string, fileName: string) {
await this.connect();
const localPath = getPath('downloads');

if (!existsSync(localPath)) {
mkdirSync(localPath);
}

this.queue.push({
remotePath,
localPath: join(localPath, fileName),
});

this.process();
}

private async process() {
if (this.transfering || !this.queue.length) return;

this.transfering = true;

const { remotePath, localPath } = this.queue[0];
const { error } = await this.client.download(remotePath, createWriteStream(localPath));

if (error) {
console.error('Error while transfering a file', remotePath, localPath, error);
}

this.queue.shift();
this.transfering = false;
await this.process();
}
}
4 changes: 2 additions & 2 deletions src/renderer/store/menu.ts
@@ -1,8 +1,8 @@
import { observable } from 'mobx';

export type MenuContent = 'file-tree' | 'transfer' | 'search' | 'sites';
export type MenuContent = 'file-tree' | 'transfers' | 'search' | 'sites';

export class MenuStore {
@observable
public content: MenuContent = 'sites';
public content: MenuContent = 'transfers';
}

0 comments on commit dc41449

Please sign in to comment.