fix(portal): app launcher opens real per-service hosts
The "Jump to" launcher only navigated for the internal tiles (Personal / Admin / Partner); every external app (Mail, Drev, Møder, …) just fired a toast and never opened. Hosts were also hardcoded to *.dezky.com, with Drev pointing at a vanity drev. subdomain instead of the real OCIS host. - Open external apps in a new tab at https://<host>.<baseDomain> - Derive the base domain from the portal's own hostname so links resolve in every environment (app.dezky.local → dezky.local, app.dezky.com → dezky.com) - Map Drev → files (OCIS); mail/meet/chat/cal/contacts/docs use their service subdomain
This commit is contained in:
@@ -15,7 +15,10 @@ interface Tile {
|
||||
key: string
|
||||
name: string
|
||||
icon: IconName
|
||||
ext: string
|
||||
// Real per-service subdomain behind Traefik (e.g. 'files' for OCIS). Combined
|
||||
// with the live base domain at click time to build the app URL. Omitted for
|
||||
// internal tiles (Personal / Admin / Partner) which navigate in-app instead.
|
||||
host?: string
|
||||
current?: boolean
|
||||
}
|
||||
|
||||
@@ -32,12 +35,13 @@ const tiles = computed<Tile[]>(() => {
|
||||
const isAdmin = section.value === 'admin'
|
||||
const isPartner = section.value === 'partner'
|
||||
const base: Tile[] = [
|
||||
{ key: 'mail', name: 'Mail', icon: 'mail', ext: 'mail.dezky.com' },
|
||||
{ key: 'drev', name: 'Drev', icon: 'folder', ext: 'drev.dezky.com' },
|
||||
{ key: 'moder', name: 'Møder', icon: 'video', ext: 'meet.dezky.com' },
|
||||
{ key: 'chat', name: 'Chat', icon: 'chat', ext: 'chat.dezky.com' },
|
||||
{ key: 'cal', name: 'Kalender', icon: 'calendar', ext: 'cal.dezky.com' },
|
||||
{ key: 'contacts', name: 'Kontakter', icon: 'users', ext: 'contacts.dezky.com' },
|
||||
{ key: 'mail', name: 'Mail', icon: 'mail', host: 'mail' },
|
||||
// Drev = OCIS files, served at files.<domain> (not a vanity 'drev' host).
|
||||
{ key: 'drev', name: 'Drev', icon: 'folder', host: 'files' },
|
||||
{ key: 'moder', name: 'Møder', icon: 'video', host: 'meet' },
|
||||
{ key: 'chat', name: 'Chat', icon: 'chat', host: 'chat' },
|
||||
{ key: 'cal', name: 'Kalender', icon: 'calendar', host: 'cal' },
|
||||
{ key: 'contacts', name: 'Kontakter', icon: 'users', host: 'contacts' },
|
||||
]
|
||||
// Admin tile is the entry point to the workspace-admin surface. Show it to any
|
||||
// tenant admin/owner (so they can get TO /admin from the personal shell), not
|
||||
@@ -46,23 +50,40 @@ const tiles = computed<Tile[]>(() => {
|
||||
// admin and personal surfaces — clicking either crosses over, "HERE" shows
|
||||
// which side you're on.
|
||||
if (isAdmin || isTenantAdmin.value) {
|
||||
base.push({ key: 'home', name: 'Personal', icon: 'home', ext: 'app.dezky.com', current: section.value === 'user' })
|
||||
base.push({ key: 'admin', name: 'Admin', icon: 'shield', ext: 'admin.dezky.com', current: isAdmin && !isPartner })
|
||||
base.push({ key: 'home', name: 'Personal', icon: 'home', current: section.value === 'user' })
|
||||
base.push({ key: 'admin', name: 'Admin', icon: 'shield', current: isAdmin && !isPartner })
|
||||
}
|
||||
if (isPartner) {
|
||||
base.push({ key: 'partner', name: 'Partner', icon: 'briefcase', ext: 'partner.nordicmsp.dk', current: true })
|
||||
base.push({ key: 'partner', name: 'Partner', icon: 'briefcase', current: true })
|
||||
}
|
||||
base.push({ key: 'docs', name: 'Docs', icon: 'file', ext: 'docs.dezky.com' })
|
||||
base.push({ key: 'docs', name: 'Docs', icon: 'file', host: 'docs' })
|
||||
return base
|
||||
})
|
||||
|
||||
// The base domain the portal itself is served on, so app links resolve in every
|
||||
// environment: app.dezky.local → dezky.local, app.dezky.com → dezky.com. Falls
|
||||
// back to the dev domain during SSR (open() only runs client-side on click).
|
||||
function appBaseDomain(): string {
|
||||
if (import.meta.client) {
|
||||
const parts = window.location.hostname.split('.')
|
||||
return parts.length > 2 ? parts.slice(1).join('.') : window.location.hostname
|
||||
}
|
||||
return 'dezky.local'
|
||||
}
|
||||
|
||||
const toast = useToast()
|
||||
function open(t: Tile) {
|
||||
launcher.hide()
|
||||
if (t.key === 'home') return navigateTo('/')
|
||||
if (t.key === 'admin') return navigateTo('/admin')
|
||||
if (t.key === 'partner') return navigateTo('/partner')
|
||||
toast.info(`Opening ${t.name}…`, t.ext)
|
||||
if (t.host) {
|
||||
const url = `https://${t.host}.${appBaseDomain()}`
|
||||
window.open(url, '_blank', 'noopener')
|
||||
toast.info(`Opening ${t.name}…`, url.replace(/^https:\/\//, ''))
|
||||
return
|
||||
}
|
||||
toast.info(`Opening ${t.name}…`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user