Skip to content

Commit

Permalink
fix: redirect redirect/returnLink with query
Browse files Browse the repository at this point in the history
Previously we always wrap the redirect link with `{ path }`,
causing query string lost when performing the redirect.

Support for `returnLink` in the URL query are also removed since
they are not used anymore

(adopted from Kong/kong-admin#2941)
  • Loading branch information
nekolab committed Nov 28, 2023
1 parent 01b3e46 commit 6aa2939
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/components/EntityForm/EntityForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ export default {
if (this.onFormCancel) {
this.onFormCancel()
} else if (this.redirectPath) {
this.$router.push({ path: this.redirectPath })
this.$router.push(this.redirectPath)
} else if (this.$router.previous) {
this.$router.push({ ...this.$router.previous })
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/components/EntityForm/NativeEntityForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ export default {
if (this.onFormCancel) {
return this.onFormCancel()
} else if (this.redirectPath) {
return this.$router.push({ path: this.redirectPath })
return this.$router.push(this.redirectPath)
} else if (this.$router.previous) {
return this.$router.push({ ...this.$router.previous })
} else {
Expand Down
10 changes: 5 additions & 5 deletions src/components/EntityForm/mixins/FormPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default {
*/
redirectRoute () {
if (this.redirectPath) {
return { path: this.redirectPath }
return this.redirectPath
}

return { name: this.resourceEndpoint }
Expand Down Expand Up @@ -92,10 +92,10 @@ export default {
return redirectCreateRoute === '-1' ? this.$router.go(-1) : this.$router.push({ name: redirectCreateRoute, params: this.$router.params })
}

const link = this.redirectPath || this.returnLink || this.$route.query.returnLink
const link = this.redirectPath || this.returnLink

if (link) {
return this.$router.push({ path: link })
return this.$router.push(link)
}

const location = typeof callback === 'function'
Expand All @@ -111,7 +111,7 @@ export default {
async updateRecord (model) {
return apiService.updateRecord(this.resourceEndpoint, this.id, model)
.then(res => {
const link = this.redirectPath || this.returnLink || this.$route.query.returnLink || this.$route.query.redirect
const link = this.redirectPath || this.returnLink

// if parent form defines a redirectRouteNames object, we either go back to previous page if -1 is passed
// else we go to the named route
Expand All @@ -121,7 +121,7 @@ export default {
}

if (link) {
return this.$router.push({ path: link })
return this.$router.push(link)
}

redirectOnResponseStatus(this.$router, 200, { name: this.resourceEndpoint })(res)
Expand Down
30 changes: 24 additions & 6 deletions src/components/EntityForm/mixins/RedirectMixin.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
const extractRedirectPath = ($route, urlKey) => {
const query = $route.query[urlKey]
let url = null

if (Array.isArray(query)) {
url = query[0]
console.warn(`extractRedirectPath: "${urlKey}" in query should not be an array, using first element this time`)
} else if (typeof query === 'string') {
url = query
}

return url
}

export default {
computed: {
redirectPath () {
return this.$route.query.redirect
return extractRedirectPath(this.$route, 'redirect')
},
redirectRouteQuery () {
return { redirect: this.redirectPath }
},
postDeletePath () {
return this.$route.query.postDelete
return extractRedirectPath(this.$route, 'postDelete')
},
postDeleteRouteQuery () {
return { postDelete: this.postDeletePath }
},
},
methods: {
createRedirectRouteQuery (redirectPath = this.$route.fullPath) {
return { redirect: redirectPath }
createRedirectRouteQuery (redirect = this.$route.fullPath) {
return { redirect }
},
createPostDeleteRouteQuery (postDeletePath = this.postDeletePath || this.$route.fullPath) {
return { postDelete: postDeletePath }
createPostDeleteRouteQuery (postDelete) {
if (typeof postDelete !== 'string') {
postDelete = this.postDeletePath ?? this.$route.fullPath
}

return { postDelete }
},
redirect (replace = false, goBack = false) {
const routerFn = replace ? this.$router.replace : this.$router.push
Expand Down
28 changes: 15 additions & 13 deletions src/components/HeaderBackButton.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<template>
<KButton
data-testid="header-back-button"
:to="backPath"
appearance="tertiary"
@click="back"
>
{{ t('global.buttons.back') }}
</KButton>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import type { RouteLocationRaw } from 'vue-router'
import { useI18n } from '@/composables/useI18n'
import { useURLFromRouteQuery } from '@/composables/useRedirect'
const props = defineProps({
entity: {
Expand All @@ -21,19 +23,19 @@ const props = defineProps({
},
})
const route = useRoute()
const { t } = useI18n()
const router = useRouter()
const redirectURL = useURLFromRouteQuery('redirect')
const backPath = computed(() => {
const { query } = route
if (query?.redirect) {
return {
path: query.redirect,
}
const back = () => {
let backTo: RouteLocationRaw = {
name: props.entity ? `${props.entity}-list` : 'overview',
}
return {
name: props.entity ? `${props.entity}-list` : 'overview',
if (redirectURL.value) {
backTo = redirectURL.value
}
})
router.replace(backTo)
}
</script>
26 changes: 15 additions & 11 deletions src/composables/useFormRedirect.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { computed } from 'vue'
import { useRoute, useRouter, type RouteLocationRaw, type MatcherLocationAsPath } from 'vue-router'
import { useRouter } from 'vue-router'
import type { RouteLocationRaw } from 'vue-router'

import { useURLFromRouteQuery } from './useRedirect'

export const useFormRedirectOnCancel = (fallback: RouteLocationRaw) => {
const route = useRoute()
const router = useRouter()
const redirectPath = computed(() => route.query.redirect)
const redirectRouteLocation = useURLFromRouteQuery('redirect')

const routeOnCancel = computed(() => {
if (redirectPath.value) {
return { path: redirectPath.value } as MatcherLocationAsPath
if (redirectRouteLocation.value) {
return redirectRouteLocation.value
}

const previousPath = router.options?.history?.state?.back
if (previousPath) {
return { path: previousPath } as MatcherLocationAsPath
if (typeof previousPath === 'string') {
return router.resolve(previousPath)
}

return fallback
Expand All @@ -22,13 +25,14 @@ export const useFormRedirectOnCancel = (fallback: RouteLocationRaw) => {
}

export const useFormRedirectOnUpdate = (fallback: RouteLocationRaw) => {
const route = useRoute()
const redirectPath = computed(() => route.query.redirect)
const redirectRouteLocation = useURLFromRouteQuery('redirect')

const routeOnUpdate = computed(() => {
const link = redirectPath.value || route.query.returnLink || route.query.redirect
if (redirectRouteLocation.value) {
return redirectRouteLocation.value
}

return link ? ({ path: link } as MatcherLocationAsPath) : fallback
return fallback
})

return routeOnUpdate.value
Expand Down
5 changes: 3 additions & 2 deletions src/composables/useListRedirect.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { LocationQueryValue } from 'vue-router'

import { useURLFromRouteQuery } from './useRedirect'

export const useListRedirect = () => {
const route = useRoute()
const router = useRouter()

const redirectPath = computed(() => route.query.redirect as LocationQueryValue)
const redirectPath = useURLFromRouteQuery('redirect')
const redirectRouteQuery = computed(() => ({ redirect: redirectPath.value }))

const createRedirectRouteQuery = (redirect = route.fullPath) => {
Expand Down
21 changes: 21 additions & 0 deletions src/composables/useRedirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import type { LocationQueryValue } from 'vue-router'

export const useURLFromRouteQuery = (urlKey: string) => {
const route = useRoute()

return computed(() => {
const query = route.query[urlKey]
let url: LocationQueryValue = null

if (Array.isArray(query)) {
url = query[0]
console.warn(`useURLFromRouteQuery: "${urlKey}" in query should not be an array, using first element this time`)
} else if (typeof query === 'string') {
url = query
}

return url
})
}
6 changes: 3 additions & 3 deletions src/pages/consumers/ConsumerCredentials.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import { pluginMeta } from '@/pages/plugins/PluginMeta'
import { useI18n } from '@/composables/useI18n'
import { useInfoStore } from '@/stores/info'
import CredentialList from './CredentialList.vue'
import { useListRedirect } from '@/composables/useListRedirect'
const router = useRouter()
const { t } = useI18n()
const infoStore = useInfoStore()
const { createRedirectRouteQuery } = useListRedirect()
const enabledPlugins = computed(() => infoStore.plugins.enabledInCluster)
const enabledPluginsFetched = ref(false)
Expand All @@ -58,9 +60,7 @@ const hasEnabledPlugins = computed(() => credentialPlugins.some(({ pluginType })
const navigateToPluginSelection = () => {
router.push({
name: 'plugin-select',
query: {
redirect: router.currentRoute.value.fullPath,
},
query: createRedirectRouteQuery(),
})
}
Expand Down
19 changes: 4 additions & 15 deletions src/pages/plugins/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,6 @@ export default {
type: String,
default: null,
},
returnLinkPath: {
type: String,
default: null,
},
useKonnectSchema: {
type: Boolean,
default: false,
Expand Down Expand Up @@ -298,18 +293,14 @@ export default {
return this.redirectPath
}
if (this.returnLinkPath) {
return this.returnLinkPath
}
const entityId = this.resourceEndpoint.match(new RegExp(uuidRegEx))
if (entityId && this.$route.query.entity_id) {
// e.g. /consumers/e22cf8e2-795a-4eac-8da1-76b47de30b5c
return `/${this.resourceEndpoint.split('/')[0]}/${entityId}`
}
return this.$route.query.returnLink
return null
},
docsLink () {
Expand Down Expand Up @@ -440,9 +431,7 @@ export default {
methods: {
onCancel () {
if (this.redirectPath) {
this.$router.push({ path: this.redirectPath })
} else if (this.returnLinkPath) {
this.$router.push({ path: this.returnLinkPath })
this.$router.push(this.redirectPath)
} else if (this.$router.previous) {
this.$router.push({ ...this.$router.previous })
} else {
Expand Down Expand Up @@ -489,7 +478,7 @@ export default {
}
this.returnLink
? this.$router.push({ path: this.returnLink })
? this.$router.push(this.returnLink)
: redirectOnResponseStatus(this.$router, 201, { name: 'plugin-list' })(res)
return res.data
Expand Down Expand Up @@ -536,7 +525,7 @@ export default {
}
this.returnLink
? this.$router.push({ path: this.returnLink })
? this.$router.push(this.returnLink)
: redirectOnResponseStatus(this.$router, 200, { name: 'plugin-detail', params: { id: this.id } })(res)
return res.data
Expand Down
2 changes: 1 addition & 1 deletion tests/playwright/specs/services/01-Service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ test.describe('services', () => {
await withNavigation(page, () =>
page
.locator('.page-header')
.locator('a[type="button"]:has-text("Back")')
.locator('[type="button"]:has-text("Back")')
.click()
)
await page.waitForSelector('.kong-ui-entities-gateway-services-list')
Expand Down

0 comments on commit 6aa2939

Please sign in to comment.