Update backup endpoints and fix some errors

This commit is contained in:
Andrew Kingston 2024-12-05 15:10:16 +00:00
parent f99372ae23
commit 29aa2cc936
No known key found for this signature in database
6 changed files with 42 additions and 112 deletions

View File

@ -99,21 +99,18 @@
} }
async function fetchBackups(filters, page, dateRange = []) { async function fetchBackups(filters, page, dateRange = []) {
const body = { const opts = {
appId: $appStore.appId,
...filters, ...filters,
page, page,
} }
const [startDate, endDate] = dateRange const [startDate, endDate] = dateRange
if (startDate) { if (startDate) {
body.startDate = startDate opts.startDate = startDate
} }
if (endDate) { if (endDate) {
body.endDate = endDate opts.endDate = endDate
} }
const response = await backups.searchBackups($appStore.appId, opts)
const response = await backups.searchBackups(body)
pageInfo.fetched(response.hasNextPage, response.nextPage) pageInfo.fetched(response.hasNextPage, response.nextPage)
// flatten so we have an easier structure to use for the table schema // flatten so we have an easier structure to use for the table schema
@ -123,9 +120,7 @@
async function createManualBackup() { async function createManualBackup() {
try { try {
loading = true loading = true
let response = await backups.createManualBackup({ let response = await backups.createManualBackup($appStore.appId)
appId: $appStore.appId,
})
await fetchBackups(filterOpt, page) await fetchBackups(filterOpt, page)
notifications.success(response.message) notifications.success(response.message)
} catch (err) { } catch (err) {
@ -149,24 +144,14 @@
async function handleButtonClick({ detail }) { async function handleButtonClick({ detail }) {
if (detail.type === "backupDelete") { if (detail.type === "backupDelete") {
await backups.deleteBackup({ await backups.deleteBackup($appStore.appId, detail.backupId)
appId: $appStore.appId,
backupId: detail.backupId,
})
await fetchBackups(filterOpt, page) await fetchBackups(filterOpt, page)
} else if (detail.type === "backupRestore") { } else if (detail.type === "backupRestore") {
await backups.restoreBackup({ await backups.restoreBackup(
appId: $appStore.appId, $appStore.appId,
backupId: detail.backupId, detail.backupId,
name: detail.restoreBackupName, detail.restoreBackupName
}) )
await fetchBackups(filterOpt, page)
} else if (detail.type === "backupUpdate") {
await backups.updateBackup({
appId: $appStore.appId,
backupId: detail.backupId,
name: detail.name,
})
await fetchBackups(filterOpt, page) await fetchBackups(filterOpt, page)
} }
} }

View File

@ -11,40 +11,28 @@ export function createBackupsStore() {
}) })
} }
async function searchBackups({ async function searchBackups(appId, opts) {
appId, return API.searchBackups(appId, opts)
trigger,
type,
page,
startDate,
endDate,
}) {
return API.searchBackups(appId, { trigger, type, page, startDate, endDate })
} }
async function restoreBackup({ appId, backupId, name }) { async function restoreBackup(appId, backupId, name) {
return API.restoreBackup({ appId, backupId, name }) return API.restoreBackup(appId, backupId, name)
} }
async function deleteBackup({ appId, backupId }) { async function deleteBackup(appId, backupId) {
return API.deleteBackup({ appId, backupId }) return API.deleteBackup(appId, backupId)
} }
async function createManualBackup(appId) { async function createManualBackup(appId) {
return API.createManualBackup(appId) return API.createManualBackup(appId)
} }
async function updateBackup({ appId, backupId, name }) {
return API.updateBackup({ appId, backupId, name })
}
return { return {
createManualBackup, createManualBackup,
searchBackups, searchBackups,
selectBackup, selectBackup,
deleteBackup, deleteBackup,
restoreBackup, restoreBackup,
updateBackup,
subscribe: store.subscribe, subscribe: store.subscribe,
} }
} }

View File

@ -20,7 +20,6 @@ vi.mock("api", () => {
restoreBackup: vi.fn(() => "restoreBackupReturn"), restoreBackup: vi.fn(() => "restoreBackupReturn"),
deleteBackup: vi.fn(() => "deleteBackupReturn"), deleteBackup: vi.fn(() => "deleteBackupReturn"),
createManualBackup: vi.fn(() => "createManualBackupReturn"), createManualBackup: vi.fn(() => "createManualBackupReturn"),
updateBackup: vi.fn(() => "updateBackupReturn"),
}, },
} }
}) })
@ -61,8 +60,7 @@ describe("backups store", () => {
ctx.page = "page" ctx.page = "page"
ctx.startDate = "startDate" ctx.startDate = "startDate"
ctx.endDate = "endDate" ctx.endDate = "endDate"
ctx.value = await ctx.returnedStore.searchBackups({ ctx.value = await ctx.returnedStore.searchBackups(ctx.appId, {
appId: ctx.appId,
trigger: ctx.trigger, trigger: ctx.trigger,
type: ctx.type, type: ctx.type,
page: ctx.page, page: ctx.page,
@ -73,8 +71,7 @@ describe("backups store", () => {
it("calls and returns the API searchBackups method", ctx => { it("calls and returns the API searchBackups method", ctx => {
expect(API.searchBackups).toHaveBeenCalledTimes(1) expect(API.searchBackups).toHaveBeenCalledTimes(1)
expect(API.searchBackups).toHaveBeenCalledWith({ expect(API.searchBackups).toHaveBeenCalledWith(ctx.appId, {
appId: ctx.appId,
trigger: ctx.trigger, trigger: ctx.trigger,
type: ctx.type, type: ctx.type,
page: ctx.page, page: ctx.page,
@ -103,18 +100,12 @@ describe("backups store", () => {
beforeEach(async ctx => { beforeEach(async ctx => {
ctx.appId = "appId" ctx.appId = "appId"
ctx.backupId = "backupId" ctx.backupId = "backupId"
ctx.value = await ctx.returnedStore.deleteBackup({ ctx.value = await ctx.returnedStore.deleteBackup(ctx.appId, ctx.backupId)
appId: ctx.appId,
backupId: ctx.backupId,
})
}) })
it("calls and returns the API deleteBackup method", ctx => { it("calls and returns the API deleteBackup method", ctx => {
expect(API.deleteBackup).toHaveBeenCalledTimes(1) expect(API.deleteBackup).toHaveBeenCalledTimes(1)
expect(API.deleteBackup).toHaveBeenCalledWith({ expect(API.deleteBackup).toHaveBeenCalledWith(ctx.appId, ctx.backupId)
appId: ctx.appId,
backupId: ctx.backupId,
})
expect(ctx.value).toBe("deleteBackupReturn") expect(ctx.value).toBe("deleteBackupReturn")
}) })
}) })
@ -124,47 +115,24 @@ describe("backups store", () => {
ctx.appId = "appId" ctx.appId = "appId"
ctx.backupId = "backupId" ctx.backupId = "backupId"
ctx.$name = "name" // `name` is used by some sort of internal ctx thing and is readonly ctx.$name = "name" // `name` is used by some sort of internal ctx thing and is readonly
ctx.value = await ctx.returnedStore.restoreBackup({ ctx.value = await ctx.returnedStore.restoreBackup(
appId: ctx.appId, ctx.appId,
backupId: ctx.backupId, ctx.backupId,
name: ctx.$name, ctx.$name
}) )
}) })
it("calls and returns the API restoreBackup method", ctx => { it("calls and returns the API restoreBackup method", ctx => {
expect(API.restoreBackup).toHaveBeenCalledTimes(1) expect(API.restoreBackup).toHaveBeenCalledTimes(1)
expect(API.restoreBackup).toHaveBeenCalledWith({ expect(API.restoreBackup).toHaveBeenCalledWith(
appId: ctx.appId, ctx.appId,
backupId: ctx.backupId, ctx.backupId,
name: ctx.$name, ctx.$name
}) )
expect(ctx.value).toBe("restoreBackupReturn") expect(ctx.value).toBe("restoreBackupReturn")
}) })
}) })
describe("updateBackup", () => {
beforeEach(async ctx => {
ctx.appId = "appId"
ctx.backupId = "backupId"
ctx.$name = "name" // `name` is used by some sort of internal ctx thing and is readonly
ctx.value = await ctx.returnedStore.updateBackup({
appId: ctx.appId,
backupId: ctx.backupId,
name: ctx.$name,
})
})
it("calls and returns the API updateBackup method", ctx => {
expect(API.updateBackup).toHaveBeenCalledTimes(1)
expect(API.updateBackup).toHaveBeenCalledWith({
appId: ctx.appId,
backupId: ctx.backupId,
name: ctx.$name,
})
expect(ctx.value).toBe("updateBackupReturn")
})
})
describe("subscribe", () => { describe("subscribe", () => {
it("calls and returns the API updateBackup method", ctx => { it("calls and returns the API updateBackup method", ctx => {
expect(ctx.returnedStore.subscribe).toBe(ctx.writableReturn.subscribe) expect(ctx.returnedStore.subscribe).toBe(ctx.writableReturn.subscribe)

View File

@ -30,6 +30,7 @@ export const buildAnalyticsEndpoints = (
...request, ...request,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}, },
parseResponse: () => null,
}) })
}, },
}) })

View File

@ -1,26 +1,20 @@
import { import {
CreateAppBackupRequest,
CreateAppBackupResponse, CreateAppBackupResponse,
ImportAppBackupResponse, ImportAppBackupResponse,
SearchAppBackupsRequest, SearchAppBackupsRequest,
UpdateAppBackupRequest,
} from "@budibase/types" } from "@budibase/types"
import { BaseAPIClient } from "./types" import { BaseAPIClient } from "./types"
export interface BackupEndpoints { export interface BackupEndpoints {
createManualBackup: ( createManualBackup: (appId: string) => Promise<CreateAppBackupResponse>
appId: string,
name?: string
) => Promise<CreateAppBackupResponse>
restoreBackup: ( restoreBackup: (
appId: string, appId: string,
backupId: string, backupId: string,
name: string name?: string
) => Promise<ImportAppBackupResponse> ) => Promise<ImportAppBackupResponse>
// Missing request or response types // Missing request or response types
searchBackups: (appId: string, opts: SearchAppBackupsRequest) => Promise<any> searchBackups: (appId: string, opts: SearchAppBackupsRequest) => Promise<any>
updateBackup: (appId: string, backupId: string, name: string) => Promise<any>
deleteBackup: ( deleteBackup: (
appId: string, appId: string,
backupId: string backupId: string
@ -28,14 +22,9 @@ export interface BackupEndpoints {
} }
export const buildBackupEndpoints = (API: BaseAPIClient): BackupEndpoints => ({ export const buildBackupEndpoints = (API: BaseAPIClient): BackupEndpoints => ({
createManualBackup: async (appId, name) => { createManualBackup: async appId => {
return await API.post<CreateAppBackupRequest, CreateAppBackupResponse>({ return await API.post({
url: `/api/apps/${appId}/backups`, url: `/api/apps/${appId}/backups`,
body: name
? {
name,
}
: undefined,
}) })
}, },
searchBackups: async (appId, opts) => { searchBackups: async (appId, opts) => {
@ -49,15 +38,12 @@ export const buildBackupEndpoints = (API: BaseAPIClient): BackupEndpoints => ({
url: `/api/apps/${appId}/backups/${backupId}`, url: `/api/apps/${appId}/backups/${backupId}`,
}) })
}, },
updateBackup: async (appId, backupId, name) => {
return await API.patch<UpdateAppBackupRequest, any>({
url: `/api/apps/${appId}/backups/${backupId}`,
body: { name },
})
},
restoreBackup: async (appId, backupId, name) => { restoreBackup: async (appId, backupId, name) => {
return await API.post({ return await API.post({
url: `/api/apps/${appId}/backups/${backupId}/import`, url: `/api/apps/${appId}/backups/${backupId}/import`,
// Name is a legacy thing, but unsure if it is needed for restoring.
// Leaving this in just in case, but not type casting the body here
// as we won't normally have it, but it's required in the type.
body: { name }, body: { name },
}) })
}, },

View File

@ -160,8 +160,10 @@ export const createAPIClient = (config: APIClientConfig = {}): APIClient => {
try { try {
if (parseResponse) { if (parseResponse) {
return await parseResponse(response) return await parseResponse(response)
} else { } else if (response.status !== 204) {
return (await response.json()) as ResponseT return (await response.json()) as ResponseT
} else {
return undefined
} }
} catch (error) { } catch (error) {
delete cache[url] delete cache[url]