1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-06-28 13:35:12 +00:00

4 Commits

61 changed files with 561 additions and 507 deletions

View File

@ -21,8 +21,8 @@ jobs:
- macos-13
- ubuntu-20.04
- ubuntu-22.04
go-version: [ 1.21 ]
node-version: [ 18 ]
go-version: [1.18]
node-version: [16]
runs-on: ${{ matrix.platform }}

View File

@ -6,7 +6,7 @@
"editor.tabSize": 4,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
"source.organizeImports": true
},
"editor.suggest.snippetsPreventQuickSuggestions": false
},

View File

@ -1,4 +1,4 @@
## [v0.3.0]
## [Unreleased]
New features:
@ -12,9 +12,6 @@ Patches:
* 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).
* Set a deadline for counting documents, and added a button to count documents if the deadline has been exceeded.
* Changed os.ModePerm (777) file permissions to 644 and 755.
* UI improvements.
* Bumped minimum reqiured Go version from 1.18 to 1.20.
Bugfixes:
@ -55,4 +52,3 @@ Initial release.
[v0.2.0]: https://github.com/garraflavatra/rolens/releases/tag/v0.2.0
[v0.2.1]: https://github.com/garraflavatra/rolens/releases/tag/v0.2.1
[v0.2.2]: https://github.com/garraflavatra/rolens/releases/tag/v0.2.2
[v0.3.0]: https://github.com/garraflavatra/rolens/releases/tag/v0.3.0

View File

@ -8,7 +8,7 @@ Robust, blazing-fast, comprehensive, yet simple [MongoDB](https://www.mongodb.co
## Why another MongoDB client?
This project arose from all flaws of similar tools many of which are slow, complicated, heavy, and fairly unwieldy. They mostly require quite a high level of knowledge on how to operate the program.
This project arose from all flaws of similar tools many of which are slow, complicated, heavy, and fairly unwieldy. They mostly require a reasonably high level of knowledge on how to operate the program.
**Rolens aims to be the intuitive, lightweight counterpart of these overengineered tools.**

View File

@ -50,18 +50,18 @@ function isNullish(val) {
return val === undefined || val === null;
}
// Check that Go ^1.20 is installed.
// Check that Go ^1.18 is installed.
try {
const goMinorVersion = /go1\.([0-9][0-9])/.exec(
execSync('go version').toString()
)?.pop();
if (isNullish(goMinorVersion) || (parseInt(goMinorVersion) < 20)) {
if (isNullish(goMinorVersion) || (parseInt(goMinorVersion) < 18)) {
throw new Error();
}
} catch {
missingDependencies.push({ name: 'Go ^1.20', url: 'https://go.dev/doc/install' });
missingDependencies.push({ name: 'Go ^1.18 ^16', url: 'https://go.dev/doc/install' });
}
// Check that Node.js ^16 is installed.

View File

@ -12,12 +12,12 @@
# - ubuntu-22.04
#
# Bundles to choose from:
# - rolens-macos-11-amd64.zip
# - rolens-macos-11-arm64.zip
# - rolens-macos-12-amd64.zip
# - rolens-macos-12-arm64.zip
# - rolens-macos-13-amd64.zip
# - rolens-macos-13-arm64.zip
# - rolens-macos-11-amd64.tar.gz
# - rolens-macos-11-arm64.tar.gz
# - rolens-macos-12-amd64.tar.gz
# - rolens-macos-12-arm64.tar.gz
# - rolens-macos-13-amd64.tar.gz
# - rolens-macos-13-arm64.tar.gz
# - rolens-ubuntu-20.04-amd64.tar.gz
# - rolens-ubuntu-22.04-amd64.tar.gz
# - rolens-windows-2019-amd64.zip
@ -32,8 +32,8 @@ version=$(<./build/version.txt)
mkdir bundle
# macOS apps
mv artifacts/*/rolens-macos-11-amd64.zip "bundle/rolens-$version-macos-11+-amd64.zip"
mv artifacts/*/rolens-macos-11-arm64.zip "bundle/rolens-$version-macos-11+-arm64.zip"
mv artifacts/*/rolens-macos-11-amd64.tar.gz "bundle/rolens-$version-macos-11+-amd64.tar.gz"
mv artifacts/*/rolens-macos-11-arm64.tar.gz "bundle/rolens-$version-macos-11+-arm64.tar.gz"
# Windows installers
mv artifacts/*/rolens-windows-2019-amd64-installer.zip "bundle/rolens-$version-windows-10+-amd64-installer.zip"

View File

@ -13,27 +13,48 @@ cat > build/darwin/dmg_settings.json << EOF
"background": "$(pwd)/build/darwin/dmg_background.png",
"icon-size": 100,
"window": {
"size": { "width": 750, "height": 400 }
"size": { "width": 155, "height": 250 },
"position": { "x": 360, "y": 360 }
},
"contents": [
{ "x": 600, "y": 175, "type": "link", "path": "/Applications" },
{ "x": 150, "y": 175, "type": "file", "path": "$(pwd)/build/bin/Rolens.app" }
{ "x": 750, "y": 500, "type": "link", "path": "/Applications" },
{ "x": 595, "y": 250, "type": "file", "path": "$(pwd)/build/bin/Rolens.app" }
]
}
EOF
# AMD/Intel
wails build -platform darwin/amd64
appdmg build/darwin/dmg_settings.json build/bin/Rolens.dmg
zip -j releases/rolens-$1-amd64.zip build/bin/Rolens.dmg
# Cleanup
rm -rf build/bin/Rolens.dmg
# ARM/AppleM1
wails build -platform darwin/arm64
appdmg build/darwin/dmg_settings.json build/bin/Rolens.dmg
zip -j releases/rolens-$1-arm64.zip build/bin/Rolens.dmg
# create-dmg \
# --volname Rolens \
# --window-size 155 250 \
# --volicon build/appicon.png \
# --eula LICENSE \
# --app-drop-link 750 500 \
# --icon-size 100 \
# --background build/darwin/dmg_background.png \
# --add-file Rolens.app build/bin/Rolens.app 595 250 \
# build/bin/Rolens.dmg emptydir
# appdmg build/darwin/dmg_settings.json build/bin/Rolens.dmg
tar -czvf releases/rolens-$1-amd64.tar.gz --directory build/bin Rolens.app
# Cleanup
rm -rf build/bin/Rolens.app
# ARM/AppleM1
wails build -platform darwin/arm64
# create-dmg \
# --volname Rolens \
# --window-size 155 250 \
# --volicon build/appicon.png \
# --eula LICENSE \
# --app-drop-link 750 500 \
# --icon-size 100 \
# --background build/darwin/dmg_background.png \
# --add-file Rolens.app build/bin/Rolens.app 595 250 \
# build/bin/Rolens.dmg emptydir
# appdmg build/darwin/dmg_settings.json build/bin/Rolens.dmg
tar -czvf releases/rolens-$1-arm64.tar.gz --directory build/bin Rolens.app
# Cleanup
rm -rf build/bin/Rolens.app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -8,9 +8,9 @@ If you just want to install Rolens, please refer to the [installation document](
## Prerequisites
Rolens is written in Go, so you should download the Go compiler from [the download page](https://go.dev/dl/). The minimum version required is 1.20. You can confirm whether it's installed correctly by running `go version` and checking that it outputs something similar to `go1.20.4` or higher.
Rolens is written in Go, so you should download the Go compiler from [the download page](https://go.dev/dl/). The minimum version required is 1.18. You can confirm whether it's installed correctly by running `go version` and checking that it outputs something similar to `go1.18.2`.
Furthermore, you need to have [Wails ^3.1](https://wails.io/docs/gettingstarted/installation) installed: `go install github.com/wailsapp/wails/v2/cmd/wails@latest`. Wails may have platform-specific dependencies; you can consult [`wails doctor`](https://wails.io/docs/reference/cli#doctor) to find out what dependencies Wails needs and how to install them.
Furthermore, you need to have [Wails ^3.1](https://wails.io/docs/gettingstarted/installation) installed: `go install github.com/wailsapp/wails/v2/cmd/wails@latest`. Wails may have platform-specific dependencies; you can consult `wails doctor` to find out what dependencies Wails needs and how to install them.
In order to compile the frontend, [Node.js](https://nodejs.org/en/download) ^16.0 and the [npm](https://npmjs.com) package manager ^8.0 (included in Node.js) are required. To confirm the installed versions of those tools, execute `node -v` and `npm -v`.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 KiB

After

Width:  |  Height:  |  Size: 462 KiB

View File

@ -7,6 +7,14 @@
</head>
<body>
<div id="app"></div>
<div id="app-loading">
<div class="ring">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
<div id="dialogoutlets"></div>
<script src="./src/main.js" type="module"></script>
</body>

View File

@ -22,6 +22,7 @@
"include": [
"src/**/*.d.ts",
"src/**/*.js",
"src/**/*.ts",
"src/**/*.svelte"
]
}

View File

@ -2489,9 +2489,9 @@
"dev": true
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"funding": [
{
@ -4913,9 +4913,9 @@
"dev": true
},
"postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",

View File

@ -1,15 +1,17 @@
<script>
import { tick } from 'svelte';
import { fly } from 'svelte/transition';
import BlankState from '$components/blankstate.svelte';
import Connection from '$organisms/connection/index.svelte';
import ContextMenu from '$components/contextmenu.svelte';
import dialogs from '$lib/dialogs.js';
import contextMenu from '$lib/stores/contextmenu.js';
import environment from '$lib/stores/environment.js';
import hostTree from '$lib/stores/hosttree.js';
import applicationInited from '$lib/stores/inited.js';
import windowTitle from '$lib/stores/windowtitle.js';
import Connection from '$organisms/connection/index.svelte';
import { EventsOn } from '$wails/runtime/runtime.js';
import { tick } from 'svelte';
import AboutDialog from './dialogs/about.svelte';
import SettingsDialog from './dialogs/settings/index.svelte';
let showWelcomeScreen = undefined;
@ -26,15 +28,26 @@
await tick();
hostTree.newHost();
}
function showAboutDialog() {
dialogs.new(AboutDialog);
}
function showSettings() {
dialogs.new(SettingsDialog);
}
EventsOn('OpenPreferences', showSettings);
EventsOn('OpenAboutModal', showAboutDialog);
</script>
<svelte:window on:contextmenu|preventDefault />
<div id="root">
<div id="root" class="platform-{$environment?.platform}">
<div class="titlebar">{$windowTitle}</div>
{#if $applicationInited && (showWelcomeScreen !== undefined)}
<main class:empty={showWelcomeScreen} in:fly={{ y: 10 }}>
<main class:empty={showWelcomeScreen}>
{#if showWelcomeScreen}
<BlankState label="Welcome to Rolens!" image="/logo.png" pale={false} big={true}>
<button class="button" on:click={createFirstHost}>Add your first host</button>
@ -52,23 +65,30 @@
<style>
.titlebar {
height: var(--titlebar-height);
height: 0;
background-color: #00002a;
--wails-draggable: drag;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
background-color: #ddd;
}
#root.platform-darwin .titlebar {
height: var(--darwin-titlebar-height);
}
main {
height: calc(100vh - var(--titlebar-height));
height: 100vh;
display: grid;
grid-template: 1fr / minmax(300px, 0.3fr) 1fr;
}
main.empty {
grid-template: 1fr / 1fr;
}
#root.platform-darwin main {
height: calc(100vh - var(--darwin-titlebar-height));
}
main > :global(*) {
overflow: auto;
@ -78,4 +98,12 @@
main > :global(.addressbar) {
grid-column: 1 / 3;
}
.databaselist {
overflow: scroll;
}
.button.create {
margin-top: 0.5rem;
}
</style>

View File

@ -101,7 +101,7 @@
text-align: left;
}
button.selected {
background-color: var(--selection);
background-color: #00008b;
color: #fff;
}

View File

@ -173,7 +173,7 @@
padding-bottom: 8px;
}
.calendar .day button.active {
background-color: var(--selection);
background-color: #00008b;
color: #fff;
}
.calendar .day button.notinmonth {

View File

@ -1,12 +1,12 @@
<script>
import { ChooseDirectory } from '$wails/go/app/App.js';
import { OpenDirectory } from '$wails/go/ui/UI.js';
export let value = '';
export let id = '';
export let title = 'Choose a directory';
async function selectDir() {
value = await ChooseDirectory(title) || value;
value = await OpenDirectory(title) || value;
}
</script>

View File

@ -52,10 +52,7 @@
return obj;
}
else if ((typeof obj === 'object') && (obj !== null)) {
return Object.entries(obj).map(([
k,
item,
]) => {
return Object.entries(obj).map(([ k, item ]) => {
return { ...item, [key]: k };
});
}
@ -70,10 +67,7 @@
}
activeKey = itemKey;
activePath = [
...path.slice(0, level),
itemKey,
];
activePath = [ ...path.slice(0, level), itemKey ];
dispatch('select', { level, itemKey, index, path: activePath });
}
@ -132,17 +126,12 @@
</script>
{#each _items as item, index}
{@const selected = canSelect && pathsAreEqual(activePath, [
...path,
item[key],
])}
<tr
on:click={() => select(item[key], index)}
on:dblclick={() => doubleClick(item[key], index)}
on:contextmenu|preventDefault={evt => showContextMenu(evt, item)}
class:selectable={canSelect}
class:selected
class:selected={canSelect && pathsAreEqual(activePath, ...path, item[key])}
class:striped
>
{#if !hideChildrenToggles}
@ -156,10 +145,6 @@
<Icon name={childrenOpen[item[key]] ? 'chev-d' : 'chev-r'} />
</button>
{/if}
{#if item.loading}
<span class="spinner" style:margin-left="{level * 10}px" />
{/if}
</td>
{/if}
@ -208,10 +193,7 @@
{hideChildrenToggles}
{canSelect}
{canRemoveItems}
path={[
...path,
item[key],
]}
path={[ ...path, item[key] ]}
items={item.children}
level={level + 1}
bind:activePath
@ -230,41 +212,28 @@
cursor: pointer;
}
tr.selectable.selected td {
background-color: var(--selection) !important;
background-color: #00008b !important;
color: #fff;
}
td {
padding: 4px 2px;
padding: 2px;
text-overflow: ellipsis;
}
td.has-toggle {
position: relative;
width: 1.5em;
}
td.has-toggle .spinner {
position: absolute;
top: 0.3em;
left: 0.22em;
width: 1em;
height: 1em;
border: 1px solid var(--primary);
border-radius: 50px;
border-top-color: transparent;
border-left-color: transparent;
animation: .6s linear 0 spin;
animation-iteration-count: infinite;
width: 20px;
}
td.has-icon {
padding: 0;
width: 1.5em;
width: 17px;
}
td.has-icon :global(svg) {
width: 1em;
height: 1em;
width: 13px;
height: 13px;
}
td .value {
height: 1.2em;
height: 15px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@ -272,13 +241,14 @@
}
button.toggle {
margin: 2px 0 0 3px;
padding: 0;
color: inherit;
padding: 0;
margin: 0;
vertical-align: top;
}
button.toggle :global(svg) {
width: 0.9em;
height: 0.9em;
width: 13px;
height: 13px;
vertical-align: top;
}

View File

@ -11,28 +11,31 @@
</script>
<style>
@keyframes spinning {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
svg {
transition: transform 0.25s;
will-change: transform;
width: 1.2em;
height: 1.2em;
}
svg.spinning {
animation: spin 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation: spinning 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
:global(.field) svg {
width: 1em;
height: 1em;
width: 13px;
height: 13px;
margin-right: 2px;
}
:global(.button) svg {
height: 1em;
height: 13px;
width: auto;
vertical-align: bottom;
}
:global(.blankstate .button) svg {
height: 1.25em;
height: 17px;
vertical-align: -3px;
margin-right: 4px;
}

View File

@ -3,9 +3,8 @@
</script>
<script>
import { createEventDispatcher } from 'svelte';
import { fade, fly } from 'svelte/transition';
import { Beep } from '$wails/go/ui/UI.js';
import { createEventDispatcher } from 'svelte';
import Icon from './icon.svelte';
export let show = true;
@ -36,7 +35,6 @@
}
function close() {
show = false;
dispatch('close');
}
</script>
@ -44,8 +42,8 @@
<svelte:window on:keydown={keydown} />
{#if show}
<div class="modal outer" on:pointerdown|self={Beep} transition:fade={{ duration: 200 }}>
<div class="inner" style:max-width={width || '80vw'} transition:fly={{ y: 20, duration: 200 }}>
<div class="modal outer" on:pointerdown|self={Beep}>
<div class="inner" style:max-width={width || '80vw'}>
{#if title}
<header>
<div class="title">{title}</div>
@ -75,14 +73,19 @@
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
margin: 0;
padding: 2rem;
padding-top: 50px;
--wails-draggable: drag;
}
:global(#root.platform-darwin) .outer {
margin-top: var(--darwin-titlebar-height);
}
.inner {
max-height: 80vh;
background-color: #fff;
margin: auto;
margin-left: auto;
margin-right: auto;
margin-bottom: auto;
width: 100%;
border-radius: var(--radius);
display: flex;

View File

@ -1,61 +1,40 @@
<script>
import { createEventDispatcher, onMount } from 'svelte';
import { tweened } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
import Icon from './icon.svelte';
export let tabs = [];
export let selectedKey = '';
export let canAddTab = false;
export let compact = true;
export let multiline = false;
const dispatch = createEventDispatcher();
const activeIndicatorLeft = tweened(0, { easing: cubicOut, duration: 400 });
const activeIndicatorRight = tweened(0, { easing: cubicOut, duration: 400 });
const liElements = {};
const maxPixelsPerMultilineTab = 120;
let navEl;
let pixelsPerTab = 0;
$: tabs && navEl && updateMeasurements();
function updateMeasurements() {
pixelsPerTab = (navEl.offsetWidth ?? 0) / tabs.length;
}
function select(tabKey) {
selectedKey = tabKey;
dispatch('select', tabKey);
}
function moveActiveIndicator(target = liElements[selectedKey]) {
if (!compact) {
return;
}
const navRect = navEl.getBoundingClientRect();
const itemRect = target.getBoundingClientRect();
$activeIndicatorLeft = itemRect.x - navRect.x;
$activeIndicatorRight = navRect.right - itemRect.right;
}
onMount(() => {
if (selectedKey) {
moveActiveIndicator(liElements[selectedKey]);
}
window.addEventListener('resize', updateMeasurements);
});
</script>
<svelte:window on:resize={() => moveActiveIndicator()} />
<nav class="tabs" class:compact bind:this={navEl}>
<nav class="tabs" class:multiline={multiline || (pixelsPerTab < maxPixelsPerMultilineTab)} bind:this={navEl}>
<ul>
{#each tabs as tab (tab.key)}
<li
class="tab"
class:active={tab.key === selectedKey}
class:closable={tab.closable}
bind:this={liElements[tab.key]}
on:mouseenter={event => moveActiveIndicator(event.target)}
on:mouseleave={() => moveActiveIndicator()}
>
<li class:active={tab.key === selectedKey}>
<button class="tab" on:click={() => select(tab.key)}>
{#if tab.icon} <Icon name={tab.icon} /> {/if}
<span class="label">{tab.title}</span>
</button>
{#if tab.closable}
<button class="button-small" on:click={() => dispatch('closeTab', tab.key)}>
<Icon name="x" />
@ -65,42 +44,39 @@
{/each}
{#if canAddTab}
<li>
<button class="button-small" on:click={() => dispatch('addTab')}>
<li class="tab add">
<button class="tab" on:click={() => dispatch('addTab')}>
<Icon name="+" />
</button>
</li>
{/if}
</ul>
{#if compact}
<span
class="activeindicator"
style:left="{$activeIndicatorLeft}px"
style:right="{$activeIndicatorRight}px"
/>
{/if}
</nav>
<style>
nav {
position: relative;
}
ul {
overflow-x: auto;
display: flex;
list-style: none;
}
li {
display: inline-block;
flex: 1;
position: relative;
}
nav.tabs :global(svg) {
li.add {
flex: 0 1;
}
.tabs :global(svg) {
width: 13px;
height: 13px;
vertical-align: bottom;
}
li.active :global(svg) {
color: #fff;
}
button.tab {
width: 100%;
@ -120,50 +96,20 @@
border-right: 1px solid #ccc;
}
li.active button.tab {
background-color: var(--selection);
border-color: var(--primary);
color: #fff;
background-color: #00008b;
border-color: #00008b;
cursor: not-allowed;
}
button.tab .label {
margin-top: 5px;
display: inline-block;
nav.tabs.multiline button.tab .label {
display: block;
margin-top: 4px;
}
nav.tabs .button-small {
margin: 12px 0 0 4px;
}
li.closable .button-small {
display: none;
.button-small {
position: absolute;
top: 0;
right: 7px;
}
li.closable.active {
padding-right: 20px;
}
li.closable.active .button-small {
display: block;
}
nav.tabs.compact {
border-bottom: 1px solid #aaa;
}
nav.tabs.compact li {
border-bottom: 2px solid transparent;
}
nav.tabs.compact button.tab {
border: none;
color: inherit;
background-color: transparent;
}
.activeindicator {
display: block;
position: absolute;
bottom: -1px;
height: 2px;
background-color: var(--primary);
top: 7px;
}
</style>

View File

@ -30,10 +30,6 @@
</Modal>
<style>
.brand, .info {
line-height: 1.2;
}
.brand {
display: flex;
align-items: center;
@ -44,9 +40,9 @@
flex: 0 1 125px;
}
.brand .title {
font-size: 2.25em;
font-size: 2.25rem;
font-weight: 600;
margin-bottom: .25em;
line-height: 2.5rem;
}
.brand .title .version {
font-size: 80%;
@ -55,6 +51,7 @@
}
.brand .description {
font-size: 1.5rem;
line-height: 1.6rem;
}
hr {
@ -63,6 +60,7 @@
.info {
font-size: 1.25rem;
line-height: 1.25rem;
margin: 0 1rem 1rem;
text-align: center;
}

View File

@ -14,7 +14,7 @@ export default function input(node, { autofocus, type, onValid, onInvalid, manda
node.setAttribute('autocomplete', false);
const getMessage = () => {
const checkInteger = () => (isInt(node.value) ? false : 'Value must be an integer');
const checkInteger = () => (Number.isInteger(node.value) ? false : 'Value must be an integer');
const checkNumberBoundaries = boundaries => {
if (node.value < boundaries[0]) {
return `Input is too low for type ${type}`;

View File

@ -1,7 +0,0 @@
// Months
export const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
export const monthsAbbr = months.map(m => m.slice(0, 3));
// Days
export const days = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ];
export const daysAbbr = days.map(d => d.slice(0, 3));

View File

@ -0,0 +1,27 @@
export const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
export const days = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
];
export const daysAbbr = days.map(d => d.slice(0, 3));
export const monthsAbbr = months.map(m => m.slice(0, 3));

View File

@ -6,17 +6,11 @@ function newDialog(dialogComponent, data = {}) {
outlet.className = 'dialogoutlet';
document.getElementById('dialogoutlets').appendChild(outlet);
const instance = new dialogComponent({
target: outlet,
intro: true,
props: data,
});
const instance = new dialogComponent({ target: outlet, props: data });
instance.$close = function() {
setTimeout(() => {
instance.$destroy();
outlet.remove();
}, 200);
instance.$destroy();
outlet.remove();
};
instance.$on('close', instance.$close);

View File

@ -1,13 +1,4 @@
// https://stackoverflow.com/a/14794066
export function isInt(value) {
if (isNaN(value)) {
return false;
}
const x = parseFloat(value);
return (x | 0) === x;
}
export function randInt(min, max) {
export function randInt(min: number, max: number) {
return Math.round(Math.random() * (max - min) + min);
}

View File

@ -0,0 +1,27 @@
import { StartProgressBar, StopProgressBar } from '$wails/go/ui/UI.js';
let taskCounter = 0;
export function startProgress(taskDescription = 'Loading…') {
const taskIndex = ++taskCounter;
let started = false;
const debouncer = setTimeout(() => {
StartProgressBar(taskIndex, taskDescription);
started = true;
}, 150);
const task = {
id: taskIndex,
description: taskDescription,
end: () => {
clearTimeout(debouncer);
if (started) {
StopProgressBar(taskIndex);
}
},
};
return task;
}

View File

@ -11,10 +11,5 @@ async function reload() {
reload();
subscribe(env => {
// @ts-ignore
document.body.dataset.platform = env?.platform;
});
const environment = { reload, subscribe };
export default environment;

View File

@ -1,4 +1,5 @@
import dialogs from '$lib/dialogs.js';
import { startProgress } from '$lib/progress.js';
import { get, writable } from 'svelte/store';
import applicationInited from './inited.js';
import queries from './queries.js';
@ -39,11 +40,7 @@ async function refresh() {
const hosts = await Hosts();
const hostTree = getValue();
for (const [
hostKey,
hostDetails,
] of Object.entries(hosts)) {
for (const [ hostKey, hostDetails ] of Object.entries(hosts)) {
hostTree[hostKey] = hostTree[hostKey] || {};
const host = hostTree[hostKey];
host.key = hostKey;
@ -51,9 +48,6 @@ async function refresh() {
host.uri = hostDetails.uri;
host.open = async function() {
host.loading = true;
set(hostTree);
const {
databases: dbNames,
status,
@ -76,10 +70,7 @@ async function refresh() {
host.databases[dbKey] = host.databases[dbKey] || {};
}
for (const [
dbKey,
database,
] of Object.entries(host.databases)) {
for (const [ dbKey, database ] of Object.entries(host.databases)) {
if (!database.new && !dbNames.includes(dbKey)) {
delete host.databases[dbKey];
continue;
@ -92,9 +83,6 @@ async function refresh() {
delete database.new;
database.open = async function() {
database.loading = true;
set(hostTree);
const { collections: collNames, stats, statsError } = await OpenDatabase(hostKey, dbKey);
database.stats = stats;
database.statsError = statsError;
@ -107,10 +95,7 @@ async function refresh() {
database.collections[collKey] = database.collections[collKey] || {};
}
for (const [
collKey,
collection,
] of Object.entries(database.collections)) {
for (const [ collKey, collection ] of Object.entries(database.collections)) {
if (!collection.new && !collNames.includes(collKey)) {
delete database.collections[collKey];
continue;
@ -136,8 +121,13 @@ async function refresh() {
collection.rename = async function() {
const newCollKey = await dialogs.enterText('Rename collection', `Enter a new name for collection ${collKey}.`, collKey);
if (newCollKey && (newCollKey !== collKey)) {
const progress = startProgress(
`Renaming collection "${collKey}" to "${newCollKey}"…`
);
const ok = await RenameCollection(hostKey, dbKey, collKey, newCollKey);
await database.open();
progress.end();
return ok;
}
};
@ -292,8 +282,6 @@ async function refresh() {
await refresh();
windowTitle.setSegments(dbKey, host.name, 'Rolens');
database.loading = false;
set(hostTree);
};
database.dump = function() {
@ -333,8 +321,6 @@ async function refresh() {
}
await refresh();
host.loading = false;
set(hostTree);
};
host.executeShellScript = async function(script) {

View File

@ -1,19 +1,19 @@
export function capitalise(string = '') {
export function capitalise(string = ''): string {
const capitalised = string.charAt(0).toUpperCase() + string.slice(1);
return capitalised;
}
export function jsonLooseParse(json) {
const obj = new Function(`return (${json})`)();
export function jsonLooseParse<T>(json: string): T {
const obj: T = new Function(`return (${json})`)();
return obj;
}
export function convertLooseJson(json) {
export function convertLooseJson(json: any) {
const j = JSON.stringify(jsonLooseParse(json));
return j;
}
export function looseJsonIsValid(json) {
export function looseJsonIsValid(json: string): boolean {
try {
jsonLooseParse(json);
return true;
@ -23,6 +23,6 @@ export function looseJsonIsValid(json) {
}
}
export function stringCouldBeID(string) {
export function stringCouldBeID(string: string) {
return /^[a-zA-Z0-9_-]{1,}$/.test(string);
}

View File

@ -1,20 +1,15 @@
import './styles/loading.css';
import './styles/reset.css';
import './styles/style.css';
import { EventsOn, LogError } from '$wails/runtime/runtime.js';
import dialogs from '$lib/dialogs.js';
import { LogError } from '$wails/runtime/runtime.js';
import App from './app.svelte';
import AboutDialog from './dialogs/about.svelte';
import SettingsDialog from './dialogs/settings/index.svelte';
window.addEventListener('unhandledrejection', event => {
LogError('Unhandled JS rejection: ' + event.reason);
});
EventsOn('global.about', () => dialogs.new(AboutDialog));
EventsOn('global.settings', () => dialogs.new(SettingsDialog));
// @ts-ignore Argument IS correct.
const app = new App({ target: document.getElementById('app') });
export default app;

View File

@ -16,7 +16,7 @@
}
</script>
<Modal title="Export results" width="500px" on:close>
<Modal title="Export results" width="450px" on:close>
<form on:submit|preventDefault={submit}>
<label class="field">
<span class="label">Export</span>
@ -40,10 +40,7 @@
<label class="field">
<span class="label">View to use</span>
<select bind:value={exportInfo.viewKey}>
{#each Object.entries(views.forCollection(collection.hostKey, collection.dbKey, collection.key)) as [
key,
{ name },
]}
{#each Object.entries(views.forCollection(collection.hostKey, collection.dbKey, collection.key)) as [ key, { name } ]}
<option value={key}>{name}</option>
{/each}
</select>

View File

@ -6,6 +6,7 @@
import input from '$lib/actions/input.js';
import dialogs from '$lib/dialogs.js';
import { deepClone } from '$lib/objects.js';
import { startProgress } from '$lib/progress.js';
import applicationSettings from '$lib/stores/settings.js';
import views from '$lib/stores/views.js';
import { convertLooseJson, stringCouldBeID } from '$lib/strings.js';
@ -177,6 +178,7 @@
}
async function saveDocument(event) {
const progress = startProgress('Performing update…');
const success = await UpdateFoundDocument(
collection.hostKey,
collection.dbKey,
@ -189,6 +191,8 @@
objectViewerSuccessMessage = 'Document has been saved!';
submitQuery();
}
progress.end();
}
$: collection && refresh();
@ -340,10 +344,7 @@
<div>
<label class="field inline">
<select bind:value={collection.viewKey}>
{#each Object.entries(viewsForCollection) as [
key,
view,
]}
{#each Object.entries(viewsForCollection) as [ key, view ]}
<option value={key}>{view.name}</option>
{/each}
</select>
@ -411,15 +412,7 @@
{/if}
<datalist id="limits">
{#each [
1,
5,
10,
25,
50,
100,
200,
] as value}
{#each [ 1, 5, 10, 25, 50, 100, 200 ] as value}
<option {value} />
{/each}
</datalist>

View File

@ -2,6 +2,7 @@
import DirectoryChooser from '$components/editors/directorychooser.svelte';
import Grid from '$components/grid/grid.svelte';
import Modal from '$components/modal.svelte';
import { startProgress } from '$lib/progress.js';
import hostTree from '$lib/stores/hosttree.js';
import applicationSettings from '$lib/stores/settings.js';
import { OpenConnection, OpenDatabase } from '$wails/go/app/App.js';
@ -22,6 +23,7 @@
info.collKeys = [];
if (hostKey) {
const progress = startProgress(`Opening connection to host "${hostKey}"`);
const databases = await OpenConnection(hostKey);
if (databases && !$hostTree[hostKey]) {
@ -30,6 +32,8 @@
$hostTree[hostKey].databases[dbKey] = $hostTree[hostKey].databases[dbKey] || { collections: {} };
});
}
progress.end();
}
}
@ -38,11 +42,14 @@
info.dbKey = dbKey;
if (dbKey) {
const progress = startProgress(`Opening database "${dbKey}"`);
const collections = await OpenDatabase(info.hostKey, dbKey);
for (const collKey of collections?.sort() || []) {
$hostTree[info.hostKey].databases[dbKey].collections[collKey] = {};
}
progress.end();
}
}

View File

@ -7,27 +7,20 @@
<Grid
striped={false}
columns={[
{ key: 'name' },
{ key: 'count', right: true },
]}
columns={[ { key: 'name' }, { key: 'count', right: true } ]}
items={Object.values($hostTree || {}).map(host => {
return {
id: host.key,
name: host.name,
loading: host.loading,
icon: 'server',
children: Object.values(host.databases || {})
.sort((a, b) => a.key.localeCompare(b))
.map(database => {
return {
id: database.key,
name: database.key,
loading: database.loading,
count: Object.keys(database.collections || {}).length || '',
icon: 'db',
count: Object.keys(database.collections || {}).length || '',
children: Object.values(database.collections)
.sort((a, b) => a.key.localeCompare(b))
.map(collection => {
@ -49,7 +42,6 @@
],
};
}) || [],
menu: [
{ label: 'Dump database (BSON via mongodump)…', fn: database.dump },
{ label: 'Drop database…', fn: database.drop },
@ -59,7 +51,6 @@
],
};
}),
menu: [
{ label: 'New database…', fn: host.newDatabase },
{ separator: true },

View File

@ -3,7 +3,7 @@
import CodeEditor from '$components/editors/codeeditor.svelte';
import Icon from '$components/icon.svelte';
import environment from '$lib/stores/environment.js';
import { OpenShellScript, SaveShellScript, SaveShellOuput } from '$wails/go/app/App.js';
import { OpenShellScript, SaveShellScript } from '$wails/go/app/App.js';
import { BrowserOpenURL } from '$wails/runtime/runtime.js';
import { javascript } from '@codemirror/lang-javascript';
import { onDestroy, onMount } from 'svelte';
@ -73,10 +73,6 @@
);
}
async function saveOutput() {
await SaveShellOuput(result.output + '\n' + result.stderr);
}
async function copyErrorDescription() {
await navigator.clipboard.writeText(result.errorDescription);
copySucceeded = true;
@ -159,10 +155,6 @@
</button>
</div>
<button class="button secondary" disabled={!result.output} on:click={saveOutput}>
<Icon name="upload" /> Save output as…
</button>
<button class="button viewtoggle" title="Toggle horizontal/vertical view" on:click={toggleView}>
<Icon name="columns" rotation={horizontal ? 90 : 0} />
</button>

View File

@ -0,0 +1,50 @@
#app-loading {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
}
/* Source of the following CSS: https://loading.io/css/ (modified) */
#app-loading .ring {
display: inline-block;
position: relative;
width: 136px;
height: 136px;
margin: auto;
}
#app-loading .ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 120px;
height: 120px;
margin: 8px;
border: 8px solid;
border-radius: 50%;
animation: loading-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: #f1dac8 transparent transparent transparent;
}
#app-loading .ring div:nth-child(1) {
animation-delay: -0.45s;
}
#app-loading .ring div:nth-child(2) {
animation-delay: -0.3s;
}
#app-loading .ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes loading-ring {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -1,9 +1,6 @@
:root {
--darwin-titlebar-height: 36px;
--radius: 4px;
--titlebar-height: 36px;
--primary: #00008b;
--selection: rgba(0, 62, 205, 0.3);
}
html,
@ -17,8 +14,8 @@ body {
-webkit-user-select: none;
user-select: none;
cursor: default;
font-size: 15px;
line-height: 17px;
font-size: 13px;
line-height: 13px;
background-color: rgba(255, 255, 255, 0.45);
}
@ -45,7 +42,7 @@ p strong {
}
a {
color: #0000cc;
color: rgb(0, 0, 204);
text-decoration: underline;
text-underline-offset: 2px;
text-decoration-thickness: 1px;
@ -69,8 +66,8 @@ select:disabled {
}
.button {
background-color: var(--primary);
border: 1px solid var(--primary);
background-color: #00008b;
border: 1px solid #00008b;
padding: 0.5rem;
border-radius: var(--radius);
color: #fff;
@ -145,7 +142,7 @@ select:disabled {
.field > textarea,
.field > select {
flex: 1;
padding: 0.5rem;
padding: 0 0.5rem;
border: 1px solid #ccc;
background-color: #fff;
appearance: none;
@ -154,8 +151,8 @@ select:disabled {
.field > textarea:focus,
.field > select:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 1px var(--primary);
border-color: #00008b;
box-shadow: 0 0 0 3px rgba(0, 0, 139, 0.2);
}
.field > input.invalid,
.field > textarea.invalid,
@ -218,8 +215,3 @@ code,
.flash-green {
animation: 1s ease-out 0s 1 flashGreen;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

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

@ -1,6 +1,7 @@
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
import {app} from '../models';
import {map[string]app} from '../models';
import {menu} from '../models';
import {context} from '../models';
import {ui} from '../models';
@ -11,8 +12,6 @@ export function Aggregate(arg1:string,arg2:string,arg3:string,arg4:string,arg5:s
export function AskConfirmation(arg1:string):Promise<boolean>;
export function ChooseDirectory(arg1:string):Promise<string>;
export function CountItems(arg1:string,arg2:string,arg3:string,arg4:string):Promise<app.CountItemsResult>;
export function CreateIndex(arg1:string,arg2:string,arg3:string,arg4:string):Promise<string>;
@ -35,7 +34,7 @@ export function GetIndexes(arg1:string,arg2:string,arg3:string):Promise<app.GetI
export function HostLogs(arg1:string,arg2:string):Promise<app.HostLogsResult>;
export function Hosts():Promise<{[key: string]: app.Host}>;
export function Hosts():Promise<map[string]app.Host>;
export function InsertItems(arg1:string,arg2:string,arg3:string,arg4:string):Promise<any>;
@ -71,11 +70,9 @@ export function ReportSharedStateVariable(arg1:string,arg2:string):Promise<void>
export function SaveQuery(arg1:string):Promise<string>;
export function SaveShellOuput(arg1:string):Promise<void>;
export function SaveShellScript(arg1:string,arg2:string,arg3:string,arg4:string,arg5:boolean):Promise<app.SaveShellScriptResult>;
export function SavedQueries():Promise<{[key: string]: app.SavedQuery}>;
export function SavedQueries():Promise<map[string]app.SavedQuery>;
export function Settings():Promise<app.Settings>;

View File

@ -14,10 +14,6 @@ export function AskConfirmation(arg1) {
return window['go']['app']['App']['AskConfirmation'](arg1);
}
export function ChooseDirectory(arg1) {
return window['go']['app']['App']['ChooseDirectory'](arg1);
}
export function CountItems(arg1, arg2, arg3, arg4) {
return window['go']['app']['App']['CountItems'](arg1, arg2, arg3, arg4);
}
@ -134,10 +130,6 @@ export function SaveQuery(arg1) {
return window['go']['app']['App']['SaveQuery'](arg1);
}
export function SaveShellOuput(arg1) {
return window['go']['app']['App']['SaveShellOuput'](arg1);
}
export function SaveShellScript(arg1, arg2, arg3, arg4, arg5) {
return window['go']['app']['App']['SaveShellScript'](arg1, arg2, arg3, arg4, arg5);
}

6
frontend/wailsjs/go/ui/UI.d.ts generated vendored
View File

@ -4,6 +4,12 @@ import {context} from '../models';
export function Beep():Promise<void>;
export function OpenDirectory(arg1:string):Promise<string>;
export function Reveal(arg1:string):Promise<void>;
export function StartProgressBar(arg1:number,arg2:string):Promise<void>;
export function Startup(arg1:context.Context):Promise<void>;
export function StopProgressBar(arg1:number):Promise<void>;

View File

@ -6,10 +6,22 @@ export function Beep() {
return window['go']['ui']['UI']['Beep']();
}
export function OpenDirectory(arg1) {
return window['go']['ui']['UI']['OpenDirectory'](arg1);
}
export function Reveal(arg1) {
return window['go']['ui']['UI']['Reveal'](arg1);
}
export function StartProgressBar(arg1, arg2) {
return window['go']['ui']['UI']['StartProgressBar'](arg1, arg2);
}
export function Startup(arg1) {
return window['go']['ui']['UI']['Startup'](arg1);
}
export function StopProgressBar(arg1) {
return window['go']['ui']['UI']['StopProgressBar'](arg1);
}

View File

@ -225,11 +225,3 @@ export function Hide(): void;
// [Show](https://wails.io/docs/reference/runtime/intro#show)
// Shows the application.
export function Show(): void;
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
// Returns the current text stored on clipboard
export function ClipboardGetText(): Promise<string>;
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
// Sets a text on the clipboard
export function ClipboardSetText(text: string): Promise<boolean>;

View File

@ -37,11 +37,11 @@ export function LogFatal(message) {
}
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
}
export function EventsOn(eventName, callback) {
return EventsOnMultiple(eventName, callback, -1);
EventsOnMultiple(eventName, callback, -1);
}
export function EventsOff(eventName, ...additionalEventNames) {
@ -49,7 +49,7 @@ export function EventsOff(eventName, ...additionalEventNames) {
}
export function EventsOnce(eventName, callback) {
return EventsOnMultiple(eventName, callback, 1);
EventsOnMultiple(eventName, callback, 1);
}
export function EventsEmit(eventName) {
@ -192,11 +192,3 @@ export function Hide() {
export function Show() {
window.runtime.Show();
}
export function ClipboardGetText() {
return window.runtime.ClipboardGetText();
}
export function ClipboardSetText(text) {
return window.runtime.ClipboardSetText(text);
}

48
go.mod
View File

@ -1,10 +1,8 @@
module github.com/garraflavatra/rolens
go 1.21
go 1.18
toolchain go1.21.5
require github.com/wailsapp/wails/v2 v2.7.1
require github.com/wailsapp/wails/v2 v2.3.1
require (
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6
@ -13,9 +11,12 @@ require (
)
require (
github.com/leaanthony/u v1.1.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/wailsapp/go-webview2 v1.0.10 // indirect
github.com/akavel/rsrc v0.10.2 // indirect
github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/josephspurrier/goversioninfo v1.4.0 // indirect
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 // indirect
golang.org/x/image v0.7.0 // indirect
)
require (
@ -26,32 +27,35 @@ require (
github.com/golang/snappy v0.0.1 // indirect
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/labstack/echo/v4 v4.10.2 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
github.com/labstack/echo/v4 v4.9.0 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
github.com/leaanthony/gosod v1.0.3 // indirect
github.com/leaanthony/slicer v1.6.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/ncruces/zenity v0.10.9
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/samber/lo v1.38.1 // indirect
github.com/samber/lo v1.27.1 // indirect
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
github.com/tkrajina/go-reflector v0.5.6 // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.3.0
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
)
// replace github.com/wailsapp/wails/v2 v2.3.1 => /Users/romeinvanburen/go/pkg/mod

126
go.sum
View File

@ -1,8 +1,12 @@
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f h1:OGqDDftRTwrvUoL6pOG7rYTmWsTCvyEWFsMjg+HcOaA=
github.com/dchest/jsmin v0.0.0-20220218165748-59f39799265f/go.mod h1:Dv9D0NUlAsaQcGQZa5kc5mqR9ua72SmA8VXi4cd+cBw=
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6 h1:jFEK/SA/7E8lg9T33+y8D4Z0I782+bbiEjmyyklRzRQ=
github.com/gen2brain/beeep v0.0.0-20220909211152-5a9ec94374f6/go.mod h1:/WeFVhhxMOGypVKS0w8DUJxUBbHypnWkUVnW7p5c9Pw=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@ -13,85 +17,78 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/josephspurrier/goversioninfo v1.4.0 h1:Puhl12NSHUSALHSuzYwPYQkqa2E1+7SrtAPJorKK0C8=
github.com/josephspurrier/goversioninfo v1.4.0/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg=
github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/ncruces/zenity v0.10.9 h1:TYdNwEj9HiDDcpdsIUecBMsQw7L80Aiu/IJMM0Tao1E=
github.com/ncruces/zenity v0.10.9/go.mod h1:FzjqP1loicusCFJTdIt5Oqbmoj2zySHpM0RsgJeeCbk=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 h1:GranzK4hv1/pqTIhMTXt2X8MmMOuH3hMeUR0o9SP5yc=
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844/go.mod h1:T1TLSfyWVBRXVGzWd0o9BI4kfoO9InEgfQe4NV3mLz8=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg=
github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ=
github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/wailsapp/go-webview2 v1.0.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w=
github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/wails/v2 v2.7.1 h1:HAzp2c5ODOzsLC6ZMDVtNOB72ozM7/SJecJPB2Ur+UU=
github.com/wailsapp/wails/v2 v2.7.1/go.mod h1:oIJVwwso5fdOgprBYWXBBqtx6PaSvxg8/KTQHNGkadc=
github.com/wailsapp/wails/v2 v2.3.1 h1:ZJz+pyIBKyASkgO8JO31NuHO1gTTHmvwiHYHwei1CqM=
github.com/wailsapp/wails/v2 v2.3.1/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
@ -100,20 +97,36 @@ github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCO
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.11.7 h1:LIwYxASDLGUg/8wOhgOOZhX8tQa/9tgZPgzZoVqJvcs=
go.mongodb.org/mongo-driver v1.11.7/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -124,19 +137,32 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@ -75,8 +75,8 @@ func NewApp(version string) *App {
panic(errors.New("unsupported platform"))
}
os.MkdirAll(a.Env.DataDirectory, 0755)
os.MkdirAll(a.Env.LogDirectory, 0755)
os.MkdirAll(a.Env.DataDirectory, os.ModePerm)
os.MkdirAll(a.Env.LogDirectory, os.ModePerm)
return a
}
@ -166,25 +166,3 @@ func (a *App) AskConfirmation(message string) bool {
return false
}
}
func (a *App) ChooseDirectory(title string) string {
if title == "" {
title = "Choose a directory"
}
dir, err := wailsRuntime.OpenDirectoryDialog(a.ctx, wailsRuntime.OpenDialogOptions{
Title: title,
DefaultDirectory: a.Env.DownloadDirectory,
CanCreateDirectories: true,
})
if err != nil {
wailsRuntime.MessageDialog(a.ctx, wailsRuntime.MessageDialogOptions{
Title: "Error while opening directory",
Message: err.Error(),
Type: wailsRuntime.ErrorDialog,
})
}
return dir
}

View File

@ -24,12 +24,12 @@ func (a *App) Menu() *menu.Menu {
appMenu := menu.NewMenu()
aboutMenu := appMenu.AddSubmenu("Rolens")
aboutMenu.AddText("About Rolens", nil, menuCallbackEmit(a, "global.about"))
aboutMenu.AddText("About Rolens", nil, menuCallbackEmit(a, "OpenAboutModal"))
aboutMenu.AddSeparator()
aboutMenu.AddText("Preferences…", keys.CmdOrCtrl(","), menuCallbackEmit(a, "global.settings"))
aboutMenu.AddText("Preferences…", keys.CmdOrCtrl(","), menuCallbackEmit(a, "OpenPreferences"))
aboutMenu.AddSeparator()
aboutMenu.AddText("Open data directory", nil, func(cd *menu.CallbackData) { a.ui.Reveal(a.Env.DataDirectory) })
aboutMenu.AddText("Open log directory", nil, func(cd *menu.CallbackData) { a.ui.Reveal(a.Env.LogDirectory) })
aboutMenu.AddText("Open data directory", nil, func(cd *menu.CallbackData) { a.ui.Reveal(a.Env.DataDirectory) })
aboutMenu.AddText("Open log directory", nil, func(cd *menu.CallbackData) { a.ui.Reveal(a.Env.LogDirectory) })
aboutMenu.AddText("Purge logs…", nil, func(cd *menu.CallbackData) { a.PurgeLogDirectory() })
aboutMenu.AddSeparator()
@ -47,10 +47,9 @@ func (a *App) Menu() *menu.Menu {
hostMenu.AddText("New…", keys.OptionOrAlt("C"), menuCallbackEmit(a, "ui.host.new"))
hostMenu.AddText("Edit host…", keys.OptionOrAlt("H"), menuCallbackEmit(a, "ui.host.edit"))
hostMenu.AddSeparator()
hostMenu.AddText("Host status", nil, menuCallbackEmit(a, "ui.host.tab", "status"))
hostMenu.AddText("Shell", nil, menuCallbackEmit(a, "ui.host.tab", "shell"))
hostMenu.AddText("Logs", nil, menuCallbackEmit(a, "ui.host.tab", "logs"))
hostMenu.AddText("Server status", nil, menuCallbackEmit(a, "ui.host.tab", "status"))
hostMenu.AddText("System info", nil, menuCallbackEmit(a, "ui.host.tab", "systemInfo"))
hostMenu.AddText("Shell", nil, menuCallbackEmit(a, "ui.host.tab", "shell"))
hostMenu.AddSeparator()
hostMenu.AddText("Remove host…", nil, menuCallbackEmit(a, "ui.host.remove"))

View File

@ -3,6 +3,7 @@ package app
import (
"encoding/json"
"io/ioutil"
"os"
"path"
"github.com/wailsapp/wails/v2/pkg/runtime"
@ -76,7 +77,7 @@ func (a *App) UpdateSettings(jsonData string) Settings {
}
filePath := path.Join(a.Env.DataDirectory, "settings.json")
err = ioutil.WriteFile(filePath, newJson, 0644)
err = ioutil.WriteFile(filePath, newJson, os.ModePerm)
if err != nil {
runtime.LogErrorf(a.ctx, "Could not update host list: %s", err.Error())
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{

View File

@ -3,6 +3,7 @@ package app
import (
"encoding/json"
"io/ioutil"
"os"
"path"
"github.com/wailsapp/wails/v2/pkg/runtime"
@ -24,7 +25,7 @@ func updateQueryFile(a *App, newData map[string]SavedQuery) error {
return err
}
err = ioutil.WriteFile(filePath, jsonData, 0644)
err = ioutil.WriteFile(filePath, jsonData, os.ModePerm)
return err
}

View File

@ -142,7 +142,7 @@ func (a *App) SaveShellScript(hostKey, dbKey, collKey, script string, temp bool)
scriptHeader = scriptHeader + "\n"
script = scriptHeader + strings.TrimLeft(strings.TrimRight(script, " \t\n"), "\n")
if err := os.WriteFile(result.Fname, []byte(script), 0755); err != nil {
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()
@ -154,7 +154,7 @@ func (a *App) SaveShellScript(hostKey, dbKey, collKey, script string, temp bool)
func (a *App) OpenShellScript() string {
dir := path.Join(a.Env.DataDirectory, "Shell Scripts")
os.MkdirAll(dir, 0755)
os.MkdirAll(dir, os.ModePerm)
fname, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
DefaultDirectory: path.Join(a.Env.DataDirectory, "Shell Scripts"),
@ -182,30 +182,3 @@ func (a *App) OpenShellScript() string {
return string(script)
}
func (a *App) SaveShellOuput(output string) {
fname, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
DefaultFilename: "mongosh-output.txt",
DefaultDirectory: a.Env.DownloadDirectory,
Title: "Save mongosh output",
CanCreateDirectories: true,
})
if err != nil {
runtime.LogWarningf(a.ctx, "Shell: error exporting output to %s: %s", fname, err.Error())
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Title: "Error exporting output",
Message: err.Error(),
Type: runtime.ErrorDialog,
})
}
if err := os.WriteFile(fname, []byte(output), 0755); err != nil {
runtime.LogWarningf(a.ctx, "Shell: error writing shell output to %s: %s", fname, err.Error())
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Title: "Error writing shell output",
Message: err.Error(),
Type: runtime.ErrorDialog,
})
}
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path"
"github.com/google/uuid"
@ -22,7 +23,7 @@ func updateHostsFile(a *App, newData map[string]Host) error {
return err
}
err = ioutil.WriteFile(filePath, jsonData, 0644)
err = ioutil.WriteFile(filePath, jsonData, os.ModePerm)
return err
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path"
"github.com/wailsapp/wails/v2/pkg/runtime"
@ -62,7 +63,7 @@ func updateViewStore(a *App, newData ViewStore) error {
return err
}
err = ioutil.WriteFile(filePath, jsonData, 0644)
err = ioutil.WriteFile(filePath, jsonData, os.ModePerm)
return err
}

View File

@ -4,8 +4,12 @@ import (
"os"
"path"
"strings"
"github.com/ncruces/zenity"
)
var showError = true
type AppLogger struct {
directory string
filename string
@ -21,9 +25,25 @@ func NewAppLogger(directory, filename string) *AppLogger {
}
func (l *AppLogger) Print(message string) {
os.MkdirAll(l.directory, 0755)
f, _ := os.OpenFile(l.filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
f.WriteString(message)
os.MkdirAll(l.directory, os.ModePerm)
f, err := os.OpenFile(l.filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil && showError {
zenity.Error(err.Error(), zenity.Title("Could not open logfile!"), zenity.ErrorIcon)
showError = false
}
if _, err = f.WriteString(message); err != nil {
if showError {
zenity.Error(err.Error(), zenity.Title("Could not write to logfile!"), zenity.ErrorIcon)
showError = false
} else {
showError = true
}
} else {
showError = true
}
f.Close()
}

17
internal/ui/dialogs.go Normal file
View File

@ -0,0 +1,17 @@
package ui
import "github.com/ncruces/zenity"
func (u *UI) OpenDirectory(title string) string {
if title == "" {
title = "Choose a directory"
}
dir, err := zenity.SelectFile(zenity.Title(title), zenity.Directory(), zenity.Modal())
if err != nil && err != zenity.ErrCanceled {
zenity.Error("Error while opening directory", zenity.ErrorIcon)
}
return dir
}

34
internal/ui/progress.go Normal file
View File

@ -0,0 +1,34 @@
package ui
import (
"time"
"github.com/ncruces/zenity"
)
// @todo: this takes ~0.5 seconds. Improve?
func (u *UI) StartProgressBar(id uint, title string) {
if title == "" {
// default title
title = "Loading…"
}
p, err := zenity.Progress(zenity.Title(title), zenity.Pulsate(), zenity.Modal())
if err != nil {
return
}
u.progressBars[id] = p
}
func (u *UI) StopProgressBar(id uint) {
for try := 0; try < 10; try++ {
if p := u.progressBars[id]; p != nil {
p.Complete()
p.Close()
p = nil
return
}
println("Progress dialog not found:", id, try)
time.Sleep(100 * time.Millisecond)
}
}

View File

@ -5,14 +5,18 @@ import (
"runtime"
"github.com/gen2brain/beeep"
"github.com/ncruces/zenity"
)
type UI struct {
ctx context.Context
progressBars map[uint]zenity.ProgressDialog
}
func New() *UI {
return &UI{}
return &UI{
progressBars: make(map[uint]zenity.ProgressDialog),
}
}
func (u *UI) Startup(ctx context.Context) {

View File

@ -13,7 +13,7 @@
"info": {
"productName": "Rolens",
"companyName": "Romein van Buren",
"productVersion": "0.3.0",
"productVersion": "0.2.2",
"comments": "The intuitive MongoDB administration tool",
"copyright": "© Romein van Buren 2023 (GNU GPL 3.0)."
},

View File

@ -119,5 +119,6 @@ module.exports = function (eleventyConfig) {
templateFormats: ['html', 'liquid', 'md', '11ty.js'],
markdownTemplateEngine: 'liquid',
htmlTemplateEngine: 'liquid',
pathPrefix: '/rolens/',
};
};

View File

@ -1 +0,0 @@
rolens.romein.me