Updates to upgrade page to change config based on offlineMode value

This commit is contained in:
Rory Powell 2023-07-06 20:47:12 +01:00
parent efe53bb217
commit 1ba3665ed4
3 changed files with 201 additions and 72 deletions

View File

@ -10,6 +10,8 @@
Label, Label,
ButtonGroup, ButtonGroup,
notifications, notifications,
CopyInput,
File
} from "@budibase/bbui" } from "@budibase/bbui"
import { auth, admin } from "stores/portal" import { auth, admin } from "stores/portal"
import { redirect } from "@roxi/routify" import { redirect } from "@roxi/routify"
@ -21,44 +23,122 @@
$: license = $auth.user.license $: license = $auth.user.license
$: upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade` $: upgradeUrl = `${$admin.accountPortalUrl}/portal/upgrade`
// LICENSE KEY
$: activateDisabled = !licenseKey || licenseKeyDisabled $: activateDisabled = !licenseKey || licenseKeyDisabled
let licenseInfo
let licenseKeyDisabled = false let licenseKeyDisabled = false
let licenseKeyType = "text" let licenseKeyType = "text"
let licenseKey = "" let licenseKey = ""
let deleteLicenseKeyModal let deleteLicenseKeyModal
// OFFLINE LICENSE
let installationIdentifier = undefined
let offlineLicense = undefined
const offlineLicenseExtensions = [
".txt",
]
// Make sure page can't be visited directly in cloud // Make sure page can't be visited directly in cloud
$: { $: {
if ($admin.cloud) { if ($admin.cloud) {
$redirect("../../portal") $redirect("../../portal")
} }
console.log({ offlineLicense })
} }
const activate = async () => { // LICENSE KEY
const getLicenseKey = async () => {
try { try {
await API.activateLicenseKey({ licenseKey }) licenseKey = await API.getLicenseKey()
await auth.getSelf() if (licenseKey) {
await setLicenseInfo() licenseKey = "**********************************************"
notifications.success("Successfully activated") licenseKeyType = "password"
licenseKeyDisabled = true
activateDisabled = true
}
} catch (e) { } catch (e) {
notifications.error(e.message) console.error(e)
notifications.error("Error retrieving license key")
} }
} }
const destroy = async () => { const activateLicenseKey = async () => {
try {
await API.activateLicenseKey({ licenseKey })
await auth.getSelf()
await getLicenseKey()
notifications.success("Successfully activated")
} catch (e) {
console.error(e)
notifications.error("Error activating license key")
}
}
const deleteLicenseKey = async () => {
try { try {
await API.deleteLicenseKey({ licenseKey }) await API.deleteLicenseKey({ licenseKey })
await auth.getSelf() await auth.getSelf()
await setLicenseInfo() await getLicenseKey()
// reset the form // reset the form
licenseKey = "" licenseKey = ""
licenseKeyDisabled = false licenseKeyDisabled = false
notifications.success("Successfully deleted") notifications.success("Offline license removed")
} catch (e) { } catch (e) {
notifications.error(e.message) console.error(e)
notifications.error("Error deleting license key")
}
}
// OFFLINE LICENSE
const getOfflineLicense = async () => {
try {
const license = await API.getOfflineLicense()
if (license) {
offlineLicense = {
name: "license"
}
} else {
offlineLicense = undefined
}
} catch (e) {
console.error(e)
notifications.error("Error loading offline license")
}
}
async function activateOfflineLicense(offlineLicense) {
try {
await API.activateOfflineLicense({ offlineLicense })
await auth.getSelf()
await getOfflineLicense()
notifications.success("Successfully activated")
} catch (e) {
console.error(e)
notifications.error("Error activating offline license")
}
}
async function deleteOfflineLicense() {
try {
await API.deleteOfflineLicense()
await auth.getSelf()
await getOfflineLicense()
notifications.success("Successfully removed ofline license")
} catch (e) {
console.error(e)
notifications.error("Error upload offline license")
}
}
async function onOfflineLicenseChange(event) {
if (event.detail) {
const reader = new FileReader()
reader.readAsText(event.detail)
reader.onload = () => activateOfflineLicense(reader.result)
} else {
await deleteOfflineLicense()
} }
} }
@ -73,29 +153,19 @@
} }
} }
// deactivate the license key field if there is a license key set
$: {
if (licenseInfo?.licenseKey) {
licenseKey = "**********************************************"
licenseKeyType = "password"
licenseKeyDisabled = true
activateDisabled = true
}
}
const setLicenseInfo = async () => {
licenseInfo = await API.getLicenseInfo()
}
onMount(async () => { onMount(async () => {
await setLicenseInfo() if ($admin.offlineMode) {
await getOfflineLicense()
} else {
await getLicenseKey()
}
}) })
</script> </script>
{#if $auth.isAdmin} {#if $auth.isAdmin}
<DeleteLicenseKeyModal <DeleteLicenseKeyModal
bind:this={deleteLicenseKeyModal} bind:this={deleteLicenseKeyModal}
onConfirm={destroy} onConfirm={deleteLicenseKey}
/> />
<Layout noPadding> <Layout noPadding>
<Layout gap="XS" noPadding> <Layout gap="XS" noPadding>
@ -112,38 +182,73 @@
</Body> </Body>
</Layout> </Layout>
<Divider /> <Divider />
<Layout gap="XS" noPadding> {#if $admin.offlineMode}
<Heading size="S">Activate</Heading> <Layout gap="XS" noPadding>
<Body size="S">Enter your license key below to activate your plan</Body> <Heading size="XS">Installation identifier</Heading>
</Layout> <Body size="S">Share this with support@budibase.com to obtain your offline license</Body>
<Layout noPadding> </Layout>
<div class="fields"> <Layout noPadding>
<div class="field"> <div class="fields">
<Label size="L">License key</Label> <div class="field">
<Input <CopyInput value={installationIdentifier} />
thin </div>
bind:value={licenseKey} </div>
type={licenseKeyType} </Layout>
disabled={licenseKeyDisabled} <Divider />
<Layout gap="XS" noPadding>
<Heading size="XS">License</Heading>
<Body size="S">Upload your license to activate your plan</Body>
</Layout>
<Layout noPadding>
<div>
<File
title="Upload license"
extensions={offlineLicenseExtensions}
value={offlineLicense}
on:change={onOfflineLicenseChange}
allowClear={true}
disabled={!!offlineLicense}
/> />
</div> </div>
</div> </Layout>
<ButtonGroup gap="M"> {:else}
<Button cta on:click={activate} disabled={activateDisabled}> <Layout gap="XS" noPadding>
Activate <Heading size="XS">Activate</Heading>
</Button> <Body size="S">Enter your license key below to activate your plan</Body>
{#if licenseInfo?.licenseKey} </Layout>
<Button warning on:click={() => deleteLicenseKeyModal.show()}> <Layout noPadding>
Delete <div class="fields">
<div class="field">
<Label size="L">License key</Label>
<Input
thin
bind:value={licenseKey}
type={licenseKeyType}
disabled={licenseKeyDisabled}
/>
</div>
</div>
<ButtonGroup gap="M">
<Button cta on:click={activateLicenseKey} disabled={activateDisabled}>
Activate
</Button> </Button>
{/if} {#if licenseKey}
</ButtonGroup> <Button warning on:click={() => deleteLicenseKeyModal.show()}>
</Layout> Delete
</Button>
{/if}
</ButtonGroup>
</Layout>
{/if}
<Divider /> <Divider />
<Layout gap="XS" noPadding> <Layout gap="XS" noPadding>
<Heading size="S">Plan</Heading> <Heading size="XS">Plan</Heading>
<Layout noPadding gap="XXS"> <Layout noPadding gap="S">
<Body size="S">You are currently on the {license.plan.type} plan</Body> <Body size="S">You are currently on the {license.plan.type} plan</Body>
<div>
<Body size="S">If you purchase or update your plan on the account</Body>
<Body size="S">portal, click the refresh button to sync those changes</Body>
</div>
<Body size="XS"> <Body size="XS">
{processStringSync("Updated {{ duration time 'millisecond' }} ago", { {processStringSync("Updated {{ duration time 'millisecond' }} ago", {
time: time:

View File

@ -17,6 +17,7 @@ export const DEFAULT_CONFIG = {
adminUser: { checked: false }, adminUser: { checked: false },
sso: { checked: false }, sso: { checked: false },
}, },
offlineMode: false
} }
export function createAdminStore() { export function createAdminStore() {

View File

@ -1,32 +1,56 @@
export const buildLicensingEndpoints = API => ({ export const buildLicensingEndpoints = API => ({
/**
* Activates a self hosted license key // LICENSE KEY
*/
activateLicenseKey: async data => { activateLicenseKey: async data => {
return API.post({ return API.post({
url: `/api/global/license/activate`, url: `/api/global/license/key`,
body: data, body: data,
}) })
}, },
/**
* Delete a self hosted license key
*/
deleteLicenseKey: async () => { deleteLicenseKey: async () => {
return API.delete({ return API.delete({
url: `/api/global/license/info`, url: `/api/global/license/key`,
}) })
}, },
getLicenseKey: async () => {
try {
return await API.get({
url: "/api/global/license/key",
})
} catch (e) {
if (e.status !== 404) {
throw e
}
}
},
/** // OFFLINE LICENSE
* Get the license info - metadata about the license including the
* obfuscated license key. activateOfflineLicense: async ({ offlineLicense }) => {
*/ return API.post({
getLicenseInfo: async () => { url: "/api/global/license/offline",
return API.get({ body: {
url: "/api/global/license/info", offlineLicense
},
}) })
}, },
deleteOfflineLicense: async () => {
return API.delete({
url: "/api/global/license/offline",
})
},
getOfflineLicense: async () => {
try {
return await API.get({
url: "/api/global/license/offline",
})
} catch (e) {
if (e.status !== 404) {
throw e
}
}
},
/** /**
* Refreshes the license cache * Refreshes the license cache
@ -36,7 +60,6 @@ export const buildLicensingEndpoints = API => ({
url: "/api/global/license/refresh", url: "/api/global/license/refresh",
}) })
}, },
/** /**
* Retrieve the usage information for the tenant * Retrieve the usage information for the tenant
*/ */