Backups UI Changes (#9726)

* Backups UI Changes

* PR Feedback

---------

Co-authored-by: Rory Powell <rory.codes@gmail.com>
This commit is contained in:
Gerard Burns 2023-02-22 10:03:11 +00:00 committed by GitHub
parent faaf01cd53
commit e7f8a8a801
10 changed files with 67 additions and 116 deletions

View File

@ -0,0 +1,13 @@
const getUserInitials = user => {
if (user.firstName && user.lastName) {
return user.firstName[0] + user.lastName[0]
} else if (user.firstName) {
return user.firstName[0]
} else if (user.email) {
return user.email[0]
}
return "U"
}
export default getUserInitials

View File

@ -3,31 +3,26 @@
ActionMenu,
MenuItem,
Icon,
Input,
Heading,
Body,
Modal,
} from "@budibase/bbui"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import CreateRestoreModal from "./CreateRestoreModal.svelte"
import { createEventDispatcher, onMount } from "svelte"
import { createEventDispatcher } from "svelte"
export let row
let deleteDialog
let restoreDialog
let updateDialog
let name
let restoreBackupModal
const dispatch = createEventDispatcher()
const onClickRestore = name => {
const onClickRestore = () => {
dispatch("buttonclick", {
type: "backupRestore",
name,
backupId: row._id,
restoreBackupName: name,
})
}
@ -38,21 +33,9 @@
})
}
const onClickUpdate = () => {
dispatch("buttonclick", {
type: "backupUpdate",
backupId: row._id,
name,
})
}
async function downloadExport() {
window.open(`/api/apps/${row.appId}/backups/${row._id}/file`, "_blank")
}
onMount(() => {
name = row.name
})
</script>
<div class="cell">
@ -66,12 +49,11 @@
<MenuItem on:click={deleteDialog.show} icon="Delete">Delete</MenuItem>
<MenuItem on:click={downloadExport} icon="Download">Download</MenuItem>
{/if}
<MenuItem on:click={updateDialog.show} icon="Edit">Rename</MenuItem>
</ActionMenu>
</div>
<Modal bind:this={restoreBackupModal}>
<CreateRestoreModal confirm={name => onClickRestore(name)} />
<CreateRestoreModal confirm={onClickRestore} />
</Modal>
<ConfirmDialog
@ -80,9 +62,7 @@
onOk={onClickDelete}
title="Confirm Deletion"
>
Are you sure you wish to delete the backup
<i>{row.name}?</i>
This action cannot be undone.
Are you sure you wish to delete this backup? This action cannot be undone.
</ConfirmDialog>
<ConfirmDialog
@ -92,21 +72,10 @@
title="Confirm restore"
warning={false}
>
<Heading size="S">{row.name || "Backup"}</Heading>
<Heading size="S">Backup</Heading>
<Body size="S">{new Date(row.timestamp).toLocaleString()}</Body>
</ConfirmDialog>
<ConfirmDialog
bind:this={updateDialog}
disabled={!name}
okText="Confirm"
onOk={onClickUpdate}
title="Update Backup"
warning={false}
>
<Input onlabel="Backup name" bind:value={name} />
</ConfirmDialog>
<style>
.cell {
display: flex;

View File

@ -1,22 +0,0 @@
<script>
import { ModalContent, Input } from "@budibase/bbui"
import { auth } from "stores/portal"
export let createManualBackup
let templateName = $auth.user.firstName
? `${$auth.user.firstName}'s Backup`
: "New Backup"
let name = templateName
</script>
<ModalContent
onConfirm={() => createManualBackup(name)}
title="Create new backup"
diabled={!name}
confirmText="Create"
><Input label="Backup name" bind:value={name} /></ModalContent
>
<style>
</style>

View File

@ -1,8 +0,0 @@
<script>
import { truncate } from "lodash"
export let value
$: truncatedValue = truncate(value, { length: 12 })
</script>
{truncatedValue}

View File

@ -0,0 +1,10 @@
<script>
import dayjs from "dayjs"
import relativeTime from "dayjs/plugin/relativeTime"
dayjs.extend(relativeTime)
export let value
</script>
<span title={value}>{dayjs(value).fromNow()}</span>

View File

@ -1,17 +1,14 @@
<script>
import getUserInitials from "helpers/userInitials.js"
import { Avatar } from "@budibase/bbui"
export let value
let firstName = value?.firstName
let lastName = value?.lastName || ""
$: username =
firstName && lastName ? `${firstName} ${lastName}` : value?.email
$: initials = getUserInitials(value)
</script>
<div class="cell">
{#if value != null}
<div>{username}</div>
{/if}
<div title={value.email} class="cell">
<Avatar size="M" {initials} />
</div>
<style>

View File

@ -4,7 +4,6 @@
DatePicker,
Divider,
Layout,
Modal,
notifications,
Pagination,
Select,
@ -16,25 +15,22 @@
} from "@budibase/bbui"
import { backups, licensing, auth, admin, overview } from "stores/portal"
import { createPaginationStore } from "helpers/pagination"
import DateRenderer from "components/common/renderers/DateTimeRenderer.svelte"
import TimeAgoRenderer from "./_components/TimeAgoRenderer.svelte"
import AppSizeRenderer from "./_components/AppSizeRenderer.svelte"
import CreateBackupModal from "./_components/CreateBackupModal.svelte"
import ActionsRenderer from "./_components/ActionsRenderer.svelte"
import UserRenderer from "./_components/UserRenderer.svelte"
import StatusRenderer from "./_components/StatusRenderer.svelte"
import TypeRenderer from "./_components/TypeRenderer.svelte"
import NameRenderer from "./_components/NameRenderer.svelte"
import BackupsDefault from "assets/backups-default.png"
import { BackupTrigger, BackupType } from "constants/backend/backups"
import { onMount } from "svelte"
let loading = true
let backupData = null
let modal
let pageInfo = createPaginationStore()
let filterOpt = null
let startDate = null
let endDate = null
let loaded = false
let filters = [
{
label: "Manual backup",
@ -44,10 +40,6 @@
label: "Published backup",
value: { type: BackupType.BACKUP, trigger: BackupTrigger.PUBLISH },
},
{
label: "Scheduled backup",
value: { type: BackupType.BACKUP, trigger: BackupTrigger.SCHEDULED },
},
{
label: "Pre-restore backup",
value: { type: BackupType.BACKUP, trigger: BackupTrigger.RESTORING },
@ -71,10 +63,6 @@
displayName: "Date",
width: "auto",
},
name: {
displayName: "Name",
width: "auto",
},
appSize: {
displayName: "App size",
width: "auto",
@ -96,11 +84,10 @@
const customRenderers = [
{ column: "appSize", component: AppSizeRenderer },
{ column: "actions", component: ActionsRenderer },
{ column: "createdAt", component: DateRenderer },
{ column: "createdAt", component: TimeAgoRenderer },
{ column: "createdBy", component: UserRenderer },
{ column: "status", component: StatusRenderer },
{ column: "type", component: TypeRenderer },
{ column: "name", component: NameRenderer },
]
function flattenBackups(backups) {
@ -126,11 +113,11 @@
backupData = flattenBackups(response.data)
}
async function createManualBackup(name) {
async function createManualBackup() {
try {
loading = true
let response = await backups.createManualBackup({
appId: app.instance._id,
name,
})
await fetchBackups(filterOpt, page)
notifications.success(response.message)
@ -139,6 +126,20 @@
}
}
const poll = backupData => {
if (backupData === null) {
return
}
if (backupData.some(datum => datum.status === "started")) {
setTimeout(() => fetchBackups(filterOpt, page), 2000)
} else {
loading = false
}
}
$: poll(backupData)
async function handleButtonClick({ detail }) {
if (detail.type === "backupDelete") {
await backups.deleteBackup({
@ -165,7 +166,7 @@
onMount(async () => {
await fetchBackups(filterOpt, page, startDate, endDate)
loaded = true
loading = false
})
</script>
@ -206,7 +207,7 @@
View plans
</Button>
</div>
{:else if !backupData?.length && loaded && !filterOpt && !startDate}
{:else if !backupData?.length && !loading && !filterOpt && !startDate}
<div class="center">
<Layout noPadding gap="S" justifyItems="center">
<img height="130px" src={BackupsDefault} alt="BackupsDefault" />
@ -215,11 +216,13 @@
<Body>You can manually back up your app any time</Body>
</Layout>
<div>
<Button on:click={modal.show} cta>Create backup</Button>
<Button cta disabled={loading} on:click={createManualBackup}>
Create backup
</Button>
</div>
</Layout>
</div>
{:else if loaded}
{:else}
<Layout noPadding gap="M" alignContent="start">
<div class="controls">
<div class="search">
@ -245,7 +248,9 @@
/>
</div>
<div>
<Button cta on:click={modal.show}>Create new backup</Button>
<Button cta disabled={loading} on:click={createManualBackup}
>Create new backup</Button
>
</div>
</div>
<div class="table">
@ -275,10 +280,6 @@
{/if}
</Layout>
<Modal bind:this={modal}>
<CreateBackupModal {createManualBackup} />
</Modal>
<style>
.title {
display: flex;

View File

@ -2,6 +2,7 @@ import { derived, writable, get } from "svelte/store"
import { API } from "api"
import { admin } from "stores/portal"
import analytics from "analytics"
import getUserInitials from "helpers/userInitials.js"
export function createAuthStore() {
const auth = writable({
@ -18,16 +19,7 @@ export function createAuthStore() {
let isBuilder = false
if ($store.user) {
const user = $store.user
if (user.firstName) {
initials = user.firstName[0]
if (user.lastName) {
initials += user.lastName[0]
}
} else if (user.email) {
initials = user.email[0]
} else {
initials = "Unknown"
}
initials = getUserInitials(user)
isAdmin = !!user.admin?.global
isBuilder = !!user.builder?.global
}

View File

@ -30,8 +30,8 @@ export function createBackupsStore() {
return API.deleteBackup({ appId, backupId })
}
async function createManualBackup(appId, name) {
return API.createManualBackup(appId, name)
async function createManualBackup(appId) {
return API.createManualBackup(appId)
}
async function updateBackup({ appId, backupId, name }) {

View File

@ -21,10 +21,9 @@ export const buildBackupsEndpoints = API => ({
})
},
createManualBackup: async ({ appId, name }) => {
createManualBackup: async ({ appId }) => {
return await API.post({
url: `/api/apps/${appId}/backups`,
body: { name },
})
},