conditionalAvailabilityExpression in SDK for Widget Visibility (and ideally Tabs too)
How should an app declare record-dependent widget visibility on a page layout?
Context
Self-hosted v2.41.0, twenty-sdk 2.41.0. We extend the standard task object with a
discriminator field (taskType) and a group of type-specific fields, and we want the
page-layout widget that holds those fields to appear only on records of that type.
Two things exist in the product today:
PageLayoutWidgetEntityhas both aconditionalDisplay(JsonLogic) column and aconditionalAvailabilityExpression(string) column.- The front end evaluates them in
evaluateWidgetVisibility.ts:conditionalAvailabilityExpressionwins when it is defined, otherwisejsonLogic.apply(conditionalDisplay, context)must betrue.buildWidgetVisibilityContext.tsexposes the open record asselectedRecords[0].
The SDK's widget manifest exposes only one of the two:
// [email protected] · dist/define/index.d.ts
type PageLayoutWidgetManifest = SyncableEntityOptions & {
title: string;
type: `${WidgetType}`;
objectUniversalIdentifier?: string;
conditionalDisplay?: PageLayoutWidgetConditionalDisplay;
position?: PageLayoutWidgetPosition;
heightBehavior?: `${PageLayoutWidgetVerticalListHeightBehavior}`;
configuration: PageLayoutWidgetUniversalConfiguration;
};
conditionalAvailabilityExpression is not on the type, and a value passed anyway is
dropped silently by twenty apply — no error, no warning, the widget is created without
it. CommandMenuItemManifest does carry the property, which is what made us expect it
here too.
We currently hand-write the JsonLogic:
conditionalDisplay: { '==': [{ var: 'selectedRecords.0.taskType' }, 'INFO'] }
That works, but selectedRecords.0.<field> is an undocumented shape we read out of the
front-end source, and nothing validates it at apply time — a typo produces a widget that
is simply never visible.
Questions
- Is
conditionalAvailabilityExpressionintended to be app-authorable at all, or isconditionalDisplaythe supported path for page-layout widgets and the second column internal? - If
conditionalDisplayis the supported path, isselectedRecords[0]a stable part of the public contract for record-page widgets? - Is record-dependent visibility meant to reach page-layout tabs as well?
PageLayoutTabManifesthas no conditional property of any kind, so today the only way to hide a tab is to make every widget in it invisible and rely ongetTabsWithVisibleWidgets.tsdropping it.
Desired outcome
An app can declare, in its manifest, that a page-layout widget (and ideally a tab) is
visible only for records matching a condition on the record's own fields — using a
documented, typed API, where a wrong field reference fails at twenty apply rather than
silently producing a widget nobody ever sees.
Reproduction
- Add a
SELECTfield to a standard object from an app. definePageLayoutWidget({ ..., conditionalAvailabilityExpression: '...' }).npx twenty apply— succeeds; the widget is created with the columnnull.
Source: twentyhq/twenty