Merge pull request #14384 from Budibase/feature-flag-cleanup
Feature flag cleanup
This commit is contained in:
commit
216b032f55
|
@ -139,7 +139,7 @@ $ helm install --create-namespace --namespace budibase budibase . -f values.yaml
|
||||||
| globals.smtp.user | string | `""` | The username to use when authenticating with your SMTP server. |
|
| globals.smtp.user | string | `""` | The username to use when authenticating with your SMTP server. |
|
||||||
| globals.sqs.enabled | bool | `false` | Whether to use the CouchDB "structured query service" or not. This is disabled by default for now, but will become the default in a future release. |
|
| globals.sqs.enabled | bool | `false` | Whether to use the CouchDB "structured query service" or not. This is disabled by default for now, but will become the default in a future release. |
|
||||||
| globals.tempBucketName | string | `""` | |
|
| globals.tempBucketName | string | `""` | |
|
||||||
| globals.tenantFeatureFlags | string | `"*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR"` | Sets what feature flags are enabled and for which tenants. Should not ordinarily need to be changed. |
|
| globals.tenantFeatureFlags | string | `` | Sets what feature flags are enabled and for which tenants. Should not ordinarily need to be changed. |
|
||||||
| imagePullSecrets | list | `[]` | Passed to all pods created by this chart. Should not ordinarily need to be changed. |
|
| imagePullSecrets | list | `[]` | Passed to all pods created by this chart. Should not ordinarily need to be changed. |
|
||||||
| ingress.className | string | `""` | What ingress class to use. |
|
| ingress.className | string | `""` | What ingress class to use. |
|
||||||
| ingress.enabled | bool | `true` | Whether to create an Ingress resource pointing to the Budibase proxy. |
|
| ingress.enabled | bool | `true` | Whether to create an Ingress resource pointing to the Budibase proxy. |
|
||||||
|
|
|
@ -62,7 +62,7 @@ globals:
|
||||||
budibaseEnv: PRODUCTION
|
budibaseEnv: PRODUCTION
|
||||||
# -- Sets what feature flags are enabled and for which tenants. Should not ordinarily need to be
|
# -- Sets what feature flags are enabled and for which tenants. Should not ordinarily need to be
|
||||||
# changed.
|
# changed.
|
||||||
tenantFeatureFlags: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR"
|
tenantFeatureFlags: ""
|
||||||
# -- Whether to enable analytics or not. You can read more about our analytics here:
|
# -- Whether to enable analytics or not. You can read more about our analytics here:
|
||||||
# <https://docs.budibase.com/docs/analytics>.
|
# <https://docs.budibase.com/docs/analytics>.
|
||||||
enableAnalytics: "1"
|
enableAnalytics: "1"
|
||||||
|
|
|
@ -10,7 +10,6 @@ declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONME
|
||||||
[[ -z "${MINIO_URL}" ]] && [[ -z "${USE_S3}" ]] && export MINIO_URL=http://127.0.0.1:9000
|
[[ -z "${MINIO_URL}" ]] && [[ -z "${USE_S3}" ]] && export MINIO_URL=http://127.0.0.1:9000
|
||||||
[[ -z "${NODE_ENV}" ]] && export NODE_ENV=production
|
[[ -z "${NODE_ENV}" ]] && export NODE_ENV=production
|
||||||
[[ -z "${POSTHOG_TOKEN}" ]] && export POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
[[ -z "${POSTHOG_TOKEN}" ]] && export POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
[[ -z "${TENANT_FEATURE_FLAGS}" ]] && export TENANT_FEATURE_FLAGS="*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR"
|
|
||||||
[[ -z "${ACCOUNT_PORTAL_URL}" ]] && export ACCOUNT_PORTAL_URL=https://account.budibase.app
|
[[ -z "${ACCOUNT_PORTAL_URL}" ]] && export ACCOUNT_PORTAL_URL=https://account.budibase.app
|
||||||
[[ -z "${REDIS_URL}" ]] && export REDIS_URL=127.0.0.1:6379
|
[[ -z "${REDIS_URL}" ]] && export REDIS_URL=127.0.0.1:6379
|
||||||
[[ -z "${SELF_HOSTED}" ]] && export SELF_HOSTED=1
|
[[ -z "${SELF_HOSTED}" ]] && export SELF_HOSTED=1
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 32b8fa4643b4f0f74ee89760deffe431ab347ad9
|
Subproject commit 516b27b74cbcb7069a25f5e738dc91c22d7c4538
|
|
@ -265,9 +265,5 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
|
||||||
// All of the machinery in this file is to make sure that flags have their
|
// All of the machinery in this file is to make sure that flags have their
|
||||||
// default values set correctly and their types flow through the system.
|
// default values set correctly and their types flow through the system.
|
||||||
export const flags = new FlagSet({
|
export const flags = new FlagSet({
|
||||||
LICENSING: Flag.boolean(false),
|
|
||||||
GOOGLE_SHEETS: Flag.boolean(false),
|
|
||||||
USER_GROUPS: Flag.boolean(false),
|
|
||||||
ONBOARDING_TOUR: Flag.boolean(false),
|
|
||||||
DEFAULT_VALUES: Flag.boolean(false),
|
DEFAULT_VALUES: Flag.boolean(false),
|
||||||
})
|
})
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
import { RowUtils } from "@budibase/frontend-core"
|
import { RowUtils } from "@budibase/frontend-core"
|
||||||
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
import ServerBindingPanel from "components/common/bindings/ServerBindingPanel.svelte"
|
||||||
import OptionsEditor from "./OptionsEditor.svelte"
|
import OptionsEditor from "./OptionsEditor.svelte"
|
||||||
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
|
import { isEnabled } from "helpers/featureFlags"
|
||||||
|
|
||||||
const AUTO_TYPE = FieldType.AUTO
|
const AUTO_TYPE = FieldType.AUTO
|
||||||
const FORMULA_TYPE = FieldType.FORMULA
|
const FORMULA_TYPE = FieldType.FORMULA
|
||||||
|
@ -168,8 +168,7 @@
|
||||||
$: canBeDisplay =
|
$: canBeDisplay =
|
||||||
canBeDisplayColumn(editableColumn.type) && !editableColumn.autocolumn
|
canBeDisplayColumn(editableColumn.type) && !editableColumn.autocolumn
|
||||||
$: canHaveDefault =
|
$: canHaveDefault =
|
||||||
isEnabled(TENANT_FEATURE_FLAGS.DEFAULT_VALUES) &&
|
isEnabled("DEFAULT_VALUES") && canHaveDefaultColumn(editableColumn.type)
|
||||||
canHaveDefaultColumn(editableColumn.type)
|
|
||||||
$: canBeRequired =
|
$: canBeRequired =
|
||||||
editableColumn?.type !== LINK_TYPE &&
|
editableColumn?.type !== LINK_TYPE &&
|
||||||
!uneditable &&
|
!uneditable &&
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import FontAwesomeIcon from "./FontAwesomeIcon.svelte"
|
import FontAwesomeIcon from "./FontAwesomeIcon.svelte"
|
||||||
import { Popover, Heading, Body } from "@budibase/bbui"
|
import { Popover, Heading, Body } from "@budibase/bbui"
|
||||||
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
|
|
||||||
import { licensing } from "stores/portal"
|
import { licensing } from "stores/portal"
|
||||||
import { isPremiumOrAbove } from "helpers/planTitle"
|
import { isPremiumOrAbove } from "helpers/planTitle"
|
||||||
import { ChangelogURL } from "constants"
|
import { ChangelogURL } from "constants"
|
||||||
|
@ -62,31 +61,26 @@
|
||||||
<Body size="S">Budibase University</Body>
|
<Body size="S">Budibase University</Body>
|
||||||
</a>
|
</a>
|
||||||
<div class="divider" />
|
<div class="divider" />
|
||||||
{#if isEnabled(TENANT_FEATURE_FLAGS.LICENSING)}
|
<a
|
||||||
<a
|
href={premiumOrAboveLicense
|
||||||
href={premiumOrAboveLicense
|
? "mailto:support@budibase.com"
|
||||||
? "mailto:support@budibase.com"
|
: "/builder/portal/account/usage"}
|
||||||
: "/builder/portal/account/usage"}
|
>
|
||||||
>
|
<div class="premiumLinkContent" class:disabled={!premiumOrAboveLicense}>
|
||||||
<div
|
<div class="icon">
|
||||||
class="premiumLinkContent"
|
<FontAwesomeIcon name="fa-solid fa-envelope" />
|
||||||
class:disabled={!premiumOrAboveLicense}
|
|
||||||
>
|
|
||||||
<div class="icon">
|
|
||||||
<FontAwesomeIcon name="fa-solid fa-envelope" />
|
|
||||||
</div>
|
|
||||||
<Body size="S">Email support</Body>
|
|
||||||
</div>
|
</div>
|
||||||
{#if !premiumOrAboveLicense}
|
<Body size="S">Email support</Body>
|
||||||
<div class="premiumBadge">
|
</div>
|
||||||
<div class="icon">
|
{#if !premiumOrAboveLicense}
|
||||||
<FontAwesomeIcon name="fa-solid fa-lock" />
|
<div class="premiumBadge">
|
||||||
</div>
|
<div class="icon">
|
||||||
<Body size="XS">Premium</Body>
|
<FontAwesomeIcon name="fa-solid fa-lock" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
<Body size="XS">Premium</Body>
|
||||||
</a>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
import { ExpiringKeys } from "./constants"
|
import { ExpiringKeys } from "./constants"
|
||||||
import { getBanners } from "./licensingBanners"
|
import { getBanners } from "./licensingBanners"
|
||||||
import { banner } from "@budibase/bbui"
|
import { banner } from "@budibase/bbui"
|
||||||
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
|
|
||||||
|
|
||||||
const oneDayInSeconds = 86400
|
const oneDayInSeconds = 86400
|
||||||
|
|
||||||
|
@ -89,8 +88,7 @@
|
||||||
userLoaded &&
|
userLoaded &&
|
||||||
$licensing.usageMetrics &&
|
$licensing.usageMetrics &&
|
||||||
domLoaded &&
|
domLoaded &&
|
||||||
!licensingLoaded &&
|
!licensingLoaded
|
||||||
isEnabled(TENANT_FEATURE_FLAGS.LICENSING)
|
|
||||||
) {
|
) {
|
||||||
licensingLoaded = true
|
licensingLoaded = true
|
||||||
queuedModals = processModals()
|
queuedModals = processModals()
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
import { auth } from "../stores/portal"
|
import { auth } from "../stores/portal"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
|
|
||||||
export const TENANT_FEATURE_FLAGS = {
|
|
||||||
LICENSING: "LICENSING",
|
|
||||||
USER_GROUPS: "USER_GROUPS",
|
|
||||||
ONBOARDING_TOUR: "ONBOARDING_TOUR",
|
|
||||||
GOOGLE_SHEETS: "GOOGLE_SHEETS",
|
|
||||||
DEFAULT_VALUES: "DEFAULT_VALUES",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isEnabled = featureFlag => {
|
export const isEnabled = featureFlag => {
|
||||||
const user = get(auth).user
|
const user = get(auth).user
|
||||||
return !!user?.flags?.[featureFlag]
|
return !!user?.flags?.[featureFlag]
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
deploymentStore,
|
deploymentStore,
|
||||||
} from "stores/builder"
|
} from "stores/builder"
|
||||||
import { auth, appsStore } from "stores/portal"
|
import { auth, appsStore } from "stores/portal"
|
||||||
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
|
|
||||||
import {
|
import {
|
||||||
Icon,
|
Icon,
|
||||||
Tabs,
|
Tabs,
|
||||||
|
@ -90,16 +89,14 @@
|
||||||
|
|
||||||
const initTour = async () => {
|
const initTour = async () => {
|
||||||
// Check if onboarding is enabled.
|
// Check if onboarding is enabled.
|
||||||
if (isEnabled(TENANT_FEATURE_FLAGS.ONBOARDING_TOUR)) {
|
if (!$auth.user?.onboardedAt) {
|
||||||
if (!$auth.user?.onboardedAt) {
|
builderStore.startBuilderOnboarding()
|
||||||
builderStore.startBuilderOnboarding()
|
} else {
|
||||||
} else {
|
// Feature tour date
|
||||||
// Feature tour date
|
const release_date = new Date("2023-03-01T00:00:00.000Z")
|
||||||
const release_date = new Date("2023-03-01T00:00:00.000Z")
|
const onboarded = new Date($auth.user?.onboardedAt)
|
||||||
const onboarded = new Date($auth.user?.onboardedAt)
|
if (onboarded < release_date) {
|
||||||
if (onboarded < release_date) {
|
builderStore.setTour(TOUR_KEYS.FEATURE_ONBOARDING)
|
||||||
builderStore.setTour(TOUR_KEYS.FEATURE_ONBOARDING)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
import { Button } from "@budibase/bbui"
|
import { Button } from "@budibase/bbui"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
import { auth, admin, licensing } from "stores/portal"
|
import { auth, admin, licensing } from "stores/portal"
|
||||||
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
|
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isEnabled(TENANT_FEATURE_FLAGS.LICENSING) && !$licensing.isEnterprisePlan && !$licensing.isEnterpriseTrial}
|
{#if !$licensing.isEnterprisePlan && !$licensing.isEnterpriseTrial}
|
||||||
{#if $admin.cloud && $auth?.user?.accountPortalAccess}
|
{#if $admin.cloud && $auth?.user?.accountPortalAccess}
|
||||||
<Button
|
<Button
|
||||||
cta
|
cta
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { API } from "api"
|
||||||
import { auth, admin } from "stores/portal"
|
import { auth, admin } from "stores/portal"
|
||||||
import { Constants } from "@budibase/frontend-core"
|
import { Constants } from "@budibase/frontend-core"
|
||||||
import { StripeStatus } from "components/portal/licensing/constants"
|
import { StripeStatus } from "components/portal/licensing/constants"
|
||||||
import { TENANT_FEATURE_FLAGS, isEnabled } from "helpers/featureFlags"
|
|
||||||
import { PlanModel } from "@budibase/types"
|
import { PlanModel } from "@budibase/types"
|
||||||
|
|
||||||
const UNLIMITED = -1
|
const UNLIMITED = -1
|
||||||
|
@ -183,93 +182,91 @@ export const createLicensingStore = () => {
|
||||||
return usersLimitExceeded(userCount, get(store).userLimit)
|
return usersLimitExceeded(userCount, get(store).userLimit)
|
||||||
},
|
},
|
||||||
setUsageMetrics: async () => {
|
setUsageMetrics: async () => {
|
||||||
if (isEnabled(TENANT_FEATURE_FLAGS.LICENSING)) {
|
const usage = get(store).quotaUsage
|
||||||
const usage = get(store).quotaUsage
|
const license = get(auth).user.license
|
||||||
const license = get(auth).user.license
|
const now = new Date()
|
||||||
const now = new Date()
|
|
||||||
|
|
||||||
const getMetrics = (keys, license, quota) => {
|
const getMetrics = (keys, license, quota) => {
|
||||||
if (!license || !quota || !keys) {
|
if (!license || !quota || !keys) {
|
||||||
return {}
|
return {}
|
||||||
}
|
|
||||||
return keys.reduce((acc, key) => {
|
|
||||||
const quotaLimit = license[key].value
|
|
||||||
const quotaUsed = (quota[key] / quotaLimit) * 100
|
|
||||||
acc[key] = quotaLimit > -1 ? Math.floor(quotaUsed) : -1
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
}
|
}
|
||||||
const monthlyMetrics = getMetrics(
|
return keys.reduce((acc, key) => {
|
||||||
["dayPasses", "queries", "automations"],
|
const quotaLimit = license[key].value
|
||||||
license.quotas.usage.monthly,
|
const quotaUsed = (quota[key] / quotaLimit) * 100
|
||||||
usage.monthly.current
|
acc[key] = quotaLimit > -1 ? Math.floor(quotaUsed) : -1
|
||||||
)
|
return acc
|
||||||
const staticMetrics = getMetrics(
|
}, {})
|
||||||
["apps", "rows"],
|
|
||||||
license.quotas.usage.static,
|
|
||||||
usage.usageQuota
|
|
||||||
)
|
|
||||||
|
|
||||||
const getDaysBetween = (dateStart, dateEnd) => {
|
|
||||||
return dateEnd > dateStart
|
|
||||||
? Math.round(
|
|
||||||
(dateEnd.getTime() - dateStart.getTime()) / oneDayInMilliseconds
|
|
||||||
)
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const quotaResetDate = new Date(usage.quotaReset)
|
|
||||||
const quotaResetDaysRemaining = getDaysBetween(now, quotaResetDate)
|
|
||||||
|
|
||||||
const accountDowngraded =
|
|
||||||
license?.billing?.subscription?.downgradeAt &&
|
|
||||||
license?.billing?.subscription?.downgradeAt <= now.getTime() &&
|
|
||||||
license?.billing?.subscription?.status === StripeStatus.PAST_DUE &&
|
|
||||||
license?.plan.type === Constants.PlanType.FREE
|
|
||||||
|
|
||||||
const pastDueAtMilliseconds = license?.billing?.subscription?.pastDueAt
|
|
||||||
const downgradeAtMilliseconds =
|
|
||||||
license?.billing?.subscription?.downgradeAt
|
|
||||||
let pastDueDaysRemaining
|
|
||||||
let pastDueEndDate
|
|
||||||
|
|
||||||
if (pastDueAtMilliseconds && downgradeAtMilliseconds) {
|
|
||||||
pastDueEndDate = new Date(downgradeAtMilliseconds)
|
|
||||||
pastDueDaysRemaining = getDaysBetween(
|
|
||||||
new Date(pastDueAtMilliseconds),
|
|
||||||
pastDueEndDate
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const userQuota = license.quotas.usage.static.users
|
|
||||||
const userLimit = userQuota?.value
|
|
||||||
const userCount = usage.usageQuota.users
|
|
||||||
const userLimitReached = usersLimitReached(userCount, userLimit)
|
|
||||||
const userLimitExceeded = usersLimitExceeded(userCount, userLimit)
|
|
||||||
const isCloudAccount = await isCloud()
|
|
||||||
const errUserLimit =
|
|
||||||
isCloudAccount &&
|
|
||||||
license.plan.model === PlanModel.PER_USER &&
|
|
||||||
userLimitExceeded
|
|
||||||
|
|
||||||
store.update(state => {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
usageMetrics: { ...monthlyMetrics, ...staticMetrics },
|
|
||||||
quotaResetDaysRemaining,
|
|
||||||
quotaResetDate,
|
|
||||||
accountDowngraded,
|
|
||||||
accountPastDue: pastDueAtMilliseconds != null,
|
|
||||||
pastDueEndDate,
|
|
||||||
pastDueDaysRemaining,
|
|
||||||
// user limits
|
|
||||||
userCount,
|
|
||||||
userLimit,
|
|
||||||
userLimitReached,
|
|
||||||
errUserLimit,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
const monthlyMetrics = getMetrics(
|
||||||
|
["dayPasses", "queries", "automations"],
|
||||||
|
license.quotas.usage.monthly,
|
||||||
|
usage.monthly.current
|
||||||
|
)
|
||||||
|
const staticMetrics = getMetrics(
|
||||||
|
["apps", "rows"],
|
||||||
|
license.quotas.usage.static,
|
||||||
|
usage.usageQuota
|
||||||
|
)
|
||||||
|
|
||||||
|
const getDaysBetween = (dateStart, dateEnd) => {
|
||||||
|
return dateEnd > dateStart
|
||||||
|
? Math.round(
|
||||||
|
(dateEnd.getTime() - dateStart.getTime()) / oneDayInMilliseconds
|
||||||
|
)
|
||||||
|
: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const quotaResetDate = new Date(usage.quotaReset)
|
||||||
|
const quotaResetDaysRemaining = getDaysBetween(now, quotaResetDate)
|
||||||
|
|
||||||
|
const accountDowngraded =
|
||||||
|
license?.billing?.subscription?.downgradeAt &&
|
||||||
|
license?.billing?.subscription?.downgradeAt <= now.getTime() &&
|
||||||
|
license?.billing?.subscription?.status === StripeStatus.PAST_DUE &&
|
||||||
|
license?.plan.type === Constants.PlanType.FREE
|
||||||
|
|
||||||
|
const pastDueAtMilliseconds = license?.billing?.subscription?.pastDueAt
|
||||||
|
const downgradeAtMilliseconds =
|
||||||
|
license?.billing?.subscription?.downgradeAt
|
||||||
|
let pastDueDaysRemaining
|
||||||
|
let pastDueEndDate
|
||||||
|
|
||||||
|
if (pastDueAtMilliseconds && downgradeAtMilliseconds) {
|
||||||
|
pastDueEndDate = new Date(downgradeAtMilliseconds)
|
||||||
|
pastDueDaysRemaining = getDaysBetween(
|
||||||
|
new Date(pastDueAtMilliseconds),
|
||||||
|
pastDueEndDate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const userQuota = license.quotas.usage.static.users
|
||||||
|
const userLimit = userQuota?.value
|
||||||
|
const userCount = usage.usageQuota.users
|
||||||
|
const userLimitReached = usersLimitReached(userCount, userLimit)
|
||||||
|
const userLimitExceeded = usersLimitExceeded(userCount, userLimit)
|
||||||
|
const isCloudAccount = await isCloud()
|
||||||
|
const errUserLimit =
|
||||||
|
isCloudAccount &&
|
||||||
|
license.plan.model === PlanModel.PER_USER &&
|
||||||
|
userLimitExceeded
|
||||||
|
|
||||||
|
store.update(state => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
usageMetrics: { ...monthlyMetrics, ...staticMetrics },
|
||||||
|
quotaResetDaysRemaining,
|
||||||
|
quotaResetDate,
|
||||||
|
accountDowngraded,
|
||||||
|
accountPastDue: pastDueAtMilliseconds != null,
|
||||||
|
pastDueEndDate,
|
||||||
|
pastDueDaysRemaining,
|
||||||
|
// user limits
|
||||||
|
userCount,
|
||||||
|
userLimit,
|
||||||
|
userLimitReached,
|
||||||
|
errUserLimit,
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { derived } from "svelte/store"
|
import { derived } from "svelte/store"
|
||||||
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
|
|
||||||
import { admin } from "./admin"
|
import { admin } from "./admin"
|
||||||
import { auth } from "./auth"
|
import { auth } from "./auth"
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
|
@ -15,12 +14,10 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
|
||||||
href: "/builder/portal/users/users",
|
href: "/builder/portal/users/users",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
if (isEnabled(TENANT_FEATURE_FLAGS.USER_GROUPS)) {
|
userSubPages.push({
|
||||||
userSubPages.push({
|
title: "Groups",
|
||||||
title: "Groups",
|
href: "/builder/portal/users/groups",
|
||||||
href: "/builder/portal/users/groups",
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pages that all devs and admins can access
|
// Pages that all devs and admins can access
|
||||||
let menu = [
|
let menu = [
|
||||||
|
@ -83,50 +80,48 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add account page
|
// Add account page
|
||||||
if (isEnabled(TENANT_FEATURE_FLAGS.LICENSING)) {
|
let accountSubPages = [
|
||||||
let accountSubPages = [
|
{
|
||||||
{
|
title: "Usage",
|
||||||
title: "Usage",
|
href: "/builder/portal/account/usage",
|
||||||
href: "/builder/portal/account/usage",
|
},
|
||||||
},
|
]
|
||||||
]
|
if (isAdmin) {
|
||||||
if (isAdmin) {
|
accountSubPages.push({
|
||||||
accountSubPages.push({
|
title: "Audit Logs",
|
||||||
title: "Audit Logs",
|
href: "/builder/portal/account/auditLogs",
|
||||||
href: "/builder/portal/account/auditLogs",
|
})
|
||||||
})
|
|
||||||
|
|
||||||
if (!cloud) {
|
if (!cloud) {
|
||||||
accountSubPages.push({
|
|
||||||
title: "System Logs",
|
|
||||||
href: "/builder/portal/account/systemLogs",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cloud && user?.accountPortalAccess) {
|
|
||||||
accountSubPages.push({
|
accountSubPages.push({
|
||||||
title: "Upgrade",
|
title: "System Logs",
|
||||||
href: $admin?.accountPortalUrl + "/portal/upgrade",
|
href: "/builder/portal/account/systemLogs",
|
||||||
})
|
|
||||||
} else if (!cloud && isAdmin) {
|
|
||||||
accountSubPages.push({
|
|
||||||
title: "Upgrade",
|
|
||||||
href: "/builder/portal/account/upgrade",
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// add license check here
|
}
|
||||||
if (user?.accountPortalAccess && user.account.stripeCustomerId) {
|
if (cloud && user?.accountPortalAccess) {
|
||||||
accountSubPages.push({
|
accountSubPages.push({
|
||||||
title: "Billing",
|
title: "Upgrade",
|
||||||
href: $admin?.accountPortalUrl + "/portal/billing",
|
href: $admin?.accountPortalUrl + "/portal/upgrade",
|
||||||
})
|
})
|
||||||
}
|
} else if (!cloud && isAdmin) {
|
||||||
menu.push({
|
accountSubPages.push({
|
||||||
title: "Account",
|
title: "Upgrade",
|
||||||
href: "/builder/portal/account",
|
href: "/builder/portal/account/upgrade",
|
||||||
subPages: accountSubPages,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// add license check here
|
||||||
|
if (user?.accountPortalAccess && user.account.stripeCustomerId) {
|
||||||
|
accountSubPages.push({
|
||||||
|
title: "Billing",
|
||||||
|
href: $admin?.accountPortalUrl + "/portal/billing",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
menu.push({
|
||||||
|
title: "Account",
|
||||||
|
href: "/builder/portal/account",
|
||||||
|
subPages: accountSubPages,
|
||||||
|
})
|
||||||
|
|
||||||
return menu
|
return menu
|
||||||
})
|
})
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 94747fd5bb67c218244bb60b9540f3a6f1c3f6f1
|
Subproject commit bc43c5230520d83f23afb14489aa9a2a92e7cd27
|
|
@ -12,7 +12,6 @@ ENV COUCH_DB_URL=https://couchdb.budi.live:5984
|
||||||
ENV BUDIBASE_ENVIRONMENT=PRODUCTION
|
ENV BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||||
ENV SERVICE=app-service
|
ENV SERVICE=app-service
|
||||||
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR
|
|
||||||
ENV ACCOUNT_PORTAL_URL=https://account.budibase.app
|
ENV ACCOUNT_PORTAL_URL=https://account.budibase.app
|
||||||
ENV TOP_LEVEL_PATH=/
|
ENV TOP_LEVEL_PATH=/
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ async function init() {
|
||||||
BB_ADMIN_USER_EMAIL: "",
|
BB_ADMIN_USER_EMAIL: "",
|
||||||
BB_ADMIN_USER_PASSWORD: "",
|
BB_ADMIN_USER_PASSWORD: "",
|
||||||
PLUGINS_DIR: "",
|
PLUGINS_DIR: "",
|
||||||
TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
|
|
||||||
HTTP_MIGRATIONS: "0",
|
HTTP_MIGRATIONS: "0",
|
||||||
HTTP_LOGGING: "0",
|
HTTP_LOGGING: "0",
|
||||||
VERSION: "0.0.0+local",
|
VERSION: "0.0.0+local",
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export enum FeatureFlag {
|
export enum FeatureFlag {
|
||||||
LICENSING = "LICENSING",
|
|
||||||
PER_CREATOR_PER_USER_PRICE = "PER_CREATOR_PER_USER_PRICE",
|
PER_CREATOR_PER_USER_PRICE = "PER_CREATOR_PER_USER_PRICE",
|
||||||
PER_CREATOR_PER_USER_PRICE_ALERT = "PER_CREATOR_PER_USER_PRICE_ALERT",
|
PER_CREATOR_PER_USER_PRICE_ALERT = "PER_CREATOR_PER_USER_PRICE_ALERT",
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ ENV NODE_OPTIONS="--no-node-snapshot"
|
||||||
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
ENV CLUSTER_MODE=${CLUSTER_MODE}
|
||||||
ENV SERVICE=worker-service
|
ENV SERVICE=worker-service
|
||||||
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
ENV POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||||
ENV TENANT_FEATURE_FLAGS=*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR
|
|
||||||
ENV ACCOUNT_PORTAL_URL=https://account.budibase.app
|
ENV ACCOUNT_PORTAL_URL=https://account.budibase.app
|
||||||
|
|
||||||
ARG BUDIBASE_VERSION
|
ARG BUDIBASE_VERSION
|
||||||
|
|
|
@ -26,7 +26,6 @@ async function init() {
|
||||||
APPS_URL: "http://localhost:4001",
|
APPS_URL: "http://localhost:4001",
|
||||||
SERVICE: "worker-service",
|
SERVICE: "worker-service",
|
||||||
DEPLOYMENT_ENVIRONMENT: "development",
|
DEPLOYMENT_ENVIRONMENT: "development",
|
||||||
TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
|
|
||||||
ENABLE_EMAIL_TEST_MODE: "1",
|
ENABLE_EMAIL_TEST_MODE: "1",
|
||||||
HTTP_LOGGING: "0",
|
HTTP_LOGGING: "0",
|
||||||
VERSION: "0.0.0+local",
|
VERSION: "0.0.0+local",
|
||||||
|
|
Loading…
Reference in New Issue