Merge branch 'feature/audit-logs' of github.com:Budibase/budibase into feature/audit-logs

This commit is contained in:
mike12345567 2023-02-21 12:25:59 +00:00
commit 59afdc94d4
6 changed files with 80 additions and 41 deletions

View File

@ -145,7 +145,8 @@
{#if autocomplete}
<Search
value={fetchTerm ? fetchTerm : searchTerm}
on:change={event => (fetchTerm = event.detail)}
on:change={event =>
fetchTerm ? (fetchTerm = event.detail) : (searchTerm = event.detail)}
{disabled}
placeholder="Search"
/>
@ -265,7 +266,6 @@
.popover-content :global(.spectrum-Search) {
margin-top: -1px;
margin-left: -1px;
width: calc(100% + 2px);
}
.popover-content :global(.spectrum-Search input) {
height: auto;

View File

@ -0,0 +1,5 @@
<script>
export let value
</script>
<div>{value.name}</div>

View File

@ -1,12 +1,11 @@
<script>
import dayjs from "dayjs"
export let row
import relativeTime from "dayjs/plugin/relativeTime"
dayjs.extend(relativeTime)
export let row
</script>
<div>
{dayjs(row.date).fromNow()}
{dayjs(row.timestamp).fromNow()}
</div>

View File

@ -1,6 +1,14 @@
<script>
import { Avatar } from "@budibase/bbui"
export let row
const getInitials = user => {
let initials = ""
initials += user.firstName ? user.firstName[0] : ""
initials += user.lastName ? user.lastName[0] : ""
return initials === "" ? user.email[0] : initials
}
</script>
<Avatar size="M" initials={row.user[0]} />
<Avatar size="M" initials={getInitials(row.user)} />

View File

@ -13,17 +13,17 @@
import { licensing, users, apps, auditLogs } from "stores/portal"
import LockedFeature from "../../_components/LockedFeature.svelte"
import { createPaginationStore } from "helpers/pagination"
import { setContext } from "svelte"
import { onMount, setContext } from "svelte"
import ViewDetailsRenderer from "./_components/ViewDetailsRenderer.svelte"
import UserRenderer from "./_components/UserRenderer.svelte"
import TimeRenderer from "./_components/TimeRenderer.svelte"
import AppColumnRenderer from "./_components/AppColumnRenderer.svelte"
const schema = {
name: { width: "1fr" },
date: { width: "1.5fr" },
date: { width: "0.8fr" },
user: { width: "0.5fr" },
app: { width: "1fr" },
event: { width: "1fr" },
app: { width: "1fr", fieldName: "name" },
name: { width: "1fr" },
view: { width: "auto", borderLeft: true, displayName: "" },
}
@ -40,6 +40,10 @@
column: "date",
component: TimeRenderer,
},
{
column: "app",
component: AppColumnRenderer,
},
]
let userSearchTerm = ""
@ -55,22 +59,15 @@
let sidePanelVisible = false
let startDate, endDate
let data = [
{
name: "User created",
date: "2023-02-14T10:19:52.021Z",
user: "Peter Clement",
app: "School Admin Panel",
event: "User added",
metadata: {
name: "Peter Clement",
email: "",
},
},
]
$: fetchUsers(userPage, userSearchTerm)
$: fetchLogs(logsPage, logSearchTerm)
$: fetchLogs(
logsPage,
logSearchTerm,
startDate,
endDate,
selectedUsers,
selectedApps
)
$: userPage = $userPageInfo.page
$: logsPage = $logsPageInfo.page
@ -97,7 +94,14 @@
}
}
const fetchLogs = async (logsPage, search) => {
const fetchLogs = async (
logsPage,
search,
startDate,
endDate,
selectedUsers,
selectedApps
) => {
if ($logsPageInfo.loading) {
return
}
@ -117,7 +121,10 @@
userIds: selectedUsers,
appIds: selectedApps,
})
logsPageInfo.fetched($auditLogs.hasNextPage, $auditLogs.nextPage)
logsPageInfo.fetched(
$auditLogs.logs.hasNextPage,
$auditLogs.logs.nextPage
)
} catch (error) {
console.log(error)
notifications.error("Error getting audit logs")
@ -170,6 +177,10 @@
setContext("auditLogs", {
viewDetails,
})
onMount(async () => {
await auditLogs.getEventDefinitions()
})
</script>
<LockedFeature
@ -211,16 +222,24 @@
</div>
<div class="select">
<Multiselect
autocomplete
placeholder="All apps"
label="App"
getOptionValue={app => app.appId}
getOptionValue={app => "app_dev_" + app.appId}
getOptionLabel={app => app.name}
options={$apps}
bind:value={selectedApps}
/>
</div>
<div class="select">
<Multiselect placeholder="All events" label="Event" />
<Multiselect
autocomplete
getOptionValue={event => event[0]}
getOptionLabel={event => event[1]}
options={Object.entries($auditLogs.events)}
placeholder="All events"
label="Event"
/>
</div>
</div>
<div style="padding-bottom: var(--spacing-s)">
@ -228,14 +247,14 @@
</div>
<div style="max-width: 150px; ">
<Search placeholder="Search" value={""} />
<Search placeholder="Search" bind:value={logSearchTerm} />
</div>
</div>
<Layout noPadding>
<Table
{customRenderers}
on:click={viewDetails}
{data}
data={$auditLogs.logs.data}
allowEditColumns={false}
allowEditRows={false}
allowSelectRows={false}
@ -255,7 +274,8 @@
<div class="side-panel-header">
Audit Logs
<Icon
icon="Close"
hoverable
name="Close"
on:click={() => {
sidePanelVisible = false
}}
@ -263,7 +283,6 @@
</div>
<div style="padding-top: 10px; height: 95%">
<CoreTextArea
disabled={true}
minHeight={"300px"}
height={"100%"}
value={JSON.stringify(selectedLog.metadata, null, 2)}

View File

@ -3,23 +3,31 @@ import { API } from "api"
import { licensing } from "stores/portal"
export function createAuditLogsStore() {
const { subscribe, set } = writable({
logs: [],
const { subscribe, update } = writable({
events: {},
logs: {},
})
async function search(opts = {}) {
if (get(licensing).auditLogsEnabled) {
const paged = await API.searchAuditLogs(opts)
set({
...paged,
...opts,
update(state => {
return { ...state, logs: { ...paged, opts } }
})
return paged
}
}
async function getEventDefinitions() {
return await API.getEventDefinitions()
const events = await API.getEventDefinitions()
update(state => {
return { ...state, ...events }
})
console.log(events)
}
async function downloadLogs(opts = {}) {