Compare commits
4 Commits
bc66c63b3d
...
cefc5a5078
Author | SHA1 | Date |
---|---|---|
Lykin | cefc5a5078 | |
Lykin | 8c69ce7257 | |
Lykin | c497423711 | |
Lykin | 927678ebbb |
23
README.md
23
README.md
|
@ -28,20 +28,20 @@ Linux.</strong>
|
|||
|
||||
* Super lightweight, built on Webview2, without embedded browsers (Thanks
|
||||
to [Wails](https://github.com/wailsapp/wails)).
|
||||
* More elegant UI, frameless, offering light and dark themes (Thanks to [Naive UI](https://github.com/tusen-ai/naive-ui)
|
||||
* Provides visually and user-friendly UI, light and dark themes (Thanks to [Naive UI](https://github.com/tusen-ai/naive-ui)
|
||||
and [IconPark](https://iconpark.oceanengine.com)).
|
||||
* Multi-language support ([Need more languages ? Click here to contribute](.github/CONTRIBUTING.md)).
|
||||
* Better connection management: supports SSH Tunnel/SSL/Sentinel Mode/Cluster Mode.
|
||||
* Visualize key value operations, CRUD support for Lists, Hashes, Strings, Sets, Sorted Sets, and Streams.
|
||||
* Support multiple data viewing format and decode/decompression methods.
|
||||
* Use SCAN for segmented loading, making it easy to list millions of keys.
|
||||
* Operation command execution logs.
|
||||
* Provides command-line operations.
|
||||
* Provides slow logs.
|
||||
* Logs list for command operation history.
|
||||
* Provides command-line mode.
|
||||
* Provides slow logs list.
|
||||
* Segmented loading and querying for List/Hash/Set/Sorted Set.
|
||||
* Decode/decompression display for value of List/Hash/Set/Sorted Set.
|
||||
* Inbuilt advanced editor - Monaco Editor.
|
||||
* Real-time commands monitoring.
|
||||
* Provide value decode/decompression for List/Hash/Set/Sorted Set.
|
||||
* Integrate with Monaco Editor
|
||||
* Support real-time commands monitoring.
|
||||
* Support import/export data.
|
||||
|
||||
## Roadmap
|
||||
|
@ -89,7 +89,12 @@ npm install --prefix ./frontend
|
|||
```bash
|
||||
wails dev
|
||||
```
|
||||
## About
|
||||
|
||||
## License
|
||||
### Sponsor
|
||||
|
||||
Tiny RDM is licensed under [GNU General Public](/LICENSE) license.
|
||||
If this project helpful for you, feel free to buy me a cup of coffee ☕️.
|
||||
|
||||
* Wechat Sponsor
|
||||
|
||||
<img src="docs/images/wechat_sponsor.jpg" alt="wechat" width="200" />
|
||||
|
|
27
README_zh.md
27
README_zh.md
|
@ -10,8 +10,6 @@
|
|||
![GitHub All Releases](https://img.shields.io/github/downloads/tiny-craft/tiny-rdm/total)
|
||||
[![GitHub stars](https://img.shields.io/github/stars/tiny-craft/tiny-rdm)](https://github.com/tiny-craft/tiny-rdm/stargazers)
|
||||
[![GitHub forks](https://img.shields.io/github/forks/tiny-craft/tiny-rdm)](https://github.com/tiny-craft/tiny-rdm/fork)
|
||||
[![Discord](https://img.shields.io/discord/1170373259133456434?label=Discord&color=5865F2)](https://discord.gg/VTFbBMGjWh)
|
||||
[![X](https://img.shields.io/badge/Twitter-black?logo=x&logoColor=white)](https://twitter.com/Lykin53448)
|
||||
|
||||
<strong>一个现代化轻量级的跨平台Redis桌面客户端,支持Mac、Windows和Linux</strong>
|
||||
</div>
|
||||
|
@ -25,7 +23,7 @@
|
|||
## 功能特性
|
||||
|
||||
* 极度轻量,基于Webview2,无内嵌浏览器(感谢[Wails](https://github.com/wailsapp/wails))
|
||||
* 更精美的界面,无边框窗口,提供浅色/深色主题(感谢[Naive UI](https://github.com/tusen-ai/naive-ui)
|
||||
* 界面精美易用,提供浅色/深色主题(感谢[Naive UI](https://github.com/tusen-ai/naive-ui)
|
||||
和 [IconPark](https://iconpark.oceanengine.com))
|
||||
* 多国语言支持:英文/中文([需要更多语言支持?点我贡献语言](.github/CONTRIBUTING_zh.md))
|
||||
* 更好用的连接管理:支持SSH隧道/SSL/哨兵模式/集群模式
|
||||
|
@ -89,11 +87,24 @@ wails dev
|
|||
|
||||
## 关于
|
||||
|
||||
此APP由我个人开发,也作为本人第一个开源项目的尝试,由于精力有限,可能会存在BUG或者使用体验上的问题,欢迎提交issue和PR。
|
||||
同时本人也在探索开源代码、独立开发和盈利性商业应用之间的平衡关系,欢迎有共同意向的小伙伴加入群聊探讨和交换想法。
|
||||
如果你也同为独立开发者(团队),喜欢开源,或者对Tiny Craft的相关产品感兴趣,可以关注微信公众号或者加入QQ群,探讨心得,反馈意见,交个朋友。
|
||||
|
||||
* QQ群:831077639
|
||||
### 微信公众号(用户交流微信群)
|
||||
|
||||
## 开源许可
|
||||
我会不定期更新一些关于独立开发的思考和感悟,以及独立产品的介绍,欢迎扫码关注~👏
|
||||
|
||||
Tiny RDM 基于 [GNU General Public](/LICENSE) 开源协议.
|
||||
<img src="docs/images/wechat_official.png" alt="wechat" width="360" />
|
||||
|
||||
### 独立开发互助QQ群
|
||||
|
||||
```
|
||||
831077639
|
||||
```
|
||||
|
||||
### 赞助
|
||||
|
||||
该项目完全为爱发电,如果对你有所帮助,可以请作者喝杯咖啡 ☕️
|
||||
|
||||
* 微信赞赏
|
||||
|
||||
<img src="docs/images/wechat_sponsor.jpg" alt="wechat" width="200" />
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
|
@ -21,7 +21,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.2",
|
||||
"naive-ui": "^2.37.0",
|
||||
"naive-ui": "^2.36.0",
|
||||
"prettier": "^3.1.1",
|
||||
"unplugin-auto-import": "^0.17.3",
|
||||
"unplugin-icons": "^0.18.1",
|
||||
|
@ -1545,9 +1545,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/naive-ui": {
|
||||
"version": "2.37.0",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.37.0.tgz",
|
||||
"integrity": "sha512-TcuXM1zysnK6i/7o2ZqNjcLp3QMmcdSLWWiXcpEk+xdGpkJzs53/OXNpF4CoDM/npjha7qqtB8Pl17YPN5egFw==",
|
||||
"version": "2.36.0",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.36.0.tgz",
|
||||
"integrity": "sha512-r1ydtEm1Ryf/aWpbLCf32mQAGK99jd1eXgpkCtIomcBRZeAtusfy6zCtIpCppoCuIKM3BW5DMafhVxilubk/lQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@css-render/plugin-bem": "^0.15.12",
|
||||
|
@ -1557,7 +1557,6 @@
|
|||
"@types/lodash-es": "^4.17.9",
|
||||
"async-validator": "^4.2.5",
|
||||
"css-render": "^0.15.12",
|
||||
"csstype": "^3.1.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns-tz": "^2.0.0",
|
||||
"evtd": "^0.2.4",
|
||||
|
@ -1568,18 +1567,12 @@
|
|||
"treemate": "^0.3.11",
|
||||
"vdirs": "^0.1.8",
|
||||
"vooks": "^0.2.12",
|
||||
"vueuc": "^0.4.58"
|
||||
"vueuc": "^0.4.54"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/naive-ui/node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz",
|
||||
|
@ -3401,9 +3394,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"naive-ui": {
|
||||
"version": "2.37.0",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.37.0.tgz",
|
||||
"integrity": "sha512-TcuXM1zysnK6i/7o2ZqNjcLp3QMmcdSLWWiXcpEk+xdGpkJzs53/OXNpF4CoDM/npjha7qqtB8Pl17YPN5egFw==",
|
||||
"version": "2.36.0",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.36.0.tgz",
|
||||
"integrity": "sha512-r1ydtEm1Ryf/aWpbLCf32mQAGK99jd1eXgpkCtIomcBRZeAtusfy6zCtIpCppoCuIKM3BW5DMafhVxilubk/lQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@css-render/plugin-bem": "^0.15.12",
|
||||
|
@ -3413,7 +3406,6 @@
|
|||
"@types/lodash-es": "^4.17.9",
|
||||
"async-validator": "^4.2.5",
|
||||
"css-render": "^0.15.12",
|
||||
"csstype": "^3.1.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns-tz": "^2.0.0",
|
||||
"evtd": "^0.2.4",
|
||||
|
@ -3424,15 +3416,7 @@
|
|||
"treemate": "^0.3.11",
|
||||
"vdirs": "^0.1.8",
|
||||
"vooks": "^0.2.12",
|
||||
"vueuc": "^0.4.58"
|
||||
},
|
||||
"dependencies": {
|
||||
"csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"dev": true
|
||||
}
|
||||
"vueuc": "^0.4.54"
|
||||
}
|
||||
},
|
||||
"nanoid": {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.2",
|
||||
"naive-ui": "^2.37.0",
|
||||
"naive-ui": "^2.36.0",
|
||||
"prettier": "^3.1.1",
|
||||
"unplugin-auto-import": "^0.17.3",
|
||||
"unplugin-icons": "^0.18.1",
|
||||
|
|
|
@ -1 +1 @@
|
|||
6dd5fc2cecb3eb5a0c7297245ac11808
|
||||
41f065f6e9d8aa8ad43c4d2d8065d48a
|
|
@ -60,10 +60,10 @@ const columns = computed(() => [
|
|||
ellipsis: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
},
|
||||
render: ({ client, addr }, index) => {
|
||||
|
|
|
@ -90,10 +90,10 @@ const fieldColumn = computed(() => ({
|
|||
ellipsis: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
lineClamp: 10,
|
||||
},
|
||||
|
@ -122,10 +122,10 @@ const valueColumn = computed(() => ({
|
|||
: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
},
|
||||
// filterOptionValue: valueFilterOption.value,
|
||||
|
|
|
@ -91,10 +91,10 @@ const valueColumn = computed(() => ({
|
|||
: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
},
|
||||
filterOptionValue: valueFilterOption.value,
|
||||
|
|
|
@ -90,10 +90,10 @@ const valueColumn = computed(() => ({
|
|||
: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
},
|
||||
filterOptionValue: valueFilterOption.value,
|
||||
|
|
|
@ -139,10 +139,10 @@ const valueColumn = computed(() => ({
|
|||
: {
|
||||
tooltip: {
|
||||
style: {
|
||||
maxWidth: '80vw',
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'scroll',
|
||||
maxWidth: '50vw',
|
||||
maxHeight: '50vh',
|
||||
},
|
||||
scrollable: true,
|
||||
},
|
||||
},
|
||||
filterOptionValue: valueFilterOption.value,
|
||||
|
|
|
@ -64,7 +64,7 @@ const resetAffected = () => {
|
|||
deleteForm.affectedKeys = []
|
||||
}
|
||||
|
||||
const logLines = computed(() => {
|
||||
const keyLines = computed(() => {
|
||||
return map(deleteForm.affectedKeys, (k) => decodeRedisKey(k))
|
||||
})
|
||||
|
||||
|
@ -126,12 +126,13 @@ const onClose = () => {
|
|||
embedded
|
||||
size="small">
|
||||
<n-skeleton v-if="deleteForm.loadingAffected" :repeat="10" text />
|
||||
<n-log
|
||||
v-else
|
||||
:line-height="1.5"
|
||||
:lines="logLines"
|
||||
:rows="10"
|
||||
style="user-select: text; cursor: text" />
|
||||
<n-virtual-list v-else :item-size="25" :items="keyLines" class="list-wrapper">
|
||||
<template #default="{ item }">
|
||||
<div class="line-item content-value">
|
||||
{{ item }}
|
||||
</div>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
</n-card>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
|
@ -152,7 +153,7 @@ const onClose = () => {
|
|||
:disabled="isEmpty(deleteForm.affectedKeys)"
|
||||
:focusable="false"
|
||||
:loading="loading"
|
||||
type="error"
|
||||
type="primary"
|
||||
@click="onConfirmDelete">
|
||||
{{ $t('dialogue.key.confirm_delete_key', { num: size(deleteForm.affectedKeys) }) }}
|
||||
</n-button>
|
||||
|
@ -161,4 +162,15 @@ const onClose = () => {
|
|||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.line-item {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
box-sizing: border-box;
|
||||
max-height: 180px;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -95,7 +95,13 @@ const onClose = () => {
|
|||
:title="$t('dialogue.key.affected_key') + `(${size(exportKeyForm.keys)})`"
|
||||
embedded
|
||||
size="small">
|
||||
<n-log :line-height="1.5" :lines="keyLines" :rows="10" style="user-select: text; cursor: text" />
|
||||
<n-virtual-list :item-size="25" :items="keyLines" class="list-wrapper">
|
||||
<template #default="{ item }">
|
||||
<div class="line-item content-value">
|
||||
{{ item }}
|
||||
</div>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
</n-card>
|
||||
</n-form>
|
||||
</n-spin>
|
||||
|
@ -118,4 +124,15 @@ const onClose = () => {
|
|||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.line-item {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
box-sizing: border-box;
|
||||
max-height: 180px;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { computed, reactive, ref, watchEffect } from 'vue'
|
|||
import useDialog from 'stores/dialog'
|
||||
import useBrowserStore from 'stores/browser.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { isEmpty } from 'lodash'
|
||||
import { isEmpty, size } from 'lodash'
|
||||
import TtlInput from '@/components/common/TtlInput.vue'
|
||||
|
||||
const ttlForm = reactive({
|
||||
|
@ -42,6 +42,14 @@ const isBatchAction = computed(() => {
|
|||
return !isEmpty(ttlForm.keys)
|
||||
})
|
||||
|
||||
const title = computed(() => {
|
||||
if (isBatchAction.value) {
|
||||
return i18n.t('dialogue.ttl.title_batch', { count: size(ttlForm.keys) })
|
||||
} else {
|
||||
return i18n.t('dialogue.ttl.title')
|
||||
}
|
||||
})
|
||||
|
||||
const i18n = useI18n()
|
||||
const quickOption = computed(() => [
|
||||
{ value: -1, unit: 1, label: i18n.t('interface.forever') },
|
||||
|
@ -94,9 +102,7 @@ const onConfirm = async () => {
|
|||
:positive-button-props="{ focusable: false, size: 'medium', loading: procssing }"
|
||||
:positive-text="$t('common.save')"
|
||||
:show-icon="false"
|
||||
:title="
|
||||
isBatchAction ? $t('dialogue.ttl.title_batch', { count: size(ttlForm.keys) }) : $t('dialogue.ttl.title')
|
||||
"
|
||||
:title="title"
|
||||
preset="dialog"
|
||||
transform-origin="center">
|
||||
<n-form :model="ttlForm" :show-require-mark="false" label-placement="top">
|
||||
|
|
Loading…
Reference in New Issue