1
0
Fork 0
mirror of synced 2024-09-21 11:53:49 +12:00
budibase/packages/builder/src/components/start/CreateAppModal.svelte

202 lines
5.7 KiB
Svelte
Raw Normal View History

<script>
import { writable, get as svelteGet } from "svelte/store"
import {
notifications,
Input,
ModalContent,
Dropzone,
Body,
Checkbox,
} from "@budibase/bbui"
import { store, automationStore, hostingStore } from "builderStore"
import { admin } from "stores/portal"
import { string, mixed, object } from "yup"
import api, { get, post } from "builderStore/api"
2021-09-21 22:47:14 +12:00
import analytics, { Events } from "analytics"
2021-01-07 06:28:22 +13:00
import { onMount } from "svelte"
import { capitalise } from "helpers"
2021-05-08 00:13:51 +12:00
import { goto } from "@roxi/routify"
import { APP_NAME_REGEX } from "constants"
import TemplateList from "./TemplateList.svelte"
2020-05-27 22:54:53 +12:00
2020-09-26 01:47:42 +12:00
export let template
export let inline
2020-05-27 22:54:53 +12:00
const values = writable({ name: null })
const errors = writable({})
const touched = writable({})
const validator = {
name: string()
.trim()
.required("Your application must have a name")
.matches(
APP_NAME_REGEX,
"App name must be letters, numbers and spaces only"
),
2021-10-06 11:02:28 +13:00
file: template?.fromFile
? mixed().required("Please choose a file to import")
: null,
}
2020-08-04 01:59:50 +12:00
let submitting = false
let valid = false
let initialTemplateInfo = template?.fromFile || template?.key
2021-10-06 11:02:28 +13:00
$: checkValidity($values, validator)
$: showTemplateSelection = !template && !initialTemplateInfo
onMount(async () => {
await hostingStore.actions.fetchDeployedApps()
const existingAppNames = svelteGet(hostingStore).deployedAppNames
validator.name = string()
.trim()
.required("Your application must have a name")
.matches(APP_NAME_REGEX, "App name must be letters and numbers only")
.test(
"non-existing-app-name",
"Another app with the same name already exists",
value => {
return !existingAppNames.some(
appName => appName.toLowerCase() === value.toLowerCase()
)
}
)
})
2020-08-04 01:59:50 +12:00
const checkValidity = async (values, validator) => {
const obj = object().shape(validator)
2021-05-04 22:32:22 +12:00
Object.keys(validator).forEach(key => ($errors[key] = null))
2020-08-04 01:59:50 +12:00
try {
await obj.validate(values, { abortEarly: false })
} catch (validationErrors) {
2021-05-04 22:32:22 +12:00
validationErrors.inner.forEach(error => {
$errors[error.path] = capitalise(error.message)
})
2020-08-04 01:59:50 +12:00
}
valid = await obj.isValid(values)
2020-08-04 01:59:50 +12:00
}
async function createNewApp() {
const letTemplateToUse =
Object.keys(template).length === 0 ? null : template
2020-08-04 01:59:50 +12:00
submitting = true
// Check a template exists if we are important
if (letTemplateToUse?.fromFile && !$values.file) {
$errors.file = "Please choose a file to import"
valid = false
submitting = false
return false
}
2020-08-04 01:59:50 +12:00
try {
2021-03-16 07:32:20 +13:00
// Create form data to create app
let data = new FormData()
data.append("name", $values.name.trim())
data.append("useTemplate", letTemplateToUse != null)
if (letTemplateToUse) {
data.append("templateName", letTemplateToUse.name)
data.append("templateKey", letTemplateToUse.key)
data.append("templateFile", $values.file)
2021-03-16 07:32:20 +13:00
}
2020-08-04 02:26:28 +12:00
// Create App
2021-03-16 07:32:20 +13:00
const appResp = await post("/api/applications", data, {})
2020-08-04 02:26:28 +12:00
const appJson = await appResp.json()
2021-02-24 07:37:37 +13:00
if (!appResp.ok) {
throw new Error(appJson.message)
}
2021-09-21 22:47:14 +12:00
analytics.captureEvent(Events.APP.CREATED, {
name: $values.name,
2021-09-21 22:47:14 +12:00
appId: appJson.instance._id,
letTemplateToUse,
2020-08-04 01:59:50 +12:00
})
2020-08-04 02:26:28 +12:00
// Select Correct Application/DB in prep for creating user
2020-11-20 05:56:23 +13:00
const applicationPkg = await get(
2021-05-17 08:25:37 +12:00
`/api/applications/${appJson.instance._id}/appPackage`
2020-11-20 05:56:23 +13:00
)
2020-08-04 02:26:28 +12:00
const pkg = await applicationPkg.json()
if (applicationPkg.ok) {
2020-11-05 06:09:45 +13:00
await store.actions.initialise(pkg)
2020-11-25 07:11:34 +13:00
await automationStore.actions.fetch()
// update checklist - incase first app
await admin.init()
2020-08-04 02:26:28 +12:00
} else {
throw new Error(pkg)
}
// Create user
const user = {
roleId: $values.roleId,
2020-08-04 02:26:28 +12:00
}
const userResp = await api.post(`/api/users/metadata/self`, user)
await userResp.json()
2021-05-17 08:25:37 +12:00
$goto(`/builder/app/${appJson.instance._id}`)
2020-08-04 01:59:50 +12:00
} catch (error) {
console.error(error)
notifications.error(error)
2021-02-24 07:37:37 +13:00
submitting = false
2020-05-27 21:44:15 +12:00
}
}
2020-05-27 02:25:37 +12:00
</script>
{#if showTemplateSelection}
<ModalContent
2021-10-07 02:33:21 +13:00
title={"Get started quickly"}
showConfirmButton={false}
size="L"
onConfirm={() => {
template = {}
return false
}}
showCancelButton={!inline}
showCloseIcon={!inline}
>
<TemplateList
onSelect={(selected, { useImport } = {}) => {
2021-10-07 02:33:21 +13:00
if (!selected) {
template = useImport ? { fromFile: true } : {}
2021-10-07 02:33:21 +13:00
return
}
template = selected
}}
/>
</ModalContent>
{:else}
<ModalContent
title={template?.fromFile ? "Import app" : "Create app"}
confirmText={template?.fromFile ? "Import app" : "Create app"}
onConfirm={createNewApp}
onCancel={inline ? () => (template = null) : null}
cancelText={inline ? "Back" : undefined}
showCloseIcon={!inline}
disabled={!valid}
>
{#if template?.fromFile}
<Dropzone
error={$touched.file && $errors.file}
gallery={false}
label="File to import"
value={[$values.file]}
on:change={e => {
$values.file = e.detail?.[0]
$touched.file = true
}}
/>
{/if}
<Body size="S">
Give your new app a name, and choose which groups have access (paid plans
only).
</Body>
<Input
bind:value={$values.name}
error={$touched.name && $errors.name}
on:blur={() => ($touched.name = true)}
label="Name"
/>
<Checkbox label="Group access" disabled value={true} text="All users" />
</ModalContent>
{/if}