diff --git a/packages/backend-core/src/events/publishers/app.ts b/packages/backend-core/src/events/publishers/app.ts
index d08d59b5f1..af26b09e72 100644
--- a/packages/backend-core/src/events/publishers/app.ts
+++ b/packages/backend-core/src/events/publishers/app.ts
@@ -13,6 +13,7 @@ import {
AppVersionRevertedEvent,
AppRevertedEvent,
AppExportedEvent,
+ AppDuplicatedEvent,
} from "@budibase/types"
const created = async (app: App, timestamp?: string | number) => {
@@ -77,6 +78,17 @@ async function fileImported(app: App) {
await publishEvent(Event.APP_FILE_IMPORTED, properties)
}
+async function duplicated(app: App, duplicateAppId: string) {
+ const properties: AppDuplicatedEvent = {
+ duplicateAppId,
+ appId: app.appId,
+ audited: {
+ name: app.name,
+ },
+ }
+ await publishEvent(Event.APP_DUPLICATED, properties)
+}
+
async function templateImported(app: App, templateKey: string) {
const properties: AppTemplateImportedEvent = {
appId: app.appId,
@@ -147,6 +159,7 @@ export default {
published,
unpublished,
fileImported,
+ duplicated,
templateImported,
versionUpdated,
versionReverted,
diff --git a/packages/backend-core/tests/core/utilities/mocks/events.ts b/packages/backend-core/tests/core/utilities/mocks/events.ts
index fef730768a..96f351de10 100644
--- a/packages/backend-core/tests/core/utilities/mocks/events.ts
+++ b/packages/backend-core/tests/core/utilities/mocks/events.ts
@@ -15,6 +15,7 @@ beforeAll(async () => {
jest.spyOn(events.app, "created")
jest.spyOn(events.app, "updated")
+ jest.spyOn(events.app, "duplicated")
jest.spyOn(events.app, "deleted")
jest.spyOn(events.app, "published")
jest.spyOn(events.app, "unpublished")
diff --git a/packages/bbui/src/Form/Core/index.js b/packages/bbui/src/Form/Core/index.js
index b0edf52748..3e5befca0b 100644
--- a/packages/bbui/src/Form/Core/index.js
+++ b/packages/bbui/src/Form/Core/index.js
@@ -14,3 +14,4 @@ export { default as CoreStepper } from "./Stepper.svelte"
export { default as CoreRichTextField } from "./RichTextField.svelte"
export { default as CoreSlider } from "./Slider.svelte"
export { default as CoreFile } from "./File.svelte"
+export { default as CoreEnv } from "./EnvSwitch.svelte"
diff --git a/packages/builder/src/components/deploy/DeleteModal.svelte b/packages/builder/src/components/deploy/DeleteModal.svelte
index 855f6a0757..293d0adf60 100644
--- a/packages/builder/src/components/deploy/DeleteModal.svelte
+++ b/packages/builder/src/components/deploy/DeleteModal.svelte
@@ -3,9 +3,16 @@
import { goto } from "@roxi/routify"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { apps } from "stores/portal"
- import { appStore } from "stores/builder"
import { API } from "api"
+ export let appId
+ export let appName
+ export let onDeleteSuccess = () => {
+ $goto("/builder")
+ }
+
+ let deleting = false
+
export const show = () => {
deletionModal.show()
}
@@ -17,14 +24,24 @@
let deletionModal
let deletionConfirmationAppName
+ const copyName = () => {
+ deletionConfirmationAppName = appName
+ }
+
const deleteApp = async () => {
+ if (!appId) {
+ console.log("No app id provided")
+ return
+ }
+ deleting = true
try {
- await API.deleteApp($appStore.appId)
+ await API.deleteApp(appId)
apps.load()
notifications.success("App deleted successfully")
- $goto("/builder")
+ onDeleteSuccess()
} catch (err) {
notifications.error("Error deleting app")
+ deleting = false
}
}
@@ -35,14 +52,19 @@
okText="Delete"
onOk={deleteApp}
onCancel={() => (deletionConfirmationAppName = null)}
- disabled={deletionConfirmationAppName !== $appStore.name}
+ disabled={deletionConfirmationAppName !== appName || deleting}
>
- Are you sure you want to delete {$appStore.name}?
+
+ Are you sure you want to delete
+ {appName}?
Please enter the app name below to confirm.
-
+
+
+
diff --git a/packages/builder/src/components/start/AppRow.svelte b/packages/builder/src/components/start/AppRow.svelte
index c05ae4c624..dd23487870 100644
--- a/packages/builder/src/components/start/AppRow.svelte
+++ b/packages/builder/src/components/start/AppRow.svelte
@@ -5,6 +5,7 @@
import { goto } from "@roxi/routify"
import { UserAvatars } from "@budibase/frontend-core"
import { sdk } from "@budibase/shared-core"
+ import AppRowContext from "./AppRowContext.svelte"
export let app
export let lockedAction
@@ -74,12 +75,10 @@
{#if isBuilder}