Add date range picker and update backups and audit logs to use it
This commit is contained in:
parent
0a4dfef8cf
commit
b1bd8993a6
|
@ -0,0 +1,89 @@
|
||||||
|
<script>
|
||||||
|
import { DatePicker } from "@budibase/bbui"
|
||||||
|
import dayjs from "dayjs"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
import { memo } from "@budibase/frontend-core"
|
||||||
|
|
||||||
|
export let value
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
const valueStore = memo(value)
|
||||||
|
|
||||||
|
let date1
|
||||||
|
let date2
|
||||||
|
|
||||||
|
$: valueStore.set(value)
|
||||||
|
$: parseValue($valueStore)
|
||||||
|
|
||||||
|
const parseValue = value => {
|
||||||
|
if (!Array.isArray(value) || !value[0] || !value[1]) {
|
||||||
|
date1 = null
|
||||||
|
date2 = null
|
||||||
|
} else {
|
||||||
|
date1 = value[0]
|
||||||
|
date2 = value[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangeDate1 = e => {
|
||||||
|
date1 = e.detail ? dayjs(e.detail).startOf("day") : null
|
||||||
|
if (date1 && (!date2 || date1.isAfter(date2))) {
|
||||||
|
date2 = date1.endOf("day")
|
||||||
|
} else if (!date1) {
|
||||||
|
date2 = null
|
||||||
|
}
|
||||||
|
broadcastChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangeDate2 = e => {
|
||||||
|
date2 = e.detail ? dayjs(e.detail).endOf("day") : null
|
||||||
|
if (date2 && (!date1 || date2.isBefore(date1))) {
|
||||||
|
date1 = date2.startOf("day")
|
||||||
|
} else if (!date2) {
|
||||||
|
date1 = null
|
||||||
|
}
|
||||||
|
broadcastChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
const broadcastChange = () => {
|
||||||
|
dispatch("change", [date1, date2])
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="date-range-picker">
|
||||||
|
<DatePicker
|
||||||
|
value={date1}
|
||||||
|
label="Date range"
|
||||||
|
enableTime={false}
|
||||||
|
on:change={onChangeDate1}
|
||||||
|
/>
|
||||||
|
<DatePicker value={date2} enableTime={false} on:change={onChangeDate2} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.date-range-picker {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlap date pickers to remove double border, but put the focused one on top */
|
||||||
|
.date-range-picker :global(.spectrum-InputGroup.is-focused) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.date-range-picker :global(> :last-child) {
|
||||||
|
margin-left: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove border radius at the join */
|
||||||
|
.date-range-picker :global(> :first-child .spectrum-InputGroup),
|
||||||
|
.date-range-picker :global(> :first-child .spectrum-Picker) {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
.date-range-picker :global(> :last-child .spectrum-InputGroup),
|
||||||
|
.date-range-picker :global(> :last-child .spectrum-Textfield-input) {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
DatePicker,
|
|
||||||
Divider,
|
Divider,
|
||||||
Layout,
|
Layout,
|
||||||
notifications,
|
notifications,
|
||||||
|
@ -25,14 +24,13 @@
|
||||||
import BackupsDefault from "assets/backups-default.png"
|
import BackupsDefault from "assets/backups-default.png"
|
||||||
import { BackupTrigger, BackupType } from "constants/backend/backups"
|
import { BackupTrigger, BackupType } from "constants/backend/backups"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import dayjs from "dayjs"
|
import DateRangePicker from "components/common/DateRangePicker.svelte"
|
||||||
|
|
||||||
let loading = true
|
let loading = true
|
||||||
let backupData = null
|
let backupData = null
|
||||||
let pageInfo = createPaginationStore()
|
let pageInfo = createPaginationStore()
|
||||||
let filterOpt = null
|
let filterOpt = null
|
||||||
let startDate = null
|
let dateRange = []
|
||||||
let endDate = null
|
|
||||||
let filters = [
|
let filters = [
|
||||||
{
|
{
|
||||||
label: "Manual backup",
|
label: "Manual backup",
|
||||||
|
@ -53,7 +51,7 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
$: page = $pageInfo.page
|
$: page = $pageInfo.page
|
||||||
$: fetchBackups(filterOpt, page, startDate, endDate)
|
$: fetchBackups(filterOpt, page, dateRange)
|
||||||
|
|
||||||
let schema = {
|
let schema = {
|
||||||
type: {
|
type: {
|
||||||
|
@ -100,13 +98,13 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchBackups(filters, page, startDate, endDate) {
|
async function fetchBackups(filters, page, dateRange) {
|
||||||
const response = await backups.searchBackups({
|
const response = await backups.searchBackups({
|
||||||
appId: $appStore.appId,
|
appId: $appStore.appId,
|
||||||
...filters,
|
...filters,
|
||||||
page,
|
page,
|
||||||
startDate: startDate ? dayjs(startDate).startOf("day") : null,
|
startDate: dateRange[0],
|
||||||
endDate: endDate ? dayjs(endDate).endOf("day") : null,
|
endDate: dateRange[1],
|
||||||
})
|
})
|
||||||
pageInfo.fetched(response.hasNextPage, response.nextPage)
|
pageInfo.fetched(response.hasNextPage, response.nextPage)
|
||||||
|
|
||||||
|
@ -166,7 +164,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await fetchBackups(filterOpt, page, startDate, endDate)
|
await fetchBackups(filterOpt, page, dateRange)
|
||||||
loading = false
|
loading = false
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -208,7 +206,7 @@
|
||||||
View plans
|
View plans
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{:else if !backupData?.length && !loading && !filterOpt && !startDate}
|
{:else if !backupData?.length && !loading && !filterOpt && !dateRange?.length}
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<Layout noPadding gap="S" justifyItems="center">
|
<Layout noPadding gap="S" justifyItems="center">
|
||||||
<img height="130px" src={BackupsDefault} alt="BackupsDefault" />
|
<img height="130px" src={BackupsDefault} alt="BackupsDefault" />
|
||||||
|
@ -237,21 +235,9 @@
|
||||||
bind:value={filterOpt}
|
bind:value={filterOpt}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<DatePicker
|
<DateRangePicker
|
||||||
value={startDate}
|
value={dateRange}
|
||||||
label="From"
|
on:change={e => (dateRange = e.detail)}
|
||||||
enableTime={false}
|
|
||||||
on:change={e => {
|
|
||||||
startDate = e.detail
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DatePicker
|
|
||||||
value={endDate}
|
|
||||||
label="Until"
|
|
||||||
enableTime={false}
|
|
||||||
on:change={e => {
|
|
||||||
endDate = e.detail
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
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 { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
|
import DateRangePicker from "components/common/DateRangePicker.svelte"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
|
@ -70,15 +71,13 @@
|
||||||
let sidePanelVisible = false
|
let sidePanelVisible = false
|
||||||
let wideSidePanel = false
|
let wideSidePanel = false
|
||||||
let timer
|
let timer
|
||||||
let endDate = dayjs()
|
let dateRange = [dayjs().subtract(30, "days"), dayjs()]
|
||||||
let startDate = endDate.subtract(30, "days")
|
|
||||||
|
|
||||||
$: fetchUsers(userPage, userSearchTerm)
|
$: fetchUsers(userPage, userSearchTerm)
|
||||||
$: fetchLogs({
|
$: fetchLogs({
|
||||||
logsPage,
|
logsPage,
|
||||||
logSearchTerm,
|
logSearchTerm,
|
||||||
startDate,
|
dateRange,
|
||||||
endDate,
|
|
||||||
selectedUsers,
|
selectedUsers,
|
||||||
selectedApps,
|
selectedApps,
|
||||||
selectedEvents,
|
selectedEvents,
|
||||||
|
@ -136,8 +135,7 @@
|
||||||
const fetchLogs = async ({
|
const fetchLogs = async ({
|
||||||
logsPage,
|
logsPage,
|
||||||
logSearchTerm,
|
logSearchTerm,
|
||||||
startDate,
|
dateRange,
|
||||||
endDate,
|
|
||||||
selectedUsers,
|
selectedUsers,
|
||||||
selectedApps,
|
selectedApps,
|
||||||
selectedEvents,
|
selectedEvents,
|
||||||
|
@ -155,8 +153,8 @@
|
||||||
logsPageInfo.loading()
|
logsPageInfo.loading()
|
||||||
await auditLogs.search({
|
await auditLogs.search({
|
||||||
bookmark: logsPage,
|
bookmark: logsPage,
|
||||||
startDate: startDate ? dayjs(startDate).startOf("day") : null,
|
startDate: dateRange[0],
|
||||||
endDate: endDate ? dayjs(endDate).endOf("day") : null,
|
endDate: dateRange[1],
|
||||||
fullSearch: logSearchTerm,
|
fullSearch: logSearchTerm,
|
||||||
userIds: selectedUsers,
|
userIds: selectedUsers,
|
||||||
appIds: selectedApps,
|
appIds: selectedApps,
|
||||||
|
@ -214,8 +212,8 @@
|
||||||
const downloadLogs = async () => {
|
const downloadLogs = async () => {
|
||||||
try {
|
try {
|
||||||
window.location = auditLogs.getDownloadUrl({
|
window.location = auditLogs.getDownloadUrl({
|
||||||
startDate,
|
startDate: dateRange[0],
|
||||||
endDate,
|
endDate: dateRange[1],
|
||||||
fullSearch: logSearchTerm,
|
fullSearch: logSearchTerm,
|
||||||
userIds: selectedUsers,
|
userIds: selectedUsers,
|
||||||
appIds: selectedApps,
|
appIds: selectedApps,
|
||||||
|
@ -302,21 +300,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="date-picker">
|
<div class="date-picker">
|
||||||
<DatePicker
|
<DateRangePicker
|
||||||
value={startDate}
|
value={dateRange}
|
||||||
label="From"
|
on:change={e => (dateRange = e.detail)}
|
||||||
enableTime={false}
|
|
||||||
on:change={e => {
|
|
||||||
startDate = e.detail
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DatePicker
|
|
||||||
value={endDate}
|
|
||||||
label="Until"
|
|
||||||
enableTime={false}
|
|
||||||
on:change={e => {
|
|
||||||
endDate = e.detail
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="freeSearch">
|
<div class="freeSearch">
|
||||||
|
@ -506,9 +492,9 @@
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--spacing-l);
|
|
||||||
}
|
}
|
||||||
.date-picker :global(> *) {
|
.date-picker :global(.date-range-picker),
|
||||||
|
.date-picker :global(.spectrum-Form-item) {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
width: 0;
|
width: 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue