mirror of
https://github.com/garraflavatra/rolens.git
synced 2025-01-18 13:07:58 +00:00
Added functionality to save and import shell scripts (#37)
This commit is contained in:
parent
ae5002d356
commit
9d577ac429
@ -24,8 +24,5 @@ export function looseJsonIsValid(json) {
|
||||
}
|
||||
|
||||
export function stringCouldBeID(string) {
|
||||
if (looseJsonIsValid(string)) {
|
||||
return false;
|
||||
}
|
||||
return /^[a-zA-Z0-9_-]{1,}$/.test(string);
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
import Stats from './stats.svelte';
|
||||
import Update from './update.svelte';
|
||||
|
||||
export let host;
|
||||
export let database;
|
||||
export let collection;
|
||||
export let tab = 'stats';
|
||||
|
||||
@ -47,6 +49,8 @@
|
||||
this={view.component}
|
||||
visible={tab === view.key}
|
||||
on:performFind={catchQuery}
|
||||
{host}
|
||||
{database}
|
||||
{collection}
|
||||
/>
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@
|
||||
import Shell from '../shell.svelte';
|
||||
import Stats from './stats.svelte';
|
||||
|
||||
export let host;
|
||||
export let database;
|
||||
export let tab = 'stats';
|
||||
|
||||
@ -28,7 +29,7 @@
|
||||
|
||||
{#each Object.values(tabs) as view}
|
||||
<div class="container" class:hidden={tab !== view.key}>
|
||||
<svelte:component this={view.component} visible={tab === view.key} {database} />
|
||||
<svelte:component this={view.component} visible={tab === view.key} {host} {database} />
|
||||
</div>
|
||||
{/each}
|
||||
{/key}
|
||||
|
@ -64,11 +64,20 @@
|
||||
|
||||
{#if activeCollKey}
|
||||
{#key activeCollKey}
|
||||
<CollectionView collection={$hostTree[activeHostKey]?.databases[activeDbKey]?.collections?.[activeCollKey]} bind:tab={collTab} />
|
||||
<CollectionView
|
||||
host={$hostTree[activeHostKey]}
|
||||
database={$hostTree[activeHostKey]?.databases[activeDbKey]}
|
||||
collection={$hostTree[activeHostKey]?.databases[activeDbKey]?.collections?.[activeCollKey]}
|
||||
bind:tab={collTab}
|
||||
/>
|
||||
{/key}
|
||||
{:else if activeDbKey}
|
||||
{#key activeDbKey}
|
||||
<DatabaseView database={$hostTree[activeHostKey]?.databases[activeDbKey]} bind:tab={dbTab} />
|
||||
<DatabaseView
|
||||
host={$hostTree[activeHostKey]}
|
||||
database={$hostTree[activeHostKey]?.databases[activeDbKey]}
|
||||
bind:tab={dbTab}
|
||||
/>
|
||||
{/key}
|
||||
{:else if activeHostKey}
|
||||
{#key activeHostKey}
|
||||
|
@ -2,6 +2,7 @@
|
||||
import BlankState from '$components/blankstate.svelte';
|
||||
import CodeEditor from '$components/codeeditor.svelte';
|
||||
import Icon from '$components/icon.svelte';
|
||||
import { OpenShellScript, SaveShellScript } from '$wails/go/app/App';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
|
||||
@ -19,7 +20,7 @@
|
||||
let busy = false;
|
||||
let editor;
|
||||
|
||||
async function run() {
|
||||
async function runScript() {
|
||||
busy = true;
|
||||
|
||||
if (collection) {
|
||||
@ -35,6 +36,36 @@
|
||||
busy = false;
|
||||
}
|
||||
|
||||
async function loadScript() {
|
||||
const _script = await OpenShellScript();
|
||||
if (_script) {
|
||||
script = _script;
|
||||
editor.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: editor.state.doc.length,
|
||||
insert: script,
|
||||
},
|
||||
selection: {
|
||||
from: 0,
|
||||
anchor: 0,
|
||||
to: 0,
|
||||
head: 0,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function saveScript() {
|
||||
await SaveShellScript(
|
||||
host?.key || '',
|
||||
database?.key || '',
|
||||
collection?.key || '',
|
||||
script,
|
||||
false // not temporary
|
||||
);
|
||||
}
|
||||
|
||||
async function copyErrorDescription() {
|
||||
await navigator.clipboard.writeText(result.errorDescription);
|
||||
copySucceeded = true;
|
||||
@ -86,10 +117,19 @@
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="button" on:click={run}>
|
||||
<button class="button" on:click={runScript}>
|
||||
<Icon name="play" /> Run
|
||||
</button>
|
||||
|
||||
<div class="field inline">
|
||||
<button class="button secondary" on:click={loadScript}>
|
||||
<Icon name="upload" /> Load script…
|
||||
</button>
|
||||
<button class="button secondary" on:click={saveScript}>
|
||||
<Icon name="save" /> Save as…
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#key result}
|
||||
<div class="status flash-green">
|
||||
{#if result?.status}
|
||||
@ -145,6 +185,7 @@
|
||||
.controls {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
align-items: center;
|
||||
grid-column: 1 / 3;
|
||||
}
|
||||
|
4
frontend/wailsjs/go/app/App.d.ts
generated
vendored
4
frontend/wailsjs/go/app/App.d.ts
generated
vendored
@ -40,6 +40,8 @@ export function OpenConnection(arg1:string):Promise<app.OpenConnectionResult>;
|
||||
|
||||
export function OpenDatabase(arg1:string,arg2:string):Promise<app.OpenDatabaseResult>;
|
||||
|
||||
export function OpenShellScript():Promise<string>;
|
||||
|
||||
export function PerformDump(arg1:string):Promise<boolean>;
|
||||
|
||||
export function PerformFindExport(arg1:string,arg2:string,arg3:string,arg4:string):Promise<boolean>;
|
||||
@ -62,6 +64,8 @@ export function ReportSharedStateVariable(arg1:string,arg2:string):Promise<void>
|
||||
|
||||
export function SaveQuery(arg1:string):Promise<string>;
|
||||
|
||||
export function SaveShellScript(arg1:string,arg2:string,arg3:string,arg4:string,arg5:boolean):Promise<app.SaveShellScriptResult>;
|
||||
|
||||
export function SavedQueries():Promise<map[string]app.SavedQuery>;
|
||||
|
||||
export function Settings():Promise<app.Settings>;
|
||||
|
8
frontend/wailsjs/go/app/App.js
generated
8
frontend/wailsjs/go/app/App.js
generated
@ -70,6 +70,10 @@ export function OpenDatabase(arg1, arg2) {
|
||||
return window['go']['app']['App']['OpenDatabase'](arg1, arg2);
|
||||
}
|
||||
|
||||
export function OpenShellScript() {
|
||||
return window['go']['app']['App']['OpenShellScript']();
|
||||
}
|
||||
|
||||
export function PerformDump(arg1) {
|
||||
return window['go']['app']['App']['PerformDump'](arg1);
|
||||
}
|
||||
@ -114,6 +118,10 @@ export function SaveQuery(arg1) {
|
||||
return window['go']['app']['App']['SaveQuery'](arg1);
|
||||
}
|
||||
|
||||
export function SaveShellScript(arg1, arg2, arg3, arg4, arg5) {
|
||||
return window['go']['app']['App']['SaveShellScript'](arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
|
||||
export function SavedQueries() {
|
||||
return window['go']['app']['App']['SavedQueries']();
|
||||
}
|
||||
|
@ -20,6 +20,13 @@ type ExecuteShellScriptResult struct {
|
||||
ErrorDescription string `json:"errorDescription"`
|
||||
}
|
||||
|
||||
type SaveShellScriptResult struct {
|
||||
Host Host `json:"host"`
|
||||
Fname string `json:"filename"`
|
||||
ErrorTitle string `json:"errorTitle"`
|
||||
ErrorDescription string `json:"errorDescription"`
|
||||
}
|
||||
|
||||
func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result ExecuteShellScriptResult) {
|
||||
if !a.Env.HasMongoShell {
|
||||
result.ErrorTitle = "mongosh not found"
|
||||
@ -27,8 +34,40 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
|
||||
return
|
||||
}
|
||||
|
||||
saveRes := a.SaveShellScript(hostKey, dbKey, collKey, script, true)
|
||||
if (saveRes.ErrorTitle != "") || (saveRes.ErrorDescription != "") {
|
||||
result.ErrorTitle = saveRes.ErrorTitle
|
||||
result.ErrorDescription = saveRes.ErrorDescription
|
||||
return
|
||||
}
|
||||
|
||||
var outbuf, errbuf strings.Builder
|
||||
cmd := exec.Command("mongosh", "--file", saveRes.Fname, saveRes.Host.URI)
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
err := cmd.Run()
|
||||
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
result.Status = exiterr.ExitCode()
|
||||
} else if err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: failed to execute: mongosh --file %s: %s", saveRes.Fname, err.Error())
|
||||
result.ErrorTitle = "mongosh failure"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
} else {
|
||||
result.Status = 0
|
||||
}
|
||||
|
||||
os.Remove(saveRes.Fname)
|
||||
result.Output = outbuf.String()
|
||||
result.Stderr = errbuf.String()
|
||||
return
|
||||
}
|
||||
|
||||
func (a *App) SaveShellScript(hostKey, dbKey, collKey, script string, temp bool) (result SaveShellScriptResult) {
|
||||
hosts, err := a.Hosts()
|
||||
if err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: could not get hosts: %s", err.Error())
|
||||
result.ErrorTitle = "Could not get hosts"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
@ -36,10 +75,12 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
|
||||
|
||||
host, hostFound := hosts[hostKey]
|
||||
if !hostFound {
|
||||
runtime.LogWarningf(a.ctx, "Shell: host %s does not exist", host)
|
||||
result.ErrorTitle = "The specified host does not seem to exist"
|
||||
return
|
||||
}
|
||||
|
||||
result.Host = host
|
||||
id, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
runtime.LogErrorf(a.ctx, "Shell: failed to generate a UUID: %s", err.Error())
|
||||
@ -48,15 +89,36 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
|
||||
return
|
||||
}
|
||||
|
||||
dirname := path.Join(a.Env.DataDirectory, "Shell Scripts")
|
||||
fname := path.Join(dirname, fmt.Sprintf("%s.mongosh.js", id.String()))
|
||||
|
||||
if err := os.MkdirAll(dirname, os.ModePerm); err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: failed to mkdir %s", err.Error())
|
||||
result.ErrorTitle = "Could not create temporary directory"
|
||||
if temp {
|
||||
dirname, err := os.MkdirTemp(os.TempDir(), "rolens-script")
|
||||
if err != nil {
|
||||
runtime.LogErrorf(a.ctx, "Shell: failed to create temporary directory: %s", err.Error())
|
||||
result.ErrorTitle = "Could not generate temporary directory for script"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
}
|
||||
result.Fname = path.Join(dirname, fmt.Sprintf("%s.mongosh.js", id.String()))
|
||||
} else {
|
||||
result.Fname, err = runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
|
||||
DefaultFilename: "New Script.js",
|
||||
DefaultDirectory: path.Join(a.Env.DataDirectory, "Shell Scripts"),
|
||||
Title: "Save MongoDB Shell Script",
|
||||
CanCreateDirectories: true,
|
||||
Filters: []runtime.FileFilter{
|
||||
{
|
||||
DisplayName: "MongoDB Shell Script (*.js)",
|
||||
Pattern: "*.js",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
runtime.LogErrorf(a.ctx, "Shell: failed to save script: %s", err.Error())
|
||||
result.ErrorTitle = "Could not save shell script"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
scriptHeader := fmt.Sprintf("// Namespace: %s.%s\n", dbKey, collKey)
|
||||
|
||||
@ -77,35 +139,46 @@ func (a *App) ExecuteShellScript(hostKey, dbKey, collKey, script string) (result
|
||||
scriptHeader = scriptHeader + fmt.Sprintf("coll = db.getCollection('%s');\n", collKey)
|
||||
}
|
||||
|
||||
scriptHeader = scriptHeader + "\n// Start of user script\n"
|
||||
script = scriptHeader + script
|
||||
scriptHeader = scriptHeader + "\n"
|
||||
script = scriptHeader + strings.TrimLeft(strings.TrimRight(script, " \t\n"), "\n")
|
||||
|
||||
if err := os.WriteFile(fname, []byte(script), os.ModePerm); err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: failed to write script to %s", err.Error())
|
||||
if err := os.WriteFile(result.Fname, []byte(script), os.ModePerm); err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: failed to write script to %s: %s", result.Fname, err.Error())
|
||||
result.ErrorTitle = "Could not create temporary script file"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
var outbuf, errbuf strings.Builder
|
||||
cmd := exec.Command("mongosh", "--file", fname, host.URI)
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
err = cmd.Run()
|
||||
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
result.Status = exiterr.ExitCode()
|
||||
} else if err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: failed to execute: mongosh --file %s: %s", fname, err.Error())
|
||||
result.ErrorTitle = "mongosh failure"
|
||||
result.ErrorDescription = err.Error()
|
||||
return
|
||||
} else {
|
||||
result.Status = 0
|
||||
}
|
||||
|
||||
os.Remove(fname)
|
||||
result.Output = outbuf.String()
|
||||
result.Stderr = errbuf.String()
|
||||
return
|
||||
}
|
||||
|
||||
func (a *App) OpenShellScript() string {
|
||||
dir := path.Join(a.Env.DataDirectory, "Shell Scripts")
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
|
||||
fname, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
|
||||
DefaultDirectory: path.Join(a.Env.DataDirectory, "Shell Scripts"),
|
||||
Title: "Load a MongoDB Shell Script",
|
||||
CanCreateDirectories: true,
|
||||
Filters: []runtime.FileFilter{
|
||||
{
|
||||
DisplayName: "MongoDB Shell Script (*.js)",
|
||||
Pattern: "*.js",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: error opening script: %s", err.Error())
|
||||
return ""
|
||||
}
|
||||
|
||||
script, err := os.ReadFile(fname)
|
||||
|
||||
if err != nil {
|
||||
runtime.LogWarningf(a.ctx, "Shell: error reading script %s: %s", fname, err.Error())
|
||||
return ""
|
||||
}
|
||||
|
||||
return string(script)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user