Draft: Add Orbit dashboard namespace settings endpoints

What does this MR do and why?

Adds three endpoints at /dashboard/orbit/namespaces so group owners can manage Knowledge Graph enablement on their root namespaces. Until now only instance admins could toggle KG through the admin API. This puts the controls in the hands of the people who own the groups.

The endpoints enforce three checks: the :knowledge_graph feature flag must be enabled at the instance level, the user must be an owner of the root namespace, and the namespace must be on a Premium or Ultimate plan.

Closes #591396 Part of gitlab-org#20566

What changed

  • Registered :knowledge_graph as a licensed feature in PREMIUM_FEATURES (enables licensed_feature_available? tier checks)
  • Added /dashboard/orbit/namespaces routes (index, enable, disable)
  • Created Dashboard::Orbit::NamespacesController with ownership and tier enforcement
  • Extracted query logic into Analytics::KnowledgeGraph::OwnedRootNamespacesFinder
  • Request spec covering all three endpoints (15 examples, 0 failures)

Endpoints

Method Path Purpose
GET /dashboard/orbit/namespaces List owned root namespaces with KG status and plan eligibility
PUT /dashboard/orbit/namespaces/:id/enable Enable KG (403 if not Premium/Ultimate)
DELETE /dashboard/orbit/namespaces/:id/disable Disable KG

Design

Orbit GA Designs (Figma)

Database queries and execution plans

Index query (list owned root namespaces)

SELECT namespaces.* FROM namespaces
INNER JOIN members ON namespaces.id = members.source_id
WHERE members.type = 'GroupMember'
  AND members.source_type = 'Namespace'
  AND namespaces.type = 'Group'
  AND members.user_id = :user_id
  AND members.requested_at IS NULL
  AND members.access_level = 50
  AND namespaces.parent_id IS NULL
ORDER BY namespaces.name ASC
Sort  (cost=7.66..7.67 rows=1 width=441) (actual time=0.034..0.034 rows=8 loops=1)
  Sort Key: namespaces.name
  Sort Method: quicksort  Memory: 26kB
  Buffers: shared hit=36
  ->  Nested Loop  (cost=0.41..7.65 rows=1 width=441) (actual time=0.015..0.024 rows=8 loops=1)
        Buffers: shared hit=33
        ->  Index Scan using index_members_on_user_id_and_access_level_requested_at_is_null on members
              Index Cond: ((user_id = 1) AND (access_level >= 10) AND (access_level = 50))
              Buffers: shared hit=7
        ->  Index Scan using index_groups_on_parent_id_id on namespaces
              Index Cond: ((parent_id IS NULL) AND (id = members.source_id))
              Buffers: shared hit=26
Planning Time: 2.635 ms
Execution Time: 0.049 ms

Eager load query (enabled namespaces)

SELECT * FROM knowledge_graph_enabled_namespaces
WHERE root_namespace_id IN (:namespace_ids)
Index Scan using index_knowledge_graph_enabled_namespaces_on_root_namespace_id
  on knowledge_graph_enabled_namespaces
  Index Cond: (root_namespace_id = ANY ('{29,33,24,31,22,35,178,64}'::bigint[]))
  Buffers: shared hit=10 read=2
Planning Time: 0.041 ms
Execution Time: 0.178 ms

Both queries use index scans. The main query is bounded by the number of root groups a user owns (single digits). No new tables, indexes, or migrations.

How to set up and validate locally

  1. Enable the feature flag:
Feature.enable(:knowledge_graph)
  1. List owned namespaces:
curl -s -H "Cookie: _gitlab_session=<session>" \
  "http://localhost:3000/dashboard/orbit/namespaces" | jq
  1. Enable KG for a namespace:
curl -s -X PUT -H "Cookie: _gitlab_session=<session>" \
  "http://localhost:3000/dashboard/orbit/namespaces/<group_id>/enable" | jq
  1. Disable KG:
curl -s -X DELETE -H "Cookie: _gitlab_session=<session>" \
  "http://localhost:3000/dashboard/orbit/namespaces/<group_id>/disable" | jq

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Michael Angelo Rivera

Merge request reports

Loading