1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-01-18 13:07:58 +00:00

Added collection copy feature (fixes #63)

This commit is contained in:
Romein van Buren 2023-07-21 21:40:08 +02:00
parent 7e5e2127ff
commit 3ca561b4b4
Signed by: romein
GPG Key ID: 0EFF8478ADDF6C49
8 changed files with 199 additions and 2 deletions

View File

@ -2,6 +2,7 @@
* Added log view (#53, #54). * Added log view (#53, #54).
* Added a shell script editor (#37), plus export/import feature. * Added a shell script editor (#37), plus export/import feature.
* Added collection duplication feature (#63).
* Find view: paste ID and press Enter (#55). * Find view: paste ID and press Enter (#55).
* Preserve state after switching to another tab (#56). * Preserve state after switching to another tab (#56).
* Find view: ask for confirmation before negligently deleting documents when the user has clicked the '-' button (#58). * Find view: ask for confirmation before negligently deleting documents when the user has clicked the '-' button (#58).

View File

@ -6,7 +6,8 @@
"chev-u": "<path d=\"m18 15-6-6-6 6\"/>", "chev-u": "<path d=\"m18 15-6-6-6 6\"/>",
"chevs-l": "<path d=\"m11 17-5-5 5-5M18 17l-5-5 5-5\"/>", "chevs-l": "<path d=\"m11 17-5-5 5-5M18 17l-5-5 5-5\"/>",
"chevs-r": "<path d=\"m13 17 5-5-5-5M6 17l5-5-5-5\"/>", "chevs-r": "<path d=\"m13 17 5-5-5-5M6 17l5-5-5-5\"/>",
"arr-d": " <path d=\"M12 5v14M19 12l-7 7-7-7\"/>", "arr-d": "<path d=\"M12 5v14M19 12l-7 7-7-7\"/>",
"arr-r": "<path d=\"M5 12h14M12 5l7 7-7 7\"/>",
"db": "<ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\"></ellipse><path d=\"M21 12c0 1.66-4 3-9 3s-9-1.34-9-3\"></path><path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\"></path>", "db": "<ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\"></ellipse><path d=\"M21 12c0 1.66-4 3-9 3s-9-1.34-9-3\"></path><path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\"></path>",
"x": "<line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>", "x": "<line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>",
"+": "<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>", "+": "<line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>",

View File

@ -10,12 +10,14 @@ import IndexDetailDialog from '$organisms/connection/collection/dialogs/indexdet
import QueryChooserDialog from '$organisms/connection/collection/dialogs/querychooser.svelte'; import QueryChooserDialog from '$organisms/connection/collection/dialogs/querychooser.svelte';
import DumpDialog from '$organisms/connection/database/dialogs/dump.svelte'; import DumpDialog from '$organisms/connection/database/dialogs/dump.svelte';
import HostDetailDialog from '$organisms/connection/host/dialogs/hostdetail.svelte'; import HostDetailDialog from '$organisms/connection/host/dialogs/hostdetail.svelte';
import DuplicateDialog from '$organisms/connection/collection/dialogs/duplicate.svelte';
import { import {
CreateIndex, CreateIndex,
DropCollection, DropCollection,
DropDatabase, DropDatabase,
DropIndex, DropIndex,
DuplicateCollection,
ExecuteShellScript, ExecuteShellScript,
GetIndexes, GetIndexes,
HostLogs, HostLogs,
@ -30,6 +32,7 @@ import {
TruncateCollection TruncateCollection
} from '$wails/go/app/App'; } from '$wails/go/app/App';
const { set, subscribe } = writable({}); const { set, subscribe } = writable({});
const getValue = () => get({ subscribe }); const getValue = () => get({ subscribe });
let hostTreeInited = false; let hostTreeInited = false;
@ -120,9 +123,30 @@ async function refresh() {
} }
}; };
collection.duplicate = async function() {
const dialog = dialogs.new(DuplicateDialog, { host, dbKey, collKey });
return new Promise(resolve => {
dialog.$on('duplicate', async event => {
const success = await DuplicateCollection(
hostKey,
dbKey,
collKey,
event.detail.newHost,
event.detail.newDb,
event.detail.newColl
);
if (success) {
await refresh();
dialog.$close();
resolve();
}
});
});
};
collection.export = function(query) { collection.export = function(query) {
const dialog = dialogs.new(ExportDialog, { collection, query }); const dialog = dialogs.new(ExportDialog, { collection, query });
return new Promise(resolve => { return new Promise(resolve => {
dialog.$on('export', async event => { dialog.$on('export', async event => {
const success = await PerformFindExport(hostKey, dbKey, collKey, JSON.stringify(event.detail.exportInfo)); const success = await PerformFindExport(hostKey, dbKey, collKey, JSON.stringify(event.detail.exportInfo));

View File

@ -0,0 +1,90 @@
<script>
import Icon from '$components/icon.svelte';
import Modal from '$components/modal.svelte';
import input from '$lib/actions/input';
import hostTree from '$lib/stores/hosttree';
import { createEventDispatcher } from 'svelte';
export let host = {};
export let dbKey = '';
export let collKey = '';
const dispatch = createEventDispatcher();
let newHost = host.key;
let newDb = dbKey;
let newColl = `${collKey}-duplicate`;
function duplicate() {
dispatch('duplicate', { newHost, newDb, newColl });
}
</script>
<Modal title="Duplicate collection" width="500px" on:close>
<div class="duplicate">
<div class="origin">
<div class="field">
<span class="label">{host.name || host.uri}</span>
<!-- <input type="text" readonly value={host.name || host.uri} /> -->
</div>
<div class="field">
<span class="label">{dbKey}</span>
<!-- <input type="text" readonly value={dbKey} /> -->
</div>
<div class="field">
<span class="label">{collKey}</span>
<!-- <input type="text" readonly value={collKey} /> -->
</div>
</div>
<div class="arrow">
<Icon name="arr-r" />
</div>
<div class="destination">
<label class="field">
<span class="label">Host</span>
<select bind:value={newHost}>
{#each Object.values($hostTree) as { key, name }}
<option value={key} selected={key === host.key}>{name}</option>
{/each}
</select>
</label>
<label class="field">
<span class="label">Database</span>
<input type="text" bind:value={newDb} use:input />
</label>
<label class="field">
<span class="label">Collection</span>
<input type="text" bind:value={newColl} use:input />
</label>
</div>
</div>
<svelte:fragment slot="footer">
<button class="button" on:click={duplicate}>
<Icon name="play" /> Duplicate
</button>
</svelte:fragment>
</Modal>
<style>
.duplicate {
display: grid;
grid-template: auto / 1fr auto 1fr;
gap: 0.5rem;
}
.arrow {
align-self: center;
}
.field:not(:last-child) {
margin-bottom: 0.5rem;
}
.origin .field .label {
width: 100%;
display: inline-block;
background-color: #fff;
}
</style>

View File

@ -33,6 +33,8 @@
{ label: 'Dump collection (BSON via mongodump)…', fn: collection.dump }, { label: 'Dump collection (BSON via mongodump)…', fn: collection.dump },
{ separator: true }, { separator: true },
{ label: 'Rename collection…', fn: collection.rename }, { label: 'Rename collection…', fn: collection.rename },
{ label: 'Duplicate collection…', fn: collection.duplicate },
{ separator: true },
{ label: 'Truncate collection…', fn: collection.truncate }, { label: 'Truncate collection…', fn: collection.truncate },
{ label: 'Drop collection…', fn: collection.drop }, { label: 'Drop collection…', fn: collection.drop },
{ separator: true }, { separator: true },

2
frontend/wailsjs/go/app/App.d.ts generated vendored
View File

@ -20,6 +20,8 @@ export function DropDatabase(arg1:string,arg2:string):Promise<boolean>;
export function DropIndex(arg1:string,arg2:string,arg3:string,arg4:string):Promise<boolean>; export function DropIndex(arg1:string,arg2:string,arg3:string,arg4:string):Promise<boolean>;
export function DuplicateCollection(arg1:string,arg2:string,arg3:string,arg4:string,arg5:string,arg6:string):Promise<boolean>;
export function Environment():Promise<app.EnvironmentInfo>; export function Environment():Promise<app.EnvironmentInfo>;
export function ExecuteShellScript(arg1:string,arg2:string,arg3:string,arg4:string):Promise<app.ExecuteShellScriptResult>; export function ExecuteShellScript(arg1:string,arg2:string,arg3:string,arg4:string):Promise<app.ExecuteShellScriptResult>;

View File

@ -30,6 +30,10 @@ export function DropIndex(arg1, arg2, arg3, arg4) {
return window['go']['app']['App']['DropIndex'](arg1, arg2, arg3, arg4); return window['go']['app']['App']['DropIndex'](arg1, arg2, arg3, arg4);
} }
export function DuplicateCollection(arg1, arg2, arg3, arg4, arg5, arg6) {
return window['go']['app']['App']['DuplicateCollection'](arg1, arg2, arg3, arg4, arg5, arg6);
}
export function Environment() { export function Environment() {
return window['go']['app']['App']['Environment'](); return window['go']['app']['App']['Environment']();
} }

View File

@ -1,10 +1,12 @@
package app package app
import ( import (
"context"
"fmt" "fmt"
"github.com/wailsapp/wails/v2/pkg/runtime" "github.com/wailsapp/wails/v2/pkg/runtime"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
) )
type OpenCollectionResult struct { type OpenCollectionResult struct {
@ -55,6 +57,77 @@ func (a *App) RenameCollection(hostKey, dbKey, collKey, newCollKey string) bool
return true return true
} }
func (a *App) DuplicateCollection(origHostKey, origDbKey, origCollKey, destHostKey, destDbKey, destCollKey string) bool {
runtime.LogDebugf(a.ctx, "Duplicating collection %s:%s.%s to %s:%s.%s", origHostKey, origDbKey, origCollKey, destHostKey, destDbKey, destCollKey)
if (origHostKey == destHostKey) && (origDbKey == destDbKey) && (origCollKey == destCollKey) {
runtime.LogInfof(a.ctx, "Duplicating collection: cannot duplicate to the same collection")
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.WarningDialog,
Title: "Error while duplicating collection",
Message: "The new collection name cannot equal the old one!",
})
return false
}
origHost, origCtx, origClose, err := a.connectToHost(origHostKey)
if err != nil {
return false
}
defer origClose()
var destHost *mongo.Client
var destCtx context.Context
if origHostKey != destHostKey {
var destClose func()
destHost, destCtx, destClose, err = a.connectToHost(destHostKey)
if err != nil {
return false
}
defer destClose()
} else {
destHost = origHost
destCtx = origCtx
}
destColl := destHost.Database(destDbKey).Collection(destCollKey)
origCur, err := origHost.Database(origDbKey).Collection(origCollKey).Find(origCtx, bson.D{})
if err != nil {
runtime.LogInfof(a.ctx, "Duplicating collection: could not create origin cursor: %s", err.Error())
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.WarningDialog,
Title: "Error while duplicating collection",
Message: "Could not create origin cursor: " + err.Error(),
})
return false
}
var n int64 = 0
var ok = true
for origCur.Next(origCtx) {
_, err := destColl.InsertOne(destCtx, origCur.Current)
if err != nil {
ok = false
runtime.LogInfof(a.ctx, "Duplicating collection: could not insert item %d: %s", n, err.Error())
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.WarningDialog,
Title: "Error while duplicating collection",
Message: fmt.Sprintf("Could not insert item %d: %s", n, err.Error()),
})
}
n += 1
}
return ok
}
func (a *App) TruncateCollection(hostKey, dbKey, collKey string) bool { func (a *App) TruncateCollection(hostKey, dbKey, collKey string) bool {
choice, _ := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{ choice, _ := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Title: "Confirm", Title: "Confirm",