Getting downloading working correctly, some minor UI updates, adding a new middleware for converting a query string to a body (useful for when a GET has to be used).
This commit is contained in:
parent
382b196861
commit
3a0b3851a9
|
@ -0,0 +1,22 @@
|
||||||
|
import { Ctx } from "@budibase/types"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expects a standard "query" query string property which is the JSON body
|
||||||
|
* of the request, which has to be sent via query string due to the requirement
|
||||||
|
* of making an endpoint a GET request e.g. downloading a file stream.
|
||||||
|
*/
|
||||||
|
export default function (ctx: Ctx, next: any) {
|
||||||
|
const queryString = ctx.request.query?.query as string | undefined
|
||||||
|
if (!queryString) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
const decoded = decodeURIComponent(queryString)
|
||||||
|
let json
|
||||||
|
try {
|
||||||
|
json = JSON.parse(decoded)
|
||||||
|
} catch (err) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
ctx.request.body = json
|
||||||
|
return next()
|
||||||
|
}
|
|
@ -17,4 +17,5 @@ export { default as builderOrAdmin } from "./builderOrAdmin"
|
||||||
export { default as builderOnly } from "./builderOnly"
|
export { default as builderOnly } from "./builderOnly"
|
||||||
export { default as logging } from "./logging"
|
export { default as logging } from "./logging"
|
||||||
export { default as errorHandling } from "./errorHandling"
|
export { default as errorHandling } from "./errorHandling"
|
||||||
|
export { default as downloadBody } from "./downloadBody"
|
||||||
export * as joiValidator from "./joi-validator"
|
export * as joiValidator from "./joi-validator"
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
import UserRenderer from "./_components/UserRenderer.svelte"
|
import UserRenderer from "./_components/UserRenderer.svelte"
|
||||||
import TimeRenderer from "./_components/TimeRenderer.svelte"
|
import TimeRenderer from "./_components/TimeRenderer.svelte"
|
||||||
import AppColumnRenderer from "./_components/AppColumnRenderer.svelte"
|
import AppColumnRenderer from "./_components/AppColumnRenderer.svelte"
|
||||||
import download from "downloadjs"
|
import { cloneDeep } from "lodash"
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
date: { width: "0.8fr" },
|
date: { width: "0.8fr" },
|
||||||
user: { width: "0.5fr" },
|
user: { width: "0.5fr" },
|
||||||
app: { width: "1fr", fieldName: "name" },
|
app: { width: "0.75fr", fieldName: "name" },
|
||||||
name: { width: "1fr" },
|
name: { width: "1.5fr" },
|
||||||
view: { width: "auto", borderLeft: true, displayName: "" },
|
view: { width: "auto", borderLeft: true, displayName: "" },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +134,7 @@
|
||||||
$auditLogs.logs.bookmark
|
$auditLogs.logs.bookmark
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
notifications.error(`Error getting audit logs - ${error}`)
|
||||||
notifications.error("Error getting audit logs")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,24 +163,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewDetails = detail => {
|
const viewDetails = detail => {
|
||||||
console.log(detail)
|
|
||||||
selectedLog = detail
|
selectedLog = detail
|
||||||
sidePanelVisible = true
|
sidePanelVisible = true
|
||||||
}
|
}
|
||||||
async function exportView() {
|
|
||||||
try {
|
|
||||||
const data = await API.exportView({
|
|
||||||
viewName: view,
|
|
||||||
format: exportFormat,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
notifications.error(`Unable to export ${exportFormat.toUpperCase()} data`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const downloadLogs = async () => {
|
const downloadLogs = async () => {
|
||||||
try {
|
try {
|
||||||
let response = await auditLogs.downloadLogs({
|
window.location = auditLogs.getDownloadUrl({
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
fullSearch: logSearchTerm,
|
fullSearch: logSearchTerm,
|
||||||
|
@ -189,8 +177,6 @@
|
||||||
appIds: selectedApps,
|
appIds: selectedApps,
|
||||||
events: selectedEvents,
|
events: selectedEvents,
|
||||||
})
|
})
|
||||||
|
|
||||||
// DO SOMETHING HERE???????????
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error(`Error downloading logs: ` + error.message)
|
notifications.error(`Error downloading logs: ` + error.message)
|
||||||
}
|
}
|
||||||
|
@ -205,6 +191,20 @@
|
||||||
notifications.success("Copied")
|
notifications.success("Copied")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanupMetadata(log) {
|
||||||
|
const cloned = cloneDeep(log)
|
||||||
|
cloned.userId = cloned.user._id
|
||||||
|
if (cloned.app) {
|
||||||
|
cloned.appId = cloned.app.appId
|
||||||
|
}
|
||||||
|
// remove props that are confused/not returned in download
|
||||||
|
delete cloned._id
|
||||||
|
delete cloned._rev
|
||||||
|
delete cloned.app
|
||||||
|
delete cloned.user
|
||||||
|
return cloned
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await auditLogs.getEventDefinitions()
|
await auditLogs.getEventDefinitions()
|
||||||
await licensing.init()
|
await licensing.init()
|
||||||
|
@ -277,15 +277,15 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="max-width: 150px; ">
|
||||||
|
<Search placeholder="Search" bind:value={logSearchTerm} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
on:click={() => downloadLogs()}
|
on:click={() => downloadLogs()}
|
||||||
style="padding-bottom: var(--spacing-s)"
|
style="padding-bottom: var(--spacing-s)"
|
||||||
>
|
>
|
||||||
<Icon name="Download" />
|
<Icon name="Download" hoverable />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="max-width: 150px; ">
|
|
||||||
<Search placeholder="Search" bind:value={logSearchTerm} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
|
@ -352,7 +352,7 @@
|
||||||
disabled
|
disabled
|
||||||
minHeight={"300px"}
|
minHeight={"300px"}
|
||||||
height={"100%"}
|
height={"100%"}
|
||||||
value={JSON.stringify(selectedLog.metadata, null, 2)}
|
value={JSON.stringify(cleanupMetadata(selectedLog), null, 2)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,15 +28,15 @@ export function createAuditLogsStore() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadLogs(opts = {}) {
|
function getDownloadUrl(opts = {}) {
|
||||||
return await API.downloadLogs(opts)
|
return API.getDownloadUrl(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
search,
|
search,
|
||||||
getEventDefinitions,
|
getEventDefinitions,
|
||||||
downloadLogs,
|
getDownloadUrl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ const buildOpts = ({
|
||||||
events,
|
events,
|
||||||
}) => {
|
}) => {
|
||||||
const opts = {}
|
const opts = {}
|
||||||
|
|
||||||
if (bookmark) {
|
if (bookmark) {
|
||||||
opts.bookmark = bookmark
|
opts.bookmark = bookmark
|
||||||
}
|
}
|
||||||
|
@ -56,10 +56,8 @@ export const buildAuditLogsEndpoints = API => ({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadLogs: async opts => {
|
getDownloadUrl: opts => {
|
||||||
return await API.post({
|
const query = encodeURIComponent(JSON.stringify(opts))
|
||||||
url: `/api/global/auditlogs/download`,
|
return `/api/global/auditlogs/download?query=${query}`
|
||||||
body: buildOpts(opts),
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { mocks } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
mocks.licenses.useEnvironmentVariables()
|
||||||
|
|
||||||
|
describe("/api/global/auditlogs", () => {})
|
Loading…
Reference in New Issue