1
0
Fork 0
mirror of synced 2024-07-03 13:30:46 +12:00

Template fixes and updates to the file picker. Error handling added to display a warning when navigating to an unpublished or invalid app url.

This commit is contained in:
Dean 2023-03-21 09:20:43 +00:00
parent 5e84020849
commit bfd7e49c72
15 changed files with 209 additions and 132 deletions

View file

@ -7,6 +7,7 @@
export let value = null
export let title = "Upload file"
export let disabled = false
export let allowClear = null
export let extensions = null
export let handleFileTooLarge = null
export let fileSizeLimit = BYTES_IN_MB * 20
@ -65,14 +66,14 @@
{/if}
</div>
{/if}
{#if !disabled}
{#if !disabled || (allowClear === true && disabled)}
<div class="delete-button" on:click={clearFile}>
<Icon name="Close" size="XS" />
</div>
{/if}
</div>
{/if}
<ActionButton on:click={fileInput.click()}>{title}</ActionButton>
<ActionButton {disabled} on:click={fileInput.click()}>{title}</ActionButton>
</div>
<style>

View file

@ -6,6 +6,7 @@
export let label = null
export let labelPosition = "above"
export let disabled = false
export let allowClear = null
export let handleFileTooLarge = () => {}
export let previewUrl = null
export let extensions = null
@ -25,6 +26,7 @@
<CoreFile
{error}
{disabled}
{allowClear}
{title}
{value}
{previewUrl}

View file

@ -8,7 +8,9 @@
$: platformTitleText = $organisation.platformTitle
$: platformTitleText,
(platformTitle =
!$admin.isCloud && !$auth.user ? platformTitleText : "Budibase")
!$admin.isCloud || !$auth.user ? platformTitleText : "Budibase")
$: faviconUrl = $organisation.faviconUrl || "https://i.imgur.com/Xhdt1YP.png"
onMount(async () => {
await organisation.init()
@ -23,37 +25,10 @@
<svelte:head>
<title>{platformTitle}</title>
{#if loaded && !$auth.user}
<link
rel="icon"
href={$organisation.faviconUrl || "https://i.imgur.com/Xhdt1YP.png"}
/>
{#if loaded && !$auth.user && faviconUrl}
<link rel="icon" href={faviconUrl} />
{:else}
<!-- A default must be set or the browser defaults to favicon.ico behaviour -->
<link rel="icon" href={"https://i.imgur.com/Xhdt1YP.png"} />
{/if}
<!-- Primary Meta Tags -->
<!-- <meta name="title" content={metaTitle} /> -->
<!--
metaTitle should match the title...
should title override metaTitle, if set??
-->
<!-- <meta name="description" content={metaDescription} /> -->
<!-- Opengraph Meta Tags -->
<!-- <meta property="og:site_name" content="Budibase" />
<meta property="og:title" content="{title} - built with Budibase" />
<meta property="og:description" content={metaDescription} />
<meta property="og:type" content="website" />
<meta property="og:image" content={metaImage} /> -->
<!-- Twitter -->
<!-- <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@budibase" />
<meta name="twitter:image" content={metaImage} /> -->
<!-- Consider adding this twitter:image:alt -->
<!-- <meta name="twitter:title" content="{title} - built with Budibase" />
<meta property="twitter:description" content={metaDescription} /> -->
</svelte:head>

View file

@ -30,7 +30,7 @@
async function login() {
form.validate()
if (Object.keys(errors).length > 0) {
console.log("errors")
console.log("errors", errors)
return
}
try {
@ -135,7 +135,7 @@
disabled={Object.keys(errors).length > 0}
on:click={login}
>
{$organisation.loginButton || `Log in to {company}`}
{$organisation.loginButton || `Log in to ${company}`}
</Button>
</Layout>
<Layout gap="XS" noPadding justifyItems="center">

View file

@ -17,6 +17,7 @@
import { auth, organisation, licensing, admin } from "stores/portal"
import { API } from "api"
import { onMount } from "svelte"
import { goto } from "@roxi/routify"
const imageExtensions = [
".png",
@ -32,25 +33,32 @@
const faviconExtensions = [".png", ".ico", ".gif"]
let loaded = false
let mounted = false
let saving = false
let logoFile = null
let logoPreview = null
let faviconFile = null
let faviconPreview = null
let config = {}
let updated = false
$: onConfigUpdate(config)
$: onConfigUpdate(config, mounted)
$: init = Object.keys(config).length > 0
$: cloudPremium = !$licensing.isFreePlan
$: selfhostPremium = $licensing.isEnterprisePlan || $licensing.isBusinessPlan
$: isCloud = $admin.cloud
$: isLicenseLocked =
(isCloud && !cloudPremium) || (!isCloud && !selfhostPremium)
const onConfigUpdate = config => {
if (!loaded || updated) {
if (!mounted || updated || !init) {
return
}
updated = true
console.log("config updated ", config)
}
$: logo = config.logoUrl
@ -61,9 +69,6 @@
? { url: config.faviconUrl, type: "image", name: "Favicon" }
: null
//If type of file do this IN the picker
//If string use the string
//If object?.url us that
const previewUrl = async localFile => {
if (!localFile) {
return Promise.resolve(null)
@ -123,7 +128,7 @@
async function saveConfig() {
saving = true
console.log("SAVING CONFIG ")
if (logoFile) {
const logoResp = await uploadLogo(logoFile)
if (logoResp.url) {
@ -147,7 +152,6 @@
faviconPreview = null
}
}
console.log("SAVE CONFIG ", config)
try {
// Update settings
await organisation.save(config)
@ -157,7 +161,7 @@
console.error("Branding updated failed", e)
notifications.error("Branding updated failed")
}
updated = false
saving = false
}
@ -169,7 +173,6 @@
logoUrl: $organisation.logoUrl,
platformTitle: $organisation.platformTitle,
emailBrandingEnabled: $organisation.emailBrandingEnabled,
appFooterEnabled: $organisation.appFooterEnabled,
loginHeading: $organisation.loginHeading,
loginButton: $organisation.loginButton,
licenseAgreementEnabled: $organisation.licenseAgreementEnabled,
@ -178,21 +181,25 @@
metaImageUrl: $organisation.metaImageUrl,
metaTitle: $organisation.metaTitle,
}
loaded = true
mounted = true
})
</script>
{#if $auth.isAdmin && loaded}
{#if $auth.isAdmin && mounted}
<Layout noPadding>
<Layout gap="XS" noPadding>
<div class="title">
<Heading size="M">Branding</Heading>
{#if !$licensing.isBusinessPlan}
{#if !isCloud && !selfhostPremium}
<Tags>
<Tag icon="LockClosed">Business</Tag>
</Tags>
{/if}
{#if isCloud && !cloudPremium}
<Tags>
<Tag icon="LockClosed">Pro</Tag>
</Tags>
{/if}
</div>
<Body>Remove all Budibase branding and use your own.</Body>
</Layout>
@ -208,7 +215,6 @@
extensions={imageExtensions}
previewUrl={logoPreview || logo?.url}
on:change={e => {
console.log("Updated Logo")
let clone = { ...config }
if (e.detail) {
logoFile = e.detail
@ -220,6 +226,8 @@
config = clone
}}
value={logoFile || logo}
disabled={isLicenseLocked || saving}
allowClear={true}
/>
</div>
@ -243,19 +251,24 @@
config = clone
}}
value={faviconFile || favicon}
disabled={isLicenseLocked || saving}
allowClear={true}
/>
</div>
<div class="field">
<Label size="L">Title</Label>
<Input
on:change={e => {
let clone = { ...config }
clone.platformTitle = e.detail ? e.detail : ""
config = clone
}}
value={config.platformTitle || ""}
/>
</div>
{#if !isCloud}
<div class="field">
<Label size="L">Title</Label>
<Input
on:change={e => {
let clone = { ...config }
clone.platformTitle = e.detail ? e.detail : ""
config = clone
}}
value={config.platformTitle || ""}
disabled={!selfhostPremium || saving}
/>
</div>
{/if}
<div>
<Toggle
text={"Remove Budibase brand from emails"}
@ -265,24 +278,16 @@
config = clone
}}
value={!config.emailBrandingEnabled}
/>
<Toggle
text={"Remove Budibase footer from apps"}
on:change={e => {
let clone = { ...config }
clone.appFooterEnabled = !e.detail
config = clone
}}
value={!config.appFooterEnabled}
disabled={isLicenseLocked || saving}
/>
</div>
</div>
{#if !$admin.cloud}
{#if !isCloud}
<Divider />
<Layout gap="XS" noPadding>
<Heading size="S">Login page (Self host)</Heading>
<Body>You can only customise your login page in self host</Body>
<Heading size="S">Login page</Heading>
<Body />
</Layout>
<div class="login">
<div class="fields">
@ -295,6 +300,7 @@
config = clone
}}
value={config.loginHeading || ""}
disabled={!selfhostPremium || saving}
/>
</div>
@ -307,6 +313,7 @@
config = clone
}}
value={config.loginButton || ""}
disabled={!selfhostPremium || saving}
/>
</div>
<div>
@ -318,6 +325,7 @@
config = clone
}}
value={!config.testimonialsEnabled}
disabled={!selfhostPremium || saving}
/>
<Toggle
text={"Remove license agreement"}
@ -327,6 +335,7 @@
config = clone
}}
value={!config.licenseAgreementEnabled}
disabled={!selfhostPremium || saving}
/>
</div>
</div>
@ -348,6 +357,7 @@
config = clone
}}
value={config.metaImageUrl}
disabled={isLicenseLocked || saving}
/>
</div>
<div class="field">
@ -359,6 +369,7 @@
config = clone
}}
value={config.metaTitle}
disabled={isLicenseLocked || saving}
/>
</div>
<div class="field">
@ -370,12 +381,28 @@
config = clone
}}
value={config.metaDescription}
disabled={isLicenseLocked || saving}
/>
</div>
</div>
</div>
<div>
<Button on:click={saveConfig} cta disabled={saving || !updated}>
<div class="buttons">
{#if isLicenseLocked}
<Button
on:click={() => {
if (isCloud && $auth?.user?.accountPortalAccess) {
window.open($admin.accountPortalUrl + "/portal/upgrade", "_blank")
} else if ($auth.isAdmin) {
$goto("/builder/portal/account/upgrade")
}
}}
secondary
disabled={saving}
>
Upgrade
</Button>
{/if}
<Button on:click={saveConfig} cta disabled={saving || !updated || !init}>
Save
</Button>
</div>
@ -383,6 +410,10 @@
{/if}
<style>
.buttons {
display: flex;
gap: var(--spacing-m);
}
.title {
display: flex;
flex-direction: row;

View file

@ -5,22 +5,17 @@ import _ from "lodash"
const DEFAULT_CONFIG = {
platformUrl: "",
logoUrl: undefined,
faviconUrl: undefined,
emailBrandingEnabled: true,
appFooterEnabled: true,
testimonialsEnabled: true,
licenseAgreementEnabled: true,
platformTitle: "Budibase",
loginHeading: undefined,
loginButton: undefined,
metaDescription: undefined,
metaImageUrl: undefined,
metaTitle: undefined,
docsUrl: undefined,
company: "Budibase",
oidc: undefined,

View file

@ -16,6 +16,7 @@ export { rowSelectionStore } from "./rowSelection.js"
export { blockStore } from "./blocks.js"
export { environmentStore } from "./environment"
export { eventStore } from "./events.js"
export { orgStore } from "./org.js"
export {
dndStore,
dndIndex,

View file

@ -1,7 +1,9 @@
import { routeStore } from "./routes"
import { appStore } from "./app"
import { orgStore } from "./org"
export async function initialise() {
await routeStore.actions.fetchRoutes()
await appStore.actions.fetchAppDefinition()
await orgStore.init()
}

View file

@ -0,0 +1,27 @@
import { API } from "api"
import { writable, get } from "svelte/store"
import { appStore } from "./app"
const createOrgStore = () => {
const store = writable(null)
const { subscribe, set } = store
async function init() {
const tenantId = get(appStore).application?.tenantId
if (!tenantId) return
try {
const settingsConfigDoc = await API.getTenantConfig(tenantId)
set({ logoUrl: settingsConfigDoc.config.logoUrl })
} catch (e) {
console.log("Could not init org ", e)
}
}
return {
subscribe,
init,
}
}
export const orgStore = createOrgStore()

View file

@ -2,6 +2,7 @@ import { derived } from "svelte/store"
import { routeStore } from "./routes"
import { builderStore } from "./builder"
import { appStore } from "./app"
import { orgStore } from "./org"
import { dndIndex, dndParent, dndIsNewComponent, dndBounds } from "./dnd.js"
import { RoleUtils } from "@budibase/frontend-core"
import { findComponentById, findComponentParent } from "../utils/components.js"
@ -14,6 +15,7 @@ const createScreenStore = () => {
appStore,
routeStore,
builderStore,
orgStore,
dndParent,
dndIndex,
dndIsNewComponent,
@ -23,6 +25,7 @@ const createScreenStore = () => {
$appStore,
$routeStore,
$builderStore,
$orgStore,
$dndParent,
$dndIndex,
$dndIsNewComponent,
@ -146,6 +149,11 @@ const createScreenStore = () => {
if (!navigationSettings.title && !navigationSettings.hideTitle) {
navigationSettings.title = $appStore.application?.name
}
if (!navigationSettings.logoUrl) {
navigationSettings.logoUrl =
$orgStore?.logoUrl || navigationSettings.logoUrl
}
}
activeLayout = {
_id: "layout",

View file

@ -99,40 +99,71 @@ export const deleteObjects = async function (ctx: any) {
}
export const serveApp = async function (ctx: any) {
//Public Settings
const { config } = await configs.getSettingsConfigDoc()
let db
try {
db = context.getAppDB({ skip_setup: true })
const appInfo = await db.get(DocumentType.APP_METADATA)
let appId = context.getAppId()
const db = context.getAppDB({ skip_setup: true })
const appInfo = await db.get(DocumentType.APP_METADATA)
let appId = context.getAppId()
if (!env.isJest()) {
const App = require("./templates/BudibaseApp.svelte").default
const plugins = objectStore.enrichPluginURLs(appInfo.usedPlugins)
const { head, html, css } = App.render({
metaImage:
config?.metaImageUrl ||
"https://res.cloudinary.com/daog6scxm/image/upload/v1666109324/meta-images/budibase-meta-image_uukc1m.png",
metaDescription: config?.metaDescription || "",
metaTitle: config?.metaTitle || `${appInfo.name} - built with Budibase`,
title: appInfo.name,
production: env.isProd(),
appId,
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
usedPlugins: plugins,
favicon:
config.faviconUrl !== ""
? objectStore.getGlobalFileUrl("settings", "faviconUrl")
: "",
logo:
config?.logoUrl !== ""
? objectStore.getGlobalFileUrl("settings", "logoUrl")
: "",
})
const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`)
ctx.body = await processString(appHbs, {
head,
body: html,
style: css.code,
appId,
})
} else {
// just return the app info for jest to assert on
ctx.body = appInfo
}
} catch (error) {
if (!env.isJest()) {
const App = require("./templates/BudibaseApp.svelte").default
const { head, html, css } = App.render({
title: config?.metaTitle,
metaTitle: config?.metaTitle,
metaImage:
config?.metaImageUrl ||
"https://res.cloudinary.com/daog6scxm/image/upload/v1666109324/meta-images/budibase-meta-image_uukc1m.png",
metaDescription: config?.metaDescription || "",
favicon:
config.faviconUrl !== ""
? objectStore.getGlobalFileUrl("settings", "faviconUrl")
: "",
})
if (!env.isJest()) {
const App = require("./templates/BudibaseApp.svelte").default
const plugins = objectStore.enrichPluginURLs(appInfo.usedPlugins)
const { head, html, css } = App.render({
metaImage:
config?.metaImageUrl ||
"https://res.cloudinary.com/daog6scxm/image/upload/v1666109324/meta-images/budibase-meta-image_uukc1m.png",
metaDescription: config?.metaDescription || "",
metaTitle: `${appInfo.name} - built with Budibase` || config?.metaTitle,
title: appInfo.name,
production: env.isProd(),
appId,
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
usedPlugins: plugins,
favicon: objectStore.getGlobalFileUrl("settings", "faviconUrl"),
//logo: objectStore.getGlobalFileUrl("settings", "logoUrl"),
})
const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`)
ctx.body = await processString(appHbs, {
head,
body: html,
style: css.code,
appId,
})
} else {
// just return the app info for jest to assert on
ctx.body = appInfo
const appHbs = loadHandlebarsFile(`${__dirname}/templates/app.hbs`)
ctx.body = await processString(appHbs, {
head,
body: html,
style: css.code,
})
}
}
}

View file

@ -21,11 +21,6 @@
<meta name="title" content={metaTitle} />
<meta name="description" content={metaDescription} />
<!--
metaTitle should match the title...
should title override metaTitle, if set??
-->
<!-- Opengraph Meta Tags -->
<meta property="og:site_name" content="Budibase" />
<meta property="og:title" content="{title} - built with Budibase" />
@ -37,12 +32,17 @@
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:site" content="@budibase" />
<meta property="twitter:image" content={metaImage} />
<!-- Consider adding this twitter:image:alt -->
<meta property="twitter:image:alt" content="{title} - built with Budibase" />
<meta property="twitter:title" content="{title} - built with Budibase" />
<meta property="twitter:description" content={metaDescription} />
<title>{title}</title>
<link rel="icon" type="image/png" href={favicon} />
{#if favicon !== ""}
<link rel="icon" type="image/png" href={favicon} />
{:else}
<link rel="icon" type="image/png" href="https://i.imgur.com/Xhdt1YP.png" />
{/if}
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
@ -101,11 +101,16 @@
<body id="app">
<div id="error">
<h1>There was an error loading your app</h1>
<h2>
The Budibase client library could not be loaded. Try republishing your
app.
</h2>
{#if clientLibPath}
<h1>There was an error loading your app</h1>
<h2>
The Budibase client library could not be loaded. Try republishing your
app.
</h2>
{:else}
<h2>We couldn't find that application</h2>
<p />
{/if}
</div>
<script type="application/javascript">
window.INIT_TIME = Date.now()

View file

@ -32,7 +32,6 @@ export interface SettingsInnerConfig {
faviconUrlEtag?: string
emailBrandingEnabled?: boolean
appFooterEnabled?: boolean
testimonialsEnabled?: boolean
licenseAgreementEnabled?: boolean
platformTitle?: string

View file

@ -10,16 +10,18 @@
>
<tbody>
<tr>
<td style="padding:0 35px;" cellpadding="0" cellspacing="0">
<td
style="padding:0 35px; padding-top: 15px;"
cellpadding="0"
cellspacing="0"
>
<img
width="32px"
style="margin-right:16px; vertical-align: middle;"
alt="Budibase Logo"
src="https://i.imgur.com/Xhdt1YP.png"
/>
<strong
style="color:#333333; vertical-align: middle; font-size: 1.1em"
>
<strong style="vertical-align: middle; font-size: 1.1em">
Budibase
</strong>
</td>

View file

@ -26,9 +26,7 @@ export async function getSettingsTemplateContext(
[InternalTemplateBinding.CURRENT_YEAR]: new Date().getFullYear(),
}
// Need to be careful with the binding as it shouldn't be surfacable
// Also default to false if not explicit
context["enableEmailBranding"] = settings.emailBrandingEnabled
context["enableEmailBranding"] = settings.emailBrandingEnabled === true
// attach purpose specific context
switch (purpose) {