Merge branch 'feature/audit-logs' of github.com:Budibase/budibase into feature/audit-logs
This commit is contained in:
commit
59afdc94d4
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<script>
|
||||
export let value
|
||||
</script>
|
||||
|
||||
<div>{value.name}</div>
|
|
@ -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>
|
||||
|
|
|
@ -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)} />
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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 = {}) {
|
||||
|
|
Loading…
Reference in New Issue