Add status banner that reacts to cypress healthcheck failures
This commit is contained in:
parent
89ac67a6f0
commit
9e0a10955a
|
@ -22,3 +22,18 @@ exports.getAccount = async email => {
|
|||
|
||||
return json[0]
|
||||
}
|
||||
|
||||
exports.getStatus = async () => {
|
||||
const response = await api.get(`/api/status`, {
|
||||
headers: {
|
||||
[Headers.API_KEY]: env.ACCOUNT_PORTAL_API_KEY,
|
||||
},
|
||||
})
|
||||
const json = await response.json()
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`Error getting status`)
|
||||
}
|
||||
|
||||
return json
|
||||
}
|
||||
|
|
|
@ -57,3 +57,9 @@
|
|||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.spectrum-Toast {
|
||||
pointer-events: all;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import "@spectrum-css/toast/dist/index-vars.css"
|
||||
import Portal from "svelte-portal"
|
||||
import { banner } from "../Stores/banner"
|
||||
import Banner from "./Banner.svelte"
|
||||
import { fly } from "svelte/transition"
|
||||
</script>
|
||||
|
||||
<Portal target=".modal-container">
|
||||
<div class="banner">
|
||||
{#if $banner.message}
|
||||
<div transition:fly={{ y: -30 }}>
|
||||
<Banner
|
||||
type={$banner.type}
|
||||
extraButtonText={$banner.extraButtonText}
|
||||
extraButtonAction={$banner.extraButtonAction}
|
||||
on:change={$banner.onChange}
|
||||
>
|
||||
{$banner.message}
|
||||
</Banner>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Portal>
|
||||
|
||||
<style>
|
||||
.banner {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,37 @@
|
|||
import { writable } from "svelte/store"
|
||||
|
||||
export function createBannerStore() {
|
||||
const DEFAULT_CONFIG = {}
|
||||
|
||||
const banner = writable(DEFAULT_CONFIG)
|
||||
|
||||
const show = async (
|
||||
// eslint-disable-next-line
|
||||
config = { message, type, extraButtonText, extraButtonAction, onChange }
|
||||
) => {
|
||||
banner.update(store => {
|
||||
return {
|
||||
...store,
|
||||
...config,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const showStatus = async () => {
|
||||
const config = {
|
||||
message: "Some systems are experiencing issues",
|
||||
type: "negative",
|
||||
extraButtonText: "View Status",
|
||||
extraButtonAction: () => window.open("https://status.budibase.com/"),
|
||||
}
|
||||
|
||||
await show(config)
|
||||
}
|
||||
|
||||
return {
|
||||
subscribe: banner.subscribe,
|
||||
showStatus,
|
||||
}
|
||||
}
|
||||
|
||||
export const banner = createBannerStore()
|
|
@ -60,6 +60,7 @@ export { default as StatusLight } from "./StatusLight/StatusLight.svelte"
|
|||
export { default as ColorPicker } from "./ColorPicker/ColorPicker.svelte"
|
||||
export { default as InlineAlert } from "./InlineAlert/InlineAlert.svelte"
|
||||
export { default as Banner } from "./Banner/Banner.svelte"
|
||||
export { default as BannerDisplay } from "./Banner/BannerDisplay.svelte"
|
||||
export { default as MarkdownEditor } from "./Markdown/MarkdownEditor.svelte"
|
||||
export { default as MarkdownViewer } from "./Markdown/MarkdownViewer.svelte"
|
||||
export { default as RichTextField } from "./Form/RichTextField.svelte"
|
||||
|
@ -84,6 +85,7 @@ export { default as clickOutside } from "./Actions/click_outside"
|
|||
|
||||
// Stores
|
||||
export { notifications, createNotificationStore } from "./Stores/notifications"
|
||||
export { banner } from "./Stores/banner"
|
||||
|
||||
// Helpers
|
||||
export * as Helpers from "./helpers"
|
||||
|
|
|
@ -53,10 +53,10 @@
|
|||
to-gfm-code-block "^0.1.1"
|
||||
year "^0.2.1"
|
||||
|
||||
"@budibase/string-templates@^1.0.66-alpha.0":
|
||||
version "1.0.72"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.72.tgz#acc154e402cce98ea30eedde9c6124183ee9b37c"
|
||||
integrity sha512-w715TjgO6NUHkZNqoOEo8lAKJ/PQ4b00ATWSX5VB523SAu7y/uOiqKqV1E3fgwxq1o8L+Ff7rn9FTkiYtjkV/g==
|
||||
"@budibase/string-templates@^1.0.72-alpha.0":
|
||||
version "1.0.75"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.75.tgz#5b4061f1a626160ec092f32f036541376298100c"
|
||||
integrity sha512-hPgr6n5cpSCGFEha5DS/P+rtRXOLc72M6y4J/scl59JvUi/ZUJkjRgJdpQPdBLu04CNKp89V59+rAqAuDjOC0g==
|
||||
dependencies:
|
||||
"@budibase/handlebars-helpers" "^0.11.7"
|
||||
dayjs "^1.10.4"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { Router } from "@roxi/routify"
|
||||
import { routes } from "../.routify/routes"
|
||||
import { NotificationDisplay } from "@budibase/bbui"
|
||||
import { NotificationDisplay, BannerDisplay } from "@budibase/bbui"
|
||||
import { parse, stringify } from "qs"
|
||||
import HelpIcon from "components/common/HelpIcon.svelte"
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
|||
</script>
|
||||
|
||||
<NotificationDisplay />
|
||||
<BannerDisplay />
|
||||
<Router {routes} config={{ queryHandler }} />
|
||||
<div class="modal-container" />
|
||||
<HelpIcon />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { writable, get } from "svelte/store"
|
||||
import { API } from "api"
|
||||
import { auth } from "stores/portal"
|
||||
import { banner } from "@budibase/bbui"
|
||||
|
||||
export function createAdminStore() {
|
||||
const DEFAULT_CONFIG = {
|
||||
|
@ -30,6 +31,13 @@ export function createAdminStore() {
|
|||
x => x?.checked
|
||||
).length
|
||||
await getEnvironment()
|
||||
|
||||
// enable system status checks in the cloud
|
||||
if (get(admin).cloud) {
|
||||
await getSystemStatus()
|
||||
checkStatus()
|
||||
}
|
||||
|
||||
admin.update(store => {
|
||||
store.loaded = true
|
||||
store.checklist = checklist
|
||||
|
@ -58,6 +66,21 @@ export function createAdminStore() {
|
|||
})
|
||||
}
|
||||
|
||||
const checkStatus = async () => {
|
||||
const health = get(admin)?.status?.health
|
||||
if (!health?.passing) {
|
||||
await banner.showStatus()
|
||||
}
|
||||
}
|
||||
|
||||
async function getSystemStatus() {
|
||||
const status = await API.getSystemStatus()
|
||||
admin.update(store => {
|
||||
store.status = status
|
||||
return store
|
||||
})
|
||||
}
|
||||
|
||||
function unload() {
|
||||
admin.update(store => {
|
||||
store.loaded = false
|
||||
|
|
|
@ -17,6 +17,15 @@ export const buildOtherEndpoints = API => ({
|
|||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the current system status.
|
||||
*/
|
||||
getSystemStatus: async () => {
|
||||
return await API.get({
|
||||
url: "/api/system/status",
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the list of available integrations.
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,9 @@ const {
|
|||
const { removeUserFromInfoDB } = require("@budibase/backend-core/deprovision")
|
||||
const env = require("../../../environment")
|
||||
const { syncUserInApps } = require("../../../utilities/appService")
|
||||
const { isUserInAppTenant } = require("@budibase/backend-core/tenancy")
|
||||
const { getCookie, clearCookie } = require("@budibase/backend-core/utils")
|
||||
const { Cookies } = require("@budibase/backend-core/constants")
|
||||
|
||||
async function allUsers() {
|
||||
const db = getGlobalDB()
|
||||
|
@ -158,6 +161,16 @@ exports.removeAppRole = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
const checkCurrentApp = ctx => {
|
||||
const appCookie = getCookie(ctx, Cookies.CurrentApp)
|
||||
if (appCookie && !isUserInAppTenant(appCookie.appId)) {
|
||||
// there is a currentapp cookie from another tenant
|
||||
// remove the cookie as this is incompatible with the builder
|
||||
// due to builder and admin permissions being removed
|
||||
clearCookie(ctx, Cookies.CurrentApp)
|
||||
}
|
||||
}
|
||||
|
||||
exports.getSelf = async ctx => {
|
||||
if (!ctx.user) {
|
||||
ctx.throw(403, "User not logged in")
|
||||
|
@ -168,6 +181,8 @@ exports.getSelf = async ctx => {
|
|||
// this will set the body
|
||||
await exports.find(ctx)
|
||||
|
||||
checkCurrentApp(ctx)
|
||||
|
||||
// forward session information not found in db
|
||||
ctx.body.account = ctx.user.account
|
||||
ctx.body.budibaseAccess = ctx.user.budibaseAccess
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const accounts = require("@budibase/backend-core/accounts")
|
||||
const env = require("../../../environment")
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
if (!env.SELF_HOSTED) {
|
||||
const status = await accounts.getStatus()
|
||||
ctx.body = status
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ const PUBLIC_ENDPOINTS = [
|
|||
method: "GET",
|
||||
},
|
||||
{
|
||||
// TODO: Add an provisioning API key to this endpoint in the cloud
|
||||
route: "/api/global/users/init",
|
||||
method: "POST",
|
||||
},
|
||||
|
@ -51,6 +50,10 @@ const PUBLIC_ENDPOINTS = [
|
|||
route: "api/system/environment",
|
||||
method: "GET",
|
||||
},
|
||||
{
|
||||
route: "api/system/status",
|
||||
method: "GET",
|
||||
},
|
||||
{
|
||||
route: "/api/global/users/tenant/:id",
|
||||
method: "GET",
|
||||
|
|
|
@ -8,6 +8,7 @@ const roleRoutes = require("./global/roles")
|
|||
const sessionRoutes = require("./global/sessions")
|
||||
const environmentRoutes = require("./system/environment")
|
||||
const tenantsRoutes = require("./system/tenants")
|
||||
const statusRoutes = require("./system/status")
|
||||
|
||||
exports.routes = [
|
||||
configRoutes,
|
||||
|
@ -20,4 +21,5 @@ exports.routes = [
|
|||
sessionRoutes,
|
||||
roleRoutes,
|
||||
environmentRoutes,
|
||||
statusRoutes,
|
||||
]
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../../controllers/system/status")
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get("/api/system/status", controller.fetch)
|
||||
|
||||
module.exports = router
|
Loading…
Reference in New Issue