forked from tsai/budibase
255 changed files with 6975 additions and 2000 deletions
@ -1,2 +1,3 @@ |
|||
FROM nginx:latest |
|||
COPY .generated-nginx.prod.conf /etc/nginx/nginx.conf |
|||
COPY .generated-nginx.prod.conf /etc/nginx/nginx.conf |
|||
COPY error.html /usr/share/nginx/html/error.html |
|||
@ -0,0 +1,175 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>Budibase</title> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1"> |
|||
</head> |
|||
|
|||
<script> |
|||
function checkStatusButton() { |
|||
if (window.location.href.includes("budibase.app")) { |
|||
var button = document.getElementById("statusButton") |
|||
button.removeAttribute("hidden") |
|||
} |
|||
} |
|||
|
|||
function goToStatus() { |
|||
window.location.href = "https://status.budibase.com"; |
|||
} |
|||
function goHome() { |
|||
window.location.href = window.location.origin; |
|||
} |
|||
function getStatus() { |
|||
var http = new XMLHttpRequest() |
|||
var url = window.location.href |
|||
http.open('GET', url, true) |
|||
http.send() |
|||
http.onreadystatechange = (e) => { |
|||
var status = http.status |
|||
document.getElementById("status").innerHTML = status |
|||
|
|||
var message |
|||
if (status === 502) { |
|||
message = "Bad gateway. Please try again later." |
|||
} else if (status === 503) { |
|||
message = "Service Unavailable. Please try again later." |
|||
} else if (status === 504) { |
|||
message = "Gateway timeout. Please try again later." |
|||
} else { |
|||
message = "Please try again later." |
|||
} |
|||
|
|||
document.getElementById("message").innerHTML = message |
|||
} |
|||
} |
|||
|
|||
window.onload = function() { |
|||
checkStatusButton() |
|||
getStatus() |
|||
}; |
|||
|
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
:root { |
|||
--spectrum-global-color-gray-600: rgb(144,144,144); |
|||
--spectrum-global-color-gray-900: rgb(255,255,255); |
|||
--spectrum-global-color-gray-800: rgb(227,227,227); |
|||
--spectrum-global-color-static-blue-600: rgb(20,115,230); |
|||
--spectrum-global-color-static-blue-hover: rgb( 18, 103, 207); |
|||
} |
|||
|
|||
html, body { |
|||
background-color: #1a1a1a; |
|||
padding: 0; |
|||
margin: 0; |
|||
overflow: hidden; |
|||
color: #e7e7e7; |
|||
font-family: 'Roboto', sans-serif; |
|||
} |
|||
button { |
|||
color: #e7e7e7; |
|||
font-family: 'Roboto', sans-serif; |
|||
border: none; |
|||
font-size: 15px; |
|||
border-radius: 15px; |
|||
padding: 8px 22px; |
|||
} |
|||
button:hover { |
|||
cursor: pointer; |
|||
} |
|||
.main { |
|||
height: 100vh; |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
.info { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: left; |
|||
} |
|||
|
|||
@media only screen and (max-width: 600px) { |
|||
.info { |
|||
align-items: center; |
|||
} |
|||
} |
|||
|
|||
.status { |
|||
color: var(--spectrum-global-color-gray-600) |
|||
} |
|||
.title { |
|||
font-weight: 400; |
|||
color: var(--spectrum-global-color-gray-900) |
|||
} |
|||
.message { |
|||
font-weight: 200; |
|||
color: var(--spectrum-global-color-gray-800) |
|||
} |
|||
.buttons { |
|||
display: flex; |
|||
flex-direction: row; |
|||
margin-top: 15px; |
|||
} |
|||
.homeButton { |
|||
background-color: var(--spectrum-global-color-static-blue-600); |
|||
} |
|||
.homeButton:hover { |
|||
background-color: var(--spectrum-global-color-static-blue-hover); |
|||
} |
|||
.statusButton { |
|||
background-color: transparent; |
|||
margin-left: 20px; |
|||
border: none; |
|||
} |
|||
.hero { |
|||
height: 160px; |
|||
width: 160px; |
|||
margin-right: 80px; |
|||
} |
|||
.content { |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: flex-end; |
|||
justify-content: center; |
|||
} |
|||
|
|||
@media only screen and (max-width: 600px) { |
|||
.content { |
|||
flex-direction: column; |
|||
} |
|||
} |
|||
</style> |
|||
|
|||
<script src=""> |
|||
</script> |
|||
|
|||
<body> |
|||
<div class="main"> |
|||
<div class="content"> |
|||
<div class="hero"> |
|||
<img src="https://raw.githubusercontent.com/Budibase/budibase/master/packages/builder/assets/bb-space-man.svg" alt="Budibase Logo"> |
|||
</div> |
|||
<div class="info"> |
|||
<div> |
|||
<h4 id="status" class="status"></h4> |
|||
<h1 class="title"> |
|||
Houston we have a problem! |
|||
</h1> |
|||
<h3 id="message" class="message"> |
|||
</h3> |
|||
</div> |
|||
<div class="buttons"> |
|||
<button class="homeButton" onclick=goHome()>Return home</button> |
|||
<button id="statusButton" class="statusButton" hidden="true" onclick=goToStatus()>Check out status</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -0,0 +1,12 @@ |
|||
const { DEFAULT_TENANT_ID } = require("../constants") |
|||
const { StaticDatabases, SEPARATOR } = require("../db/constants") |
|||
|
|||
exports.baseGlobalDBName = tenantId => { |
|||
let dbName |
|||
if (!tenantId || tenantId === DEFAULT_TENANT_ID) { |
|||
dbName = StaticDatabases.GLOBAL.name |
|||
} else { |
|||
dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}` |
|||
} |
|||
return dbName |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
import filterTests from "../support/filterTests" |
|||
|
|||
filterTests(['all'], () => { |
|||
context("Publish Application Workflow", () => { |
|||
before(() => { |
|||
cy.login() |
|||
cy.createTestApp() |
|||
}) |
|||
|
|||
it("Should reflect the unpublished status correctly", () => { |
|||
cy.visit(`${Cypress.config().baseUrl}/builder`) |
|||
cy.wait(1000) |
|||
|
|||
cy.get(".appTable .app-status").eq(0) |
|||
.within(() => { |
|||
cy.contains("Unpublished") |
|||
cy.get("svg[aria-label='GlobeStrike']").should("exist") |
|||
}) |
|||
|
|||
cy.get(".appTable .app-row-actions").eq(0) |
|||
.within(() => { |
|||
cy.get(".spectrum-Button").contains("Preview") |
|||
cy.get(".spectrum-Button").contains("Edit").click({ force: true }) |
|||
}) |
|||
|
|||
cy.get(".deployment-top-nav svg[aria-label='GlobeStrike']").should("exist") |
|||
cy.get(".deployment-top-nav svg[aria-label='Globe']").should("not.exist") |
|||
}) |
|||
|
|||
it("Should publish an application and correctly reflect that", () => { |
|||
//Assuming the previous test was run and the unpublished app is open in edit mode.
|
|||
cy.get(".toprightnav button.spectrum-Button").contains("Publish").click({ force : true }) |
|||
|
|||
cy.get(".spectrum-Modal [data-cy='deploy-app-modal']").should("be.visible") |
|||
.within(() => { |
|||
cy.get(".spectrum-Button").contains("Publish").click({ force : true }) |
|||
cy.wait(1000) |
|||
}); |
|||
|
|||
//Verify that the app url is presented correctly to the user
|
|||
cy.get(".spectrum-Modal [data-cy='deploy-app-success-modal']") |
|||
.should("be.visible") |
|||
.within(() => { |
|||
let appUrl = Cypress.config().baseUrl + '/app/cypress-tests' |
|||
cy.get("[data-cy='deployed-app-url'] input").should('have.value', appUrl) |
|||
cy.get(".spectrum-Button").contains("Done").click({ force: true }) |
|||
}) |
|||
|
|||
cy.visit(`${Cypress.config().baseUrl}/builder`) |
|||
cy.wait(1000) |
|||
|
|||
cy.get(".appTable .app-status").eq(0) |
|||
.within(() => { |
|||
cy.contains("Published") |
|||
cy.get("svg[aria-label='Globe']").should("exist") |
|||
}) |
|||
|
|||
cy.get(".appTable .app-row-actions").eq(0) |
|||
.within(() => { |
|||
cy.get(".spectrum-Button").contains("View app") |
|||
cy.get(".spectrum-Button").contains("Edit").click({ force: true }) |
|||
}) |
|||
|
|||
cy.get(".deployment-top-nav svg[aria-label='Globe']").should("exist").click({ force: true }) |
|||
|
|||
cy.get("[data-cy='publish-popover-menu']").should("be.visible") |
|||
.within(() => { |
|||
cy.get("[data-cy='publish-popover-action']").should("exist") |
|||
cy.get("button").contains("View app").should("exist") |
|||
cy.get(".publish-popover-message").should("have.text", "Last published a few seconds ago") |
|||
}) |
|||
}) |
|||
|
|||
it("Should unpublish an application from the top navigation and reflect the status change", () => { |
|||
//Assuming the previous test app exists and is published
|
|||
|
|||
cy.visit(`${Cypress.config().baseUrl}/builder`) |
|||
|
|||
cy.get(".appTable .app-status").eq(0) |
|||
.within(() => { |
|||
cy.contains("Published") |
|||
cy.get("svg[aria-label='Globe']").should("exist") |
|||
}) |
|||
|
|||
cy.get(".appTable .app-row-actions").eq(0) |
|||
.within(() => { |
|||
cy.get(".spectrum-Button").contains("View app") |
|||
cy.get(".spectrum-Button").contains("Edit").click({ force: true }) |
|||
}) |
|||
|
|||
//The published status
|
|||
cy.get(".deployment-top-nav svg[aria-label='Globe']").should("exist") |
|||
.click({ force: true }) |
|||
|
|||
cy.get("[data-cy='publish-popover-menu']").should("be.visible") |
|||
cy.get("[data-cy='publish-popover-menu'] [data-cy='publish-popover-action']") |
|||
.click({ force : true }) |
|||
|
|||
cy.get("[data-cy='unpublish-modal']").should("be.visible") |
|||
.within(() => { |
|||
cy.get(".confirm-wrap button").click({ force: true } |
|||
)}) |
|||
|
|||
cy.get(".deployment-top-nav svg[aria-label='GlobeStrike']").should("exist") |
|||
|
|||
cy.visit(`${Cypress.config().baseUrl}/builder`) |
|||
|
|||
cy.get(".appTable .app-status").eq(0).contains("Unpublished") |
|||
|
|||
}) |
|||
}) |
|||
}) |
|||
@ -1,51 +1,103 @@ |
|||
import filterTests from "../support/filterTests" |
|||
|
|||
filterTests(['smoke', 'all'], () => { |
|||
context("Auto Screens UI", () => { |
|||
before(() => { |
|||
cy.login() |
|||
cy.createTestApp() |
|||
}) |
|||
|
|||
it("should generate internal table screens", () => { |
|||
// Create autogenerated screens from the internal table
|
|||
cy.createAutogeneratedScreens(["Cypress Tests"]) |
|||
// Confirm screens have been auto generated
|
|||
cy.get(".nav-items-container").contains("cypress-tests").click({ force: true }) |
|||
cy.get(".nav-items-container").should('contain', 'cypress-tests/:id') |
|||
.and('contain', 'cypress-tests/new/row') |
|||
}) |
|||
|
|||
it("should generate multiple internal table screens at once", () => { |
|||
// Create a second internal table
|
|||
const initialTable = "Cypress Tests" |
|||
const secondTable = "Table Two" |
|||
cy.createTable(secondTable) |
|||
// Create autogenerated screens from the internal tables
|
|||
cy.createAutogeneratedScreens([initialTable, secondTable]) |
|||
// Confirm screens have been auto generated
|
|||
cy.get(".nav-items-container").contains("cypress-tests").click({ force: true }) |
|||
// Previously generated tables are suffixed with numbers - as expected
|
|||
cy.get(".nav-items-container").should('contain', 'cypress-tests-2/:id') |
|||
.and('contain', 'cypress-tests-2/new/row') |
|||
cy.get(".nav-items-container").contains("table-two").click() |
|||
cy.get(".nav-items-container").should('contain', 'table-two/:id') |
|||
.and('contain', 'table-two/new/row') |
|||
}) |
|||
|
|||
if (Cypress.env("TEST_ENV")) { |
|||
it("should generate data source screens", () => { |
|||
// Using MySQL data source for testing this
|
|||
const datasource = "MySQL" |
|||
// Select & configure MySQL data source
|
|||
cy.selectExternalDatasource(datasource) |
|||
cy.addDatasourceConfig(datasource) |
|||
// Create autogenerated screens from a MySQL table - MySQL contains books table
|
|||
cy.createAutogeneratedScreens(["books"]) |
|||
cy.get(".nav-items-container").contains("books").click() |
|||
cy.get(".nav-items-container").should('contain', 'books/:id') |
|||
.and('contain', 'books/new/row') |
|||
}) |
|||
} |
|||
context("Auto Screens UI", () => { |
|||
before(() => { |
|||
cy.login() |
|||
}) |
|||
|
|||
it("should disable the autogenerated screen options if no sources are available", () => { |
|||
cy.createApp("First Test App", false) |
|||
|
|||
cy.closeModal(); |
|||
|
|||
cy.contains("Design").click() |
|||
cy.get("[aria-label=AddCircle]").click() |
|||
cy.get(".spectrum-Modal").within(() => { |
|||
cy.get(".item.disabled").contains("Autogenerated screens") |
|||
cy.get(".confirm-wrap .spectrum-Button").should('be.disabled') |
|||
}) |
|||
|
|||
cy.deleteAllApps() |
|||
}); |
|||
|
|||
it("should not display incompatible sources", () => { |
|||
cy.createApp("Test App") |
|||
|
|||
cy.selectExternalDatasource("REST") |
|||
cy.selectExternalDatasource("S3") |
|||
cy.get(".spectrum-Modal").within(() => { |
|||
cy.get(".spectrum-Button").contains("Save and continue to query").click({ force : true }) |
|||
}) |
|||
|
|||
cy.navigateToAutogeneratedModal() |
|||
|
|||
cy.get('.data-source-entry').should('have.length', 1) |
|||
cy.get('.data-source-entry') |
|||
|
|||
cy.deleteAllApps() |
|||
}); |
|||
|
|||
it("should generate internal table screens", () => { |
|||
cy.createTestApp() |
|||
// Create Autogenerated screens from the internal table
|
|||
cy.createDatasourceScreen(["Cypress Tests"]) |
|||
// Confirm screens have been auto generated
|
|||
cy.get(".nav-items-container").contains("cypress-tests").click({ force: true }) |
|||
cy.get(".nav-items-container").should('contain', 'cypress-tests/:id') |
|||
.and('contain', 'cypress-tests/new/row') |
|||
}) |
|||
|
|||
it("should generate multiple internal table screens at once", () => { |
|||
// Create a second internal table
|
|||
const initialTable = "Cypress Tests" |
|||
const secondTable = "Table Two" |
|||
cy.createTable(secondTable) |
|||
// Create Autogenerated screens from the internal tables
|
|||
cy.createDatasourceScreen([initialTable, secondTable]) |
|||
// Confirm screens have been auto generated
|
|||
cy.get(".nav-items-container").contains("cypress-tests").click({ force: true }) |
|||
// Previously generated tables are suffixed with numbers - as expected
|
|||
cy.get(".nav-items-container").should('contain', 'cypress-tests-2/:id') |
|||
.and('contain', 'cypress-tests-2/new/row') |
|||
cy.get(".nav-items-container").contains("table-two").click() |
|||
cy.get(".nav-items-container").should('contain', 'table-two/:id') |
|||
.and('contain', 'table-two/new/row') |
|||
}) |
|||
|
|||
it("should generate multiple internal table screens with the same screen access level", () => { |
|||
//The tables created in the previous step still exist
|
|||
cy.createTable("Table Three") |
|||
cy.createTable("Table Four") |
|||
cy.createDatasourceScreen(["Table Three", "Table Four"], "Admin") |
|||
|
|||
cy.get(".nav-items-container").contains("table-three").click() |
|||
cy.get(".nav-items-container").should('contain', 'table-three/:id') |
|||
.and('contain', 'table-three/new/row') |
|||
|
|||
cy.get(".nav-items-container").contains("table-four").click() |
|||
cy.get(".nav-items-container").should('contain', 'table-four/:id') |
|||
.and('contain', 'table-four/new/row') |
|||
|
|||
//The access level should now be set to admin. Previous screens should be filtered.
|
|||
cy.get(".nav-items-container").contains("table-two").should('not.exist') |
|||
cy.get(".nav-items-container").contains("cypress-tests").should('not.exist') |
|||
}) |
|||
|
|||
if (Cypress.env("TEST_ENV")) { |
|||
it("should generate data source screens", () => { |
|||
// Using MySQL data source for testing this
|
|||
const datasource = "MySQL" |
|||
// Select & configure MySQL data source
|
|||
cy.selectExternalDatasource(datasource) |
|||
cy.addDatasourceConfig(datasource) |
|||
// Create Autogenerated screens from a MySQL table - MySQL contains books table
|
|||
cy.createDatasourceScreen(["books"]) |
|||
|
|||
cy.get(".nav-items-container").contains("books").click() |
|||
cy.get(".nav-items-container").should('contain', 'books/:id') |
|||
.and('contain', 'books/new/row') |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
@ -0,0 +1,49 @@ |
|||
<script> |
|||
export let width = "100" |
|||
export let height = "100" |
|||
</script> |
|||
|
|||
<svg |
|||
{width} |
|||
{height} |
|||
viewBox="0 0 256 220" |
|||
fill="none" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
> |
|||
<path |
|||
d="M245.97 168.943C232.308 176.064 161.536 205.163 146.469 213.018C131.402 220.874 123.032 220.798 111.129 215.108C99.227 209.418 23.913 178.996 10.346 172.511C3.566 169.271 0 166.535 0 163.951V138.075C0 138.075 98.05 116.73 113.879 111.051C129.707 105.372 135.199 105.167 148.669 110.101C162.141 115.037 242.687 129.569 256 134.445L255.994 159.955C255.996 162.513 252.924 165.319 245.97 168.943" |
|||
fill="#912626" |
|||
/> |
|||
<path |
|||
d="M245.965 143.22C232.304 150.338 161.534 179.438 146.467 187.292C131.401 195.149 123.031 195.072 111.129 189.382C99.226 183.696 23.915 153.269 10.349 146.788C-3.21698 140.303 -3.50098 135.84 9.82502 130.622C23.151 125.402 98.049 96.017 113.88 90.338C129.708 84.661 135.199 84.454 148.669 89.39C162.14 94.324 232.488 122.325 245.799 127.2C259.115 132.081 259.626 136.1 245.965 143.22" |
|||
fill="#C6302B" |
|||
/> |
|||
<path |
|||
d="M245.97 127.074C232.308 134.196 161.536 163.294 146.469 171.152C131.402 179.005 123.032 178.929 111.129 173.239C99.226 167.552 23.913 137.127 10.346 130.642C3.566 127.402 0 124.67 0 122.085V96.206C0 96.206 98.05 74.862 113.879 69.183C129.707 63.504 135.199 63.298 148.669 68.233C162.142 73.168 242.688 87.697 256 92.574L255.994 118.087C255.996 120.644 252.924 123.45 245.97 127.074Z" |
|||
fill="#912626" |
|||
/> |
|||
<path |
|||
d="M245.965 101.351C232.304 108.471 161.534 137.569 146.467 145.426C131.401 153.28 123.031 153.203 111.129 147.513C99.226 141.827 23.915 111.401 10.349 104.919C-3.21698 98.436 -3.50098 93.972 9.82502 88.752C23.151 83.535 98.05 54.148 113.88 48.47C129.708 42.792 135.199 42.586 148.669 47.521C162.14 52.455 232.488 80.454 245.799 85.331C259.115 90.211 259.626 94.231 245.965 101.351" |
|||
fill="#C6302B" |
|||
/> |
|||
<path |
|||
d="M245.97 83.653C232.308 90.773 161.536 119.873 146.469 127.731C131.402 135.585 123.032 135.508 111.129 129.818C99.226 124.131 23.913 93.705 10.346 87.223C3.566 83.98 0 81.247 0 78.665V52.785C0 52.785 98.05 31.442 113.879 25.764C129.707 20.084 135.199 19.88 148.669 24.814C162.142 29.749 242.688 44.278 256 49.155L255.994 74.667C255.996 77.222 252.924 80.028 245.97 83.653Z" |
|||
fill="#912626" |
|||
/> |
|||
<path |
|||
d="M245.965 57.93C232.304 65.05 161.534 94.15 146.467 102.004C131.401 109.858 123.031 109.781 111.129 104.094C99.227 98.404 23.915 67.98 10.35 61.497C-3.21699 55.015 -3.49999 50.55 9.82501 45.331C23.151 40.113 98.05 10.73 113.88 5.04999C129.708 -0.629006 135.199 -0.833006 148.669 4.10199C162.14 9.03699 232.488 37.036 245.799 41.913C259.115 46.789 259.626 50.81 245.965 57.93" |
|||
fill="#C6302B" |
|||
/> |
|||
<path |
|||
d="M159.283 32.757L137.273 35.042L132.346 46.898L124.388 33.668L98.9729 31.384L117.937 24.545L112.247 14.047L130.002 20.991L146.74 15.511L142.216 26.366L159.283 32.757V32.757ZM131.032 90.275L89.9549 73.238L148.815 64.203L131.032 90.275V90.275ZM74.0819 39.347C91.4569 39.347 105.542 44.807 105.542 51.541C105.542 58.277 91.4569 63.736 74.0819 63.736C56.7069 63.736 42.6219 58.276 42.6219 51.541C42.6219 44.807 56.7069 39.347 74.0819 39.347" |
|||
fill="white" |
|||
/> |
|||
<path |
|||
d="M185.295 35.998L220.131 49.764L185.325 63.517L185.295 35.997" |
|||
fill="#621B1C" |
|||
/> |
|||
<path |
|||
d="M146.755 51.243L185.295 35.998L185.325 63.517L181.546 64.995L146.755 51.243Z" |
|||
fill="#9A2928" |
|||
/> |
|||
</svg> |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue