Skip to content

Commit

Permalink
feat: add storage preferences (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonreshetov committed Apr 9, 2022
1 parent 392376e commit 7756db5
Show file tree
Hide file tree
Showing 22 changed files with 736 additions and 100 deletions.
7 changes: 6 additions & 1 deletion src/main/components/menu.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { MenuItemConstructorOptions } from 'electron'
import { Menu, BrowserWindow } from 'electron'

export const createPopupMenu = (template: MenuItemConstructorOptions[]) => {
export const createMenu = (template: MenuItemConstructorOptions[]) => {
const menu = Menu.buildFromTemplate(template)
return menu
}

export const createPopupMenu = (template: MenuItemConstructorOptions[]) => {
const menu = createMenu(template)
menu.popup({ window: BrowserWindow.getFocusedWindow()! })

return menu
Expand Down
23 changes: 11 additions & 12 deletions src/main/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import { app, BrowserWindow, ipcMain } from 'electron'
import { app, BrowserWindow, ipcMain, Menu } from 'electron'
import path from 'path'
import os from 'os'
import { store } from './store'
import { createApiServer } from './services/api/server'
import { ApiServer } from './services/api/server'
import { createDb } from './services/db'
import { debounce } from 'lodash'
import { subscribeToChannels } from './services/ipc'
import { mainMenu } from './menu/main'
import { subscribeToDialog } from './services/ipc/dialog'

const isDev = process.env.NODE_ENV === 'development'

createDb()
createApiServer()
const apiServer = new ApiServer()

subscribeToChannels()
subscribeToDialog()

function createWindow () {
if (isDev) {
store.preferences.set('storagePath', os.homedir() + '/massCode/dev')
store.preferences.set('backupPath', os.homedir() + '/massCode/dev')
}

const bounds = store.app.get('bounds')
const mainWindow = new BrowserWindow({
width: 1000,
Expand All @@ -33,6 +32,8 @@ function createWindow () {
}
})

Menu.setApplicationMenu(mainMenu)

if (isDev) {
const rendererPort = process.argv[2]
mainWindow.loadURL(`http://localhost:${rendererPort}`)
Expand Down Expand Up @@ -64,10 +65,8 @@ app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

ipcMain.handle('restart', () => {
console.log('App is restart...')
app.relaunch()
app.exit()
ipcMain.handle('main:restart-api', () => {
apiServer.restart()
})

ipcMain.on('request-info', event => {
Expand Down
108 changes: 108 additions & 0 deletions src/main/menu/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { createMenu } from '../components/menu'
import type { MenuItemConstructorOptions } from 'electron'
import { app, BrowserWindow } from 'electron'
import { version, author } from '../../../package.json'

const isDev = process.env.NODE_ENV === 'development'
const isMac = process.platform === 'darwin'
const year = new Date().getFullYear()

if (isMac) {
app.setAboutPanelOptions({
applicationName: 'massCode',
applicationVersion: version,
version,
copyright: `${author.name}\n https://masscode.io \n©2019-${year}`
})
}

const appMenuCommon: Record<
'preferences' | 'quit',
MenuItemConstructorOptions
> = {
preferences: {
label: 'Preferences',
accelerator: 'CommandOrControl+,',
click: () => {
BrowserWindow.getFocusedWindow()?.webContents.send(
'main-menu:preferences'
)
}
},
quit: {
label: 'Quit massCode',
role: 'quit'
}
}

const appMenuMac: MenuItemConstructorOptions[] = [
{
label: 'About massCode',
click: () => {
app.showAboutPanel()
}
},
{
type: 'separator'
},
{
...appMenuCommon.preferences
},
{
type: 'separator'
},
{
label: 'Hide massCode',
role: 'hide'
},
{
label: 'Hide Others',
role: 'hideOthers'
},
{
label: 'Show All',
role: 'unhide'
},
{
type: 'separator'
},
{
...appMenuCommon.quit
}
]

const appMenu: MenuItemConstructorOptions[] = [
{ ...appMenuCommon.preferences },
{ ...appMenuCommon.quit }
]

const helpMenu: MenuItemConstructorOptions[] = [
{
label: 'Toogle Dev tools',
role: 'toggleDevTools'
}
]

if (isDev) {
helpMenu.push({
label: 'Reload',
role: 'reload'
})
}

const menuItems: MenuItemConstructorOptions[] = [
{
label: 'massCode',
submenu: isMac ? appMenuMac : appMenu
},
{
label: 'Edit',
role: 'editMenu'
},
{
label: 'Help',
submenu: helpMenu
}
]

export const mainMenu = createMenu(menuItems)
6 changes: 4 additions & 2 deletions src/main/preload.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { contextBridge, ipcRenderer } from 'electron'
import { migrate } from './services/db'
import { isDbExist, migrate, move } from './services/db'
import { store } from './store'
import type { ElectronBridge } from '@shared/types/main'

Expand All @@ -22,6 +22,8 @@ contextBridge.exposeInMainWorld('electron', {
}
},
db: {
migrate: (path: string) => migrate(path)
migrate: path => migrate(path),
move: (from, to) => move(from, to),
isExist: path => isDbExist(path)
}
} as ElectronBridge)
170 changes: 104 additions & 66 deletions src/main/services/api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,95 +4,133 @@ import { nanoid } from 'nanoid'
import { API_PORT } from '../../config'
import path from 'path'
import type { DB, Snippet, Tag } from '@shared/types/main/db'
import type { Server } from 'http'
import type { Socket } from 'net'
import { remove } from 'lodash'

export const createApiServer = () => {
const db = path.resolve(store.preferences.get('storagePath') + '/db.json')
const app = jsonServer.create()
const middlewares = jsonServer.defaults()
const router = jsonServer.router<DB>(db)
interface ServerWithDestroy extends Server {
destroy: Function
}

app.use(jsonServer.bodyParser)
app.use(middlewares)
export class ApiServer {
server: ServerWithDestroy
connections: Record<string, Socket> = {}

app.post('/db/update/:table', (req, res) => {
const table = req.params.table as keyof DB
const isAllowedTable = ['folders', 'snippets', 'tags'].includes(table)
constructor () {
this.server = this.create()
}

if (!isAllowedTable) {
return res.status(400).send('Table is not defined in DB')
}
if (req.body.value?.length === 0) {
res.status(400).send("'value' is required")
} else {
const db = router.db.getState()
create (): ServerWithDestroy {
const db = path.resolve(store.preferences.get('storagePath') + '/db.json')
const app = jsonServer.create()
const middlewares = jsonServer.defaults()
const router = jsonServer.router<DB>(db)

db[table] = req.body.value
app.use(jsonServer.bodyParser)
app.use(middlewares)

router.db.setState(db)
router.db.write()
app.post('/db/update/:table', (req, res) => {
const table = req.params.table as keyof DB
const isAllowedTable = ['folders', 'snippets', 'tags'].includes(table)

res.sendStatus(200)
}
})
if (!isAllowedTable) {
return res.status(400).send('Table is not defined in DB')
}
if (req.body.value?.length === 0) {
res.status(400).send("'value' is required")
} else {
const db = router.db.getState()

db[table] = req.body.value

router.db.setState(db)
router.db.write()

res.sendStatus(200)
}
})

app.post('/snippets/delete', (req, res) => {
const ids: string[] = req.body.ids
const snippets = router.db.get<Snippet[]>('snippets').value()

app.post('/snippets/delete', (req, res) => {
const ids: string[] = req.body.ids
const snippets = router.db.get<Snippet[]>('snippets').value()
ids.forEach(i => {
const index = snippets.findIndex(s => s.id === i)
if (index !== -1) snippets.splice(index, 1)
})

ids.forEach(i => {
const index = snippets.findIndex(s => s.id === i)
if (index !== -1) snippets.splice(index, 1)
router.db.write()

res.sendStatus(200)
})

router.db.write()
app.delete('/tags/:id', (req, res) => {
const id = req.params.id
const tags = router.db.get<Tag[]>('tags').value()
const snippets = router.db
.get<Snippet[]>('snippets')
.filter(i => i.tagsIds.includes(id))
.value()
const index = tags.findIndex(i => i.id === id)

res.sendStatus(200)
})
snippets.forEach(i => {
remove(i.tagsIds, item => item === id)
})

app.delete('/tags/:id', (req, res) => {
const id = req.params.id
const tags = router.db.get<Tag[]>('tags').value()
const snippets = router.db
.get<Snippet[]>('snippets')
.filter(i => i.tagsIds.includes(id))
.value()
const index = tags.findIndex(i => i.id === id)
tags.splice(index, 1)
router.db.write()

snippets.forEach(i => {
remove(i.tagsIds, item => item === id)
res.sendStatus(200)
})

tags.splice(index, 1)
router.db.write()
app.get('/tags/:id/snippets', (req, res) => {
const id = req.params.id
const _snippets = router.db.get<Snippet[]>('snippets').value()
const snippets = _snippets.filter(i => i.tagsIds.includes(id))

res.sendStatus(200)
})
res.status(200).send(snippets)
})

app.get('/tags/:id/snippets', (req, res) => {
const id = req.params.id
const _snippets = router.db.get<Snippet[]>('snippets').value()
const snippets = _snippets.filter(i => i.tagsIds.includes(id))
app.use((req, res, next) => {
if (req.method === 'POST') {
req.body.id = nanoid(8)
req.body.createdAt = Date.now().valueOf()
req.body.updatedAt = Date.now().valueOf()
}

if (req.method === 'PATCH' || req.method === 'PUT') {
req.body.updatedAt = Date.now().valueOf()
}
next()
})

res.status(200).send(snippets)
})
app.use(router)

app.use((req, res, next) => {
if (req.method === 'POST') {
req.body.id = nanoid(8)
req.body.createdAt = Date.now().valueOf()
req.body.updatedAt = Date.now().valueOf()
}
const server = app.listen(API_PORT, () => {
console.log(`API server is running on port ${API_PORT}`)
}) as ServerWithDestroy

server.on('connection', conn => {
const key = conn.remoteAddress + ':' + conn.remotePort
this.connections[key] = conn
conn.on('close', () => {
delete this.connections[key]
})
})

if (req.method === 'PATCH' || req.method === 'PUT') {
req.body.updatedAt = Date.now().valueOf()
server.destroy = () => {
server.close()
for (const key in this.connections) {
this.connections[key].destroy()
}
}
next()
})

app.use(router)
return server
}

app.listen(API_PORT, () => {
console.log(`API server is running on port ${API_PORT}`)
})
restart () {
console.log('API server restart...')
this.server.destroy()
this.server = this.create()
}
}

0 comments on commit 7756db5

Please sign in to comment.