Compare commits
3 Commits
f3a43c8083
...
581a1b79ca
Author | SHA1 | Date |
---|---|---|
Lykin | 581a1b79ca | |
Lykin | b361e9b0be | |
Lykin | 4032c80add |
|
@ -15,6 +15,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -512,3 +513,36 @@ func (c *connectionService) ImportConnections() (resp types.JSResp) {
|
||||||
resp.Success = true
|
resp.Success = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseConnectURL parse connection url string
|
||||||
|
func (c *connectionService) ParseConnectURL(url string) (resp types.JSResp) {
|
||||||
|
urlOpt, err := redis.ParseURL(url)
|
||||||
|
if err != nil {
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addrPart := strings.Split(urlOpt.Addr, ":")
|
||||||
|
addr := addrPart[0]
|
||||||
|
port := 6379
|
||||||
|
if len(addrPart) > 1 {
|
||||||
|
port, _ = strconv.Atoi(addrPart[1])
|
||||||
|
}
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = struct {
|
||||||
|
Addr string `json:"addr"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConnTimeout int64 `json:"connTimeout"`
|
||||||
|
ExecTimeout int64 `json:"execTimeout"`
|
||||||
|
}{
|
||||||
|
Addr: addr,
|
||||||
|
Port: port,
|
||||||
|
Username: urlOpt.Username,
|
||||||
|
Password: urlOpt.Password,
|
||||||
|
ConnTimeout: int64(urlOpt.DialTimeout.Seconds()),
|
||||||
|
ExecTimeout: int64(urlOpt.ReadTimeout.Seconds()),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package services
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
runtime2 "runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"tinyrdm/backend/consts"
|
"tinyrdm/backend/consts"
|
||||||
|
@ -11,7 +12,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type systemService struct {
|
type systemService struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
appVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
var system *systemService
|
var system *systemService
|
||||||
|
@ -20,15 +22,18 @@ var onceSystem sync.Once
|
||||||
func System() *systemService {
|
func System() *systemService {
|
||||||
if system == nil {
|
if system == nil {
|
||||||
onceSystem.Do(func() {
|
onceSystem.Do(func() {
|
||||||
system = &systemService{}
|
system = &systemService{
|
||||||
|
appVersion: "0.0.0",
|
||||||
|
}
|
||||||
go system.loopWindowEvent()
|
go system.loopWindowEvent()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return system
|
return system
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemService) Start(ctx context.Context) {
|
func (s *systemService) Start(ctx context.Context, version string) {
|
||||||
s.ctx = ctx
|
s.ctx = ctx
|
||||||
|
s.appVersion = version
|
||||||
|
|
||||||
// maximize the window if screen size is lower than the minimum window size
|
// maximize the window if screen size is lower than the minimum window size
|
||||||
if screen, err := runtime.ScreenGetAll(ctx); err == nil && len(screen) > 0 {
|
if screen, err := runtime.ScreenGetAll(ctx); err == nil && len(screen) > 0 {
|
||||||
|
@ -43,6 +48,20 @@ func (s *systemService) Start(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *systemService) Info() (resp types.JSResp) {
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = struct {
|
||||||
|
OS string `json:"os"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}{
|
||||||
|
OS: runtime2.GOOS,
|
||||||
|
Arch: runtime2.GOARCH,
|
||||||
|
Version: s.appVersion,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SelectFile open file dialog to select a file
|
// SelectFile open file dialog to select a file
|
||||||
func (s *systemService) SelectFile(title string, extensions []string) (resp types.JSResp) {
|
func (s *systemService) SelectFile(title string, extensions []string) (resp types.JSResp) {
|
||||||
filters := sliceutil.Map(extensions, func(i int) runtime.FileFilter {
|
filters := sliceutil.Map(extensions, func(i int) runtime.FileFilter {
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang='en'>
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset='UTF-8' />
|
<meta charset="UTF-8" />
|
||||||
<meta content='width=device-width, initial-scale=1.0' name='viewport' />
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
||||||
<title>Tiny RDM</title>
|
<title>Tiny RDM</title>
|
||||||
<!-- <link href="./src/styles/style.scss" rel="stylesheet">-->
|
<!-- <link href="./src/styles/style.scss" rel="stylesheet">-->
|
||||||
</head>
|
</head>
|
||||||
<body spellcheck="false">
|
<body spellcheck="false">
|
||||||
<div id='app'></div>
|
<div id="app"></div>
|
||||||
<script src='./src/main.js' type='module'></script>
|
<script async data-website-id="ad6de51d-1e27-44a5-958d-319679c56aec"
|
||||||
|
src="https://analytics.tinycraft.cc/script.js"></script>
|
||||||
|
<script src="./src/main.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"@vitejs/plugin-vue": "^5.0.3",
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
"naive-ui": "^2.37.3",
|
"naive-ui": "^2.37.3",
|
||||||
"prettier": "^3.2.4",
|
"prettier": "^3.2.4",
|
||||||
"unplugin-auto-import": "^0.17.3",
|
"unplugin-auto-import": "^0.17.4",
|
||||||
"unplugin-icons": "^0.18.2",
|
"unplugin-icons": "^0.18.2",
|
||||||
"unplugin-vue-components": "^0.26.0",
|
"unplugin-vue-components": "^0.26.0",
|
||||||
"vite": "^5.0.12"
|
"vite": "^5.0.12"
|
||||||
|
@ -2067,9 +2067,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/unplugin-auto-import": {
|
"node_modules/unplugin-auto-import": {
|
||||||
"version": "0.17.3",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.3.tgz",
|
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.4.tgz",
|
||||||
"integrity": "sha512-0cn0wr8X579TtdZKUAps0dDVrYzttx38ImdxZjmCeNlMDJX8UuSjO83vFqgS4ClNDIGWAute+xl9j5vRSX+vsw==",
|
"integrity": "sha512-sInr7+UOeFMtiRCr7lYZXouTnVqXNUJtN5yN5GDzg6Sr2rwY5ZWZmqf4yvItYCm8mq1PdzPw3oojYHgZAJnTRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@antfu/utils": "^0.7.7",
|
"@antfu/utils": "^0.7.7",
|
||||||
|
@ -2078,7 +2078,7 @@
|
||||||
"local-pkg": "^0.5.0",
|
"local-pkg": "^0.5.0",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
"minimatch": "^9.0.3",
|
"minimatch": "^9.0.3",
|
||||||
"unimport": "^3.7.0",
|
"unimport": "^3.7.1",
|
||||||
"unplugin": "^1.6.0"
|
"unplugin": "^1.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3821,9 +3821,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unplugin-auto-import": {
|
"unplugin-auto-import": {
|
||||||
"version": "0.17.3",
|
"version": "0.17.4",
|
||||||
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.3.tgz",
|
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.4.tgz",
|
||||||
"integrity": "sha512-0cn0wr8X579TtdZKUAps0dDVrYzttx38ImdxZjmCeNlMDJX8UuSjO83vFqgS4ClNDIGWAute+xl9j5vRSX+vsw==",
|
"integrity": "sha512-sInr7+UOeFMtiRCr7lYZXouTnVqXNUJtN5yN5GDzg6Sr2rwY5ZWZmqf4yvItYCm8mq1PdzPw3oojYHgZAJnTRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@antfu/utils": "^0.7.7",
|
"@antfu/utils": "^0.7.7",
|
||||||
|
@ -3832,7 +3832,7 @@
|
||||||
"local-pkg": "^0.5.0",
|
"local-pkg": "^0.5.0",
|
||||||
"magic-string": "^0.30.5",
|
"magic-string": "^0.30.5",
|
||||||
"minimatch": "^9.0.3",
|
"minimatch": "^9.0.3",
|
||||||
"unimport": "^3.7.0",
|
"unimport": "^3.7.1",
|
||||||
"unplugin": "^1.6.0"
|
"unplugin": "^1.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"@vitejs/plugin-vue": "^5.0.3",
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
"naive-ui": "^2.37.3",
|
"naive-ui": "^2.37.3",
|
||||||
"prettier": "^3.2.4",
|
"prettier": "^3.2.4",
|
||||||
"unplugin-auto-import": "^0.17.3",
|
"unplugin-auto-import": "^0.17.4",
|
||||||
"unplugin-icons": "^0.18.2",
|
"unplugin-icons": "^0.18.2",
|
||||||
"unplugin-vue-components": "^0.26.0",
|
"unplugin-vue-components": "^0.26.0",
|
||||||
"vite": "^5.0.12"
|
"vite": "^5.0.12"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
6403086a3d7567446771161c9ad44994
|
91df99a27ba619287c70d3f15e70a9ac
|
|
@ -20,6 +20,7 @@ import AboutDialog from '@/components/dialogs/AboutDialog.vue'
|
||||||
import FlushDbDialog from '@/components/dialogs/FlushDbDialog.vue'
|
import FlushDbDialog from '@/components/dialogs/FlushDbDialog.vue'
|
||||||
import ExportKeyDialog from '@/components/dialogs/ExportKeyDialog.vue'
|
import ExportKeyDialog from '@/components/dialogs/ExportKeyDialog.vue'
|
||||||
import ImportKeyDialog from '@/components/dialogs/ImportKeyDialog.vue'
|
import ImportKeyDialog from '@/components/dialogs/ImportKeyDialog.vue'
|
||||||
|
import { Info } from 'wailsjs/go/services/systemService.js'
|
||||||
|
|
||||||
const prefStore = usePreferencesStore()
|
const prefStore = usePreferencesStore()
|
||||||
const connectionStore = useConnectionStore()
|
const connectionStore = useConnectionStore()
|
||||||
|
@ -33,6 +34,10 @@ onMounted(async () => {
|
||||||
if (prefStore.autoCheckUpdate) {
|
if (prefStore.autoCheckUpdate) {
|
||||||
prefStore.checkForUpdate()
|
prefStore.checkForUpdate()
|
||||||
}
|
}
|
||||||
|
Info().then(({ data }) => {
|
||||||
|
// const {os, arch, version} = data
|
||||||
|
umami && umami.track('startup', data)
|
||||||
|
})
|
||||||
} finally {
|
} finally {
|
||||||
initializing.value = false
|
initializing.value = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,6 +267,29 @@ const onTestConnection = async () => {
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
dialogStore.closeConnDialog()
|
dialogStore.closeConnDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pasteFromClipboard = async () => {
|
||||||
|
// url example:
|
||||||
|
// redis://user:password@localhost:6789/3?dial_timeout=3&db=1&read_timeout=6s&max_retries=2
|
||||||
|
let opt = {}
|
||||||
|
try {
|
||||||
|
opt = await connectionStore.parseUrlFromClipboard()
|
||||||
|
} catch (e) {
|
||||||
|
$message.error(i18n.t('dialogue.connection.parse_fail', { reason: e.message }))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
generalForm.value.name = generalForm.value.addr = opt.addr
|
||||||
|
generalForm.value.port = opt.port
|
||||||
|
generalForm.value.username = opt.username
|
||||||
|
generalForm.value.password = opt.password
|
||||||
|
if (opt.connTimeout > 0) {
|
||||||
|
generalForm.value.connTimeout = opt.connTimeout
|
||||||
|
}
|
||||||
|
if (opt.execTimeout > 0) {
|
||||||
|
generalForm.value.execTimeout = opt.execTimeout
|
||||||
|
}
|
||||||
|
$message.success(i18n.t('dialogue.connection.parse_pass', { url: opt.url }))
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -685,6 +708,9 @@ const onClose = () => {
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-item n-dialog__action">
|
<div class="flex-item n-dialog__action">
|
||||||
|
<n-button :disabled="closingConnection" :focusable="false" @click="pasteFromClipboard">
|
||||||
|
{{ $t('dialogue.connection.parse_url_clipboard') }}
|
||||||
|
</n-button>
|
||||||
<n-button :disabled="closingConnection" :focusable="false" @click="onClose">
|
<n-button :disabled="closingConnection" :focusable="false" @click="onClose">
|
||||||
{{ $t('common.cancel') }}
|
{{ $t('common.cancel') }}
|
||||||
</n-button>
|
</n-button>
|
||||||
|
|
|
@ -109,11 +109,18 @@ const onSelectPreferenceMenu = (key) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openWechatOfficial = () => {
|
||||||
|
umami && umami.track('open', { target: 'wechat_official' })
|
||||||
|
showWechat.value = true
|
||||||
|
}
|
||||||
|
|
||||||
const openX = () => {
|
const openX = () => {
|
||||||
|
umami && umami.track('open', { target: 'x' })
|
||||||
BrowserOpenURL('https://twitter.com/LykinHuang')
|
BrowserOpenURL('https://twitter.com/LykinHuang')
|
||||||
}
|
}
|
||||||
|
|
||||||
const openGithub = () => {
|
const openGithub = () => {
|
||||||
|
umami && umami.track('open', { target: 'github' })
|
||||||
BrowserOpenURL('https://github.com/tiny-craft/tiny-rdm')
|
BrowserOpenURL('https://github.com/tiny-craft/tiny-rdm')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +170,7 @@ const exThemeVars = computed(() => {
|
||||||
:size="iconSize"
|
:size="iconSize"
|
||||||
class="nav-menu-button"
|
class="nav-menu-button"
|
||||||
t-tooltip="ribbon.wechat_official"
|
t-tooltip="ribbon.wechat_official"
|
||||||
@click="showWechat = true" />
|
@click="openWechatOfficial" />
|
||||||
<icon-button
|
<icon-button
|
||||||
v-else
|
v-else
|
||||||
:border="false"
|
:border="false"
|
||||||
|
|
|
@ -187,6 +187,9 @@
|
||||||
"test": "Test Connection",
|
"test": "Test Connection",
|
||||||
"test_succ": "Successful connection to redis-server",
|
"test_succ": "Successful connection to redis-server",
|
||||||
"test_fail": "Fail Connection",
|
"test_fail": "Fail Connection",
|
||||||
|
"parse_url_clipboard": "Parse URL from Clipboard",
|
||||||
|
"parse_pass": "Redis URL Parsed {url}",
|
||||||
|
"parse_fail": "Parse Redis URL failed: {reason}",
|
||||||
"advn": {
|
"advn": {
|
||||||
"title": "Advanced",
|
"title": "Advanced",
|
||||||
"filter": "Default Key Filter Pattern",
|
"filter": "Default Key Filter Pattern",
|
||||||
|
|
|
@ -187,6 +187,9 @@
|
||||||
"test": "测试连接",
|
"test": "测试连接",
|
||||||
"test_succ": "成功连接到Redis服务器",
|
"test_succ": "成功连接到Redis服务器",
|
||||||
"test_fail": "连接失败",
|
"test_fail": "连接失败",
|
||||||
|
"parse_url_clipboard": "解析剪切板中的URL",
|
||||||
|
"parse_pass": "解析Redis URL完成: {url}",
|
||||||
|
"parse_fail": "解析Redis URL失败: {reason}",
|
||||||
"advn": {
|
"advn": {
|
||||||
"title": "高级配置",
|
"title": "高级配置",
|
||||||
"filter": "默认键过滤表达式",
|
"filter": "默认键过滤表达式",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { get, isEmpty, uniq } from 'lodash'
|
import { get, isEmpty, isObject, uniq } from 'lodash'
|
||||||
import {
|
import {
|
||||||
CreateGroup,
|
CreateGroup,
|
||||||
DeleteConnection,
|
DeleteConnection,
|
||||||
|
@ -8,6 +8,7 @@ import {
|
||||||
GetConnection,
|
GetConnection,
|
||||||
ImportConnections,
|
ImportConnections,
|
||||||
ListConnection,
|
ListConnection,
|
||||||
|
ParseConnectURL,
|
||||||
RenameGroup,
|
RenameGroup,
|
||||||
SaveConnection,
|
SaveConnection,
|
||||||
SaveLastDB,
|
SaveLastDB,
|
||||||
|
@ -18,6 +19,7 @@ import { ConnectionType } from '@/consts/connection_type.js'
|
||||||
import { KeyViewType } from '@/consts/key_view_type.js'
|
import { KeyViewType } from '@/consts/key_view_type.js'
|
||||||
import useBrowserStore from 'stores/browser.js'
|
import useBrowserStore from 'stores/browser.js'
|
||||||
import { i18nGlobal } from '@/utils/i18n.js'
|
import { i18nGlobal } from '@/utils/i18n.js'
|
||||||
|
import { ClipboardGetText } from 'wailsjs/runtime/runtime.js'
|
||||||
|
|
||||||
const useConnectionStore = defineStore('connections', {
|
const useConnectionStore = defineStore('connections', {
|
||||||
/**
|
/**
|
||||||
|
@ -404,6 +406,10 @@ const useConnectionStore = defineStore('connections', {
|
||||||
return { success: true }
|
return { success: true }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* export connections to zip
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
async exportConnections() {
|
async exportConnections() {
|
||||||
const {
|
const {
|
||||||
success,
|
success,
|
||||||
|
@ -420,6 +426,10 @@ const useConnectionStore = defineStore('connections', {
|
||||||
$message.success(i18nGlobal.t('dialogue.handle_succ'))
|
$message.success(i18nGlobal.t('dialogue.handle_succ'))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* import connections from zip
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
async importConnections() {
|
async importConnections() {
|
||||||
const { success, msg } = await ImportConnections()
|
const { success, msg } = await ImportConnections()
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -431,6 +441,25 @@ const useConnectionStore = defineStore('connections', {
|
||||||
|
|
||||||
$message.success(i18nGlobal.t('dialogue.handle_succ'))
|
$message.success(i18nGlobal.t('dialogue.handle_succ'))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parse redis url from text in clipboard
|
||||||
|
* @return {Promise<{}>}
|
||||||
|
*/
|
||||||
|
async parseUrlFromClipboard() {
|
||||||
|
const urlString = await ClipboardGetText()
|
||||||
|
if (isEmpty(urlString)) {
|
||||||
|
throw new Error('no text in clipboard')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { success, msg, data } = await ParseConnectURL(urlString)
|
||||||
|
if (!success || !isObject(data)) {
|
||||||
|
throw new Error(msg || 'unknown')
|
||||||
|
}
|
||||||
|
|
||||||
|
data.url = urlString
|
||||||
|
return data
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
2
main.go
2
main.go
|
@ -66,7 +66,7 @@ func main() {
|
||||||
BackgroundColour: options.NewRGBA(27, 38, 54, 0),
|
BackgroundColour: options.NewRGBA(27, 38, 54, 0),
|
||||||
StartHidden: true,
|
StartHidden: true,
|
||||||
OnStartup: func(ctx context.Context) {
|
OnStartup: func(ctx context.Context) {
|
||||||
sysSvc.Start(ctx)
|
sysSvc.Start(ctx, version)
|
||||||
connSvc.Start(ctx)
|
connSvc.Start(ctx)
|
||||||
browserSvc.Start(ctx)
|
browserSvc.Start(ctx)
|
||||||
cliSvc.Start(ctx)
|
cliSvc.Start(ctx)
|
||||||
|
|
Loading…
Reference in New Issue