Merge pull request #14459 from Budibase/BUDI-8562/BUDI-8560/feature-flagging
Feature flagging pick relationship fields
This commit is contained in:
commit
4830b0e4d6
|
@ -1,7 +1,7 @@
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
import * as context from "../context"
|
import * as context from "../context"
|
||||||
import { PostHog, PostHogOptions } from "posthog-node"
|
import { PostHog, PostHogOptions } from "posthog-node"
|
||||||
import { IdentityType, UserCtx } from "@budibase/types"
|
import { FeatureFlag, IdentityType, UserCtx } from "@budibase/types"
|
||||||
import tracer from "dd-trace"
|
import tracer from "dd-trace"
|
||||||
|
|
||||||
let posthog: PostHog | undefined
|
let posthog: PostHog | undefined
|
||||||
|
@ -267,4 +267,5 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
|
||||||
// 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({
|
||||||
DEFAULT_VALUES: Flag.boolean(false),
|
DEFAULT_VALUES: Flag.boolean(false),
|
||||||
|
[FeatureFlag.ENRICHED_RELATIONSHIPS]: Flag.boolean(false),
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
import GridEditColumnModal from "components/backend/DataTable/modals/grid/GridEditColumnModal.svelte"
|
||||||
import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte"
|
import GridUsersTableButton from "components/backend/DataTable/modals/grid/GridUsersTableButton.svelte"
|
||||||
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
import { DB_TYPE_EXTERNAL } from "constants/backend"
|
||||||
|
import { isEnabled } from "helpers/featureFlags"
|
||||||
|
import { FeatureFlag } from "@budibase/types"
|
||||||
|
|
||||||
const userSchemaOverrides = {
|
const userSchemaOverrides = {
|
||||||
firstName: { displayName: "First name", disabled: true },
|
firstName: { displayName: "First name", disabled: true },
|
||||||
|
@ -66,6 +68,7 @@
|
||||||
canDeleteRows={!isUsersTable}
|
canDeleteRows={!isUsersTable}
|
||||||
canEditRows={!isUsersTable || !$appStore.features.disableUserMetadata}
|
canEditRows={!isUsersTable || !$appStore.features.disableUserMetadata}
|
||||||
canEditColumns={!isUsersTable || !$appStore.features.disableUserMetadata}
|
canEditColumns={!isUsersTable || !$appStore.features.disableUserMetadata}
|
||||||
|
canSetRelationshipSchemas={isEnabled(FeatureFlag.ENRICHED_RELATIONSHIPS)}
|
||||||
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
schemaOverrides={isUsersTable ? userSchemaOverrides : null}
|
||||||
showAvatars={false}
|
showAvatars={false}
|
||||||
on:updatedatasource={handleGridTableUpdate}
|
on:updatedatasource={handleGridTableUpdate}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte"
|
import GridCreateEditRowModal from "components/backend/DataTable/modals/grid/GridCreateEditRowModal.svelte"
|
||||||
import GridFilterButton from "components/backend/DataTable/buttons/grid/GridFilterButton.svelte"
|
import GridFilterButton from "components/backend/DataTable/buttons/grid/GridFilterButton.svelte"
|
||||||
import GridManageAccessButton from "components/backend/DataTable/buttons/grid/GridManageAccessButton.svelte"
|
import GridManageAccessButton from "components/backend/DataTable/buttons/grid/GridManageAccessButton.svelte"
|
||||||
|
import { isEnabled } from "helpers/featureFlags"
|
||||||
|
import { FeatureFlag } from "@budibase/types"
|
||||||
|
|
||||||
$: id = $viewsV2.selected?.id
|
$: id = $viewsV2.selected?.id
|
||||||
$: datasource = {
|
$: datasource = {
|
||||||
|
@ -29,6 +31,7 @@
|
||||||
on:updatedatasource={handleGridViewUpdate}
|
on:updatedatasource={handleGridViewUpdate}
|
||||||
isCloud={$admin.cloud}
|
isCloud={$admin.cloud}
|
||||||
allowViewReadonlyColumns={$licensing.isViewReadonlyColumnsEnabled}
|
allowViewReadonlyColumns={$licensing.isViewReadonlyColumnsEnabled}
|
||||||
|
canSetRelationshipSchemas={isEnabled(FeatureFlag.ENRICHED_RELATIONSHIPS)}
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="filter">
|
<svelte:fragment slot="filter">
|
||||||
<GridFilterButton />
|
<GridFilterButton />
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
export let columns
|
export let columns
|
||||||
export let fromRelationshipField
|
export let fromRelationshipField
|
||||||
|
|
||||||
const { datasource, dispatch, cache } = getContext("grid")
|
const { datasource, dispatch, cache, config } = getContext("grid")
|
||||||
|
|
||||||
|
$: canSetRelationshipSchemas = $config.canSetRelationshipSchemas
|
||||||
|
|
||||||
let relationshipPanelAnchor
|
let relationshipPanelAnchor
|
||||||
let relationshipFieldName
|
let relationshipFieldName
|
||||||
|
@ -30,8 +32,6 @@
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
|
||||||
$: allowRelationshipSchemas = true // TODO
|
|
||||||
|
|
||||||
$: displayColumns = columns.map(c => {
|
$: displayColumns = columns.map(c => {
|
||||||
const isRequired =
|
const isRequired =
|
||||||
c.primaryDisplay || helpers.schema.isRequired(c.schema.constraints)
|
c.primaryDisplay || helpers.schema.isRequired(c.schema.constraints)
|
||||||
|
@ -196,7 +196,7 @@
|
||||||
value={columnToPermissionOptions(column)}
|
value={columnToPermissionOptions(column)}
|
||||||
options={column.options}
|
options={column.options}
|
||||||
/>
|
/>
|
||||||
{#if allowRelationshipSchemas && column.schema.type === FieldType.LINK && columnToPermissionOptions(column) !== FieldPermissions.HIDDEN}
|
{#if canSetRelationshipSchemas && column.schema.type === FieldType.LINK && columnToPermissionOptions(column) !== FieldPermissions.HIDDEN}
|
||||||
<div class="relationship-columns">
|
<div class="relationship-columns">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
on:click={e => {
|
on:click={e => {
|
||||||
|
@ -214,7 +214,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if allowRelationshipSchemas}
|
{#if canSetRelationshipSchemas}
|
||||||
<Popover
|
<Popover
|
||||||
on:close={() => (relationshipFieldName = null)}
|
on:close={() => (relationshipFieldName = null)}
|
||||||
open={relationshipFieldName}
|
open={relationshipFieldName}
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
export let canDeleteRows = true
|
export let canDeleteRows = true
|
||||||
export let canEditColumns = true
|
export let canEditColumns = true
|
||||||
export let canSaveSchema = true
|
export let canSaveSchema = true
|
||||||
|
export let canSetRelationshipSchemas = false
|
||||||
export let stripeRows = false
|
export let stripeRows = false
|
||||||
export let quiet = false
|
export let quiet = false
|
||||||
export let collaboration = true
|
export let collaboration = true
|
||||||
|
@ -99,6 +100,7 @@
|
||||||
canDeleteRows,
|
canDeleteRows,
|
||||||
canEditColumns,
|
canEditColumns,
|
||||||
canSaveSchema,
|
canSaveSchema,
|
||||||
|
canSetRelationshipSchemas,
|
||||||
stripeRows,
|
stripeRows,
|
||||||
quiet,
|
quiet,
|
||||||
collaboration,
|
collaboration,
|
||||||
|
|
|
@ -40,6 +40,7 @@ import {
|
||||||
TableSchema,
|
TableSchema,
|
||||||
JsonFieldSubType,
|
JsonFieldSubType,
|
||||||
RowExportFormat,
|
RowExportFormat,
|
||||||
|
FeatureFlag,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { generator, mocks } from "@budibase/backend-core/tests"
|
import { generator, mocks } from "@budibase/backend-core/tests"
|
||||||
import _, { merge } from "lodash"
|
import _, { merge } from "lodash"
|
||||||
|
@ -95,7 +96,12 @@ describe.each([
|
||||||
let envCleanup: (() => void) | undefined
|
let envCleanup: (() => void) | undefined
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await withCoreEnv({ SQS_SEARCH_ENABLE: "true" }, () => config.init())
|
await withCoreEnv(
|
||||||
|
{
|
||||||
|
SQS_SEARCH_ENABLE: "true",
|
||||||
|
},
|
||||||
|
() => config.init()
|
||||||
|
)
|
||||||
if (isSqs) {
|
if (isSqs) {
|
||||||
envCleanup = setCoreEnv({
|
envCleanup = setCoreEnv({
|
||||||
SQS_SEARCH_ENABLE: "true",
|
SQS_SEARCH_ENABLE: "true",
|
||||||
|
@ -2436,7 +2442,13 @@ describe.each([
|
||||||
|
|
||||||
let auxData: Row[] = []
|
let auxData: Row[] = []
|
||||||
|
|
||||||
|
let flagCleanup: (() => void) | undefined
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
flagCleanup = setCoreEnv({
|
||||||
|
TENANT_FEATURE_FLAGS: `*:${FeatureFlag.ENRICHED_RELATIONSHIPS}`,
|
||||||
|
})
|
||||||
|
|
||||||
const aux2Table = await config.api.table.save(saveTableRequest())
|
const aux2Table = await config.api.table.save(saveTableRequest())
|
||||||
const aux2Data = await config.api.row.save(aux2Table._id!, {})
|
const aux2Data = await config.api.row.save(aux2Table._id!, {})
|
||||||
|
|
||||||
|
@ -2558,7 +2570,11 @@ describe.each([
|
||||||
tableId = table._id!
|
tableId = table._id!
|
||||||
})
|
})
|
||||||
|
|
||||||
it.each([
|
afterAll(() => {
|
||||||
|
flagCleanup?.()
|
||||||
|
})
|
||||||
|
|
||||||
|
const testScenarios: [string, (row: Row) => Promise<Row> | Row][] = [
|
||||||
["get row", (row: Row) => config.api.row.get(tableId, row._id!)],
|
["get row", (row: Row) => config.api.row.get(tableId, row._id!)],
|
||||||
[
|
[
|
||||||
"fetch",
|
"fetch",
|
||||||
|
@ -2591,7 +2607,9 @@ describe.each([
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
["from original saved row", (row: Row) => row],
|
["from original saved row", (row: Row) => row],
|
||||||
])(
|
]
|
||||||
|
|
||||||
|
it.each(testScenarios)(
|
||||||
"can retrieve rows with populated relationships (via %s)",
|
"can retrieve rows with populated relationships (via %s)",
|
||||||
async (__, retrieveDelegate) => {
|
async (__, retrieveDelegate) => {
|
||||||
const otherRows = _.sampleSize(auxData, 5)
|
const otherRows = _.sampleSize(auxData, 5)
|
||||||
|
@ -2606,6 +2624,7 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
const retrieved = await retrieveDelegate(row)
|
const retrieved = await retrieveDelegate(row)
|
||||||
|
|
||||||
expect(retrieved).toEqual(
|
expect(retrieved).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
title: row.title,
|
title: row.title,
|
||||||
|
@ -2648,6 +2667,67 @@ describe.each([
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.each(testScenarios)(
|
||||||
|
"does not enrich relationships when not enabled (via %s)",
|
||||||
|
async (__, retrieveDelegate) => {
|
||||||
|
await withCoreEnv(
|
||||||
|
{
|
||||||
|
TENANT_FEATURE_FLAGS: ``,
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
const otherRows = _.sampleSize(auxData, 5)
|
||||||
|
|
||||||
|
const row = await config.api.row.save(tableId, {
|
||||||
|
title: generator.word(),
|
||||||
|
relWithNoSchema: [otherRows[0]],
|
||||||
|
relWithEmptySchema: [otherRows[1]],
|
||||||
|
relWithFullSchema: [otherRows[2]],
|
||||||
|
relWithHalfSchema: [otherRows[3]],
|
||||||
|
relWithIllegalSchema: [otherRows[4]],
|
||||||
|
})
|
||||||
|
|
||||||
|
const retrieved = await retrieveDelegate(row)
|
||||||
|
|
||||||
|
expect(retrieved).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
title: row.title,
|
||||||
|
relWithNoSchema: [
|
||||||
|
{
|
||||||
|
_id: otherRows[0]._id,
|
||||||
|
primaryDisplay: otherRows[0].name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
relWithEmptySchema: [
|
||||||
|
{
|
||||||
|
_id: otherRows[1]._id,
|
||||||
|
primaryDisplay: otherRows[1].name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
relWithFullSchema: [
|
||||||
|
{
|
||||||
|
_id: otherRows[2]._id,
|
||||||
|
primaryDisplay: otherRows[2].name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
relWithHalfSchema: [
|
||||||
|
{
|
||||||
|
_id: otherRows[3]._id,
|
||||||
|
primaryDisplay: otherRows[3].name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
relWithIllegalSchema: [
|
||||||
|
{
|
||||||
|
_id: otherRows[4]._id,
|
||||||
|
primaryDisplay: otherRows[4].name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("Formula fields", () => {
|
describe("Formula fields", () => {
|
||||||
|
|
|
@ -11,9 +11,10 @@ import { USER_METDATA_PREFIX } from "../utils"
|
||||||
import partition from "lodash/partition"
|
import partition from "lodash/partition"
|
||||||
import { getGlobalUsersFromMetadata } from "../../utilities/global"
|
import { getGlobalUsersFromMetadata } from "../../utilities/global"
|
||||||
import { processFormulas } from "../../utilities/rowProcessor"
|
import { processFormulas } from "../../utilities/rowProcessor"
|
||||||
import { context } from "@budibase/backend-core"
|
import { context, features } from "@budibase/backend-core"
|
||||||
import {
|
import {
|
||||||
ContextUser,
|
ContextUser,
|
||||||
|
FeatureFlag,
|
||||||
FieldType,
|
FieldType,
|
||||||
LinkDocumentValue,
|
LinkDocumentValue,
|
||||||
Row,
|
Row,
|
||||||
|
@ -272,7 +273,9 @@ export async function squashLinksToPrimaryDisplay(
|
||||||
const obj: any = { _id: link._id }
|
const obj: any = { _id: link._id }
|
||||||
obj.primaryDisplay = getPrimaryDisplayValue(link, linkedTable)
|
obj.primaryDisplay = getPrimaryDisplayValue(link, linkedTable)
|
||||||
|
|
||||||
const allowRelationshipSchemas = true // TODO
|
const allowRelationshipSchemas = await features.flags.isEnabled(
|
||||||
|
FeatureFlag.ENRICHED_RELATIONSHIPS
|
||||||
|
)
|
||||||
if (schema.schema && allowRelationshipSchemas) {
|
if (schema.schema && allowRelationshipSchemas) {
|
||||||
for (const relField of Object.entries(schema.schema)
|
for (const relField of Object.entries(schema.schema)
|
||||||
.filter(([_, field]) => field.visible !== false)
|
.filter(([_, field]) => field.visible !== false)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export enum FeatureFlag {
|
export enum FeatureFlag {
|
||||||
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",
|
||||||
|
ENRICHED_RELATIONSHIPS = "ENRICHED_RELATIONSHIPS",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TenantFeatureFlags {
|
export interface TenantFeatureFlags {
|
||||||
|
|
Loading…
Reference in New Issue