Compare commits
No commits in common. "f0c9b745456cdce2af3d94ecf172904432855b3f" and "abf5534165d887cc92d4e3119e8f6114c7d2ee9e" have entirely different histories.
f0c9b74545
...
abf5534165
|
@ -1,8 +1,9 @@
|
||||||
package convutil
|
package convutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
strutil "tinyrdm/backend/utils/string"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type JsonConvert struct{}
|
type JsonConvert struct{}
|
||||||
|
@ -15,11 +16,18 @@ func (JsonConvert) Decode(str string) (string, bool) {
|
||||||
trimedStr := strings.TrimSpace(str)
|
trimedStr := strings.TrimSpace(str)
|
||||||
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
||||||
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
||||||
return strutil.JSONBeautify(trimedStr, " "), true
|
var out bytes.Buffer
|
||||||
|
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
||||||
|
return out.String(), true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return str, false
|
return str, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (JsonConvert) Encode(str string) (string, bool) {
|
func (JsonConvert) Encode(str string) (string, bool) {
|
||||||
return strutil.JSONMinify(str), true
|
var dst bytes.Buffer
|
||||||
|
if err := json.Compact(&dst, []byte(str)); err != nil {
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
return dst.String(), true
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package convutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
strutil "tinyrdm/backend/utils/string"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -20,16 +20,22 @@ func (UnicodeJsonConvert) Decode(str string) (string, bool) {
|
||||||
trimedStr := strings.TrimSpace(str)
|
trimedStr := strings.TrimSpace(str)
|
||||||
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
if (strings.HasPrefix(trimedStr, "{") && strings.HasSuffix(trimedStr, "}")) ||
|
||||||
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
(strings.HasPrefix(trimedStr, "[") && strings.HasSuffix(trimedStr, "]")) {
|
||||||
resultStr := strutil.JSONBeautify(trimedStr, " ")
|
var out bytes.Buffer
|
||||||
if quoteStr, ok := UnquoteUnicodeJson([]byte(resultStr)); ok {
|
if err := json.Indent(&out, []byte(trimedStr), "", " "); err == nil {
|
||||||
return string(quoteStr), true
|
if quoteStr, ok := UnquoteUnicodeJson(out.Bytes()); ok {
|
||||||
|
return string(quoteStr), true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str, false
|
return str, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (UnicodeJsonConvert) Encode(str string) (string, bool) {
|
func (UnicodeJsonConvert) Encode(str string) (string, bool) {
|
||||||
return strutil.JSONMinify(str), true
|
var dst bytes.Buffer
|
||||||
|
if err := json.Compact(&dst, []byte(str)); err != nil {
|
||||||
|
return str, false
|
||||||
|
}
|
||||||
|
return dst.String(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnquoteUnicodeJson(s []byte) ([]byte, bool) {
|
func UnquoteUnicodeJson(s []byte) ([]byte, bool) {
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
package strutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Convert from https://github.com/ObuchiYuki/SwiftJSONFormatter
|
|
||||||
|
|
||||||
// ArrayIterator defines the iterator for an array
|
|
||||||
type ArrayIterator[T any] struct {
|
|
||||||
array []T
|
|
||||||
head int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewArrayIterator initializes a new ArrayIterator with the given array
|
|
||||||
func NewArrayIterator[T any](array []T) *ArrayIterator[T] {
|
|
||||||
return &ArrayIterator[T]{
|
|
||||||
array: array,
|
|
||||||
head: -1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasNext returns true if there are more elements to iterate over
|
|
||||||
func (it *ArrayIterator[T]) HasNext() bool {
|
|
||||||
return it.head+1 < len(it.array)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeekNext returns the next element without advancing the iterator
|
|
||||||
func (it *ArrayIterator[T]) PeekNext() *T {
|
|
||||||
if it.head+1 < len(it.array) {
|
|
||||||
return &it.array[it.head+1]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next returns the next element and advances the iterator
|
|
||||||
func (it *ArrayIterator[T]) Next() *T {
|
|
||||||
defer func() {
|
|
||||||
it.head++
|
|
||||||
}()
|
|
||||||
return it.PeekNext()
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONBeautify formats a JSON string with indentation
|
|
||||||
func JSONBeautify(value string, indent string) string {
|
|
||||||
if len(indent) <= 0 {
|
|
||||||
indent = " "
|
|
||||||
}
|
|
||||||
return format(value, indent, "\n", " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONMinify formats a JSON string by removing all unnecessary whitespace
|
|
||||||
func JSONMinify(value string) string {
|
|
||||||
return format(value, "", "", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// format applies the specified formatting to a JSON string
|
|
||||||
func format(value string, indent string, newLine string, separator string) string {
|
|
||||||
var formatted strings.Builder
|
|
||||||
chars := NewArrayIterator([]rune(value))
|
|
||||||
indentLevel := 0
|
|
||||||
|
|
||||||
for chars.HasNext() {
|
|
||||||
if char := chars.Next(); char != nil {
|
|
||||||
switch *char {
|
|
||||||
case '{', '[':
|
|
||||||
formatted.WriteRune(*char)
|
|
||||||
consumeWhitespaces(chars)
|
|
||||||
peeked := chars.PeekNext()
|
|
||||||
if peeked != nil && (*peeked == '}' || *peeked == ']') {
|
|
||||||
chars.Next()
|
|
||||||
formatted.WriteRune(*peeked)
|
|
||||||
} else {
|
|
||||||
indentLevel++
|
|
||||||
formatted.WriteString(newLine)
|
|
||||||
formatted.WriteString(strings.Repeat(indent, indentLevel))
|
|
||||||
}
|
|
||||||
case '}', ']':
|
|
||||||
indentLevel--
|
|
||||||
formatted.WriteString(newLine)
|
|
||||||
formatted.WriteString(strings.Repeat(indent, max(0, indentLevel)))
|
|
||||||
formatted.WriteRune(*char)
|
|
||||||
case '"':
|
|
||||||
str := consumeString(chars)
|
|
||||||
//str = convertUnicodeString(str)
|
|
||||||
formatted.WriteString(str)
|
|
||||||
case ',':
|
|
||||||
consumeWhitespaces(chars)
|
|
||||||
formatted.WriteRune(',')
|
|
||||||
peeked := chars.PeekNext()
|
|
||||||
if peeked != nil && *peeked != '}' && *peeked != ']' {
|
|
||||||
formatted.WriteString(newLine)
|
|
||||||
formatted.WriteString(strings.Repeat(indent, max(0, indentLevel)))
|
|
||||||
}
|
|
||||||
case ':':
|
|
||||||
formatted.WriteString(":" + separator)
|
|
||||||
default:
|
|
||||||
if !unicode.IsSpace(*char) {
|
|
||||||
formatted.WriteRune(*char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatted.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumeWhitespaces advances the iterator past any whitespace characters
|
|
||||||
func consumeWhitespaces(iter *ArrayIterator[rune]) {
|
|
||||||
for iter.HasNext() {
|
|
||||||
if peeked := iter.PeekNext(); peeked != nil && unicode.IsSpace(*peeked) {
|
|
||||||
iter.Next()
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumeString consumes a JSON string value from the iterator
|
|
||||||
func consumeString(iter *ArrayIterator[rune]) string {
|
|
||||||
var sb strings.Builder
|
|
||||||
sb.WriteRune('"')
|
|
||||||
escaping := false
|
|
||||||
|
|
||||||
for iter.HasNext() {
|
|
||||||
if char := iter.Next(); char != nil {
|
|
||||||
if *char == '\n' {
|
|
||||||
return sb.String() // Unterminated string
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.WriteRune(*char)
|
|
||||||
|
|
||||||
if escaping {
|
|
||||||
escaping = false
|
|
||||||
} else {
|
|
||||||
if *char == '\\' {
|
|
||||||
escaping = true
|
|
||||||
}
|
|
||||||
if *char == '"' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertUnicodeString(str string) string {
|
|
||||||
// TODO: quote UTF-16 characters
|
|
||||||
//if len(str) > 2 {
|
|
||||||
// if unqStr, err := strconv.Unquote(str); err == nil {
|
|
||||||
// return strconv.Quote(unqStr)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
return str
|
|
||||||
}
|
|
|
@ -110,27 +110,12 @@ onMounted(async () => {
|
||||||
const maximised = await WindowIsMaximised()
|
const maximised = await WindowIsMaximised()
|
||||||
onToggleMaximize(maximised)
|
onToggleMaximize(maximised)
|
||||||
})
|
})
|
||||||
|
|
||||||
const onKeyShortcut = (e) => {
|
|
||||||
switch (e.key) {
|
|
||||||
case 'w':
|
|
||||||
if (e.metaKey) {
|
|
||||||
// close current tab
|
|
||||||
const tabStore = useTabStore()
|
|
||||||
const currentTab = tabStore.currentTab
|
|
||||||
if (currentTab != null) {
|
|
||||||
tabStore.closeTab(currentTab.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- app content-->
|
<!-- app content-->
|
||||||
<n-spin :show="props.loading" :style="spinStyle" :theme-overrides="{ opacitySpinning: 0 }">
|
<n-spin :show="props.loading" :style="spinStyle" :theme-overrides="{ opacitySpinning: 0 }">
|
||||||
<div id="app-content-wrapper" :style="wrapperStyle" class="flex-box-v" tabindex="0" @keydown="onKeyShortcut">
|
<div id="app-content-wrapper" :style="wrapperStyle" class="flex-box-v">
|
||||||
<!-- title bar -->
|
<!-- title bar -->
|
||||||
<div
|
<div
|
||||||
id="app-toolbar"
|
id="app-toolbar"
|
||||||
|
|
|
@ -2,24 +2,32 @@
|
||||||
import Server from '@/components/icons/Server.vue'
|
import Server from '@/components/icons/Server.vue'
|
||||||
import useTabStore from 'stores/tab.js'
|
import useTabStore from 'stores/tab.js'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { get, map } from 'lodash'
|
import { get, map } from 'lodash'
|
||||||
import { useThemeVars } from 'naive-ui'
|
import { useThemeVars } from 'naive-ui'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import useConnectionStore from 'stores/connections.js'
|
||||||
import { extraTheme } from '@/utils/extra_theme.js'
|
import { extraTheme } from '@/utils/extra_theme.js'
|
||||||
import usePreferencesStore from 'stores/preferences.js'
|
import usePreferencesStore from 'stores/preferences.js'
|
||||||
|
import useBrowserStore from 'stores/browser.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value content tab on head
|
* Value content tab on head
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const themeVars = useThemeVars()
|
const themeVars = useThemeVars()
|
||||||
|
const i18n = useI18n()
|
||||||
const tabStore = useTabStore()
|
const tabStore = useTabStore()
|
||||||
const connectionStore = useConnectionStore()
|
const connectionStore = useConnectionStore()
|
||||||
|
const browserStore = useBrowserStore()
|
||||||
const prefStore = usePreferencesStore()
|
const prefStore = usePreferencesStore()
|
||||||
|
|
||||||
const onCloseTab = (tabIndex) => {
|
const onCloseTab = (tabIndex) => {
|
||||||
const tab = get(tabStore.tabs, tabIndex)
|
const tab = get(tabStore.tabs, tabIndex)
|
||||||
tabStore.closeTab(tab.name)
|
if (tab != null) {
|
||||||
|
$dialog.warning(i18n.t('dialogue.close_confirm', { name: tab.name }), () => {
|
||||||
|
browserStore.closeConnection(tab.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabMarkColor = computed(() => {
|
const tabMarkColor = computed(() => {
|
||||||
|
|
|
@ -80,11 +80,9 @@ const refreshInfo = async (force) => {
|
||||||
}
|
}
|
||||||
if (!isEmpty(props.server) && browserStore.isConnected(props.server)) {
|
if (!isEmpty(props.server) && browserStore.isConnected(props.server)) {
|
||||||
try {
|
try {
|
||||||
const info = await browserStore.getServerInfo(props.server, true)
|
const info = await browserStore.getServerInfo(props.server)
|
||||||
if (!isEmpty(info)) {
|
serverInfo.value = info
|
||||||
serverInfo.value = info
|
_updateChart(info)
|
||||||
_updateChart(info)
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
pageState.loading = false
|
pageState.loading = false
|
||||||
pageState.autoLoading = false
|
pageState.autoLoading = false
|
||||||
|
|
|
@ -343,11 +343,10 @@ const useBrowserStore = defineStore('browser', {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} server
|
* @param server
|
||||||
* @param {boolean} mute
|
|
||||||
* @returns {Promise<{}>}
|
* @returns {Promise<{}>}
|
||||||
*/
|
*/
|
||||||
async getServerInfo(server, mute) {
|
async getServerInfo(server) {
|
||||||
try {
|
try {
|
||||||
const { success, data, msg } = await ServerInfo(server)
|
const { success, data, msg } = await ServerInfo(server)
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -357,7 +356,7 @@ const useBrowserStore = defineStore('browser', {
|
||||||
serverInst.stats = data
|
serverInst.stats = data
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
} else if (!isEmpty(msg) && mute !== true) {
|
} else if (!isEmpty(msg)) {
|
||||||
$message.warning(msg)
|
$message.warning(msg)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { assign, find, findIndex, get, includes, indexOf, isEmpty, pullAt, remove, set, size } from 'lodash'
|
import { assign, find, findIndex, get, includes, indexOf, isEmpty, pullAt, remove, set, size } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { TabItem } from '@/objects/tabItem.js'
|
import { TabItem } from '@/objects/tabItem.js'
|
||||||
import useBrowserStore from 'stores/browser.js'
|
|
||||||
import { i18nGlobal } from '@/utils/i18n.js'
|
|
||||||
|
|
||||||
const useTabStore = defineStore('tab', {
|
const useTabStore = defineStore('tab', {
|
||||||
/**
|
/**
|
||||||
|
@ -134,17 +132,6 @@ const useTabStore = defineStore('tab', {
|
||||||
this.upsertTab({ server, clearValue: true })
|
this.upsertTab({ server, clearValue: true })
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} tabName
|
|
||||||
*/
|
|
||||||
closeTab(tabName) {
|
|
||||||
$dialog.warning(i18nGlobal.t('dialogue.close_confirm', { name: tabName }), () => {
|
|
||||||
const browserStore = useBrowserStore()
|
|
||||||
browserStore.closeConnection(tabName)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update or insert a new tab if not exists with the same name
|
* update or insert a new tab if not exists with the same name
|
||||||
* @param {string} subTab
|
* @param {string} subTab
|
||||||
|
|
Loading…
Reference in New Issue