templates working end to end
This commit is contained in:
parent
15a01f0c1d
commit
ddfecf14dc
Binary file not shown.
After Width: | Height: | Size: 167 KiB |
|
@ -31,11 +31,14 @@
|
||||||
APP_NAME_REGEX,
|
APP_NAME_REGEX,
|
||||||
"App name must be letters, numbers and spaces only"
|
"App name must be letters, numbers and spaces only"
|
||||||
),
|
),
|
||||||
file: template ? mixed().required("Please choose a file to import") : null,
|
file: template?.fromFile
|
||||||
|
? mixed().required("Please choose a file to import")
|
||||||
|
: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
let submitting = false
|
let submitting = false
|
||||||
let valid = false
|
let valid = false
|
||||||
|
|
||||||
$: checkValidity($values, validator)
|
$: checkValidity($values, validator)
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
|
@ -73,7 +76,7 @@
|
||||||
submitting = true
|
submitting = true
|
||||||
|
|
||||||
// Check a template exists if we are important
|
// Check a template exists if we are important
|
||||||
if (template && !$values.file) {
|
if (template?.fromFile && !$values.file) {
|
||||||
$errors.file = "Please choose a file to import"
|
$errors.file = "Please choose a file to import"
|
||||||
valid = false
|
valid = false
|
||||||
submitting = false
|
submitting = false
|
||||||
|
@ -134,12 +137,12 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ModalContent
|
<ModalContent
|
||||||
title={template ? "Import app" : "Create app"}
|
title={template?.fromFile ? "Import app" : "Create app"}
|
||||||
confirmText={template ? "Import app" : "Create app"}
|
confirmText={template?.fromFile ? "Import app" : "Create app"}
|
||||||
onConfirm={createNewApp}
|
onConfirm={createNewApp}
|
||||||
disabled={!valid}
|
disabled={!valid}
|
||||||
>
|
>
|
||||||
{#if template}
|
{#if template?.fromFile}
|
||||||
<Dropzone
|
<Dropzone
|
||||||
error={$touched.file && $errors.file}
|
error={$touched.file && $errors.file}
|
||||||
gallery={false}
|
gallery={false}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<script>
|
||||||
|
import { ModalContent, Body } from "@budibase/bbui"
|
||||||
|
import { auth } from "stores/portal"
|
||||||
|
import TemplateList from "./TemplateList.svelte"
|
||||||
|
import CreateAppModal from "./CreateAppModal.svelte"
|
||||||
|
import BudiWorldImage from "assets/budiworld.webp"
|
||||||
|
|
||||||
|
let step = 0
|
||||||
|
let template
|
||||||
|
|
||||||
|
function nextStep() {
|
||||||
|
step += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTemplate(selectedTemplate) {
|
||||||
|
// get the template from the URL
|
||||||
|
template = selectedTemplate
|
||||||
|
nextStep()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if step === 0}
|
||||||
|
<ModalContent
|
||||||
|
title={`Welcome ${$auth.user?.firstName + "!" || "!"}`}
|
||||||
|
confirmText="Next"
|
||||||
|
onConfirm={() => {
|
||||||
|
nextStep()
|
||||||
|
return false
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body size="S">
|
||||||
|
<p>Welcome to Budibase!</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We're different from other development tools in some really special
|
||||||
|
ways, so we'd like to take you through them.
|
||||||
|
</p>
|
||||||
|
</Body>
|
||||||
|
<img
|
||||||
|
alt="Budibase community world"
|
||||||
|
class="budibase-world-image"
|
||||||
|
src={BudiWorldImage}
|
||||||
|
/>
|
||||||
|
</ModalContent>
|
||||||
|
{:else if step === 1}
|
||||||
|
<ModalContent
|
||||||
|
title={"Start from scratch or select a template"}
|
||||||
|
confirmText="Start from Scratch"
|
||||||
|
onConfirm={() => {
|
||||||
|
nextStep()
|
||||||
|
return false
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body size="S">
|
||||||
|
One of the coolest things about Budibase is that you don't have to start
|
||||||
|
from scratch. Simply select a template below, and get to work.
|
||||||
|
</Body>
|
||||||
|
<TemplateList onSelect={selectTemplate} />
|
||||||
|
</ModalContent>
|
||||||
|
{:else if step === 2}
|
||||||
|
<CreateAppModal {template} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.budibase-world-image {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { Button, Heading, Body } from "@budibase/bbui"
|
import { Heading, Body } from "@budibase/bbui"
|
||||||
import Spinner from "components/common/Spinner.svelte"
|
import Spinner from "components/common/Spinner.svelte"
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<Heading size="M">Start With a Template</Heading>
|
|
||||||
{#await templatesPromise}
|
{#await templatesPromise}
|
||||||
<div class="spinner-container">
|
<div class="spinner-container">
|
||||||
<Spinner size="30" />
|
<Spinner size="30" />
|
||||||
|
@ -23,16 +22,14 @@
|
||||||
<div class="templates">
|
<div class="templates">
|
||||||
{#each templates as template}
|
{#each templates as template}
|
||||||
<div class="templates-card">
|
<div class="templates-card">
|
||||||
<Heading size="S">{template.name}</Heading>
|
<img
|
||||||
<Body size="M" grey>{template.category}</Body>
|
alt="template"
|
||||||
|
on:click={() => onSelect(template)}
|
||||||
|
src={template.image}
|
||||||
|
width="100%"
|
||||||
|
/>
|
||||||
|
<Heading size="XS">{template.name}</Heading>
|
||||||
<Body size="S" black>{template.description}</Body>
|
<Body size="S" black>{template.description}</Body>
|
||||||
<div><img alt="template" src={template.image} width="100%" /></div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<Button secondary on:click={() => onSelect(template)}>
|
|
||||||
Create
|
|
||||||
{template.name}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,19 +41,20 @@
|
||||||
<style>
|
<style>
|
||||||
.templates {
|
.templates {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
width: 100%;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-gap: var(--layout-m);
|
grid-gap: var(--layout-m);
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.templates-card {
|
.templates-card {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
padding: var(--spacing-xl);
|
|
||||||
border-radius: var(--border-radius-m);
|
|
||||||
border: var(--border-dark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-footer {
|
img {
|
||||||
margin-top: var(--spacing-m);
|
height: 135px;
|
||||||
|
width: 278px;
|
||||||
|
margin-bottom: var(--layout-m);
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -159,8 +159,6 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
filter: brightness(110%);
|
filter: brightness(110%);
|
||||||
}
|
}
|
||||||
.group {
|
|
||||||
}
|
|
||||||
.app {
|
.app {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
import CreateAppModal from "components/start/CreateAppModal.svelte"
|
||||||
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
import UpdateAppModal from "components/start/UpdateAppModal.svelte"
|
||||||
|
import OnboardingModal from "components/start/OnboardingModal.svelte"
|
||||||
import { del } from "builderStore/api"
|
import { del } from "builderStore/api"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { apps, auth, admin } from "stores/portal"
|
import { apps, auth, admin } from "stores/portal"
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
let updatingModal
|
let updatingModal
|
||||||
let deletionModal
|
let deletionModal
|
||||||
let unpublishModal
|
let unpublishModal
|
||||||
|
let onboardingModal
|
||||||
let creatingApp = false
|
let creatingApp = false
|
||||||
let loaded = false
|
let loaded = false
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
|
@ -197,6 +199,9 @@
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await apps.load()
|
await apps.load()
|
||||||
loaded = true
|
loaded = true
|
||||||
|
// TODO: only show when they have not onboarded yet
|
||||||
|
// If apps = 0 or user isn't onboarded?
|
||||||
|
onboardingModal.show()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -316,6 +321,9 @@
|
||||||
</ConfirmDialog>
|
</ConfirmDialog>
|
||||||
|
|
||||||
<UpdateAppModal app={selectedApp} bind:this={updatingModal} />
|
<UpdateAppModal app={selectedApp} bind:this={updatingModal} />
|
||||||
|
<Modal width={"100px"} bind:this={onboardingModal}>
|
||||||
|
<OnboardingModal />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.title,
|
.title,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -76,7 +76,7 @@ exports.getTemplateStream = async template => {
|
||||||
if (template.file) {
|
if (template.file) {
|
||||||
return fs.createReadStream(template.file.path)
|
return fs.createReadStream(template.file.path)
|
||||||
} else {
|
} else {
|
||||||
const tmpPath = await exports.downloadTemplate(...template.key.split("/"))
|
const tmpPath = await exports.downloadTemplate(template.key)
|
||||||
return fs.createReadStream(join(tmpPath, "db", "dump.txt"))
|
return fs.createReadStream(join(tmpPath, "db", "dump.txt"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,11 +218,13 @@ exports.deleteApp = async appId => {
|
||||||
* @param name
|
* @param name
|
||||||
* @return {Promise<*>}
|
* @return {Promise<*>}
|
||||||
*/
|
*/
|
||||||
exports.downloadTemplate = async (type, name) => {
|
exports.downloadTemplate = async path => {
|
||||||
|
const [type, name] = path.split("/")
|
||||||
|
|
||||||
const DEFAULT_TEMPLATES_BUCKET =
|
const DEFAULT_TEMPLATES_BUCKET =
|
||||||
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
||||||
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz`
|
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz`
|
||||||
return downloadTarball(templateUrl, ObjectStoreBuckets.TEMPLATES, type)
|
return downloadTarball(templateUrl, ObjectStoreBuckets.TEMPLATES, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue