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_graphas a licensed feature inPREMIUM_FEATURES(enableslicensed_feature_available?tier checks) - Added
/dashboard/orbit/namespacesroutes (index, enable, disable) - Created
Dashboard::Orbit::NamespacesControllerwith 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
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
- Enable the feature flag:
Feature.enable(:knowledge_graph)
- List owned namespaces:
curl -s -H "Cookie: _gitlab_session=<session>" \
"http://localhost:3000/dashboard/orbit/namespaces" | jq
- Enable KG for a namespace:
curl -s -X PUT -H "Cookie: _gitlab_session=<session>" \
"http://localhost:3000/dashboard/orbit/namespaces/<group_id>/enable" | jq
- 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