Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: IPFS Desktop settings #883

Merged
merged 13 commits into from
Nov 22, 2018
7,712 changes: 4,493 additions & 3,219 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/bundles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import connectedBundle from './connected'
import retryInitBundle from './retry-init'
import identityBundle from './identity'
import bundleCache from '../lib/bundle-cache'
import ipfsDesktop from './ipfs-desktop'

export default composeBundles(
createCacheBundle(bundleCache.set),
Expand All @@ -40,5 +41,6 @@ export default composeBundles(
peerLocationsBundle({ concurrency: 1 }),
notifyBundle,
connectedBundle,
retryInitBundle
retryInitBundle,
ipfsDesktop
)
43 changes: 43 additions & 0 deletions src/bundles/ipfs-desktop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
let bundle = {
name: 'ipfsDesktop',
reducer: (state = {}) => state,
selectIsIpfsDesktop: () => !!window.ipfsDesktop
}

if (window.ipfsDesktop) {
bundle = {
...bundle,
reducer: (state = {}, action) => {
if (!action.type.startsWith('DESKTOP_')) {
return state
}

if (action.type === 'DESKTOP_SETTINGS_CHANGED') {
return action.payload
}

return state
},

selectDesktopSettings: state => state.ipfsDesktop,

doDesktopStartListening: () => async ({ dispatch }) => {
window.ipfsDesktop.onConfigChanged(config => {
dispatch({
type: 'DESKTOP_SETTINGS_CHANGED',
payload: config
})
})
},

doDesktopSettingsToggle: (setting) => () => {
window.ipfsDesktop.toggleSetting(setting)
},

init: store => {
store.doDesktopStartListening()
}
}
}

export default bundle
57 changes: 57 additions & 0 deletions src/settings/DesktopSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react'
import { connect } from 'redux-bundler-react'
import { translate } from 'react-i18next'
import Box from '../components/box/Box'
import Checkbox from '../components/checkbox/Checkbox'
import Title from './Title'

const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0

const CheckboxSetting = ({ children, title, ...props }) => (
<div className='mt2'>
<div className='flex items-center'>
<div className='w2'>
<Checkbox {...props} className='mr1' />
</div>
<p className='ma0 f6 b'>{title}</p>
</div>

<div className='pl4'>
<span>{children}</span>
</div>
</div>
)

const Key = ({ children }) => <span className='monospace br2 bg-snow ph1'>{ children }</span>

export function DesktopSettings ({ doDesktopSettingsToggle, desktopSettings }) {
return (
<Box className='mb3 pa4'>
<Title>IPFS Desktop</Title>

<CheckboxSetting checked={desktopSettings['autoLaunch'] || false}
title='Launch on startup'
onChange={() => doDesktopSettingsToggle('autoLaunch')} />
<CheckboxSetting checked={desktopSettings['screenshotShortcut'] || false}
title='Auto add screenshots'
onChange={() => doDesktopSettingsToggle('screenshotShortcut')}>
<p className='mb0 mt1 lh-copy'>
Use <Key>{isMac ? 'CMD' : 'CTRL'}</Key>+<Key>ALT</Key>+<Key>S</Key> to take screenshots and add them to the repository.
</p>
</CheckboxSetting>
<CheckboxSetting checked={desktopSettings['downloadHashShortcut'] || false}
title='Download copied hash'
onChange={() => doDesktopSettingsToggle('downloadHashShortcut')}>
<p className='mb0 mt1 lh-copy'>
Use <Key>{isMac ? 'CMD' : 'CTRL'}</Key>+<Key>ALT</Key>+<Key>D</Key> to download the last copied hash.
</p>
</CheckboxSetting>
</Box>
)
}

export default connect(
'selectDesktopSettings',
'doDesktopSettingsToggle',
translate('settings')(DesktopSettings)
)
18 changes: 11 additions & 7 deletions src/settings/SettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@ import Box from '../components/box/Box'
import Button from '../components/button/Button'
import LanguageSelector from '../components/language-selector/LanguageSelector'
import JsonEditor from './editor/JsonEditor'
import DesktopSettings from './DesktopSettings'
import Title from './Title'

const PAUSE_AFTER_SAVE_MS = 3000

const Title = ({ props, children }) => (
<h2 className='ttu tracked f6 fw4 aqua mt0 mb3' {...props}>{ children }</h2>
)

export const SettingsPage = ({
t, tReady,
isConfigBlocked, isLoading, isSaving,
hasSaveFailed, hasSaveSucceded, hasErrors, hasLocalChanges, hasExternalChanges,
hasSaveFailed, hasSaveSucceded, hasErrors, hasLocalChanges, hasExternalChanges, isIpfsDesktop,
config, onChange, onReset, onSave, editorKey
}) => (
<div data-id='SettingsPage'>
<Helmet>
<title>{t('title')} - IPFS</title>
</Helmet>

{ isIpfsDesktop &&
<DesktopSettings />
}

<Box className='mb3 pa4'>
<Title>{t('language')}</Title>
<LanguageSelector t={t} />
Expand Down Expand Up @@ -215,7 +217,7 @@ export class SettingsPageContainer extends React.Component {
}

render () {
const { t, tReady, isConfigBlocked, configIsLoading, configLastError, configIsSaving, configSaveLastSuccess, configSaveLastError } = this.props
const { t, tReady, isConfigBlocked, configIsLoading, configLastError, configIsSaving, configSaveLastSuccess, configSaveLastError, isIpfsDesktop } = this.props
const { hasErrors, hasLocalChanges, hasExternalChanges, editableConfig, editorKey } = this.state
const hasSaveSucceded = this.isRecent(configSaveLastSuccess)
const hasSaveFailed = this.isRecent(configSaveLastError)
Expand All @@ -236,7 +238,8 @@ export class SettingsPageContainer extends React.Component {
editorKey={editorKey}
onChange={this.onChange}
onReset={this.onReset}
onSave={this.onSave} />
onSave={this.onSave}
isIpfsDesktop={isIpfsDesktop} />
)
}
}
Expand All @@ -251,6 +254,7 @@ export default connect(
'selectConfigIsSaving',
'selectConfigSaveLastSuccess',
'selectConfigSaveLastError',
'selectIsIpfsDesktop',
'doSaveConfig',
TranslatedSettingsPage
)
13 changes: 13 additions & 0 deletions src/settings/SettingsPage.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { action } from '@storybook/addon-actions'
import { withKnobs, boolean } from '@storybook/addon-knobs'
import i18n from '../i18n'
import { SettingsPage } from './SettingsPage'
import { DesktopSettings } from './DesktopSettings'
import config from './editor/fixtures/example-config.json'

storiesOf('Settings Page', module)
Expand All @@ -28,3 +29,15 @@ storiesOf('Settings Page', module)
onSave={action('save')} />
</div>
))
.add('Desktop Settings', () => (
<div className='sans-serif'>
<DesktopSettings
doDesktopSettingsToggle={action('toggle')}
desktopSettings={{
autoLaunch: true,
screenshotShortcut: false,
downloadHashShortcut: true
}}
/>
</div>
))
5 changes: 5 additions & 0 deletions src/settings/Title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export default ({ props, children }) => (
<h2 className='ttu tracked f6 fw4 aqua mt0 mb3' {...props}>{ children }</h2>
)
3 changes: 2 additions & 1 deletion test/e2e/navigation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ it('Navigation test: node not running', async () => {
// const page = await browser.newPage()
const page = (await browser.pages())[0]
await page.goto(appUrl)
await page.waitForFunction(`document.title === 'Welcome to IPFS'`, { timeout: 5000 })
await page.waitForFunction(`document.title === 'Welcome to IPFS'`, { timeout: 8000 })

// No settings tab if IPFS is not available.
const settingsLink = await page.$('nav a[href="#/settings"]')
Expand Down Expand Up @@ -55,6 +55,7 @@ function addMockIpfs (page) {
id: () => Promise.resolve({}),
get: () => Promise.resolve({}),
files: {
get: () => Promise.resolve({}),
ls: () => Promise.resolve([]),
stat: () => Promise.resolve({})
},
Expand Down