mirror of https://github.com/Budibase/budibase.git
29 changed files with 315 additions and 156 deletions
@ -0,0 +1,110 @@ |
|||
<script> |
|||
import { onMount, onDestroy } from "svelte" |
|||
import { Button, Modal, notifications, ModalContent } from "@budibase/bbui" |
|||
import { store } from "builderStore" |
|||
import api from "builderStore/api" |
|||
import analytics from "analytics" |
|||
import FeedbackIframe from "components/feedback/FeedbackIframe.svelte" |
|||
|
|||
const DeploymentStatus = { |
|||
SUCCESS: "SUCCESS", |
|||
PENDING: "PENDING", |
|||
FAILURE: "FAILURE", |
|||
} |
|||
|
|||
const POLL_INTERVAL = 1000 |
|||
|
|||
|
|||
let loading = false |
|||
let feedbackModal |
|||
let deployments = [] |
|||
let poll |
|||
let publishModal |
|||
|
|||
$: appId = $store.appId |
|||
|
|||
async function deployApp() { |
|||
try { |
|||
notifications.info(`Deployment started. Please wait.`) |
|||
const response = await api.post("/api/deploy") |
|||
const json = await response.json() |
|||
if (response.status !== 200) { |
|||
throw new Error() |
|||
} |
|||
|
|||
if (analytics.requestFeedbackOnDeploy()) { |
|||
feedbackModal.show() |
|||
} |
|||
} catch (err) { |
|||
analytics.captureException(err) |
|||
notifications.error("Deployment unsuccessful. Please try again later.") |
|||
} |
|||
} |
|||
|
|||
async function fetchDeployments() { |
|||
try { |
|||
const response = await api.get(`/api/deployments`) |
|||
const json = await response.json() |
|||
|
|||
if (deployments.length > 0) { |
|||
checkIncomingDeploymentStatus(deployments, json) |
|||
} |
|||
|
|||
deployments = json |
|||
} catch (err) { |
|||
console.error(err) |
|||
clearInterval(poll) |
|||
notifications.error( |
|||
"Error fetching deployment history. Please try again." |
|||
) |
|||
} |
|||
} |
|||
|
|||
// Required to check any updated deployment statuses between polls |
|||
function checkIncomingDeploymentStatus(current, incoming) { |
|||
for (let incomingDeployment of incoming) { |
|||
if (incomingDeployment.status === DeploymentStatus.FAILURE || incomingDeployment.status === DeploymentStatus.SUCCESS) { |
|||
const currentDeployment = current.find( |
|||
deployment => deployment._id === incomingDeployment._id |
|||
) |
|||
|
|||
// We have just been notified of an ongoing deployments status change |
|||
if ( |
|||
!currentDeployment || |
|||
currentDeployment.status === DeploymentStatus.PENDING |
|||
) { |
|||
if (incomingDeployment.status === DeploymentStatus.FAILURE) { |
|||
notifications.error(incomingDeployment.err) |
|||
} else { |
|||
notifications.send("Published to Production.", "success", "CheckmarkCircle") |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
onMount(() => { |
|||
fetchDeployments() |
|||
poll = setInterval(fetchDeployments, POLL_INTERVAL) |
|||
}) |
|||
|
|||
onDestroy(() => clearInterval(poll)) |
|||
</script> |
|||
|
|||
|
|||
<Button |
|||
secondary |
|||
on:click={publishModal.show} |
|||
> |
|||
Publish |
|||
</Button> |
|||
<Modal bind:this={publishModal}> |
|||
<ModalContent |
|||
title="Publish to Production" |
|||
confirmText="Publish" |
|||
onConfirm={deployApp} |
|||
> |
|||
<span>The changes you have made will be published to the production version of the application.</span> |
|||
</ModalContent> |
|||
</Modal> |
|||
@ -0,0 +1,44 @@ |
|||
<script> |
|||
import { onMount, onDestroy } from "svelte" |
|||
import { Button, Icon, Modal, notifications, ModalContent } from "@budibase/bbui" |
|||
import { store } from "builderStore" |
|||
import { apps } from "stores/portal" |
|||
import api from "builderStore/api" |
|||
|
|||
let revertModal |
|||
|
|||
$: appId = $store.appId |
|||
|
|||
const revert = async () => { |
|||
try { |
|||
const response = await api.post(`/api/dev/${appId}/revert`) |
|||
const json = await response.json() |
|||
if (response.status !== 200) throw json.message |
|||
|
|||
// Reset frontend state after revert |
|||
const applicationPkg = await api.get(`/api/applications/${appId}/appPackage`) |
|||
const pkg = await applicationPkg.json() |
|||
if (applicationPkg.ok) { |
|||
await store.actions.initialise(pkg) |
|||
} else { |
|||
throw new Error(pkg) |
|||
} |
|||
|
|||
notifications.info("Changes reverted.") |
|||
} catch (err) { |
|||
notifications.error(`Error reverting changes: ${err}`) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
|
|||
<Icon name="Revert" hoverable on:click={revertModal.show} /> |
|||
<Modal bind:this={revertModal}> |
|||
<ModalContent |
|||
title="Revert Changes" |
|||
confirmText="Revert" |
|||
onConfirm={revert} |
|||
> |
|||
<span>The changes you have made will be deleted and the application reverted back to its production state.</span> |
|||
</ModalContent> |
|||
</Modal> |
|||
@ -1,2 +0,0 @@ |
|||
<!-- routify:options index=4 --> |
|||
<slot /> |
|||
@ -1,79 +0,0 @@ |
|||
<script> |
|||
import { Button, Modal, notifications, Heading } from "@budibase/bbui" |
|||
import { store } from "builderStore" |
|||
import api from "builderStore/api" |
|||
import DeploymentHistory from "components/deploy/DeploymentHistory.svelte" |
|||
import analytics from "analytics" |
|||
import FeedbackIframe from "components/feedback/FeedbackIframe.svelte" |
|||
import Rocket from "/assets/deploy-rocket.jpg" |
|||
|
|||
let loading = false |
|||
let deployments = [] |
|||
let poll |
|||
let feedbackModal |
|||
|
|||
$: appId = $store.appId |
|||
|
|||
async function deployApp() { |
|||
try { |
|||
notifications.info(`Deployment started. Please wait.`) |
|||
const response = await api.post("/api/deploy") |
|||
const json = await response.json() |
|||
if (response.status !== 200) { |
|||
throw new Error() |
|||
} |
|||
|
|||
if (analytics.requestFeedbackOnDeploy()) { |
|||
feedbackModal.show() |
|||
} |
|||
} catch (err) { |
|||
analytics.captureException(err) |
|||
notifications.error("Deployment unsuccessful. Please try again later.") |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<section> |
|||
<img src={Rocket} alt="Rocket flying through sky" /> |
|||
<div> |
|||
<Heading size="M">It's time to shine!</Heading> |
|||
<Button size="XL" cta medium on:click={deployApp}>Publish App</Button> |
|||
</div> |
|||
</section> |
|||
<Modal bind:this={feedbackModal}> |
|||
<FeedbackIframe on:finished={() => feedbackModal.hide()} /> |
|||
</Modal> |
|||
<DeploymentHistory {appId} /> |
|||
|
|||
<style> |
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
filter: brightness(80%); |
|||
} |
|||
|
|||
section { |
|||
position: relative; |
|||
min-height: 100%; |
|||
} |
|||
|
|||
div { |
|||
position: absolute; |
|||
display: flex; |
|||
text-align: center; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
left: 0; |
|||
right: 0; |
|||
top: 20%; |
|||
margin-left: auto; |
|||
margin-right: auto; |
|||
width: 50%; |
|||
gap: var(--spacing-xl); |
|||
} |
|||
div :global(h1) { |
|||
color: white; |
|||
} |
|||
</style> |
|||
@ -1,4 +1,4 @@ |
|||
export { organisation } from "./organisation" |
|||
export { admin } from "./admin" |
|||
export { apps } from "./apps" |
|||
export { email } from "./email" |
|||
export { email } from "./email" |
|||
@ -1,24 +1,37 @@ |
|||
const { getAllRoles } = require("@budibase/auth/roles") |
|||
const { getAllApps } = require("@budibase/auth/db") |
|||
const { getAllApps, getDeployedAppID, DocumentTypes } = require("@budibase/auth/db") |
|||
const CouchDB = require("../../../db") |
|||
|
|||
exports.fetch = async ctx => { |
|||
// always use the dev apps as they'll be most up to date (true)
|
|||
const apps = await getAllApps(true) |
|||
const promises = [] |
|||
for (let app of apps) { |
|||
promises.push(getAllRoles(app._id)) |
|||
// use dev app IDs
|
|||
promises.push(getAllRoles(app.appId)) |
|||
} |
|||
const roles = await Promise.all(promises) |
|||
const response = {} |
|||
for (let app of apps) { |
|||
response[app._id] = roles.shift() |
|||
const deployedAppId = getDeployedAppID(app.appId) |
|||
response[deployedAppId] = { |
|||
roles: roles.shift(), |
|||
name: app.name, |
|||
version: app.version, |
|||
url: app.url, |
|||
} |
|||
} |
|||
ctx.body = response |
|||
} |
|||
|
|||
exports.find = async ctx => { |
|||
const appId = ctx.params.appId |
|||
const db = new CouchDB(appId) |
|||
const app = await db.get(DocumentTypes.APP_METADATA) |
|||
ctx.body = { |
|||
roles: await getAllRoles(appId), |
|||
name: app.name, |
|||
version: app.version, |
|||
url: app.url, |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue