Summary
The conditional-visibility rule builder's group picker has no groups to pick, so a group rule cannot be created, edited or previewed through the UI at all. The rule TYPE is offered, the row renders, and the combobox is empty.
src/views/Views.vue renders
<VisibilityRulesModal
:open="isVisibilityModalOpen"
:placement-id="visibilityPlacementId"
@close="closeVisibilityRules"
… />
and never passes :available-groups. The prop keeps its declared default: () => [] in VisibilityRulesModal.vue, which forwards it to ConditionalVisibilityEditor, which feeds it to two NcSelectTags: the per-row group operand (data-test="rule-groups") and the preview-as-audience picker (data-test="preview-groups").
Measured in a browser (admin, launchpad development @ 66957c17)
Opening Visibility rules → Add rule → the Group operand combobox:
GROUP OPTIONS: []
GROUP NO-OPTIONS: [ 'No results' ]
It is not taggable either — typing a group name and pressing Enter selects nothing:
AFTER TYPING "marketing" — options: [] no-options: [ 'No results' ]
SELECTED AFTER ENTER: []
And the row's Save stays disabled, correctly, because isValid for a group rule requires ruleConfig.groups.length > 0.
The group rule itself is fine end to end when seeded through the API — POST /api/widgets/{id}/rules {"ruleType":"group","ruleConfig":{"groups":["marketing"]},"isInclude":true} returns 201, the editor loads and renders it, and the preview endpoint evaluates it. Only the option list is missing.
Why this is not a one-line fix
The obvious source is GET /api/admin/groups (adminSettings#listGroups), but it is declared #[AuthorizedAdminSetting(LaunchPadAdmin::class)] — admin only. The visibility editor is reached by any dashboard owner, including non-admins (Views.vue gates it on canEdit, which is isAdmin || dashboardSource === 'user').
So wiring the existing endpoint in would 403 for exactly the users the editor is built for, and adding a non-admin-readable group list is an information-disclosure decision — it hands every dashboard owner the instance's full group roster. That is a product/authorization call, not a mechanical fix, which is why this is filed rather than patched.
Options, roughly:
- A non-admin endpoint returning only the caller's own groups. Safe; but an author cannot then scope a widget to a group they are not in.
- A non-admin endpoint returning all group ids, accepting the disclosure.
- Admin-only group rules: populate for admins, and tell non-admins why the picker is empty instead of showing "No results".
Whichever is chosen, the empty-with-no-explanation state is worth fixing on its own — "No results" reads as "this instance has no groups".
Impact on gate-19
Five conditional-visibility-editor scenarios cannot be covered until this is wired:
All five are left uncovered and NOT @e2e excluded. An exclusion states "a browser cannot observe this scenario", which is false — a browser observes it very clearly, and what it observes is that the feature is not wired. Per .github#345 the gate reads an exclusion as POSITIVE coverage, so excluding these would buy five findings with a false statement.
Recorded in the header of tests/e2e/conditional-visibility-editor.spec.ts. Found while writing gate-19 round-3 coverage.
Summary
The conditional-visibility rule builder's group picker has no groups to pick, so a group rule cannot be created, edited or previewed through the UI at all. The rule TYPE is offered, the row renders, and the combobox is empty.
src/views/Views.vuerendersand never passes
:available-groups. The prop keeps its declareddefault: () => []inVisibilityRulesModal.vue, which forwards it toConditionalVisibilityEditor, which feeds it to twoNcSelectTags: the per-row group operand (data-test="rule-groups") and the preview-as-audience picker (data-test="preview-groups").Measured in a browser (admin, launchpad
development@66957c17)Opening Visibility rules → Add rule → the Group operand combobox:
It is not taggable either — typing a group name and pressing Enter selects nothing:
And the row's Save stays disabled, correctly, because
isValidfor a group rule requiresruleConfig.groups.length > 0.The group rule itself is fine end to end when seeded through the API —
POST /api/widgets/{id}/rules {"ruleType":"group","ruleConfig":{"groups":["marketing"]},"isInclude":true}returns 201, the editor loads and renders it, and the preview endpoint evaluates it. Only the option list is missing.Why this is not a one-line fix
The obvious source is
GET /api/admin/groups(adminSettings#listGroups), but it is declared#[AuthorizedAdminSetting(LaunchPadAdmin::class)]— admin only. The visibility editor is reached by any dashboard owner, including non-admins (Views.vuegates it oncanEdit, which isisAdmin || dashboardSource === 'user').So wiring the existing endpoint in would 403 for exactly the users the editor is built for, and adding a non-admin-readable group list is an information-disclosure decision — it hands every dashboard owner the instance's full group roster. That is a product/authorization call, not a mechanical fix, which is why this is filed rather than patched.
Options, roughly:
Whichever is chosen, the empty-with-no-explanation state is worth fixing on its own — "No results" reads as "this instance has no groups".
Impact on gate-19
Five
conditional-visibility-editorscenarios cannot be covered until this is wired:REQ-CVUI-001 add-a-group-inclusion-rule-through-the-uiREQ-CVUI-002 group-row-operandsREQ-CVUI-004 preview-shows-visible-for-a-matching-audienceREQ-CVUI-004 preview-shows-hidden-for-a-non-matching-audienceREQ-CVUI-004 preview-reflects-an-exclude-override(also blocked by No conditional-visibility EXCLUDE rule can be created: isInclude=false is a boolean bound into a smallint column (400 on PostgreSQL = the CI default) #96)All five are left uncovered and NOT
@e2e excluded. An exclusion states "a browser cannot observe this scenario", which is false — a browser observes it very clearly, and what it observes is that the feature is not wired. Per.github#345the gate reads an exclusion as POSITIVE coverage, so excluding these would buy five findings with a false statement.Recorded in the header of
tests/e2e/conditional-visibility-editor.spec.ts. Found while writing gate-19 round-3 coverage.