Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(links): integrate app version and update link management #1826

Merged
merged 2 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/desktop/electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import VueRouter from 'unplugin-vue-router/vite'

import { version } from './package.json'

export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()],
Expand All @@ -17,6 +19,9 @@ export default defineConfig({
plugins: [externalizeDepsPlugin()],
},
renderer: {
define: {
__APP_VERSION__: JSON.stringify(version),
ysfscream marked this conversation as resolved.
Show resolved Hide resolved
},
resolve: {
alias: {
'@database': resolve('src/database'),
Expand Down
5 changes: 5 additions & 0 deletions apps/web/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ import Components from 'unplugin-vue-components/vite'
import VueRouter from 'unplugin-vue-router/vite'
import { defineConfig } from 'vite'

import { version } from './package.json'

// https://vitejs.dev/config/
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify(version),
},
plugins: [
VueRouter(),
vue(),
Expand Down
6 changes: 6 additions & 0 deletions packages/types/base.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
declare global {
interface Window {
__APP_VERSION__: string
}
}

export type PlatformType = 'desktop' | 'web'

export type MQTTVersion = 3 | 4 | 5
Expand Down
6 changes: 4 additions & 2 deletions packages/ui/src/components/HelpView.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script setup lang="ts">

const { help } = useLinks()
</script>

<template>
<div>
TODO: help page
<pre>
{{ help }}
</pre>
</div>
</template>
4 changes: 2 additions & 2 deletions packages/ui/src/components/common/LeftMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import IconNew from '~icons/custom/new'
import IconScript from '~icons/custom/script'
import IconSettings from '~icons/custom/settings'

const { linksMap } = useLinks()
const { leftBarLogo } = useLinks()

const featMenus = reactive({
connections: {
Expand Down Expand Up @@ -46,7 +46,7 @@ const helpMenus = reactive({

<template>
<ElAside width="80px" class="flex flex-col justify-between items-center">
<a :href="linksMap.homepage" target="_blank" rel="noopener noreferrer" class="w-[40px] h-[40px] block mt-12">
<a :href="leftBarLogo" target="_blank" rel="noopener" class="w-[40px] h-[40px] block mt-12">
<img src="../../assets/images/logo.png" alt="app-logo" width="40" height="40">
</a>
<div class="flex flex-col">
Expand Down
135 changes: 130 additions & 5 deletions packages/ui/src/composables/__test__/useLinks.test.ts
Copy link
Member

@ysfscream ysfscream Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a link 404 check, I think would make it even more complete and help validate doc links.

const checkLink = async (url) => {
  if (url === '') return true
  try {
    const { status } = await axios.head(url, { timeout: 30000 })
    return status >= 200 && status < 400
  } catch (error) {
    console.error(`error link url: ${url}`)
    return false
  }
}

Then use Promise.all() to check all links in parallel:

const results = await Promise.all(links.map((link) => checkLink(link)))
results.forEach((isValid) => {
  expect(isValid).toBe(true)
})

Original file line number Diff line number Diff line change
@@ -1,13 +1,138 @@
import type { Lang } from 'mqttx'
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import { defineComponent, h, nextTick } from 'vue'
import { createI18n } from 'vue-i18n'
import useLinks from '../useLinks'

describe('useLinks', () => {
it('should initialize linksMap correctly', () => {
const { linksMap } = useLinks()
const i18n = createI18n({
locale: 'en',
messages: {
en: {},
zh: {},
ja: {},
hu: {},
tr: {},
},
})

const setupI18n = (locale: Lang) => {
i18n.global.locale = locale
return nextTick()
}

const expectedLinksMap = ref({
homepage: 'https://mqttx.app',
const createTestComponent = () => {
return defineComponent({
setup() {
return useLinks()
},
render() {
return h('div')
},
})
}

it('should return correct MQTTXSite based on locale', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.MQTTXSite).toBe('https://mqttx.app/zh')

await setupI18n('en')
expect(wrapper.vm.MQTTXSite).toBe('https://mqttx.app')

await setupI18n('ja')
expect(wrapper.vm.MQTTXSite).toBe('https://mqttx.app/ja')
})

it('should return correct EMQSite based on locale', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.EMQSite).toBe('https://emqx.com/zh')

await setupI18n('ja')
expect(wrapper.vm.EMQSite).toBe('https://emqx.com/ja')

expect(linksMap.value).toEqual(expectedLinksMap.value)
await setupI18n('hu')
expect(wrapper.vm.EMQSite).toBe('https://emqx.com/en')
})

it('should return correct forumSite based on locale', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.forumSite).toBe('https://askemq.com/c/tools/11')

await setupI18n('en')
expect(wrapper.vm.forumSite).toBe('https://github.com/emqx/MQTTX/discussions')
})

it('should return correct leftBarLogo', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.leftBarLogo).toBe('https://mqttx.app/zh?utm_source=mqttx&utm_medium=referral&utm_campaign=logo-to-homepage')

await setupI18n('en')
expect(wrapper.vm.leftBarLogo).toBe('https://mqttx.app?utm_source=mqttx&utm_medium=referral&utm_campaign=logo-to-homepage')
})

it('should return correct empty links', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.empty).toEqual({
EMQX: 'https://emqx.com/zh/products/emqx?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-emqx',
EMQXCloud: 'https://emqx.com/zh/cloud?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-cloud',
})

await setupI18n('en')
expect(wrapper.vm.empty).toEqual({
EMQX: 'https://emqx.com/en/products/emqx?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-emqx',
EMQXCloud: 'https://emqx.com/en/cloud?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-cloud',
})
})

it('should return correct about links', async () => {
await setupI18n('zh')
window.__APP_VERSION__ = '2.0.0'
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.about).toEqual({
releases: 'https://mqttx.app/zh/changelogs/v2.0.0?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-release',
faq: 'https://mqttx.app/zh/docs/faq?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-faq',
MQTTX: 'https://mqttx.app/zh?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-mqttx',
EMQ: 'https://emqx.com/zh?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-homepage',
EMQXCloud: 'https://emqx.com/zh/cloud?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-cloud',
})

await setupI18n('en')
expect(wrapper.vm.about).toEqual({
releases: 'https://mqttx.app/changelogs/v2.0.0?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-release',
faq: 'https://mqttx.app/docs/faq?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-faq',
MQTTX: 'https://mqttx.app?utm_source=mqttx&utm_medium=referral&utm_campaign=about-to-mqttx',
EMQ: 'https://emqx.com/en?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-homepage',
EMQXCloud: 'https://emqx.com/en/cloud?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-to-cloud',
})
})

it('should return correct help links', async () => {
await setupI18n('zh')
const wrapper = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapper.vm.help).toEqual({
docs: 'https://mqttx.app/zh/docs?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-docs',
forum: 'https://askemq.com/c/tools/11?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-forum',
learnMQTT: 'https://emqx.com/zh/mqtt-guide?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-learn-mqtt',
publicMqttBroker: 'https://emqx.com/zh/mqtt/public-mqtt5-broker',
mqtt5: 'https://emqx.com/zh/mqtt/mqtt5',
blogUtm: '?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-blog',
})

await setupI18n('en')
const wrapperEn = mount(createTestComponent(), { global: { plugins: [i18n] } })
expect(wrapperEn.vm.help).toEqual({
docs: 'https://mqttx.app/docs?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-docs',
forum: 'https://github.com/emqx/MQTTX/discussions?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-forum',
learnMQTT: 'https://emqx.com/en/mqtt-guide?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-learn-mqtt',
publicMqttBroker: 'https://emqx.com/en/mqtt/public-mqtt5-broker',
mqtt5: 'https://emqx.com/en/mqtt/mqtt5',
blogUtm: '?utm_source=mqttx&utm_medium=referral&utm_campaign=mqttx-help-to-blog',
})
})
})
53 changes: 50 additions & 3 deletions packages/ui/src/composables/useLinks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,55 @@
export default function useLinks() {
const linksMap = ref({
homepage: 'https://mqttx.app',
const { locale } = useI18n()

const MQTTXSite = computed(() => {
if (['zh', 'ja'].includes(locale.value)) {
return `https://mqttx.app/${locale.value}`
}
return 'https://mqttx.app'
})

const EMQSite = computed(() => {
if (['en', 'zh', 'ja'].includes(locale.value)) {
return `https://emqx.com/${locale.value}`
}
return 'https://emqx.com/en'
})

const forumSite = computed(() => locale.value === 'zh' ? 'https://askemq.com/c/tools/11' : 'https://github.com/emqx/MQTTX/discussions')

const utm = '?utm_source=mqttx&utm_medium=referral&utm_campaign='

const leftBarLogo = computed(() => `${MQTTXSite.value}${utm}logo-to-homepage`)

const empty = computed(() => ({
EMQX: `${EMQSite.value}/products/emqx${utm}mqttx-to-emqx`,
EMQXCloud: `${EMQSite.value}/cloud${utm}mqttx-to-cloud`,
}))

const about = computed(() => ({
releases: `${MQTTXSite.value}/changelogs/v${window.__APP_VERSION__}${utm}about-to-release`,
faq: `${MQTTXSite.value}/docs/faq${utm}about-to-faq`,
MQTTX: `${MQTTXSite.value}${utm}about-to-mqttx`,
EMQ: `${EMQSite.value}${utm}mqttx-to-homepage`,
EMQXCloud: `${EMQSite.value}/cloud${utm}mqttx-to-cloud`,
}))

const help = computed(() => ({
docs: `${MQTTXSite.value}/docs${utm}mqttx-help-to-docs`,
forum: `${forumSite.value}${utm}mqttx-help-to-forum`,
learnMQTT: `${EMQSite.value}/mqtt-guide${utm}mqttx-help-to-learn-mqtt`,
publicMqttBroker: `${EMQSite.value}/mqtt/public-mqtt5-broker`,
mqtt5: `${EMQSite.value}/mqtt/mqtt5`,
blogUtm: `${utm}mqttx-help-to-blog`,
}))

return {
linksMap,
MQTTXSite,
EMQSite,
forumSite,
leftBarLogo,
empty,
about,
help,
}
}
6 changes: 0 additions & 6 deletions scripts/gen-version.js

This file was deleted.

Loading