Skip to content
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
13 changes: 10 additions & 3 deletions web-app/packages/admin-app/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,12 @@ import {
useNotificationStore,
useUserStore,
useLayoutStore,
useProjectStore
useProjectStore,
useRouterTitle
} from '@mergin/lib'
import { mapActions, mapState } from 'pinia'
import { useToast } from 'primevue/usetoast'
import { defineComponent } from 'vue'
import { defineComponent, watchEffect } from 'vue'
import { useMeta } from 'vue-meta'

export default defineComponent({
Expand Down Expand Up @@ -120,8 +121,11 @@ export default defineComponent({
}
},
setup() {
const { title } = useRouterTitle({
defaultTitle: 'Mergin Maps Admin Panel'
})
useMeta({
title: 'Mergin Maps',
title: 'Mergin Maps Admin Panel',
meta: [
{
name: 'description',
Expand All @@ -144,6 +148,9 @@ export default defineComponent({
notificationStore.init(toast)
layoutStore.init()
projectStore.filterPermissions(['editor'], ['edit'])
watchEffect(() => {
document.title = title.value
})
},
async created() {
await this.fetchConfig()
Expand Down
8 changes: 7 additions & 1 deletion web-app/packages/admin-app/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
ProjectSettingsView,
ProjectVersionView,
ProjectVersionsView,
OverviewView
OverviewView,
getAdminTitle
} from '@mergin/admin-lib'
import {
NotFoundView,
Expand Down Expand Up @@ -165,5 +166,10 @@ export const createRouter = (pinia: Pinia) => {
routeUtils.isSuperUser(to, from, next, userStore)
})

router.beforeEach((to, from, next) => {
// Set the page title based on the route's meta title
to.meta.title = getAdminTitle
next()
})
return router
}
4 changes: 1 addition & 3 deletions web-app/packages/admin-app/src/shims-vue-router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import 'vue-router'

declare module 'vue-router' {
interface RouteMeta {
public?: boolean
allowedForNoWorkspace?: boolean
breadcrump?: { title: string; path: string }[]
title?: string | string[] | ((route, extened) => string | string[])
}
}
26 changes: 24 additions & 2 deletions web-app/packages/admin-lib/src/modules/admin/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

import { RouteRecord } from 'vue-router'
import { RouteLocationNormalizedLoaded, RouteRecord } from 'vue-router'

import { AdminRouteParams } from './types'

export enum AdminRoutes {
ACCOUNTS = 'accounts',
Expand All @@ -15,7 +17,27 @@ export enum AdminRoutes {
ProjectHistory = 'project-versions',
ProjectSettings = 'project-settings',
ProjectVersion = 'project-version',
FileVersionDetail = 'file-version-detail'
FileVersionDetail = 'file-version-detail',
Login = 'login'
}

export const getAdminTitle = (route: RouteLocationNormalizedLoaded) => {
const params = route.params as AdminRouteParams
const titles: Record<AdminRoutes, string | string[]> = {
[AdminRoutes.Login]: ['Sign in', 'Mergin Maps Admin Panel'],
[AdminRoutes.ACCOUNTS]: 'Accounts',
[AdminRoutes.ACCOUNT]: 'Account details',
[AdminRoutes.OVERVIEW]: 'Admin overview',
[AdminRoutes.PROJECTS]: 'Projects',
[AdminRoutes.PROJECT]: ['Details', params.projectName],
[AdminRoutes.SETTINGS]: 'Settings',
[AdminRoutes.ProjectTree]: ['Files', params.projectName],
[AdminRoutes.ProjectHistory]: ['History', params.projectName],
[AdminRoutes.ProjectSettings]: ['Settings', params.projectName],
[AdminRoutes.ProjectVersion]: [params.version_id, params.projectName],
[AdminRoutes.FileVersionDetail]: [params.path, params.version_id]
}
return titles[route.name as AdminRoutes]
}

export const getRoutes = (): RouteRecord[] => []
8 changes: 8 additions & 0 deletions web-app/packages/admin-lib/src/modules/admin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,12 @@ export interface DownloadReportParams {
date_to: string
}

export interface AdminRouteParams {
namespace?: string
projectName?: string
version_id?: string
path?: string
username?: string
}

/* eslint-enable camelcase */
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
<project-version-changes v-if="data" :version="data" />
</app-section>
</app-container>
<download-progress />
<download-file-large />
</admin-layout>
</template>

Expand All @@ -74,7 +76,9 @@ import {
useNotificationStore,
ProjectVersion,
errorUtils,
ProjectVersionChanges
ProjectVersionChanges,
DownloadProgress,
DownloadFileLarge
} from '@mergin/lib'
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
Expand Down
7 changes: 7 additions & 0 deletions web-app/packages/admin-lib/src/shims-vue-router.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'vue-router'

declare module 'vue-router' {
interface RouteMeta {
title?: string | string[] | ((route, extended) => string | string[])
}
}
5 changes: 4 additions & 1 deletion web-app/packages/app/shims-vue-router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ declare module 'vue-router' {
interface RouteMeta {
public?: boolean
allowedForNoWorkspace?: boolean
breadcrump?: { title: string; path: string }[]
breadcrump?:
| { title: string; path: string }[]
| ((route) => { title: string; path: string }[])
title?: string | string[] | ((route, extended) => string | string[])
}
}
16 changes: 12 additions & 4 deletions web-app/packages/app/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ import {
useNotificationStore,
useUserStore,
InstanceMaintenanceMessage,
useProjectStore
useProjectStore,
useRouterTitle,
routeUtils
} from '@mergin/lib'
import { mapActions, mapState } from 'pinia'
import { useToast } from 'primevue/usetoast'
import { defineComponent } from 'vue'
import { defineComponent, watchEffect } from 'vue'
import { useMeta } from 'vue-meta'

export default defineComponent({
Expand Down Expand Up @@ -101,8 +103,11 @@ export default defineComponent({
}
},
setup() {
const { title } = useRouterTitle({
defaultTitle: routeUtils.DEFAULT_PAGE_TITLE
})
useMeta({
title: 'Mergin Maps',
title: routeUtils.DEFAULT_PAGE_TITLE,
meta: [
{
name: 'description',
Expand All @@ -125,6 +130,9 @@ export default defineComponent({
notificationStore.init(toast)
layoutStore.init()
projectStore.filterPermissions(['editor'], ['edit'])
watchEffect(() => {
document.title = title.value
})
},
async created() {
await this.fetchConfig()
Expand Down Expand Up @@ -152,7 +160,7 @@ export default defineComponent({
},
methods: {
...mapActions(useAppStore, ['setServerError']),
...mapActions(useInstanceStore, ['fetchPing', 'fetchConfig', 'initApp']),
...mapActions(useInstanceStore, ['fetchPing', 'fetchConfig']),
...mapActions(useNotificationStore, {
notificationError: 'error'
}),
Expand Down
37 changes: 27 additions & 10 deletions web-app/packages/app/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
routeUtils,
useUserStore,
SideBarTemplate as SideBar,
ProjectRouteName
ProjectRouteName,
UserRouteName,
DashboardRouteName,
getDashboardTitle,
getUserTitle,
getProjectTitle
} from '@mergin/lib'
import { Pinia } from 'pinia'
import {
Expand Down Expand Up @@ -57,28 +62,28 @@ export const createRouter = (pinia: Pinia) => {
}
},
path: '/login/:reset?',
name: 'login',
name: UserRouteName.Login,
component: LoginView,
props: true,
meta: { public: true }
},
{
path: '/confirm-email/:token',
name: 'confirm_email',
name: UserRouteName.ConfirmEmail,
component: VerifyEmailView,
props: true,
meta: { public: true }
},
{
path: '/change-password/:token',
name: 'change_password',
name: UserRouteName.ChangePassword,
component: ChangePasswordView,
props: true,
meta: { public: true }
},
{
path: '/dashboard',
name: 'dashboard',
name: DashboardRouteName.Dashboard,
components: {
default: DashboardView,
header: AppHeader,
Expand All @@ -93,7 +98,7 @@ export const createRouter = (pinia: Pinia) => {
},
{
path: '/profile',
name: 'user_profile',
name: UserRouteName.UserProfile,
meta: {
allowedForNoWorkspace: true,
breadcrump: [{ title: 'Profile', path: '/profile' }]
Expand All @@ -107,7 +112,7 @@ export const createRouter = (pinia: Pinia) => {
},
{
path: '/projects',
name: 'projects',
name: ProjectRouteName.Projects,
components: {
default: ProjectsListView,
header: AppHeader,
Expand All @@ -118,13 +123,12 @@ export const createRouter = (pinia: Pinia) => {
},
meta: {
public: true,
title: 'Projects',
breadcrump: [{ title: 'Projects', path: '/projects' }]
},
children: [
{
path: 'explore',
name: 'explore',
name: ProjectRouteName.ProjectsExplore,
component: ProjectsListView,
props: true,
meta: {
Expand Down Expand Up @@ -248,7 +252,7 @@ export const createRouter = (pinia: Pinia) => {
},
{
path: 'history/:version_id/:path',
name: 'file-version-detail',
name: ProjectRouteName.FileVersionDetail,
component: FileVersionDetailView,
props: true,
meta: {
Expand Down Expand Up @@ -284,5 +288,18 @@ export const createRouter = (pinia: Pinia) => {
const userStore = useUserStore(pinia)
routeUtils.isAuthenticatedGuard(to, from, next, userStore)
})

router.beforeEach(async (to, from, next) => {
const titleResolvers = [getProjectTitle, getUserTitle, getDashboardTitle]

// Use `find` to get the first resolved title
to.meta.title = (route) => {
return titleResolvers
.map((resolver) => resolver(route))
.find((title) => title)
}

next()
})
return router
}
5 changes: 5 additions & 0 deletions web-app/packages/lib/src/common/composables/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) Lutra Consulting Limited
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

export { default as useRouterTitle } from './use_router_title'
43 changes: 43 additions & 0 deletions web-app/packages/lib/src/common/composables/use_router_title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (C) Lutra Consulting Limited
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

import { computed, toValue } from 'vue'
import { useRoute } from 'vue-router'

interface RouterTitleConfig {
defaultTitle?: string | string[]
}

const SEPARATOR = ' \u2022 ' // Unicode for bullet character

const useRouterTitle = (config: RouterTitleConfig = {}, extended = {}) => {
const route = useRoute()

const metaTitle = computed<string | string[]>(() => {
const metaTitle = route.meta.title
const defaultTitle = config.defaultTitle
if (!metaTitle) {
return defaultTitle
}
if (typeof metaTitle === 'function') {
return metaTitle(route, toValue(extended)) || defaultTitle
}
return metaTitle
})

const title = computed<string>(() => {
const result = metaTitle.value
if (Array.isArray(result)) {
return result.filter(Boolean).join(` ${SEPARATOR} `)
}
return result
})

return {
metaTitle,
title
}
}

export default useRouterTitle
1 change: 1 addition & 0 deletions web-app/packages/lib/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from './errors'
export * from './mixins'
export * from './http'
export * from './types'
export * from './composables'
// export * from './router_without_navigation_failure'
export * as dateUtils from './date_utils'
export * as htmlUtils from './html_utils'
Expand Down
2 changes: 2 additions & 0 deletions web-app/packages/lib/src/common/route_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import isEqual from 'lodash/isEqual'
import pick from 'lodash/pick'
import { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'

export const DEFAULT_PAGE_TITLE = 'Mergin Maps'

export type IsAuthenticatedGuardOptions = {
notAuthenticatedRedirectPath?: string
}
Expand Down
Loading
Loading