Ensure view names are properly encoded to handle certain special characters (#9145)
This commit is contained in:
parent
3a204b72e8
commit
66674c7277
|
@ -10,6 +10,7 @@
|
|||
$: views = $tables.list.flatMap(table => Object.keys(table.views || {}))
|
||||
|
||||
const saveView = async () => {
|
||||
name = name?.trim()
|
||||
if (views.includes(name)) {
|
||||
notifications.error(`View exists with name ${name}`)
|
||||
return
|
||||
|
@ -21,7 +22,7 @@
|
|||
field,
|
||||
})
|
||||
notifications.success(`View ${name} created`)
|
||||
$goto(`../../view/${name}`)
|
||||
$goto(`../../view/${encodeURIComponent(name)}`)
|
||||
} catch (error) {
|
||||
notifications.error("Error creating view")
|
||||
}
|
||||
|
|
|
@ -36,9 +36,8 @@
|
|||
indentLevel={2}
|
||||
icon="Remove"
|
||||
text={viewName}
|
||||
selected={$isActive("./view/:viewName") &&
|
||||
$views.selected?.name === viewName}
|
||||
on:click={() => $goto(`./view/${viewName}`)}
|
||||
selected={$isActive("./view") && $views.selected?.name === viewName}
|
||||
on:click={() => $goto(`./view/${encodeURIComponent(viewName)}`)}
|
||||
>
|
||||
<EditViewPopover
|
||||
view={{ name: viewName, ...table.views[viewName] }}
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
|
||||
async function deleteView() {
|
||||
try {
|
||||
const isSelected = $params.viewName === $views.selectedViewName
|
||||
const isSelected =
|
||||
decodeURIComponent($params.viewName) === $views.selectedViewName
|
||||
const name = view.name
|
||||
const id = view.tableId
|
||||
await views.delete(name)
|
||||
|
|
|
@ -12,6 +12,7 @@ export const syncURLToState = options => {
|
|||
store,
|
||||
routify,
|
||||
beforeNavigate,
|
||||
decode,
|
||||
} = options || {}
|
||||
if (
|
||||
!urlParam ||
|
||||
|
@ -29,11 +30,23 @@ export const syncURLToState = options => {
|
|||
return
|
||||
}
|
||||
|
||||
// Decodes encoded URL params if required
|
||||
const decodeParams = urlParams => {
|
||||
if (!decode) {
|
||||
return urlParams
|
||||
}
|
||||
let decoded = {}
|
||||
Object.keys(urlParams || {}).forEach(key => {
|
||||
decoded[key] = decode(urlParams[key])
|
||||
})
|
||||
return decoded
|
||||
}
|
||||
|
||||
// We can't dynamically fetch the value of stateful routify stores so we need
|
||||
// to just subscribe and cache the latest versions.
|
||||
// We can grab their initial values as this is during component
|
||||
// initialisation.
|
||||
let cachedParams = get(routify.params)
|
||||
let cachedParams = decodeParams(get(routify.params))
|
||||
let cachedGoto = get(routify.goto)
|
||||
let cachedRedirect = get(routify.redirect)
|
||||
let cachedPage = get(routify.page)
|
||||
|
@ -77,7 +90,7 @@ export const syncURLToState = options => {
|
|||
// Check if new value is valid
|
||||
if (validate && fallbackUrl) {
|
||||
if (!validate(urlValue)) {
|
||||
log("Invalid URL param!")
|
||||
log("Invalid URL param!", urlValue)
|
||||
redirectUrl(fallbackUrl)
|
||||
return
|
||||
}
|
||||
|
@ -109,7 +122,7 @@ export const syncURLToState = options => {
|
|||
log(`url.${urlParam} (${urlValue}) <= state.${stateKey} (${stateValue})`)
|
||||
if (validate && fallbackUrl) {
|
||||
if (!validate(stateValue)) {
|
||||
log("Invalid state param!")
|
||||
log("Invalid state param!", stateValue)
|
||||
redirectUrl(fallbackUrl)
|
||||
return
|
||||
}
|
||||
|
@ -137,6 +150,7 @@ export const syncURLToState = options => {
|
|||
|
||||
// Subscribe to URL changes and cache them
|
||||
const unsubscribeParams = routify.params.subscribe($urlParams => {
|
||||
$urlParams = decodeParams($urlParams)
|
||||
cachedParams = $urlParams
|
||||
mapUrlToState($urlParams)
|
||||
})
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
fallbackUrl: "../",
|
||||
store: views,
|
||||
routify,
|
||||
decode: decodeURIComponent,
|
||||
})
|
||||
|
||||
onDestroy(stopSyncing)
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
onMount(async () => {
|
||||
const { list, selected } = $views
|
||||
if (selected) {
|
||||
$redirect(`./${selected?.name}`)
|
||||
$redirect(`./${encodeURIComponent(selected?.name)}`)
|
||||
} else if (list?.length) {
|
||||
$redirect(`./${list[0].name}`)
|
||||
$redirect(`./${encodeURIComponent(list[0].name)}`)
|
||||
} else {
|
||||
$redirect("../")
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ export const buildViewEndpoints = API => ({
|
|||
params.set("group", groupBy)
|
||||
}
|
||||
const QUERY_VIEW_URL = field
|
||||
? `/api/views/${name}?${params}`
|
||||
: `/api/views/${name}`
|
||||
? `/api/views/${encodeURIComponent(name)}?${params}`
|
||||
: `/api/views/${encodeURIComponent(name)}`
|
||||
return await API.get({ url: QUERY_VIEW_URL })
|
||||
},
|
||||
|
||||
|
@ -53,7 +53,7 @@ export const buildViewEndpoints = API => ({
|
|||
*/
|
||||
deleteView: async viewName => {
|
||||
return await API.delete({
|
||||
url: `/api/views/${viewName}`,
|
||||
url: `/api/views/${encodeURIComponent(viewName)}`,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
|
@ -187,7 +187,7 @@ export async function save(ctx: UserCtx) {
|
|||
}
|
||||
|
||||
export async function fetchView(ctx: Ctx) {
|
||||
const viewName = ctx.params.viewName
|
||||
const viewName = decodeURIComponent(ctx.params.viewName)
|
||||
|
||||
// if this is a table view being looked for just transfer to that
|
||||
if (viewName.startsWith(DocumentType.TABLE)) {
|
||||
|
|
|
@ -113,7 +113,7 @@ async function handleViewEvents(existingView: View, newView: View) {
|
|||
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const viewName = decodeURI(ctx.params.viewName)
|
||||
const viewName = decodeURIComponent(ctx.params.viewName)
|
||||
const view = await deleteView(viewName)
|
||||
const table = await db.get(view.meta.tableId)
|
||||
delete table.views[viewName]
|
||||
|
@ -124,7 +124,7 @@ export async function destroy(ctx: BBContext) {
|
|||
}
|
||||
|
||||
export async function exportView(ctx: BBContext) {
|
||||
const viewName = decodeURI(ctx.query.view as string)
|
||||
const viewName = decodeURIComponent(ctx.query.view as string)
|
||||
const view = await getView(viewName)
|
||||
|
||||
const format = ctx.query.format as string
|
||||
|
|
Loading…
Reference in New Issue