Merge branch 'master' of github.com:Budibase/budibase into feature/sqs-table-cleanup
This commit is contained in:
commit
2e8b655417
|
@ -431,10 +431,28 @@ export class QueryBuilder<T> {
|
|||
})
|
||||
}
|
||||
if (this.#query.empty) {
|
||||
build(this.#query.empty, (key: string) => `(*:* -${key}:["" TO *])`)
|
||||
build(this.#query.empty, (key: string) => {
|
||||
// Because the structure of an empty filter looks like this:
|
||||
// { empty: { someKey: null } }
|
||||
//
|
||||
// The check inside of `build` does not set `allFiltersEmpty`, which results
|
||||
// in weird behaviour when the empty filter is the only filter. We get around
|
||||
// this by setting `allFiltersEmpty` to false here.
|
||||
allFiltersEmpty = false
|
||||
return `(*:* -${key}:["" TO *])`
|
||||
})
|
||||
}
|
||||
if (this.#query.notEmpty) {
|
||||
build(this.#query.notEmpty, (key: string) => `${key}:["" TO *]`)
|
||||
build(this.#query.notEmpty, (key: string) => {
|
||||
// Because the structure of a notEmpty filter looks like this:
|
||||
// { notEmpty: { someKey: null } }
|
||||
//
|
||||
// The check inside of `build` does not set `allFiltersEmpty`, which results
|
||||
// in weird behaviour when the empty filter is the only filter. We get around
|
||||
// this by setting `allFiltersEmpty` to false here.
|
||||
allFiltersEmpty = false
|
||||
return `${key}:["" TO *]`
|
||||
})
|
||||
}
|
||||
if (this.#query.oneOf) {
|
||||
build(this.#query.oneOf, oneOf)
|
||||
|
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 804 KiB |
|
@ -0,0 +1,64 @@
|
|||
<script>
|
||||
import { Modal, ModalContent } from "@budibase/bbui"
|
||||
import FreeTrial from "../../../../assets/FreeTrial.svelte"
|
||||
import { get } from "svelte/store"
|
||||
import { auth, licensing } from "stores/portal"
|
||||
import { API } from "api"
|
||||
import { PlanType } from "@budibase/types"
|
||||
|
||||
let freeTrialModal
|
||||
|
||||
$: planType = $licensing?.license?.plan?.type
|
||||
$: showFreeTrialModal(planType, freeTrialModal)
|
||||
|
||||
const showFreeTrialModal = (planType, freeTrialModal) => {
|
||||
if (
|
||||
planType === PlanType.ENTERPRISE_BASIC_TRIAL &&
|
||||
!$auth.user?.freeTrialConfirmedAt
|
||||
) {
|
||||
freeTrialModal?.show()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal bind:this={freeTrialModal} disableCancel={true}>
|
||||
<ModalContent
|
||||
confirmText="Get started"
|
||||
size="M"
|
||||
showCancelButton={false}
|
||||
showCloseIcon={false}
|
||||
onConfirm={async () => {
|
||||
if (get(auth).user) {
|
||||
try {
|
||||
await API.updateSelf({
|
||||
freeTrialConfirmedAt: new Date().toISOString(),
|
||||
})
|
||||
// Update the cached user
|
||||
await auth.getSelf()
|
||||
} finally {
|
||||
freeTrialModal.hide()
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<h1>Experience all of Budibase with a free 14-day trial</h1>
|
||||
<div class="free-trial-text">
|
||||
We've upgraded you to a free 14-day trial that allows you to try all our
|
||||
features before deciding which plan is right for you.
|
||||
<p>
|
||||
At the end of your trial, we'll automatically downgrade you to the Free
|
||||
plan unless you choose to upgrade.
|
||||
</p>
|
||||
</div>
|
||||
<FreeTrial />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
}
|
||||
.free-trial-text {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
|
@ -20,6 +20,9 @@ export function getFormattedPlanName(userPlanType) {
|
|||
case PlanType.ENTERPRISE:
|
||||
planName = "Enterprise"
|
||||
break
|
||||
case PlanType.ENTERPRISE_BASIC_TRIAL:
|
||||
planName = "Trial"
|
||||
break
|
||||
default:
|
||||
planName = "Free" // Default to "Free" if the type is not explicitly handled
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
import { UserAvatars } from "@budibase/frontend-core"
|
||||
import { TOUR_KEYS } from "components/portal/onboarding/tours.js"
|
||||
import PreviewOverlay from "./_components/PreviewOverlay.svelte"
|
||||
import EnterpriseBasicTrialModal from "components/portal/onboarding/EnterpriseBasicTrialModal.svelte"
|
||||
|
||||
export let application
|
||||
|
||||
|
@ -192,6 +193,8 @@
|
|||
<CommandPalette />
|
||||
</Modal>
|
||||
|
||||
<EnterpriseBasicTrialModal />
|
||||
|
||||
<style>
|
||||
.back-to-apps {
|
||||
display: contents;
|
||||
|
|
|
@ -103,6 +103,8 @@ export const createLicensingStore = () => {
|
|||
const isEnterprisePlan = planType === Constants.PlanType.ENTERPRISE
|
||||
const isFreePlan = planType === Constants.PlanType.FREE
|
||||
const isBusinessPlan = planType === Constants.PlanType.BUSINESS
|
||||
const isEnterpriseTrial =
|
||||
planType === Constants.PlanType.ENTERPRISE_BASIC_TRIAL
|
||||
const groupsEnabled = license.features.includes(
|
||||
Constants.Features.USER_GROUPS
|
||||
)
|
||||
|
@ -143,6 +145,7 @@ export const createLicensingStore = () => {
|
|||
isEnterprisePlan,
|
||||
isFreePlan,
|
||||
isBusinessPlan,
|
||||
isEnterpriseTrial,
|
||||
groupsEnabled,
|
||||
backupsEnabled,
|
||||
brandingEnabled,
|
||||
|
|
|
@ -4220,8 +4220,8 @@
|
|||
]
|
||||
},
|
||||
"attachmentfield": {
|
||||
"name": "Attachment list",
|
||||
"icon": "Attach",
|
||||
"name": "Attachment List",
|
||||
"icon": "DocumentFragmentGroup",
|
||||
"styles": ["size"],
|
||||
"requiredAncestors": ["form"],
|
||||
"editable": true,
|
||||
|
@ -4318,7 +4318,7 @@
|
|||
},
|
||||
"attachmentsinglefield": {
|
||||
"name": "Single Attachment",
|
||||
"icon": "Attach",
|
||||
"icon": "DocumentFragment",
|
||||
"styles": ["size"],
|
||||
"requiredAncestors": ["form"],
|
||||
"editable": true,
|
||||
|
|
|
@ -57,6 +57,7 @@ export const PlanType = {
|
|||
PRO: "pro",
|
||||
BUSINESS: "business",
|
||||
ENTERPRISE: "enterprise",
|
||||
ENTERPRISE_BASIC_TRIAL: "enterprise_basic_trial",
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,8 +125,8 @@ export const TypeIconMap = {
|
|||
[FieldType.ARRAY]: "Duplicate",
|
||||
[FieldType.NUMBER]: "123",
|
||||
[FieldType.BOOLEAN]: "Boolean",
|
||||
[FieldType.ATTACHMENTS]: "Attach",
|
||||
[FieldType.ATTACHMENT_SINGLE]: "Attach",
|
||||
[FieldType.ATTACHMENTS]: "DocumentFragmentGroup",
|
||||
[FieldType.ATTACHMENT_SINGLE]: "DocumentFragment",
|
||||
[FieldType.LINK]: "DataCorrelated",
|
||||
[FieldType.FORMULA]: "Calculator",
|
||||
[FieldType.JSON]: "Brackets",
|
||||
|
|
|
@ -252,6 +252,31 @@ describe.each([
|
|||
}).toFindNothing())
|
||||
})
|
||||
|
||||
describe("empty", () => {
|
||||
it("finds no empty rows", () =>
|
||||
expectQuery({ empty: { name: null } }).toFindNothing())
|
||||
|
||||
it("should not be affected by when filter empty behaviour", () =>
|
||||
expectQuery({
|
||||
empty: { name: null },
|
||||
onEmptyFilter: EmptyFilterOption.RETURN_ALL,
|
||||
}).toFindNothing())
|
||||
})
|
||||
|
||||
describe("notEmpty", () => {
|
||||
it("finds all non-empty rows", () =>
|
||||
expectQuery({ notEmpty: { name: null } }).toContainExactly([
|
||||
{ name: "foo" },
|
||||
{ name: "bar" },
|
||||
]))
|
||||
|
||||
it("should not be affected by when filter empty behaviour", () =>
|
||||
expectQuery({
|
||||
notEmpty: { name: null },
|
||||
onEmptyFilter: EmptyFilterOption.RETURN_NONE,
|
||||
}).toContainExactly([{ name: "foo" }, { name: "bar" }]))
|
||||
})
|
||||
|
||||
describe("sort", () => {
|
||||
it("sorts ascending", () =>
|
||||
expectSearch({
|
||||
|
|
|
@ -18,6 +18,7 @@ export interface UpdateSelfRequest {
|
|||
password?: string
|
||||
forceResetPassword?: boolean
|
||||
onboardedAt?: string
|
||||
freeTrialConfirmedAt?: string
|
||||
appFavourites?: string[]
|
||||
tours?: Record<string, Date>
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ export interface User extends Document {
|
|||
dayPassRecordedAt?: string
|
||||
userGroups?: string[]
|
||||
onboardedAt?: string
|
||||
freeTrialConfirmedAt?: string
|
||||
tours?: Record<string, Date>
|
||||
scimInfo?: { isSync: true } & Record<string, any>
|
||||
appFavourites?: string[]
|
||||
|
|
|
@ -55,6 +55,7 @@ describe("/api/global/self", () => {
|
|||
const res = await config.api.self
|
||||
.updateSelf(user, {
|
||||
onboardedAt: "2023-03-07T14:10:54.869Z",
|
||||
freeTrialConfirmedAt: "2024-03-17T14:10:54.869Z",
|
||||
})
|
||||
.expect(200)
|
||||
|
||||
|
@ -63,6 +64,7 @@ describe("/api/global/self", () => {
|
|||
user._rev = dbUser._rev
|
||||
user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
|
||||
expect(dbUser.onboardedAt).toBe("2023-03-07T14:10:54.869Z")
|
||||
expect(dbUser.freeTrialConfirmedAt).toBe("2024-03-17T14:10:54.869Z")
|
||||
expect(res.body._id).toBe(user._id)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -26,6 +26,7 @@ export const buildSelfSaveValidation = () => {
|
|||
firstName: OPTIONAL_STRING,
|
||||
lastName: OPTIONAL_STRING,
|
||||
onboardedAt: Joi.string().optional(),
|
||||
freeTrialConfirmedAt: Joi.string().optional(),
|
||||
appFavourites: Joi.array().optional(),
|
||||
tours: Joi.object().optional(),
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ cd src/main/resources/models
|
|||
echo "deploy processes..."
|
||||
zbctl deploy resource offboarding.bpmn --insecure
|
||||
zbctl deploy resource onboarding.bpmn --insecure
|
||||
zbctl deploy resource free_trial.bpmn --insecure
|
||||
|
||||
cd ../../../../../budibase/packages/account-portal/packages/server
|
||||
|
||||
|
|
Loading…
Reference in New Issue