Skip to content

Commit

Permalink
Merge pull request #658 from branchvincent/feat/open-url
Browse files Browse the repository at this point in the history
feat: directly open url or file
  • Loading branch information
rathboma committed May 25, 2021
2 parents b5ed0c1 + 722d565 commit e9f668c
Show file tree
Hide file tree
Showing 15 changed files with 207 additions and 38 deletions.
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v14.16.1
6 changes: 5 additions & 1 deletion build/launcher-script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ if [ ! -f "$CLONE" ]; then
exec "$SCRIPT_DIR/beekeeper-studio-bin" "$@"
else
UNPRIVILEGED_USERNS_ENABLED=$(cat "$CLONE" 2>/dev/null)
exec "$SCRIPT_DIR/beekeeper-studio-bin" "$([[ $UNPRIVILEGED_USERNS_ENABLED == 0 ]] && echo '--no-sandbox')" "$@"
if [[ $UNPRIVILEGED_USERNS_ENABLED == 0 ]]; then
exec "$SCRIPT_DIR/beekeeper-studio-bin" "--no-sandbox" "$@"
else
exec "$SCRIPT_DIR/beekeeper-studio-bin" "$@"
fi
fi
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ services:
- mssqllatin:/var/opt/mssql/data
- ./dev/docker_sqlserver:/docker_init
environment:
ACCEPT_EULA: Y
ACCEPT_EULA: "Y"
SA_PASSWORD: Example@1"
MSSQL_COLLATION: Latin1_General_CS_AS
MSSQL_PID: "Express"
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"pluralize": "^8.0.0",
"popper.js": "^1.15.0",
"portfinder": "^1.0.26",
"query-string": "^7.0.0",
"reflect-metadata": "^0.1.10",
"sass-loader": "^7.1.0",
"shortid": "^2.2.14",
Expand All @@ -84,6 +85,7 @@
"vuex-persist": "^2.0.1",
"xel": "beekeeper-studio/xel",
"xlsx": "^0.16.2",
"yargs-parser": "^20.2.7",
"yup": "^0.27.0"
},
"devDependencies": {
Expand Down
24 changes: 24 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Titlebar from './components/Titlebar'
import CoreInterface from './components/CoreInterface'
import ConnectionInterface from './components/ConnectionInterface'
import AutoUpdater from './components/AutoUpdater'
import querystring from 'query-string'
export default {
name: 'app',
Expand All @@ -25,6 +26,7 @@ export default {
},
data() {
return {
url: null
}
},
computed: {
Expand All @@ -42,13 +44,35 @@ export default {
}
},
async mounted() {
await this.$store.dispatch('loadSavedConfigs')
await this.$store.dispatch('loadUsedConfigs')
await this.$store.dispatch('fetchUsername')
const query = querystring.parse(global.location.search)
if (query) {
this.url = query.url || null
}
console.log("received query", query)
this.$nextTick(() => {
ipcRenderer.send('ready')
})
if (this.themeValue) {
console.log("setting background to ", this.themeValue)
document.body.className = `theme-${this.themeValue}`
}
if (this.url) {
try {
await this.$store.dispatch('openUrl', this.url)
} catch (error) {
console.error(error)
this.$noty.error(`Error opening ${this.url}: ${error}`)
throw error
}
}
},
methods: {
databaseSelected(db) {
Expand Down
52 changes: 42 additions & 10 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import { manageUpdates } from './background/update_manager'

import platformInfo from './common/platform_info'
import MenuHandler from './background/NativeMenuBuilder'
import { UserSetting } from './common/appdb/models/user_setting'
import { IGroupedUserSettings, UserSetting } from './common/appdb/models/user_setting'
import Connection from './common/appdb/Connection'
import Migration from './migration/index'
import { buildWindow } from './background/WindowBuilder'
import { buildWindow, getActiveWindows } from './background/WindowBuilder'
import yargs from 'yargs-parser'

import { AppEvent } from './common/AppEvent'
function initUserDirectory(d: string) {
Expand All @@ -36,40 +37,42 @@ if (platformInfo.isDevelopment || platformInfo.debugEnabled) {

const isDevelopment = platformInfo.isDevelopment


initUserDirectory(platformInfo.userDirectory)
log.info("initializing user ORM connection")
const ormConnection = new Connection(platformInfo.appDbPath, false)

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let settings: IGroupedUserSettings
let menuHandler
log.info("registering schema")
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([{scheme: 'app', privileges: { secure: true, standard: true } }])
let initialized = false


async function createFirstWindow () {
log.info("Creating first window")
async function initBasics() {
if (initialized) return settings
initialized = true
await ormConnection.connect()
log.info("running migrations")
const migrator = new Migration(ormConnection, process.env.NODE_ENV)
await migrator.run()

log.info("getting settings")
const settings = await UserSetting.all()
settings = await UserSetting.all()

log.info("setting up the menu")
menuHandler = new MenuHandler(electron, settings)
menuHandler.initialize()
log.info("Building the window")
buildWindow(settings)
log.info("managing updates")
manageUpdates()
ipcMain.on(AppEvent.openExternally, (_e: electron.IpcMainEvent, args: any[]) => {
const url = args[0]
if (!url) return
electron.shell.openExternal(url)
})
return settings
}


Expand All @@ -86,7 +89,7 @@ app.on('activate', async (_event, hasVisibleWindows) => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (!hasVisibleWindows) {
const settings = await UserSetting.all()
if (!settings) throw "No settings initialized!"
buildWindow(settings)
}
})
Expand All @@ -104,9 +107,38 @@ app.on('ready', async () => {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createFirstWindow()
const slice = platformInfo.isDevelopment ? 2 : 1
const parsedArgs = yargs(process.argv.slice(slice))
console.log("Parsing app args", parsedArgs)
const options = parsedArgs._.map((url: string) => ({ url }))
const settings = await initBasics()

if (options.length > 0) {

await Promise.all(options.map((option) => buildWindow(settings, option)))
} else {
if (getActiveWindows().length === 0) {
const settings = await initBasics()
await buildWindow(settings)
}
}
})

// Open a connection from a file (e.g. ./sqlite.db)
app.on('open-file', async (event, file) => {
event.preventDefault();
const settings = await initBasics()

await buildWindow(settings, { url: file })
});

// Open a connection from a url (e.g. postgres://host)
app.on('open-url', async (event, url) => {
event.preventDefault();
const settings = await initBasics()
await buildWindow(settings, { url })
});

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
Expand Down
24 changes: 16 additions & 8 deletions src/background/WindowBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@ import { createProtocol } from "vue-cli-plugin-electron-builder/lib"
import platformInfo from '../common/platform_info'
import { IGroupedUserSettings } from '../common/appdb/models/user_setting'
import rawLog from 'electron-log'
import querystring from 'query-string'

const log = rawLog.scope('WindowBuilder')

const windows: BeekeeperWindow[] = []

export interface OpenOptions {
url?: string
}

function getIcon() {
return path.resolve(path.join(__dirname, '..', `public/icons/png/512x512.png`))
}

class BeekeeperWindow {
private win: Nullable<BrowserWindow>
private reloaded = false
private win: BrowserWindow | null
private reloaded = false

constructor(settings: IGroupedUserSettings) {
constructor(settings: IGroupedUserSettings, openOptions?: OpenOptions) {
const theme = settings.theme
const showFrame = settings.menuStyle && settings.menuStyle.value == 'native' ? true : false
log.info('constructing the window')
Expand All @@ -40,7 +45,10 @@ class BeekeeperWindow {
})

const runningInWebpack = !!process.env.WEBPACK_DEV_SERVER_URL
const appUrl = process.env.WEBPACK_DEV_SERVER_URL || 'app://./index.html'
let appUrl = process.env.WEBPACK_DEV_SERVER_URL || 'app://./index.html'
const query = openOptions ? querystring.stringify(openOptions) : null

appUrl = query ? `${appUrl}?${query}` : appUrl

this.win.webContents.zoomLevel = Number(settings.zoomLevel?.value) || 0
if (!runningInWebpack) {
Expand Down Expand Up @@ -68,8 +76,8 @@ class BeekeeperWindow {
return !!this.win
}

send(channel: string) {
this.win?.webContents.send(channel)
send(channel: string, ...args: any[]) {
this.win?.webContents.send(channel, ...args)
}

initializeCallbacks() {
Expand All @@ -94,6 +102,6 @@ export function getActiveWindows() {
return _.filter(windows, 'active')
}

export function buildWindow(settings: IGroupedUserSettings) {
windows.push(new BeekeeperWindow(settings))
export function buildWindow(settings: IGroupedUserSettings, options?: OpenOptions) {
windows.push(new BeekeeperWindow(settings, options))
}
2 changes: 1 addition & 1 deletion src/common/AppEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export enum AppEvent {
beekeeperAdded = 'bkadd',
openExternally = 'oe',
toggleSidebar = 'ts',
beginExport = 'be',
beginExport = 'be'
}


Expand Down
18 changes: 15 additions & 3 deletions src/common/appdb/models/saved_connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,22 @@ export class SavedConnection extends DbConnectionBase {
return this._sshMode
}

private smellsLikeUrl(url: string): boolean {
return url.includes("://")
}

parse(url: string) {
try {
const parsed = new ConnectionString(url)
this.connectionType = parsed.protocol as IDbClients || this.connectionType
const goodEndings = ['.db', '.sqlite', '.sqlite3']
if(goodEndings.find((e) => url.endsWith(e)) && !this.smellsLikeUrl(url)) {
// it's a sqlite file
this.connectionType = 'sqlite'
this.defaultDatabase = url
return true
}

const parsed = new ConnectionString(url)
this.connectionType = parsed.protocol as IDbClients || this.connectionType || 'postgresql'
if (parsed.hostname && parsed.hostname.includes('redshift.amazonaws.com')) {
this.connectionType = 'redshift'
}
Expand All @@ -229,7 +241,7 @@ export class SavedConnection extends DbConnectionBase {
this.defaultDatabase = parsed.path ? parsed.path[0] : null || this.defaultDatabase
return true
} catch (ex) {
log.error("SavedConnection unable to parse connection string", url, ex)
log.error('unable to parse connection string, assuming sqlite file', ex)
return false
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/components/ConnectionInterface.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@
async mounted() {
this.config = this.defaultConfig
this.config.sshUsername = os.userInfo().username
await this.$store.dispatch('loadSavedConfigs')
await this.$store.dispatch('loadUsedConfigs')
await this.$store.dispatch('fetchUsername')
this.$nextTick(() => {
const components = [
this.$refs.sidebar.$refs.sidebar,
Expand Down
9 changes: 1 addition & 8 deletions src/lib/events/AppEventHandler.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AppEvent} from "../../common/AppEvent"
import { AppEvent } from "../../common/AppEvent"

export default class {

Expand Down Expand Up @@ -47,11 +47,4 @@ export default class {
menuStyle() {
this.vueApp.$noty.success("Restart Beekeeper for the change to take effect")
}







}
10 changes: 10 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,16 @@ const store = new Vuex.Store<State>({
context.commit('setUsername', name)
},

async openUrl(context, url: string) {
console.log("open url", url)
const conn = new SavedConnection();
if (!conn.parse(url)) {
throw `Unable to parse ${url}`
} else {
await context.dispatch('connect', conn)
}
},

async connect(context, config: SavedConnection) {
if (context.state.username) {
const server = ConnectionProvider.for(config, context.state.username)
Expand Down
6 changes: 4 additions & 2 deletions tests/unit/common/appdb/models/saved_connection.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ describe("Saved Connection", () => {
"one:123": {host: 'one', port: 123},
"postgresql://host:123": {connectionType: 'postgresql', host: 'host', port: 123},
"user:password@host:12345": {host: 'host', port: 12345, username: 'user', password: 'password'},
"superduperhost": {host: 'superduperhost'},
"host/database": {host: 'host', defaultDatabase: 'database'}
"superduperhost.db": {defaultDatabase: 'superduperhost.db', connectionType: 'sqlite'},
"some/path.sqlite3": {connectionType: 'sqlite', defaultDatabase: 'some/path.sqlite3'},
"/Path/to file/with space.sqlite": { connectionType: 'sqlite', defaultDatabase: "/Path/to file/with space.sqlite"},
"postgresql://database.db": {connectionType: 'postgresql', host: 'database.db'},
}

Object.keys(testCases).forEach(url => {
Expand Down

0 comments on commit e9f668c

Please sign in to comment.