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

[0.6.1]: small fixes #570

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Run Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- run: yarn
- run: yarn test --detectOpenHandles --forceExit
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ After installation use default shortcut `ctrl+space` to show an app window. You

## Plugins
### Core plugins
* Search in the web with google suggestions;

The following plugins are downloaded when you first install Cerebro:

* Search & launch application, i.e. `spotify`;
* Navigate in file system with file previews (i.e. `~/Dropbox/passport.pdf`);
* Calculator;
* Smart converter. `15$`, `150 рублей в евро`, `100 eur in gbp`;
* Search in the web with google suggestions (`cerebro-google`). There are more providers available (ecosia, duck-duck-go, ...)
* Navigate in file system with file previews (i.e. `~/Dropbox/passport.pdf`)
* Calculator (`cerebro-math`)
* Smart converter. `15$`, `150 рублей в евро`, `100 eur in gbp` (`cerebro-converter`)

## Shortcuts

Cerebro provides several shortcuts to improve your productivity:
- `ctrl+c`: copy the result from a plugin to the clipboard, if the plugin does not provida a result, the term you introduced will be copied
- `ctrl+1...9`: select directly a result from the list
- `ctrl+[hjkl]`: navigate through the results using vim-like keys (Also `ctrl+o` to select the result)

### Install and manage custom plugins
Use built-in `plugins` command to search and manage custom plugins.
Expand Down Expand Up @@ -104,7 +114,7 @@ $ yarn build
CerebroApp is using GH actions to build the app and publish it to a release. To publish a new release follow the steps below:

1. Update the version on both `package.json` and `app/package.json` files.
2. Create a release with from GH and publish it. 🚧 The release **tag** SHOULD NOT contain the `v` prefix (❌ `v0.1.2` → ✅`0.1.2`).
2. Create a release with from GH and publish it. 🚧 The release **tag** MUST contain the `v` prefix (❌ `0.1.2` → ✅`v0.1.2`).
3. Complete the name with a name and a description of the release.
4. The GH action is triggered and the release is updated when executables are built.

Expand Down
2 changes: 1 addition & 1 deletion __mocks__/@electron/remote.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
app: {
getPath: jest.fn(),
getPath: () => '',
}
}
5 changes: 5 additions & 0 deletions __mocks__/plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
'test-plugin': {
fn: () => {}
}
}
13 changes: 3 additions & 10 deletions app/lib/config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { app, ipcRenderer } from 'electron'
import fs from 'fs'
import path from 'path'
import { memoize } from 'cerebro-tools'
import { trackEvent } from './trackEvent'
import loadThemes from './loadThemes'

const remote = process.type === 'browser'
Expand All @@ -14,11 +14,11 @@ const electronApp = remote ? remote.app : app
// set data directory to ./userdata
process.argv.forEach((arg) => {
if (arg.toLowerCase() === '-p' || arg.toLowerCase() === '--portable') {
electronApp.setPath('userData', `${process.cwd()}/userdata`)
electronApp.setPath('userData', path.join(process.cwd(), 'userdata'))
}
})

const CONFIG_FILE = `${electronApp.getPath('userData')}/config.json`
const CONFIG_FILE = path.join(electronApp.getPath('userData'), 'config.json')

const defaultSettings = memoize(() => {
const locale = electronApp.getLocale() || 'en-US'
Expand All @@ -38,7 +38,6 @@ const defaultSettings = memoize(() => {
lastShownDonateDialog: null,
plugins: {},
isMigratedPlugins: false,
trackingEnabled: true,
crashreportingEnabled: true,
openAtLogin: true
}
Expand Down Expand Up @@ -85,12 +84,6 @@ const set = (key, value) => {
}
config[key] = value
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2))
// Track settings changes
trackEvent({
category: 'Settings',
event: `Change ${key}`,
label: value
})

if (ipcRenderer) {
console.log('notify main process', key, value)
Expand Down
32 changes: 32 additions & 0 deletions app/lib/loadThemes.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import themesLoader from './loadThemes'

const productionThemes = [
{
value: '../dist/main/css/themes/light.css',
label: 'Light'
},
{
value: '../dist/main/css/themes/dark.css',
label: 'Dark'
}
]

const developmentThemes = [
{
value: 'http://localhost:3000/dist/main/css/themes/light.css',
label: 'Light'
},
{
value: 'http://localhost:3000/dist/main/css/themes/dark.css',
label: 'Dark'
}
]

test('returns themes for production', () => {
expect(themesLoader()).toEqual(productionThemes)
})

test('returns themes for development', () => {
process.env.HOT = true
expect(themesLoader()).toEqual(developmentThemes)
})
1 change: 0 additions & 1 deletion app/lib/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const EMPTY_PACKAGE_JSON = JSON.stringify({

export const pluginsPath = path.join(getAppDataPath('Cerebro'), 'plugins')
export const modulesDirectory = path.join(pluginsPath, 'node_modules')
export const cerebroappModulesDirectory = path.join(pluginsPath, 'node_modules', '@cerebroapp')
export const packageJsonPath = path.join(pluginsPath, 'package.json')

export const ensureFiles = () => {
Expand Down
84 changes: 84 additions & 0 deletions app/lib/plugins/settings/validate.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import validate from './validate'

const validSettings = {
option1: {
description: 'Just a test description',
type: 'option',
options: ['option_1', 'option_2'],
},
option2: {
description: 'Just a test description',
type: 'number',
defaultValue: 0
},
option3: {
description: 'Just a test description',
type: 'number',
defaultValue: 0
},
option4: {
description: 'Just a test description',
type: 'bool'
},
option5: {
description: 'Just a test description',
type: 'string',
defaultValue: 'test'
}
}

const invalidSettingsNoOptionsProvided = {
option1: {
description: 'Just a test description',
type: 'option',
options: [],
}
}

const invalidSettingsInvalidType = {
option1: {
description: 'Just a test description',
type: 'test'
}
}

describe('Validate settings function', () => {
it('returns true when plugin has no settings field', () => {
const plugin = {
fn: () => {}
}
expect(validate(plugin)).toEqual(true)
})

it('returns true when plugin has empty settings field', () => {
const plugin = {
fn: () => {},
settings: {}
}
expect(validate(plugin)).toEqual(true)
})

it('returns true when plugin has valid settings', () => {
const plugin = {
fn: () => {},
settings: validSettings
}
expect(validate(plugin)).toEqual(true)
})

it('returns false when option type is options and no options provided', () => {
const plugin = {
fn: () => {},
settings: invalidSettingsNoOptionsProvided
}
expect(validate(plugin)).toEqual(false)
})

it('returns false when option type is incorrect', () => {
const plugin = {
fn: () => {},
settings: invalidSettingsInvalidType
}
expect(validate(plugin)).toEqual(false)
})
})
36 changes: 0 additions & 36 deletions app/lib/trackEvent.js

This file was deleted.

4 changes: 0 additions & 4 deletions app/main/actions/search.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/**
* @jest-environment jsdom
*/

import {
MOVE_CURSOR,
SELECT_ELEMENT,
Expand Down
23 changes: 23 additions & 0 deletions app/main/actions/statusBar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
SET_STATUS_BAR_TEXT
} from 'main/constants/actionTypes'

import * as actions from './statusBar'

describe('reset', () => {
it('returns valid action', () => {
expect(actions.reset()).toEqual({
type: SET_STATUS_BAR_TEXT,
payload: null
})
})
})

describe('setValue', () => {
it('returns valid action when value passed', () => {
expect(actions.setValue('test value')).toEqual({
type: SET_STATUS_BAR_TEXT,
payload: 'test value'
})
})
})
30 changes: 9 additions & 21 deletions app/main/components/Cerebro/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import escapeStringRegexp from 'escape-string-regexp'

import debounce from 'lodash/debounce'

import { trackEvent } from 'lib/trackEvent'
import getWindowPosition from 'lib/getWindowPosition'
import {
WINDOW_WIDTH,
Expand All @@ -29,19 +28,6 @@ const remote = process.type === 'browser'
? { getCurrentWindow: BrowserWindow.getFocusedWindow }
: require('@electron/remote')

const SHOW_EVENT = {
category: 'Window',
event: 'show'
}

const SELECT_EVENT = {
category: 'Plugins',
event: 'select'
}

const trackShowWindow = () => trackEvent(SHOW_EVENT)
const trackSelectItem = (label) => trackEvent({ ...SELECT_EVENT, label })

/**
* Wrap click or mousedown event to custom `select-item` event,
* that includes only information about clicked keys (alt, shift, ctrl and meta)
Expand Down Expand Up @@ -112,7 +98,6 @@ class Cerebro extends Component {
window.addEventListener('beforeunload', this.cleanup)
this.electronWindow.on('show', this.focusMainInput)
this.electronWindow.on('show', this.updateElectronWindow)
this.electronWindow.on('show', trackShowWindow)
}

componentDidMount() {
Expand Down Expand Up @@ -194,23 +179,28 @@ class Cerebro extends Component {
}
}

if (event.metaKey || event.ctrlKey) {
// shortcuts for ctrl+...
if ((event.metaKey || event.ctrlKey) && !event.altKey) {
if (event.keyCode === 67) {
// Copy to clipboard on cmd+c
const text = this.highlightedResult().clipboard
const text = this.highlightedResult()?.clipboard || this.props.term
if (text) {
clipboard.writeText(text)
this.props.actions.reset()
if (!event.defaultPrevented) {
this.electronWindow.hide()
}
event.preventDefault()
}
return
}

// Select element by number
if (event.keyCode >= 49 && event.keyCode <= 57) {
// Select element by number
const number = Math.abs(49 - event.keyCode)
const result = this.props.results[number]
if (result) {
return this.selectItem(result)
return this.selectItem(result, event)
}
}

Expand Down Expand Up @@ -268,7 +258,6 @@ class Cerebro extends Component {
window.removeEventListener('beforeunload', this.cleanup)
this.electronWindow.removeListener('show', this.focusMainInput)
this.electronWindow.removeListener('show', this.updateElectronWindow)
this.electronWindow.removeListener('show', trackShowWindow)
}

focusMainInput() {
Expand All @@ -290,7 +279,6 @@ class Cerebro extends Component {
*/
selectItem(item, realEvent) {
this.props.actions.reset()
trackSelectItem(item.plugin)
const event = wrapEvent(realEvent)
item.onSelect(event)
if (!event.defaultPrevented) {
Expand Down
Loading