Add common confirm dialog function
Add connection group handle logic Refactor local connection profile struct
This commit is contained in:
parent
8e3adbf0c3
commit
f6a4ab8de0
|
@ -92,7 +92,7 @@ func (c *connectionService) GetConnection(name string) (resp types.JSResp) {
|
|||
}
|
||||
|
||||
// SaveConnection save connection config to local profile
|
||||
func (c *connectionService) SaveConnection(name string, param types.Connection) (resp types.JSResp) {
|
||||
func (c *connectionService) SaveConnection(name string, param types.ConnectionConfig) (resp types.JSResp) {
|
||||
var err error
|
||||
if len(name) > 0 {
|
||||
// update connection
|
||||
|
@ -119,6 +119,39 @@ func (c *connectionService) RemoveConnection(name string) (resp types.JSResp) {
|
|||
return
|
||||
}
|
||||
|
||||
// CreateGroup create new group
|
||||
func (c *connectionService) CreateGroup(name string) (resp types.JSResp) {
|
||||
err := c.conns.CreateGroup(name)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
// RenameGroup rename group
|
||||
func (c *connectionService) RenameGroup(name, newName string) (resp types.JSResp) {
|
||||
err := c.conns.RenameGroup(name, newName)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveGroup remove group by name
|
||||
func (c *connectionService) RemoveGroup(name string, includeConn bool) (resp types.JSResp) {
|
||||
err := c.conns.RemoveGroup(name, includeConn)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
// OpenConnection open redis server connection
|
||||
func (c *connectionService) OpenConnection(name string) (resp types.JSResp) {
|
||||
rdb, ctx, err := c.getRedisClient(name, 0)
|
||||
|
@ -195,18 +228,9 @@ func (c *connectionService) getRedisClient(connName string, db int) (*redis.Clie
|
|||
if ok {
|
||||
rdb, ctx = item.rdb, item.ctx
|
||||
} else {
|
||||
connGroups := c.conns.GetConnections()
|
||||
var selConn *types.Connection
|
||||
for _, connGroup := range connGroups {
|
||||
for _, conn := range connGroup.Connections {
|
||||
if conn.Name == connName {
|
||||
selConn = &conn
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
selConn := c.conns.GetConnection(connName)
|
||||
if selConn == nil {
|
||||
return nil, nil, errors.New("no match connection connName")
|
||||
return nil, nil, fmt.Errorf("no match connection \"%s\"", connName)
|
||||
}
|
||||
|
||||
rdb = redis.NewClient(&redis.Options{
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
"sync"
|
||||
"tinyrdm/backend/types"
|
||||
sliceutil "tinyrdm/backend/utils/slice"
|
||||
)
|
||||
|
||||
type ConnectionsStorage struct {
|
||||
|
@ -19,17 +18,12 @@ func NewConnections() *ConnectionsStorage {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionsStorage) defaultConnections() []types.ConnectionGroup {
|
||||
return []types.ConnectionGroup{
|
||||
{
|
||||
GroupName: "",
|
||||
Connections: []types.Connection{},
|
||||
},
|
||||
}
|
||||
func (c *ConnectionsStorage) defaultConnections() types.Connections {
|
||||
return types.Connections{}
|
||||
}
|
||||
|
||||
func (c *ConnectionsStorage) defaultConnectionItem() types.Connection {
|
||||
return types.Connection{
|
||||
func (c *ConnectionsStorage) defaultConnectionItem() types.ConnectionConfig {
|
||||
return types.ConnectionConfig{
|
||||
Name: "",
|
||||
Addr: "127.0.0.1",
|
||||
Port: 6379,
|
||||
|
@ -43,7 +37,7 @@ func (c *ConnectionsStorage) defaultConnectionItem() types.Connection {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionsStorage) getConnections() (ret []types.ConnectionGroup) {
|
||||
func (c *ConnectionsStorage) getConnections() (ret types.Connections) {
|
||||
b, err := c.storage.Load()
|
||||
if err != nil {
|
||||
ret = c.defaultConnections()
|
||||
|
@ -66,15 +60,19 @@ func (c *ConnectionsStorage) getConnections() (ret []types.ConnectionGroup) {
|
|||
}
|
||||
|
||||
// GetConnections get all store connections from local
|
||||
func (c *ConnectionsStorage) GetConnections() (ret []types.ConnectionGroup) {
|
||||
func (c *ConnectionsStorage) GetConnections() (ret types.Connections) {
|
||||
return c.getConnections()
|
||||
}
|
||||
|
||||
// GetConnectionsFlat get all store connections from local flat(exclude group level)
|
||||
func (c *ConnectionsStorage) GetConnectionsFlat() (ret []types.Connection) {
|
||||
func (c *ConnectionsStorage) GetConnectionsFlat() (ret types.Connections) {
|
||||
conns := c.getConnections()
|
||||
for _, group := range conns {
|
||||
ret = append(ret, group.Connections...)
|
||||
for _, conn := range conns {
|
||||
if conn.Type == "group" {
|
||||
ret = append(ret, conn.Connections...)
|
||||
} else {
|
||||
ret = append(ret, conn)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -82,18 +80,40 @@ func (c *ConnectionsStorage) GetConnectionsFlat() (ret []types.Connection) {
|
|||
// GetConnection get connection by name
|
||||
func (c *ConnectionsStorage) GetConnection(name string) *types.Connection {
|
||||
conns := c.getConnections()
|
||||
for _, group := range conns {
|
||||
for _, conn := range group.Connections {
|
||||
if conn.Name == name {
|
||||
conn.Group = group.GroupName
|
||||
return &conn
|
||||
|
||||
var findConn func(string, string, types.Connections) *types.Connection
|
||||
findConn = func(name, groupName string, conns types.Connections) *types.Connection {
|
||||
for i, conn := range conns {
|
||||
if conn.Type != "group" {
|
||||
if conn.Name == name {
|
||||
conns[i].Group = groupName
|
||||
return &conns[i]
|
||||
}
|
||||
} else {
|
||||
if ret := findConn(name, conn.Name, conn.Connections); ret != nil {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return findConn(name, "", conns)
|
||||
}
|
||||
|
||||
// GetGroup get connection group by name
|
||||
func (c *ConnectionsStorage) GetGroup(name string) *types.Connection {
|
||||
conns := c.getConnections()
|
||||
|
||||
for i, conn := range conns {
|
||||
if conn.Type == "group" && conn.Name == name {
|
||||
return &conns[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConnectionsStorage) saveConnections(conns []types.ConnectionGroup) error {
|
||||
func (c *ConnectionsStorage) saveConnections(conns types.Connections) error {
|
||||
b, err := yaml.Marshal(&conns)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -105,7 +125,7 @@ func (c *ConnectionsStorage) saveConnections(conns []types.ConnectionGroup) erro
|
|||
}
|
||||
|
||||
// CreateConnection create new connection
|
||||
func (c *ConnectionsStorage) CreateConnection(param types.Connection) error {
|
||||
func (c *ConnectionsStorage) CreateConnection(param types.ConnectionConfig) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
|
@ -115,72 +135,75 @@ func (c *ConnectionsStorage) CreateConnection(param types.Connection) error {
|
|||
}
|
||||
|
||||
conns := c.getConnections()
|
||||
groupIndex, existsGroup := sliceutil.Find(conns, func(i int) bool {
|
||||
return conns[i].GroupName == param.Group
|
||||
})
|
||||
if !existsGroup {
|
||||
// no group matched, create new group
|
||||
group := types.ConnectionGroup{
|
||||
GroupName: param.Group,
|
||||
Connections: []types.Connection{param},
|
||||
var group *types.Connection
|
||||
if len(param.Group) > 0 {
|
||||
for i, conn := range conns {
|
||||
if conn.Type == "group" && conn.Name == param.Group {
|
||||
group = &conns[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
conns = append(conns, group)
|
||||
}
|
||||
if group != nil {
|
||||
group.Connections = append(group.Connections, types.Connection{
|
||||
ConnectionConfig: param,
|
||||
})
|
||||
} else {
|
||||
conns[groupIndex].Connections = append(conns[groupIndex].Connections, param)
|
||||
if len(param.Group) > 0 {
|
||||
// no group matched, create new group
|
||||
conns = append(conns, types.Connection{
|
||||
Type: "group",
|
||||
Connections: types.Connections{
|
||||
types.Connection{
|
||||
ConnectionConfig: param,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
conns = append(conns, types.Connection{
|
||||
ConnectionConfig: param,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
|
||||
// UpdateConnection update existing connection by name
|
||||
func (c *ConnectionsStorage) UpdateConnection(name string, param types.Connection) error {
|
||||
func (c *ConnectionsStorage) UpdateConnection(name string, param types.ConnectionConfig) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
var updated bool
|
||||
conns := c.getConnections()
|
||||
groupIndex := -1
|
||||
connIndex := -1
|
||||
// find out edit connection
|
||||
for i, group := range conns {
|
||||
for j, conn := range group.Connections {
|
||||
// check conflict connection name
|
||||
if conn.Name == name {
|
||||
// different group name, should move to new group
|
||||
// remove from current group first
|
||||
if group.GroupName != param.Group {
|
||||
conns[i].Connections = append(conns[i].Connections[:j], conns[i].Connections[j+1:]...)
|
||||
|
||||
// find new group index
|
||||
groupIndex, _ = sliceutil.Find(conns, func(i int) bool {
|
||||
return conns[i].GroupName == param.Group
|
||||
})
|
||||
} else {
|
||||
groupIndex = i
|
||||
connIndex = j
|
||||
for i, conn := range conns {
|
||||
if conn.Name == name {
|
||||
conns[i] = types.Connection{
|
||||
ConnectionConfig: param,
|
||||
}
|
||||
updated = true
|
||||
} else if conn.Type == "group" {
|
||||
for j, conn2 := range conn.Connections {
|
||||
if conn2.Name == name {
|
||||
conns[i].Connections[j] = types.Connection{
|
||||
ConnectionConfig: param,
|
||||
}
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if groupIndex >= 0 {
|
||||
// group exists
|
||||
if connIndex >= 0 {
|
||||
// connection exists
|
||||
conns[groupIndex].Connections[connIndex] = param
|
||||
} else {
|
||||
// new connection
|
||||
conns[groupIndex].Connections = append(conns[groupIndex].Connections, param)
|
||||
}
|
||||
} else {
|
||||
// new group
|
||||
group := types.ConnectionGroup{
|
||||
GroupName: param.Group,
|
||||
Connections: []types.Connection{param},
|
||||
}
|
||||
conns = append(conns, group)
|
||||
if updated {
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
return c.saveConnections(conns)
|
||||
|
||||
return errors.New("connection not found")
|
||||
}
|
||||
|
||||
// RemoveConnection remove special connection
|
||||
|
@ -189,55 +212,82 @@ func (c *ConnectionsStorage) RemoveConnection(name string) error {
|
|||
defer c.mutex.Unlock()
|
||||
|
||||
conns := c.getConnections()
|
||||
for i, connGroup := range conns {
|
||||
for j, conn := range connGroup.Connections {
|
||||
if conn.Name == name {
|
||||
connList := conns[i].Connections
|
||||
connList = append(connList[:j], connList[j+1:]...)
|
||||
conns[i].Connections = connList
|
||||
return c.saveConnections(conns)
|
||||
var updated bool
|
||||
for i, conn := range conns {
|
||||
if conn.Type == "group" {
|
||||
for j, subConn := range conn.Connections {
|
||||
if subConn.Name == name {
|
||||
conns[i].Connections = append(conns[i].Connections[:j], conns[i].Connections[j+1:]...)
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if conn.Name == name {
|
||||
conns = append(conns[:i], conns[i+1:]...)
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
if updated {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("no match connection")
|
||||
}
|
||||
|
||||
// UpsertGroup update or insert a group
|
||||
// When want to create group only, set group == param.name
|
||||
func (c *ConnectionsStorage) UpsertGroup(group string, param types.ConnectionGroup) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
conns := c.getConnections()
|
||||
for i, connGroup := range conns {
|
||||
if connGroup.GroupName == group {
|
||||
conns[i].GroupName = param.GroupName
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
if !updated {
|
||||
return errors.New("no match connection")
|
||||
}
|
||||
|
||||
// No match group, create one
|
||||
connGroup := types.ConnectionGroup{
|
||||
GroupName: param.GroupName,
|
||||
Connections: []types.Connection{},
|
||||
}
|
||||
conns = append(conns, connGroup)
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
|
||||
// RemoveGroup remove special group, include all connections under it
|
||||
func (c *ConnectionsStorage) RemoveGroup(group string) error {
|
||||
// CreateGroup create new group
|
||||
func (c *ConnectionsStorage) CreateGroup(name string) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
conns := c.getConnections()
|
||||
for i, connGroup := range conns {
|
||||
if connGroup.GroupName == group {
|
||||
conns = append(conns[:i], conns[i+1:]...)
|
||||
for _, conn := range conns {
|
||||
if conn.Type == "group" && conn.Name == name {
|
||||
return errors.New("duplicated group name")
|
||||
}
|
||||
}
|
||||
|
||||
conns = append(conns, types.Connection{
|
||||
ConnectionConfig: types.ConnectionConfig{
|
||||
Name: name,
|
||||
},
|
||||
Type: "group",
|
||||
})
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
|
||||
// RenameGroup rename group
|
||||
func (c *ConnectionsStorage) RenameGroup(name, newName string) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
conns := c.getConnections()
|
||||
for i, conn := range conns {
|
||||
if conn.Type == "group" && conn.Name == name {
|
||||
conns[i].Name = newName
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("no match group")
|
||||
return errors.New("group not found")
|
||||
}
|
||||
|
||||
// RemoveGroup remove special group, include all connections under it
|
||||
func (c *ConnectionsStorage) RemoveGroup(group string, includeConnection bool) error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
conns := c.getConnections()
|
||||
for i, conn := range conns {
|
||||
if conn.Type == "group" && conn.Name == group {
|
||||
conns = append(conns[:i], conns[i+1:]...)
|
||||
if includeConnection {
|
||||
conns = append(conns, conn.Connections...)
|
||||
}
|
||||
return c.saveConnections(conns)
|
||||
}
|
||||
}
|
||||
return errors.New("group not found")
|
||||
}
|
||||
|
|
|
@ -2,20 +2,28 @@ package types
|
|||
|
||||
type ConnectionCategory int
|
||||
|
||||
type Connection struct {
|
||||
Group string `json:"group" yaml:"-"`
|
||||
type ConnectionConfig struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Addr string `json:"addr" yaml:"addr"`
|
||||
Port int `json:"port" yaml:"port"`
|
||||
Username string `json:"username" yaml:"username"`
|
||||
Password string `json:"password" yaml:"password"`
|
||||
DefaultFilter string `json:"defaultFilter" yaml:"default_filter"`
|
||||
KeySeparator string `json:"keySeparator" yaml:"key_separator"`
|
||||
ConnTimeout int `json:"connTimeout" yaml:"conn_timeout"`
|
||||
ExecTimeout int `json:"execTimeout" yaml:"exec_timeout"`
|
||||
MarkColor string `json:"markColor" yaml:"mark_color"`
|
||||
Group string `json:"group" yaml:"-"`
|
||||
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
DefaultFilter string `json:"defaultFilter,omitempty" yaml:"default_filter,omitempty"`
|
||||
KeySeparator string `json:"keySeparator,omitempty" yaml:"key_separator,omitempty"`
|
||||
ConnTimeout int `json:"connTimeout,omitempty" yaml:"conn_timeout,omitempty"`
|
||||
ExecTimeout int `json:"execTimeout,omitempty" yaml:"exec_timeout,omitempty"`
|
||||
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
ConnectionConfig `json:",inline" yaml:",inline"`
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
Connections []Connection `json:"connections,omitempty" yaml:"connections,omitempty"`
|
||||
}
|
||||
|
||||
type Connections []Connection
|
||||
|
||||
type ConnectionGroup struct {
|
||||
GroupName string `json:"groupName" yaml:"group_name"`
|
||||
Connections []Connection `json:"connections" yaml:"connections"`
|
||||
|
|
|
@ -9,6 +9,7 @@ import json from 'highlight.js/lib/languages/json'
|
|||
import plaintext from 'highlight.js/lib/languages/plaintext'
|
||||
import AddFieldsDialog from './components/dialogs/AddFieldsDialog.vue'
|
||||
import AppContent from './AppContent.vue'
|
||||
import GroupDialog from './components/dialogs/GroupDialog.vue'
|
||||
|
||||
hljs.registerLanguage('json', json)
|
||||
hljs.registerLanguage('plaintext', plaintext)
|
||||
|
@ -41,6 +42,7 @@ const themeOverrides = {
|
|||
|
||||
<!-- top modal dialogs -->
|
||||
<connection-dialog />
|
||||
<group-dialog />
|
||||
<new-key-dialog />
|
||||
<add-fields-dialog />
|
||||
<rename-key-dialog />
|
||||
|
|
|
@ -11,6 +11,7 @@ import useTabStore from '../../stores/tab.js'
|
|||
import { useDialog } from 'naive-ui'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
|
||||
const valueComponents = {
|
||||
[types.STRING]: ContentValueString,
|
||||
|
@ -58,22 +59,13 @@ const onAddTab = () => {
|
|||
}
|
||||
|
||||
const i18n = useI18n()
|
||||
const confirmDialog = useConfirmDialog()
|
||||
const onCloseTab = (tabIndex) => {
|
||||
dialog.warning({
|
||||
title: i18n.t('close_confirm_title'),
|
||||
content: i18n.t('close_confirm'),
|
||||
positiveText: i18n.t('confirm'),
|
||||
negativeText: i18n.t('cancel'),
|
||||
closable: false,
|
||||
closeOnEsc: false,
|
||||
maskClosable: false,
|
||||
transformOrigin: 'center',
|
||||
onPositiveClick: () => {
|
||||
const tab = get(tabStore.tabs, tabIndex)
|
||||
if (tab != null) {
|
||||
connectionStore.closeConnection(tab.name)
|
||||
}
|
||||
},
|
||||
confirmDialog.warning(i18n.t('close_confirm'), () => {
|
||||
const tab = get(tabStore.tabs, tabIndex)
|
||||
if (tab != null) {
|
||||
connectionStore.closeConnection(tab.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -85,8 +85,8 @@ const onSaveConnection = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
message.success(i18n.t('new_conn_succ'))
|
||||
dialogStore.closeNewDialog()
|
||||
message.success(i18n.t('handle_succ'))
|
||||
onClose()
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
|
@ -132,7 +132,11 @@ const onTestConnection = async () => {
|
|||
}
|
||||
|
||||
const onClose = () => {
|
||||
dialogStore.closeNewDialog()
|
||||
if (isEditMode.value) {
|
||||
dialogStore.closeEditDialog()
|
||||
} else {
|
||||
dialogStore.closeNewDialog()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -162,7 +166,7 @@ const onClose = () => {
|
|||
<n-form-item :label="$t('conn_name')" path="name" required>
|
||||
<n-input v-model:value="generalForm.name" :placeholder="$t('conn_name_tip')" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('conn_group')" required>
|
||||
<n-form-item v-if="!isEditMode" :label="$t('conn_group')" required>
|
||||
<n-select v-model:value="generalForm.group" :options="groupOptions"></n-select>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('conn_addr')" path="addr" required>
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
<script setup>
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
import useDialog from '../../stores/dialog'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { isEmpty } from 'lodash'
|
||||
|
||||
/**
|
||||
* Dialog for create or rename group
|
||||
*/
|
||||
|
||||
const editGroup = ref('')
|
||||
const groupForm = reactive({
|
||||
name: '',
|
||||
})
|
||||
|
||||
const isRenameMode = computed(() => !isEmpty(editGroup.value))
|
||||
|
||||
const dialogStore = useDialog()
|
||||
const connectionStore = useConnectionStore()
|
||||
watch(
|
||||
() => dialogStore.groupDialogVisible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
groupForm.name = editGroup.value = dialogStore.editGroup
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const i18n = useI18n()
|
||||
const message = useMessage()
|
||||
const onConfirm = async () => {
|
||||
try {
|
||||
const { name } = groupForm
|
||||
if (isRenameMode.value) {
|
||||
const { success, msg } = await connectionStore.renameGroup(editGroup.value, name)
|
||||
if (success) {
|
||||
message.success(i18n.t('handle_succ'))
|
||||
} else {
|
||||
message.error(msg)
|
||||
}
|
||||
} else {
|
||||
const { success, msg } = await connectionStore.createGroup(name)
|
||||
if (success) {
|
||||
message.success(i18n.t('handle_succ'))
|
||||
} else {
|
||||
message.error(msg)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
message.error(e.message)
|
||||
}
|
||||
onClose()
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
if (isRenameMode.value) {
|
||||
dialogStore.closeNewGroupDialog()
|
||||
} else {
|
||||
dialogStore.closeRenameGroupDialog()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="dialogStore.groupDialogVisible"
|
||||
:closable="false"
|
||||
:close-on-esc="false"
|
||||
:mask-closable="false"
|
||||
:negative-button-props="{ size: 'medium' }"
|
||||
:negative-text="$t('cancel')"
|
||||
:positive-button-props="{ size: 'medium' }"
|
||||
:positive-text="$t('confirm')"
|
||||
:show-icon="false"
|
||||
:title="isRenameMode ? $t('rename_group') : $t('new_group')"
|
||||
preset="dialog"
|
||||
transform-origin="center"
|
||||
@positive-click="onConfirm"
|
||||
@negative-click="onClose"
|
||||
>
|
||||
<n-form
|
||||
:model="groupForm"
|
||||
:show-require-mark="false"
|
||||
label-align="left"
|
||||
label-placement="left"
|
||||
label-width="auto"
|
||||
>
|
||||
<n-form-item :label="$t('group_name')" required>
|
||||
<n-input v-model:value="groupForm.name" placeholder="" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -16,6 +16,10 @@ const connectionStore = useConnectionStore()
|
|||
const onSort = () => {
|
||||
dialogStore.openPreferencesDialog()
|
||||
}
|
||||
|
||||
const onDisconnectAll = () => {
|
||||
connectionStore.closeAllConnection()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -38,7 +42,7 @@ const onSort = () => {
|
|||
size="20"
|
||||
stroke-width="4"
|
||||
t-tooltip="new_group"
|
||||
@click="dialogStore.openNewKeyDialog('aa:bb')"
|
||||
@click="dialogStore.openNewGroupDialog()"
|
||||
/>
|
||||
<icon-button
|
||||
:disabled="!connectionStore.anyConnectionOpened"
|
||||
|
@ -47,7 +51,7 @@ const onSort = () => {
|
|||
size="20"
|
||||
stroke-width="4"
|
||||
t-tooltip="disconnect_all"
|
||||
@click="dialogStore.openNewKeyDialog('aa:bb')"
|
||||
@click="onDisconnectAll"
|
||||
/>
|
||||
<n-divider style="margin: 0 4px; --n-color: #aaa; width: 2px" vertical />
|
||||
<icon-button :icon="Sort" color="#555" size="20" stroke-width="4" t-tooltip="sort_conn" @click="onSort" />
|
||||
|
|
|
@ -15,6 +15,7 @@ import Connect from '../icons/Connect.vue'
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import useTabStore from '../../stores/tab.js'
|
||||
import Edit from '../icons/Edit.vue'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
|
||||
const i18n = useI18n()
|
||||
const loadingConnection = ref(false)
|
||||
|
@ -55,9 +56,9 @@ const renderIcon = (icon) => {
|
|||
const menuOptions = {
|
||||
[ConnectionType.Group]: ({ opened }) => [
|
||||
{
|
||||
key: 'group_reload',
|
||||
label: i18n.t('edit_conn_group'),
|
||||
icon: renderIcon(Config),
|
||||
key: 'group_rename',
|
||||
label: i18n.t('rename_conn_group'),
|
||||
icon: renderIcon(Edit),
|
||||
},
|
||||
{
|
||||
key: 'group_delete',
|
||||
|
@ -182,22 +183,24 @@ const openConnection = async (name) => {
|
|||
}
|
||||
|
||||
const dialog = useDialog()
|
||||
const removeConnection = async (name) => {
|
||||
dialog.warning({
|
||||
title: i18n.t('warning'),
|
||||
content: i18n.t('remove_conn_tip', { conn: name }),
|
||||
closable: false,
|
||||
autoFocus: false,
|
||||
transformOrigin: 'center',
|
||||
positiveText: i18n.t('confirm'),
|
||||
negativeText: i18n.t('cancel'),
|
||||
onPositiveClick: async () => {
|
||||
connectionStore.removeConnection(name).then(({ success, msg }) => {
|
||||
if (!success) {
|
||||
message.error(msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
const removeConnection = (name) => {
|
||||
confirmDialog.warning(i18n.t('remove_tip', { type: i18n.t('conn_name'), name }), async () => {
|
||||
connectionStore.removeConnection(name).then(({ success, msg }) => {
|
||||
if (!success) {
|
||||
message.error(msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const confirmDialog = useConfirmDialog()
|
||||
const removeGroup = async (name) => {
|
||||
confirmDialog.warning(i18n.t('remove_tip', { type: i18n.t('conn_group'), name }), async () => {
|
||||
connectionStore.deleteGroup(name).then(({ success, msg }) => {
|
||||
if (!success) {
|
||||
message.error(msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -233,7 +236,7 @@ const renderContextLabel = (option) => {
|
|||
|
||||
const handleSelectContextMenu = (key) => {
|
||||
contextMenuParam.show = false
|
||||
const { name, db, key: nodeKey, redisKey } = contextMenuParam.currentNode
|
||||
const { name, label, db, key: nodeKey, redisKey } = contextMenuParam.currentNode
|
||||
switch (key) {
|
||||
case 'server_open':
|
||||
openConnection(name).then(() => {})
|
||||
|
@ -247,6 +250,12 @@ const handleSelectContextMenu = (key) => {
|
|||
case 'server_close':
|
||||
connectionStore.closeConnection(name)
|
||||
break
|
||||
case 'group_rename':
|
||||
dialogStore.openRenameGroupDialog(label)
|
||||
break
|
||||
case 'group_delete':
|
||||
removeGroup(label)
|
||||
break
|
||||
}
|
||||
console.warn('TODO: handle context menu:' + key)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { ConnectionType } from '../../consts/connection_type.js'
|
|||
import { NIcon, useDialog, useMessage } from 'naive-ui'
|
||||
import Key from '../icons/Key.vue'
|
||||
import ToggleDb from '../icons/ToggleDb.vue'
|
||||
import { indexOf } from 'lodash'
|
||||
import { get, indexOf } from 'lodash'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Refresh from '../icons/Refresh.vue'
|
||||
import CopyLink from '../icons/CopyLink.vue'
|
||||
|
@ -15,6 +15,7 @@ import Connect from '../icons/Connect.vue'
|
|||
import useDialogStore from '../../stores/dialog.js'
|
||||
import { ClipboardSetText } from '../../../wailsjs/runtime/runtime.js'
|
||||
import useConnectionStore from '../../stores/connections.js'
|
||||
import { useConfirmDialog } from '../../utils/confirm_dialog.js'
|
||||
|
||||
const i18n = useI18n()
|
||||
const loading = ref(false)
|
||||
|
@ -269,6 +270,7 @@ const onLoadTree = async (node) => {
|
|||
}
|
||||
}
|
||||
|
||||
const confirmDialog = useConfirmDialog()
|
||||
const handleSelectContextMenu = (key) => {
|
||||
contextMenuParam.show = false
|
||||
const { name, db, key: nodeKey, redisKey } = contextMenuParam.currentNode
|
||||
|
@ -283,21 +285,12 @@ const handleSelectContextMenu = (key) => {
|
|||
break
|
||||
case 'key_remove':
|
||||
case 'value_remove':
|
||||
dialog.warning({
|
||||
title: i18n.t('warning'),
|
||||
content: i18n.t('delete_key_tip', { key: redisKey }),
|
||||
closable: false,
|
||||
autoFocus: false,
|
||||
transformOrigin: 'center',
|
||||
positiveText: i18n.t('confirm'),
|
||||
negativeText: i18n.t('cancel'),
|
||||
onPositiveClick: () => {
|
||||
connectionStore.removeKey(name, db, redisKey).then((success) => {
|
||||
if (success) {
|
||||
message.success(i18n.t('delete_key_succ', { key: redisKey }))
|
||||
}
|
||||
})
|
||||
},
|
||||
confirmDialog.warning(i18n.t('delete_key_tip', { key: redisKey }), () => {
|
||||
connectionStore.removeKey(name, db, redisKey).then((success) => {
|
||||
if (success) {
|
||||
message.success(i18n.t('delete_key_succ', { key: redisKey }))
|
||||
}
|
||||
})
|
||||
})
|
||||
break
|
||||
case 'key_copy':
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
"save": "Save",
|
||||
"new_conn": "Add New Connection",
|
||||
"new_group": "Add New Group",
|
||||
"rename_group": "Rename Group",
|
||||
"disconnect_all": "Disconnect all connections",
|
||||
"sort_conn": "Resort Connections",
|
||||
"reload_key": "Reload Current Key",
|
||||
"close_confirm_title": "Confirm Close",
|
||||
"close_confirm": "Confirm close this tab and connection",
|
||||
"opening_connection": "Opening Connection...",
|
||||
"remove_conn_tip": "Connection \"{conn}\" will be deleted",
|
||||
"remove_tip": "{type} \"{name}\" will be deleted",
|
||||
"ttl": "TTL",
|
||||
"forever": "Forever",
|
||||
"rename_key": "Rename Key",
|
||||
|
@ -38,6 +38,7 @@
|
|||
"remove_conn": "Delete Connection",
|
||||
"edit_conn": "Edit Connection Config",
|
||||
"edit_conn_group": "Edit Connection Group",
|
||||
"rename_conn_group": "Rename Connection Group",
|
||||
"remove_conn_group": "Delete Connection Group",
|
||||
"no_group": "No Group",
|
||||
"copy_path": "Copy Path",
|
||||
|
@ -50,6 +51,7 @@
|
|||
"advanced": "Advanced",
|
||||
"editor": "Editor",
|
||||
"conn_group": "Group",
|
||||
"group_name": "Group Name",
|
||||
"conn_name": "Name",
|
||||
"conn_addr": "Address",
|
||||
"conn_usr": "Username",
|
||||
|
@ -68,7 +70,6 @@
|
|||
"conn_advn_conn_timeout": "Connection Timeout",
|
||||
"conn_advn_exec_timeout": "Execution Timeout",
|
||||
"conn_advn_mark_color": "Mark Color",
|
||||
"new_conn_succ": "Create new connection success!",
|
||||
"second": "Second(s)",
|
||||
"new_key_name": "New Key Name",
|
||||
"new_key": "Add New Key",
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
"save": "保存",
|
||||
"new_conn": "添加新连接",
|
||||
"new_group": "添加新分组",
|
||||
"rename_group": "重命名分组",
|
||||
"disconnect_all": "断开所有连接",
|
||||
"sort_conn": "调整连接顺序",
|
||||
"reload_key": "重新载入此键内容",
|
||||
"close_confirm_title": "关闭确认",
|
||||
"close_confirm": "是否关闭当前连接",
|
||||
"opening_connection": "正在打开连接...",
|
||||
"remove_conn_tip": "连接 \"{conn}\" 将会被删除",
|
||||
"remove_tip": "{type} \"{name}\" 将会被删除",
|
||||
"ttl": "TTL",
|
||||
"forever": "永久",
|
||||
"rename_key": "重命名键",
|
||||
|
@ -40,6 +40,7 @@
|
|||
"remove_conn": "删除连接",
|
||||
"edit_conn": "编辑连接配置",
|
||||
"edit_conn_group": "编辑连接分组",
|
||||
"rename_conn_group": "重命名连接分组",
|
||||
"remove_conn_group": "删除连接分组",
|
||||
"no_group": "无分组",
|
||||
"copy_path": "复制路径",
|
||||
|
@ -51,7 +52,8 @@
|
|||
"general": "常规配置",
|
||||
"advanced": "高级配置",
|
||||
"editor": "编辑器",
|
||||
"conn_group": "所属分组",
|
||||
"conn_group": "分组",
|
||||
"group_name": "分组名",
|
||||
"conn_name": "连接名",
|
||||
"conn_addr": "连接地址",
|
||||
"conn_usr": "用户名",
|
||||
|
@ -70,7 +72,6 @@
|
|||
"conn_advn_conn_timeout": "连接超时",
|
||||
"conn_advn_exec_timeout": "执行超时",
|
||||
"conn_advn_mark_color": "标记颜色",
|
||||
"new_conn_succ": "新建连接成功",
|
||||
"second": "秒",
|
||||
"new_key_name": "新键名",
|
||||
"new_key": "添加新键",
|
||||
|
|
|
@ -5,13 +5,16 @@ import {
|
|||
AddListItem,
|
||||
AddZSetValue,
|
||||
CloseConnection,
|
||||
CreateGroup,
|
||||
GetConnection,
|
||||
GetKeyValue,
|
||||
ListConnection,
|
||||
OpenConnection,
|
||||
OpenDatabase,
|
||||
RemoveConnection,
|
||||
RemoveGroup,
|
||||
RemoveKey,
|
||||
RenameGroup,
|
||||
RenameKey,
|
||||
SaveConnection,
|
||||
SetHashValue,
|
||||
|
@ -76,29 +79,23 @@ const useConnectionStore = defineStore('connections', {
|
|||
const conns = []
|
||||
const groups = []
|
||||
const { data = [{ groupName: '', connections: [] }] } = await ListConnection()
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const group = data[i]
|
||||
// Top level group
|
||||
if (isEmpty(group.groupName)) {
|
||||
const len = size(group.connections)
|
||||
for (let j = 0; j < len; j++) {
|
||||
const item = group.connections[j]
|
||||
conns.push({
|
||||
key: item.name,
|
||||
label: item.name,
|
||||
name: item.name,
|
||||
type: ConnectionType.Server,
|
||||
// isLeaf: false,
|
||||
})
|
||||
}
|
||||
for (const conn of data) {
|
||||
if (conn.type !== 'group') {
|
||||
// top level
|
||||
conns.push({
|
||||
key: conn.name,
|
||||
label: conn.name,
|
||||
name: conn.name,
|
||||
type: ConnectionType.Server,
|
||||
// isLeaf: false,
|
||||
})
|
||||
} else {
|
||||
groups.push(group.groupName)
|
||||
// Custom group
|
||||
// custom group
|
||||
groups.push(conn.name)
|
||||
const subConns = get(conn, 'connections', [])
|
||||
const children = []
|
||||
const len = size(group.connections)
|
||||
for (let j = 0; j < len; j++) {
|
||||
const item = group.connections[j]
|
||||
const value = group.groupName + '/' + item.name
|
||||
for (const item of subConns) {
|
||||
const value = conn.name + '/' + item.name
|
||||
children.push({
|
||||
key: value,
|
||||
label: item.name,
|
||||
|
@ -108,8 +105,8 @@ const useConnectionStore = defineStore('connections', {
|
|||
})
|
||||
}
|
||||
conns.push({
|
||||
key: group.groupName,
|
||||
label: group.groupName,
|
||||
key: conn.name,
|
||||
label: conn.name,
|
||||
type: ConnectionType.Group,
|
||||
children,
|
||||
})
|
||||
|
@ -127,7 +124,6 @@ const useConnectionStore = defineStore('connections', {
|
|||
async getConnectionProfile(name) {
|
||||
try {
|
||||
const { data, success } = await GetConnection(name)
|
||||
console.log(JSON.stringify(data))
|
||||
if (success) {
|
||||
return data
|
||||
}
|
||||
|
@ -263,6 +259,20 @@ const useConnectionStore = defineStore('connections', {
|
|||
return true
|
||||
},
|
||||
|
||||
/**
|
||||
* Close all connection
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async closeAllConnection() {
|
||||
for (const name in this.databases) {
|
||||
await CloseConnection(name)
|
||||
}
|
||||
|
||||
this.databases = {}
|
||||
const tabStore = useTabStore()
|
||||
tabStore.removeAllTab()
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove connection
|
||||
* @param name
|
||||
|
@ -279,6 +289,53 @@ const useConnectionStore = defineStore('connections', {
|
|||
return { success: true }
|
||||
},
|
||||
|
||||
/**
|
||||
* Create connection group
|
||||
* @param name
|
||||
* @returns {Promise<{success: boolean, [msg]: string}>}
|
||||
*/
|
||||
async createGroup(name) {
|
||||
const { success, msg } = await CreateGroup(name)
|
||||
if (!success) {
|
||||
return { success: false, msg }
|
||||
}
|
||||
await this.initConnections(true)
|
||||
return { success: true }
|
||||
},
|
||||
|
||||
/**
|
||||
* Rename connection group
|
||||
* @param name
|
||||
* @param newName
|
||||
* @returns {Promise<{success: boolean, [msg]: string}>}
|
||||
*/
|
||||
async renameGroup(name, newName) {
|
||||
if (name === newName) {
|
||||
return { success: true }
|
||||
}
|
||||
const { success, msg } = await RenameGroup(name, newName)
|
||||
if (!success) {
|
||||
return { success: false, msg }
|
||||
}
|
||||
await this.initConnections(true)
|
||||
return { success: true }
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove group by name
|
||||
* @param {string} name
|
||||
* @param {boolean} [includeConn]
|
||||
* @returns {Promise<{success: boolean, [msg]: string}>}
|
||||
*/
|
||||
async deleteGroup(name, includeConn) {
|
||||
const { success, msg } = await RemoveGroup(name, includeConn === true)
|
||||
if (!success) {
|
||||
return { success: false, msg }
|
||||
}
|
||||
await this.initConnections(true)
|
||||
return { success: true }
|
||||
},
|
||||
|
||||
/**
|
||||
* Open database and load all keys
|
||||
* @param connName
|
||||
|
|
|
@ -6,6 +6,9 @@ const useDialogStore = defineStore('dialog', {
|
|||
connDialogVisible: false,
|
||||
connParam: null,
|
||||
|
||||
groupDialogVisible: false,
|
||||
editGroup: '',
|
||||
|
||||
/**
|
||||
* @property {string} prefix
|
||||
* @property {string} server
|
||||
|
@ -58,6 +61,21 @@ const useDialogStore = defineStore('dialog', {
|
|||
this.connDialogVisible = false
|
||||
},
|
||||
|
||||
openNewGroupDialog() {
|
||||
this.groupDialogVisible = true
|
||||
},
|
||||
closeNewGroupDialog() {
|
||||
this.groupDialogVisible = false
|
||||
},
|
||||
|
||||
openRenameGroupDialog(name) {
|
||||
this.editGroup = name
|
||||
this.groupDialogVisible = true
|
||||
},
|
||||
closeRenameGroupDialog() {
|
||||
this.groupDialogVisible = false
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} server
|
||||
|
|
|
@ -199,7 +199,7 @@ const useTabStore = defineStore('tab', {
|
|||
},
|
||||
removeAllTab() {
|
||||
this.tabList = []
|
||||
this.newBlankTab()
|
||||
this._setActivatedIndex(-1, false)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { createDiscreteApi } from 'naive-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const { dialog } = createDiscreteApi(['dialog'])
|
||||
|
||||
export function useConfirmDialog() {
|
||||
let i18n
|
||||
onMounted(() => {
|
||||
i18n = useI18n()
|
||||
})
|
||||
return {
|
||||
warning: (content, onConfirm) => {
|
||||
dialog.warning({
|
||||
title: i18n.t('warning'),
|
||||
content: content,
|
||||
closable: false,
|
||||
autoFocus: false,
|
||||
transformOrigin: 'center',
|
||||
positiveText: i18n.t('confirm'),
|
||||
negativeText: i18n.t('cancel'),
|
||||
onPositiveClick: () => {
|
||||
onConfirm && onConfirm()
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue