perf: add behavior tracking instructions and switch options (#181)

This commit is contained in:
Lykin 2024-03-14 00:40:39 +08:00
parent e3ccb06a96
commit de7cdb5bd4
16 changed files with 216 additions and 19 deletions

View File

@ -27,8 +27,8 @@ func (p *PreferencesStorage) DefaultPreferences() types.Preferences {
} }
func (p *PreferencesStorage) getPreferences() (ret types.Preferences) { func (p *PreferencesStorage) getPreferences() (ret types.Preferences) {
b, err := p.storage.Load()
ret = p.DefaultPreferences() ret = p.DefaultPreferences()
b, err := p.storage.Load()
if err != nil { if err != nil {
return return
} }

View File

@ -24,6 +24,7 @@ func NewPreferences() Preferences {
ScanSize: consts.DEFAULT_SCAN_SIZE, ScanSize: consts.DEFAULT_SCAN_SIZE,
KeyIconStyle: 0, KeyIconStyle: 0,
CheckUpdate: true, CheckUpdate: true,
AllowTrack: true,
}, },
Editor: PreferencesEditor{ Editor: PreferencesEditor{
FontSize: consts.DEFAULT_FONT_SIZE, FontSize: consts.DEFAULT_FONT_SIZE,
@ -41,6 +42,7 @@ func NewPreferences() Preferences {
} }
type PreferencesBehavior struct { type PreferencesBehavior struct {
Welcomed bool `json:"welcomed" yaml:"welcomed"`
AsideWidth int `json:"asideWidth" yaml:"aside_width"` AsideWidth int `json:"asideWidth" yaml:"aside_width"`
WindowWidth int `json:"windowWidth" yaml:"window_width"` WindowWidth int `json:"windowWidth" yaml:"window_width"`
WindowHeight int `json:"windowHeight" yaml:"window_height"` WindowHeight int `json:"windowHeight" yaml:"window_height"`
@ -61,6 +63,7 @@ type PreferencesGeneral struct {
UseSysProxyHttp bool `json:"useSysProxyHttp" yaml:"use_sys_proxy_http,omitempty"` UseSysProxyHttp bool `json:"useSysProxyHttp" yaml:"use_sys_proxy_http,omitempty"`
CheckUpdate bool `json:"checkUpdate" yaml:"check_update"` CheckUpdate bool `json:"checkUpdate" yaml:"check_update"`
SkipVersion string `json:"skipVersion" yaml:"skip_version,omitempty"` SkipVersion string `json:"skipVersion" yaml:"skip_version,omitempty"`
AllowTrack bool `json:"allowTrack" yaml:"allow_track"`
} }
type PreferencesEditor struct { type PreferencesEditor struct {

View File

@ -8,8 +8,6 @@
</head> </head>
<body spellcheck="false"> <body spellcheck="false">
<div id="app"></div> <div id="app"></div>
<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> <script src="./src/main.js" type="module"></script>
</body> </body>
</html> </html>

View File

@ -8,11 +8,11 @@ import AddFieldsDialog from './components/dialogs/AddFieldsDialog.vue'
import AppContent from './AppContent.vue' import AppContent from './AppContent.vue'
import GroupDialog from './components/dialogs/GroupDialog.vue' import GroupDialog from './components/dialogs/GroupDialog.vue'
import DeleteKeyDialog from './components/dialogs/DeleteKeyDialog.vue' import DeleteKeyDialog from './components/dialogs/DeleteKeyDialog.vue'
import { onMounted, ref, watch } from 'vue' import { h, onMounted, ref, watch } from 'vue'
import usePreferencesStore from './stores/preferences.js' import usePreferencesStore from './stores/preferences.js'
import useConnectionStore from './stores/connections.js' import useConnectionStore from './stores/connections.js'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { darkTheme } from 'naive-ui' import { darkTheme, NButton, NSpace } from 'naive-ui'
import KeyFilterDialog from './components/dialogs/KeyFilterDialog.vue' import KeyFilterDialog from './components/dialogs/KeyFilterDialog.vue'
import { WindowSetDarkTheme, WindowSetLightTheme } from 'wailsjs/runtime/runtime.js' import { WindowSetDarkTheme, WindowSetLightTheme } from 'wailsjs/runtime/runtime.js'
import { darkThemeOverrides, themeOverrides } from '@/utils/theme.js' import { darkThemeOverrides, themeOverrides } from '@/utils/theme.js'
@ -22,6 +22,8 @@ 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' import { Info } from 'wailsjs/go/services/systemService.js'
import DecoderDialog from '@/components/dialogs/DecoderDialog.vue' import DecoderDialog from '@/components/dialogs/DecoderDialog.vue'
import { enableTrack, loadModule, trackEvent } from '@/utils/analytics.js'
import { endsWith } from 'lodash'
const prefStore = usePreferencesStore() const prefStore = usePreferencesStore()
const connectionStore = useConnectionStore() const connectionStore = useConnectionStore()
@ -36,10 +38,64 @@ onMounted(async () => {
if (prefStore.autoCheckUpdate) { if (prefStore.autoCheckUpdate) {
prefStore.checkForUpdate() prefStore.checkForUpdate()
} }
loadModule(prefStore.general.allowTrack !== false).then(() => {
Info().then(({ data }) => { Info().then(({ data }) => {
// const {os, arch, version} = data if (endsWith(data.version, 'dev')) {
umami && umami.track('startup', data) enableTrack(false)
} else {
trackEvent('startup', data, true)
}
}) })
})
// show greetings and user behavior tracking statements
if (!!!prefStore.behavior.welcomed) {
const n = $notification.show({
title: i18n.t('dialogue.welcome.title'),
content: i18n.t('preferences.general.track_tip') + '\n\n' + i18n.t('dialogue.welcome.content'),
// duration: 5000,
keepAliveOnHover: true,
closable: false,
meta: ' ',
action: () =>
h(
NSpace,
{},
{
default: () => [
h(
NButton,
{
secondary: true,
type: 'tertiary',
onClick: () => {
prefStore.setAsWelcomed(false)
n.destroy()
},
},
{
default: () => i18n.t('dialogue.welcome.reject'),
},
),
h(
NButton,
{
secondary: true,
type: 'primary',
onClick: () => {
prefStore.setAsWelcomed(true)
n.destroy()
},
},
{
default: () => i18n.t('dialogue.welcome.accept'),
},
),
],
},
),
})
}
} finally { } finally {
initializing.value = false initializing.value = false
} }

View File

@ -258,6 +258,19 @@ const onClose = () => {
{{ $t('preferences.general.auto_check_update') }} {{ $t('preferences.general.auto_check_update') }}
</n-checkbox> </n-checkbox>
</n-form-item-gi> </n-form-item-gi>
<n-form-item-gi :label="$t('preferences.general.privacy')" :span="24">
<n-checkbox v-model:checked="prefStore.general.allowTrack">
{{ $t('preferences.general.allow_track') }}
<n-tooltip trigger="hover">
<template #trigger>
<n-icon :component="Help" />
</template>
<div class="text-block">
{{ $t('preferences.general.track_tip') }}
</div>
</n-tooltip>
</n-checkbox>
</n-form-item-gi>
</n-grid> </n-grid>
</n-form> </n-form>
</n-tab-pane> </n-tab-pane>

View File

@ -17,6 +17,7 @@ import { useRender } from '@/utils/render.js'
import wechatUrl from '@/assets/images/wechat_official.png' import wechatUrl from '@/assets/images/wechat_official.png'
import QRCode from '@/components/icons/QRCode.vue' import QRCode from '@/components/icons/QRCode.vue'
import Twitter from '@/components/icons/Twitter.vue' import Twitter from '@/components/icons/Twitter.vue'
import { trackEvent } from '@/utils/analytics.js'
const themeVars = useThemeVars() const themeVars = useThemeVars()
const render = useRender() const render = useRender()
@ -122,17 +123,17 @@ const onSelectPreferenceMenu = (key) => {
} }
const openWechatOfficial = () => { const openWechatOfficial = () => {
umami && umami.track('open', { target: 'wechat_official' }) trackEvent('open', { target: 'wechat_official' })
showWechat.value = true showWechat.value = true
} }
const openX = () => { const openX = () => {
umami && umami.track('open', { target: 'x' }) trackEvent('open', { target: 'x' })
BrowserOpenURL('https://twitter.com/LykinHuang') BrowserOpenURL('https://twitter.com/LykinHuang')
} }
const openGithub = () => { const openGithub = () => {
umami && umami.track('open', { target: 'github' }) trackEvent('open', { target: 'github' })
BrowserOpenURL('https://github.com/tiny-craft/tiny-rdm') BrowserOpenURL('https://github.com/tiny-craft/tiny-rdm')
} }

View File

@ -46,7 +46,10 @@
"key_icon_style2": "Dot", "key_icon_style2": "Dot",
"key_icon_style3": "Common", "key_icon_style3": "Common",
"update": "Update", "update": "Update",
"auto_check_update": "Auto check for updates" "auto_check_update": "Auto check for updates",
"privacy": "Privacy",
"allow_track": "Allows anonymous data to be collected",
"track_tip": "In order to provide a better user experience, Tiny RDM collects some anonymous data to help optimize the software and improve the user experience, please rest assured that this does not involve your personal privacy information."
}, },
"editor": { "editor": {
"name": "Editor", "name": "Editor",
@ -382,6 +385,12 @@
"later": "Later", "later": "Later",
"skip": "Skip This Version" "skip": "Skip This Version"
}, },
"welcome": {
"title": "Welcome to Tiny RDM",
"content": "If you have any concerns, you can turn off this data collection feature at any time by going to Preferences. If you have any questions, feel free to contact the developer. I hope Tiny RDM can become your helpful assistant!",
"accept": "Help Improve",
"reject": "Reject"
},
"about": { "about": {
"source": "Source Code", "source": "Source Code",
"website": "Official Website" "website": "Official Website"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "Punto", "key_icon_style2": "Punto",
"key_icon_style3": "Común", "key_icon_style3": "Común",
"update": "Actualizar", "update": "Actualizar",
"auto_check_update": "Buscar actualizaciones automáticamente" "auto_check_update": "Buscar actualizaciones automáticamente",
"privacy": "Política de Privacidad",
"allow_track":"Permitir recopilar datos anónimos",
"track_tip": "Con el fin de brindar una mejor experiencia de usuario, Tiny RDM recopila algunos datos anónimos para ayudar a optimizar el software y mejorar la experiencia del usuario. Tenga la seguridad de que esto no involucrará su información de privacidad personal."
}, },
"editor": { "editor": {
"name": "Editor", "name": "Editor",
@ -382,6 +385,12 @@
"later": "Más tarde", "later": "Más tarde",
"skip": "Omitir esta versión" "skip": "Omitir esta versión"
}, },
"welcome": {
"title": "¡Bienvenido a Tiny RDM!",
"content": "Si tiene alguna inquietud, puede desactivar esta función de recopilación de datos en cualquier momento yendo a Preferencias. Si tiene alguna pregunta, no dude en ponerse en contacto con el desarrollador. ¡Espero que Tiny RDM pueda ser un buen asistente para usted!",
"accept": "Ayudar a Mejorar",
"reject": "Rechazar"
},
"about": { "about": {
"source": "Código fuente", "source": "Código fuente",
"website": "Sitio web oficial" "website": "Sitio web oficial"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "Point", "key_icon_style2": "Point",
"key_icon_style3": "Commun", "key_icon_style3": "Commun",
"update": "Mise à jour", "update": "Mise à jour",
"auto_check_update": "Vérifier automatiquement les mises à jour" "auto_check_update": "Vérifier automatiquement les mises à jour",
"privacy": "Politique de confidentialité",
"allow_track":"Autoriser la collecte de données anonymes",
"track_tip":"Afin d'offrir une meilleure expérience utilisateur, Tiny RDM collecte certaines données anonymes pour aider à optimiser le logiciel et améliorer l'expérience utilisateur. Soyez assuré que cela n'implique pas vos informations personnelles et privées."
}, },
"editor": { "editor": {
"name": "Éditeur", "name": "Éditeur",
@ -382,6 +385,12 @@
"later": "Plus tard", "later": "Plus tard",
"skip": "Ignorer cette version" "skip": "Ignorer cette version"
}, },
"welcome": {
"title": "Bienvenue dans Tiny RDM!",
"content": "Si vous avez des inquiétudes, vous pouvez désactiver cette fonction de collecte de données à tout moment en allant dans les Préférences. Si vous avez des questions, n'hésitez pas à contacter le développeur. J'espère que Tiny RDM pourra être un bon assistant pour vous!",
"accept":"Aider à Améliorer",
"reject":"Rejeter"
},
"about": { "about": {
"source": "Code source", "source": "Code source",
"website": "Site officiel" "website": "Site officiel"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "ドットタイプ", "key_icon_style2": "ドットタイプ",
"key_icon_style3": "共通アイコン", "key_icon_style3": "共通アイコン",
"update": "更新", "update": "更新",
"auto_check_update": "自動でアップデートを確認" "auto_check_update": "自動でアップデートを確認",
"privacy": "プライバシーポリシー",
"allow_track":"匿名データの収集を許可する",
"track_tip":"ユーザーエクスペリエンスを改善するために、Tiny RDMは一部の匿名データを収集し、ソフトウェアの最適化とユーザーエクスペリエンスの向上に役立てています。個人プライバシー情報は含まれませんのでご安心ください。"
}, },
"editor": { "editor": {
"name": "エディター", "name": "エディター",
@ -382,6 +385,12 @@
"later": "後で", "later": "後で",
"skip": "このバージョンをスキップ" "skip": "このバージョンをスキップ"
}, },
"welcome": {
"title": "Tiny RDMをご利用いただきありがとうございます!",
"content": "ご不安な点がありましたら、いつでも「設定」から当該機能をオフにすることができます。ご不明な点がございましたら、開発者までお問い合わせください。Tiny RDMがお役に立てることを願っております。",
"accept":"改善の支援",
"reject":"拒否する"
},
"about": { "about": {
"source": "ソースコード", "source": "ソースコード",
"website": "公式ウェブサイト" "website": "公式ウェブサイト"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "점", "key_icon_style2": "점",
"key_icon_style3": "일반", "key_icon_style3": "일반",
"update": "업데이트", "update": "업데이트",
"auto_check_update": "자동 업데이트 확인" "auto_check_update": "자동 업데이트 확인",
"privacy": "개인정보 보호정책",
"allow_track":"익명 데이터 수집을 허용합니다",
"track_tip":"Tiny RDM은 사용자 경험을 개선하기 위해 일부 익명 데이터를 수집하여 소프트웨어를 최적화하고 사용자 경험을 향상시키는 데 도움을 줍니다. 이는 귀하의 개인 정보와는 무관함을 안심하셔도 됩니다."
}, },
"editor": { "editor": {
"name": "편집기", "name": "편집기",
@ -381,6 +384,12 @@
"later": "나중에", "later": "나중에",
"skip": "이 버전 건너뛰기" "skip": "이 버전 건너뛰기"
}, },
"welcome": {
"title": "Tiny RDM을 사용해 주셔서 감사합니다!",
"content": "걱정되는 부분이 있다면 언제든지 '설정'에서 이 기능을 끌 수 있습니다. 궁금한 점이 있으면 개발자에게 문의하세요. Tiny RDM이 여러분께 좋은 도우미가 되기를 바랍니다!",
"accept":"개선 지원",
"reject":"거절"
},
"about": { "about": {
"source": "소스 코드", "source": "소스 코드",
"website": "공식 웹사이트" "website": "공식 웹사이트"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "Ponto", "key_icon_style2": "Ponto",
"key_icon_style3": "Comum", "key_icon_style3": "Comum",
"update": "Atualizar", "update": "Atualizar",
"auto_check_update": "Verificar atualizações automaticamente" "auto_check_update": "Verificar atualizações automaticamente",
"privacy": "Política de Privacidade",
"allow_track":"Permitir a coleta de dados anônimos",
"track_tip":"Para fornecer uma melhor experiência ao usuário, o Tiny RDM coleta alguns dados anônimos para ajudar a otimizar o software e melhorar a experiência do usuário. Fique tranquilo, isso não envolve suas informações de privacidade pessoal."
}, },
"editor": { "editor": {
"name": "Editor", "name": "Editor",
@ -382,6 +385,12 @@
"later": "Depois", "later": "Depois",
"skip": "Ignorar Esta Versão" "skip": "Ignorar Esta Versão"
}, },
"welcome": {
"title": "Bem-vindo ao Tiny RDM!",
"content": "Se você tiver alguma preocupação, pode desativar esse recurso de coleta de dados a qualquer momento indo em Preferências. Se tiver alguma dúvida, sinta-se à vontade para entrar em contato com o desenvolvedor. Espero que o Tiny RDM possa se tornar um assistente útil para você!",
"accept":"Help Improve",
"reject":"Reject"
},
"about": { "about": {
"source": "Código Fonte", "source": "Código Fonte",
"website": "Site Oficial" "website": "Site Oficial"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "圆点类型", "key_icon_style2": "圆点类型",
"key_icon_style3": "通用图标", "key_icon_style3": "通用图标",
"update": "更新", "update": "更新",
"auto_check_update": "自动检查更新" "auto_check_update": "自动检查更新",
"privacy": "隐私策略",
"allow_track": "允许收集匿名数据",
"track_tip": "为了提供更好的用户体验Tiny RDM会收集一些匿名的数据以帮助优化软件和改进用户体验请放心这不会涉及到您的个人隐私信息。"
}, },
"editor": { "editor": {
"name": "编辑器", "name": "编辑器",
@ -382,6 +385,12 @@
"later": "稍后提醒我", "later": "稍后提醒我",
"skip": "忽略本次更新" "skip": "忽略本次更新"
}, },
"welcome": {
"title": "欢迎使用Tiny RDM",
"content": "如果您对此有任何顾虑,可以随时前往\"偏好设置\"中关闭此项数据收集功能。有任何问题可联系开发者希望Tiny RDM可以成为您的好帮手",
"accept": "帮助改进",
"reject": "不接受"
},
"about": { "about": {
"source": "源码地址", "source": "源码地址",
"website": "官方网站" "website": "官方网站"

View File

@ -46,7 +46,10 @@
"key_icon_style2": "點類型", "key_icon_style2": "點類型",
"key_icon_style3": "通用圖示", "key_icon_style3": "通用圖示",
"update": "更新", "update": "更新",
"auto_check_update": "自動檢查更新" "auto_check_update": "自動檢查更新",
"privacy": "隱私權政策",
"allow_track":"允許收集匿名數據",
"track_tip":"為了提供更好的使用者體驗Tiny RDM 會收集一些匿名的數據,以幫助最佳化軟體和改進使用者體驗,請放心這不會涉及到您的個人隱私資訊。"
}, },
"editor": { "editor": {
"name": "編輯器", "name": "編輯器",
@ -382,6 +385,12 @@
"later": "稍後提醒我", "later": "稍後提醒我",
"skip": "忽略本次更新" "skip": "忽略本次更新"
}, },
"welcome": {
"title": "歡迎使用Tiny RDM",
"content": "如果您對此有任何顧慮,可以隨時前往\"偏好設定\"中關閉此項數據收集功能。有任何問題可聯繫開發者希望Tiny RDM可以成為您的好幫手",
"accept": "幫助改進",
"reject": "不接受"
},
"about": { "about": {
"source": "源碼地址", "source": "源碼地址",
"website": "官方網站" "website": "官方網站"

View File

@ -35,6 +35,7 @@ const usePreferencesStore = defineStore('preferences', {
*/ */
state: () => ({ state: () => ({
behavior: { behavior: {
welcomed: false,
asideWidth: 300, asideWidth: 300,
windowWidth: 0, windowWidth: 0,
windowHeight: 0, windowHeight: 0,
@ -52,6 +53,7 @@ const usePreferencesStore = defineStore('preferences', {
useSysProxyHttp: false, useSysProxyHttp: false,
checkUpdate: true, checkUpdate: true,
skipVersion: '', skipVersion: '',
allowTrack: true,
}, },
editor: { editor: {
font: '', font: '',
@ -445,6 +447,12 @@ const usePreferencesStore = defineStore('preferences', {
return true return true
}, },
setAsWelcomed(acceptTrack) {
this.behavior.welcomed = true
this.general.allowTrack = acceptTrack
this.savePreferences()
},
async checkForUpdate(manual = false) { async checkForUpdate(manual = false) {
let msgRef = null let msgRef = null
if (manual) { if (manual) {

View File

@ -0,0 +1,46 @@
let inited = false
let allow = false
/**
* load umami analytics module
* @param {boolean} allowTrack
* @return {Promise<void>}
*/
export const loadModule = async (allowTrack = true) => {
allow = allowTrack !== false
await new Promise((resolve, reject) => {
const script = document.createElement('script')
script.setAttribute('src', 'https://analytics.tinycraft.cc/script.js')
script.setAttribute('data-website-id', 'ad6de51d-1e27-44a5-958d-319679c56aec')
script.setAttribute('data-cache', 'true')
script.setAttribute('data-auto-track', allowTrack !== false ? 'true' : 'false')
script.onload = () => {
inited = true
resolve()
}
script.onerror = () => {
inited = false
reject()
}
document.body.appendChild(script)
})
}
const enable = () => {
return inited && allow && umami
}
export const enableTrack = (enable) => {
allow = enable
}
export const trackEvent = async (event, data) => {
if (enable() || event === 'startup') {
umami.track(({ website, language }) => ({
language,
website,
name: event,
data,
}))
}
}