mirror of https://github.com/Budibase/budibase.git
committed by
GitHub
30 changed files with 409 additions and 48 deletions
@ -0,0 +1,75 @@ |
|||
<script> |
|||
import { Button, Heading, Body } from "@budibase/bbui" |
|||
import AppCard from "./AppCard.svelte" |
|||
import Spinner from "components/common/Spinner.svelte" |
|||
import api from "builderStore/api" |
|||
|
|||
export let onSelect |
|||
|
|||
async function fetchTemplates() { |
|||
const response = await api.get("/api/templates?type=app") |
|||
return await response.json() |
|||
} |
|||
|
|||
let templatesPromise = fetchTemplates() |
|||
</script> |
|||
|
|||
<div class="root"> |
|||
<Heading medium black>Start With a Template</Heading> |
|||
{#await templatesPromise} |
|||
<div class="spinner-container"> |
|||
<Spinner size="30" /> |
|||
</div> |
|||
{:then templates} |
|||
<div class="templates"> |
|||
{#each templates as template} |
|||
<div class="templates-card"> |
|||
<Heading black medium>{template.name}</Heading> |
|||
<Body medium grey>{template.category}</Body> |
|||
<Body small black>{template.description}</Body> |
|||
<div> |
|||
<img src={template.image} width="300" /> |
|||
</div> |
|||
<div class="card-footer"> |
|||
<Button secondary on:click={() => onSelect(template)}> |
|||
Create {template.name} |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
{/each} |
|||
</div> |
|||
{:catch err} |
|||
<h1 style="color:red">{err}</h1> |
|||
{/await} |
|||
</div> |
|||
|
|||
<style> |
|||
.templates { |
|||
display: grid; |
|||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); |
|||
grid-gap: var(--layout-m); |
|||
justify-content: start; |
|||
} |
|||
|
|||
.templates-card { |
|||
background-color: var(--white); |
|||
padding: var(--spacing-xl); |
|||
border-radius: var(--border-radius-m); |
|||
border: var(--border-dark); |
|||
} |
|||
|
|||
.card-footer { |
|||
margin-top: var(--spacing-m); |
|||
} |
|||
|
|||
h3 { |
|||
font-size: var(--font-size-l); |
|||
font-weight: 600; |
|||
color: var(--ink); |
|||
text-transform: capitalize; |
|||
} |
|||
|
|||
.root { |
|||
margin: 20px 80px; |
|||
} |
|||
</style> |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 105 KiB |
@ -0,0 +1,40 @@ |
|||
#!/usr/bin/env node
|
|||
const { exportTemplateFromApp } = require("../src/utilities/templates") |
|||
const yargs = require("yargs") |
|||
|
|||
// Script to export a chosen budibase app into a package
|
|||
// Usage: ./scripts/exportAppTemplate.js export --name=Funky --instanceId=someInstanceId --appId=appId
|
|||
|
|||
yargs |
|||
.command( |
|||
"export", |
|||
"Export an existing budibase application to the .budibase/templates directory", |
|||
{ |
|||
name: { |
|||
description: "The name of the newly exported template", |
|||
alias: "n", |
|||
type: "string", |
|||
}, |
|||
instanceId: { |
|||
description: "The instanceId to dump the database for", |
|||
alias: "inst", |
|||
type: "string", |
|||
}, |
|||
appId: { |
|||
description: "The appId of the application you want to export", |
|||
alias: "app", |
|||
type: "string", |
|||
}, |
|||
}, |
|||
async args => { |
|||
console.log("Exporting app..") |
|||
const exportPath = await exportTemplateFromApp({ |
|||
templateName: args.name, |
|||
instanceId: args.instanceId, |
|||
appId: args.appId, |
|||
}) |
|||
console.log(`Template ${args.name} exported to ${exportPath}`) |
|||
} |
|||
) |
|||
.help() |
|||
.alias("help", "h").argv |
|||
@ -0,0 +1,44 @@ |
|||
const fetch = require("node-fetch") |
|||
const { |
|||
downloadTemplate, |
|||
exportTemplateFromApp, |
|||
} = require("../../utilities/templates") |
|||
|
|||
const DEFAULT_TEMPLATES_BUCKET = |
|||
"prod-budi-templates.s3-eu-west-1.amazonaws.com" |
|||
|
|||
exports.fetch = async function(ctx) { |
|||
const { type = "app" } = ctx.query |
|||
|
|||
const response = await fetch( |
|||
`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json` |
|||
) |
|||
const json = await response.json() |
|||
ctx.body = Object.values(json.templates[type]) |
|||
} |
|||
|
|||
exports.downloadTemplate = async function(ctx) { |
|||
const { type, name } = ctx.params |
|||
|
|||
await downloadTemplate(type, name) |
|||
|
|||
ctx.body = { |
|||
message: `template ${type}:${name} downloaded successfully.`, |
|||
} |
|||
} |
|||
|
|||
exports.exportTemplateFromApp = async function(ctx) { |
|||
const { appId, instanceId } = ctx.user |
|||
const { templateName } = ctx.request.body |
|||
|
|||
await exportTemplateFromApp({ |
|||
appId, |
|||
instanceId, |
|||
templateName, |
|||
}) |
|||
|
|||
ctx.status = 200 |
|||
ctx.body = { |
|||
message: `Created template: ${templateName}`, |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/templates") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/templates", authorized(BUILDER), controller.fetch) |
|||
.get( |
|||
"/api/templates/:type/:name", |
|||
authorized(BUILDER), |
|||
controller.downloadTemplate |
|||
) |
|||
.post("/api/templates", authorized(BUILDER), controller.exportTemplateFromApp) |
|||
|
|||
module.exports = router |
|||
@ -0,0 +1,57 @@ |
|||
const path = require("path") |
|||
const fs = require("fs-extra") |
|||
const os = require("os") |
|||
const fetch = require("node-fetch") |
|||
const stream = require("stream") |
|||
const tar = require("tar-fs") |
|||
const zlib = require("zlib") |
|||
const { promisify } = require("util") |
|||
const streamPipeline = promisify(stream.pipeline) |
|||
const { budibaseAppsDir } = require("./budibaseDir") |
|||
const CouchDB = require("../db") |
|||
|
|||
const DEFAULT_TEMPLATES_BUCKET = |
|||
"prod-budi-templates.s3-eu-west-1.amazonaws.com" |
|||
|
|||
exports.downloadTemplate = async function(type, name) { |
|||
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz` |
|||
const response = await fetch(templateUrl) |
|||
|
|||
if (!response.ok) { |
|||
throw new Error( |
|||
`Error downloading template ${type}:${name}: ${response.statusText}` |
|||
) |
|||
} |
|||
|
|||
// stream the response, unzip and extract
|
|||
await streamPipeline( |
|||
response.body, |
|||
zlib.Unzip(), |
|||
tar.extract(path.join(budibaseAppsDir(), "templates", type)) |
|||
) |
|||
|
|||
return path.join(budibaseAppsDir(), "templates", type, name) |
|||
} |
|||
|
|||
exports.exportTemplateFromApp = async function({ |
|||
appId, |
|||
templateName, |
|||
instanceId, |
|||
}) { |
|||
// Copy frontend files
|
|||
const appToExport = path.join(os.homedir(), ".budibase", appId, "pages") |
|||
const templatesDir = path.join(os.homedir(), ".budibase", "templates") |
|||
fs.ensureDirSync(templatesDir) |
|||
|
|||
const templateOutputPath = path.join(templatesDir, templateName) |
|||
fs.copySync(appToExport, `${templateOutputPath}/pages`) |
|||
|
|||
fs.ensureDirSync(path.join(templateOutputPath, "db")) |
|||
const writeStream = fs.createWriteStream(`${templateOutputPath}/db/dump.txt`) |
|||
|
|||
// perform couch dump
|
|||
const instanceDb = new CouchDB(instanceId) |
|||
|
|||
await instanceDb.dump(writeStream) |
|||
return templateOutputPath |
|||
} |
|||
Loading…
Reference in new issue