integrate properly with audit log search api
This commit is contained in:
parent
6cc96f39b1
commit
dc691bcaf7
|
@ -145,7 +145,8 @@
|
||||||
{#if autocomplete}
|
{#if autocomplete}
|
||||||
<Search
|
<Search
|
||||||
value={fetchTerm ? fetchTerm : searchTerm}
|
value={fetchTerm ? fetchTerm : searchTerm}
|
||||||
on:change={event => (fetchTerm = event.detail)}
|
on:change={event =>
|
||||||
|
fetchTerm ? (fetchTerm = event.detail) : (searchTerm = event.detail)}
|
||||||
{disabled}
|
{disabled}
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
/>
|
/>
|
||||||
|
@ -265,7 +266,6 @@
|
||||||
.popover-content :global(.spectrum-Search) {
|
.popover-content :global(.spectrum-Search) {
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
width: calc(100% + 2px);
|
|
||||||
}
|
}
|
||||||
.popover-content :global(.spectrum-Search input) {
|
.popover-content :global(.spectrum-Search input) {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
export let value
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>{value.name}</div>
|
|
@ -1,12 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
|
|
||||||
export let row
|
|
||||||
|
|
||||||
import relativeTime from "dayjs/plugin/relativeTime"
|
import relativeTime from "dayjs/plugin/relativeTime"
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
|
export let row
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{dayjs(row.date).fromNow()}
|
{dayjs(row.timestamp).fromNow()}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { Avatar } from "@budibase/bbui"
|
import { Avatar } from "@budibase/bbui"
|
||||||
export let row
|
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>
|
</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 { licensing, users, apps, auditLogs } from "stores/portal"
|
||||||
import LockedFeature from "../../_components/LockedFeature.svelte"
|
import LockedFeature from "../../_components/LockedFeature.svelte"
|
||||||
import { createPaginationStore } from "helpers/pagination"
|
import { createPaginationStore } from "helpers/pagination"
|
||||||
import { setContext } from "svelte"
|
import { onMount, setContext } from "svelte"
|
||||||
import ViewDetailsRenderer from "./_components/ViewDetailsRenderer.svelte"
|
import ViewDetailsRenderer from "./_components/ViewDetailsRenderer.svelte"
|
||||||
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"
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
name: { width: "1fr" },
|
date: { width: "0.8fr" },
|
||||||
date: { width: "1.5fr" },
|
|
||||||
user: { width: "0.5fr" },
|
user: { width: "0.5fr" },
|
||||||
app: { width: "1fr" },
|
app: { width: "1fr", fieldName: "name" },
|
||||||
event: { width: "1fr" },
|
name: { width: "1fr" },
|
||||||
view: { width: "auto", borderLeft: true, displayName: "" },
|
view: { width: "auto", borderLeft: true, displayName: "" },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,10 @@
|
||||||
column: "date",
|
column: "date",
|
||||||
component: TimeRenderer,
|
component: TimeRenderer,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
column: "app",
|
||||||
|
component: AppColumnRenderer,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
let userSearchTerm = ""
|
let userSearchTerm = ""
|
||||||
|
@ -55,22 +59,15 @@
|
||||||
let sidePanelVisible = false
|
let sidePanelVisible = false
|
||||||
let startDate, endDate
|
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)
|
$: fetchUsers(userPage, userSearchTerm)
|
||||||
$: fetchLogs(logsPage, logSearchTerm)
|
$: fetchLogs(
|
||||||
|
logsPage,
|
||||||
|
logSearchTerm,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
selectedUsers,
|
||||||
|
selectedApps
|
||||||
|
)
|
||||||
|
|
||||||
$: userPage = $userPageInfo.page
|
$: userPage = $userPageInfo.page
|
||||||
$: logsPage = $logsPageInfo.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) {
|
if ($logsPageInfo.loading) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -117,7 +121,10 @@
|
||||||
userIds: selectedUsers,
|
userIds: selectedUsers,
|
||||||
appIds: selectedApps,
|
appIds: selectedApps,
|
||||||
})
|
})
|
||||||
logsPageInfo.fetched($auditLogs.hasNextPage, $auditLogs.nextPage)
|
logsPageInfo.fetched(
|
||||||
|
$auditLogs.logs.hasNextPage,
|
||||||
|
$auditLogs.logs.nextPage
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
notifications.error("Error getting audit logs")
|
notifications.error("Error getting audit logs")
|
||||||
|
@ -170,6 +177,10 @@
|
||||||
setContext("auditLogs", {
|
setContext("auditLogs", {
|
||||||
viewDetails,
|
viewDetails,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
await auditLogs.getEventDefinitions()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LockedFeature
|
<LockedFeature
|
||||||
|
@ -211,16 +222,24 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="select">
|
<div class="select">
|
||||||
<Multiselect
|
<Multiselect
|
||||||
|
autocomplete
|
||||||
placeholder="All apps"
|
placeholder="All apps"
|
||||||
label="App"
|
label="App"
|
||||||
getOptionValue={app => app.appId}
|
getOptionValue={app => "app_dev_" + app.appId}
|
||||||
getOptionLabel={app => app.name}
|
getOptionLabel={app => app.name}
|
||||||
options={$apps}
|
options={$apps}
|
||||||
bind:value={selectedApps}
|
bind:value={selectedApps}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="select">
|
<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>
|
</div>
|
||||||
<div style="padding-bottom: var(--spacing-s)">
|
<div style="padding-bottom: var(--spacing-s)">
|
||||||
|
@ -228,14 +247,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="max-width: 150px; ">
|
<div style="max-width: 150px; ">
|
||||||
<Search placeholder="Search" value={""} />
|
<Search placeholder="Search" bind:value={logSearchTerm} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
<Table
|
<Table
|
||||||
{customRenderers}
|
{customRenderers}
|
||||||
on:click={viewDetails}
|
on:click={viewDetails}
|
||||||
{data}
|
data={$auditLogs.logs.data}
|
||||||
allowEditColumns={false}
|
allowEditColumns={false}
|
||||||
allowEditRows={false}
|
allowEditRows={false}
|
||||||
allowSelectRows={false}
|
allowSelectRows={false}
|
||||||
|
@ -255,7 +274,8 @@
|
||||||
<div class="side-panel-header">
|
<div class="side-panel-header">
|
||||||
Audit Logs
|
Audit Logs
|
||||||
<Icon
|
<Icon
|
||||||
icon="Close"
|
hoverable
|
||||||
|
name="Close"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
sidePanelVisible = false
|
sidePanelVisible = false
|
||||||
}}
|
}}
|
||||||
|
@ -263,7 +283,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div style="padding-top: 10px; height: 95%">
|
<div style="padding-top: 10px; height: 95%">
|
||||||
<CoreTextArea
|
<CoreTextArea
|
||||||
disabled={true}
|
|
||||||
minHeight={"300px"}
|
minHeight={"300px"}
|
||||||
height={"100%"}
|
height={"100%"}
|
||||||
value={JSON.stringify(selectedLog.metadata, null, 2)}
|
value={JSON.stringify(selectedLog.metadata, null, 2)}
|
||||||
|
|
|
@ -3,23 +3,31 @@ import { API } from "api"
|
||||||
import { licensing } from "stores/portal"
|
import { licensing } from "stores/portal"
|
||||||
|
|
||||||
export function createAuditLogsStore() {
|
export function createAuditLogsStore() {
|
||||||
const { subscribe, set } = writable({
|
const { subscribe, update } = writable({
|
||||||
logs: [],
|
events: {},
|
||||||
|
logs: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function search(opts = {}) {
|
async function search(opts = {}) {
|
||||||
if (get(licensing).auditLogsEnabled) {
|
if (get(licensing).auditLogsEnabled) {
|
||||||
const paged = await API.searchAuditLogs(opts)
|
const paged = await API.searchAuditLogs(opts)
|
||||||
set({
|
|
||||||
...paged,
|
update(state => {
|
||||||
...opts,
|
return { ...state, logs: { ...paged, opts } }
|
||||||
})
|
})
|
||||||
|
|
||||||
return paged
|
return paged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEventDefinitions() {
|
async function getEventDefinitions() {
|
||||||
return await API.getEventDefinitions()
|
const events = await API.getEventDefinitions()
|
||||||
|
|
||||||
|
update(state => {
|
||||||
|
return { ...state, ...events }
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function downloadLogs(opts = {}) {
|
async function downloadLogs(opts = {}) {
|
||||||
|
|
Loading…
Reference in New Issue