From 907bdc7dfbe97187054c2c9f9fd3c78343b9d28c Mon Sep 17 00:00:00 2001 From: John Cowen Date: Thu, 10 Oct 2024 15:20:15 +0100 Subject: [PATCH] chore: add route.from property to RouterView::route (#2872) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the ability to inspect the `route` of the previous page, i.e. the history using `RouteView::route.from`. This is useful for if we need to take the user to a certain page depending on where they came from. --- We could use native `location.history` to do things like this, but it doesn't give you Vue route information. The downside is here, we only store the single previous page, i.e. where you came from not the full history. This feels like Vue more seeing as Vue only works with the idea of `from`. I doubt we'll need to store a full history of routes for anything, so this is fine for the moment. If we ever need to store a full history we can do that under `route.history`, and keep `route.from` as a shortcut to `route.history[0]`. --- I also changed some naming inside RouteView here. RouteViews are nested so all of them haveParents apart from the top one (i.e. the root RouteView), and only the root RouteView doesn't have a root 🤯 . The implementation just tracks all route changes in the root RouteView (the one that is always on the page) using Vue's `route.beforeEach` callback, and all child routes then read from the property we keep up-to-date using this callback (`route.from`). --- Signed-off-by: John Cowen --- .../components/route-view/RouteView.vue | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/app/application/components/route-view/RouteView.vue b/src/app/application/components/route-view/RouteView.vue index ab58369df..7230b6c25 100644 --- a/src/app/application/components/route-view/RouteView.vue +++ b/src/app/application/components/route-view/RouteView.vue @@ -5,7 +5,7 @@ :data-testid="name" >
@@ -69,10 +70,12 @@ import DataSink from '../data-source/DataSink.vue' import DataSource from '../data-source/DataSource.vue' import { useUri } from '@/app/application/services/data-source' import { sources } from '@/app/me/sources' -import type { RouteRecordRaw } from 'vue-router' +import type { Ref } from 'vue' +import type { RouteRecordRaw, RouteLocationNormalizedLoaded } from 'vue-router' export type RouteView = { name: string + from: Ref addTitle: (item: string, sym: Symbol) => void removeTitle: (sym: Symbol) => void addAttrs: (item: Partial>, sym: Symbol) => void @@ -118,12 +121,13 @@ class UniqueId { return uniqueId(props.name) } } -const name = computed(() => props.name) +const name = computed(() => props.name) const submit = ref((_args: any) => {}) const title = ref(null) const titles = new Map() const attributes = new Map() +const from = ref() const joinTitle = (titles: string[]) => { return titles.reverse().concat(t('components.route-view.title', { name: t('common.product.name') })).join(' | ') @@ -139,6 +143,7 @@ const child = () => { const routeView = { name: props.name, + from, addTitle: (item: string, sym: Symbol) => { const $title = title.value if ($title) { @@ -238,22 +243,36 @@ const routerBack = (...args: RouteReplaceParams) => { routeReplace(...args) } -const hasParent: RouteView | undefined = inject(ROUTE_VIEW_ROOT, undefined) -if (!hasParent) { +const hasRoot: RouteView | undefined = inject(ROUTE_VIEW_ROOT, undefined) +if (!hasRoot) { // use the default title if we are the topmost RouteView setTitle(t('components.route-view.title', { name: t('common.product.name') })) + // listen for to our navigations so we can set route.from + router.beforeEach((_to, f) => { + from.value = f + return true + }) + // add the root so all other RouteView are marked as children provide(ROUTE_VIEW_ROOT, routeView) } +// add RouteTitle's parent provide(ROUTE_VIEW_PARENT, routeView) -const parent: RouteView = hasParent || routeView +// +const root: RouteView = hasRoot || routeView watch(() => props.attrs, (attrs) => { if (Object.keys(attrs).length > 0) { - parent.addAttrs(attrs, sym) + root.addAttrs(attrs, sym) } }, { immediate: true }) +if (hasRoot) { + watch(() => root.from, (val) => { + from.value = val.value + }, { immediate: true }) +} + onBeforeUnmount(() => { - parent.removeAttrs(sym) + root.removeAttrs(sym) })