aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/src/components/AppStoreDiscover/AppLink.vue
blob: 1ce19ad731993c221450cf2c6b724bd1fcb068e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!--
  - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  - SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
	<a v-if="linkProps" v-bind="linkProps">
		<slot />
	</a>
	<RouterLink v-else-if="routerProps" v-bind="routerProps">
		<slot />
	</RouterLink>
</template>

<script lang="ts">
import type { RouterLinkProps } from 'vue-router/types/router.js'

import { loadState } from '@nextcloud/initial-state'
import { generateUrl } from '@nextcloud/router'
import { defineComponent } from 'vue'
import { RouterLink } from 'vue-router'

const knownRoutes = Object.fromEntries(
	Object.entries(
		loadState<Record<string, { app?: string, href: string }>>('core', 'apps'),
	).map(([k, v]) => [v.app ?? k, v.href]),
)

/**
 * This component either shows a native link to the installed app or external size - or a router link to the appstore page of the app if not installed
 */
export default defineComponent({
	name: 'AppLink',

	components: { RouterLink },

	props: {
		href: {
			type: String,
			required: true,
		},
	},

	data() {
		return {
			routerProps: undefined as RouterLinkProps|undefined,
			linkProps: undefined as Record<string, string>|undefined,
		}
	},

	watch: {
		href: {
			immediate: true,
			handler() {
				const match = this.href.match(/^app:\/\/([^/]+)(\/.+)?$/)
				this.routerProps = undefined
				this.linkProps = undefined

				// not an app url
				if (match === null) {
					this.linkProps = {
						href: this.href,
						target: '_blank',
						rel: 'noreferrer noopener',
					}
					return
				}

				const appId = match[1]
				// Check if specific route was requested
				if (match[2]) {
					// we do no know anything about app internal path so we only allow generic app paths
					this.linkProps = {
						href: generateUrl(`/apps/${appId}${match[2]}`),
					}
					return
				}

				// If we know any route for that app we open it
				if (appId in knownRoutes) {
					this.linkProps = {
						href: knownRoutes[appId],
					}
					return
				}

				// Fallback to show the app store entry
				this.routerProps = {
					to: {
						name: 'apps-details',
						params: {
							category: this.$route.params?.category ?? 'discover',
							id: appId,
						},
					},
				}
			},
		},
	},
})
</script>