handleGetWorkspaceGraph serves GET /api/v1/workspaces/{ws}/graph. Query params: - include_terminal=true — include items in terminal status (done/fixed/archived/...). Default false: the graph view opens showing active work only; large workspaces would otherwise be hairball soup. The focused item its
(w http.ResponseWriter, r *http.Request)
| 98 | // can't infer the existence of items they can't see from dangling |
| 99 | // edge endpoints. |
| 100 | func (s *Server) handleGetWorkspaceGraph(w http.ResponseWriter, r *http.Request) { |
| 101 | workspaceID, ok := s.getWorkspaceID(w, r) |
| 102 | if !ok { |
| 103 | return |
| 104 | } |
| 105 | includeTerminal := r.URL.Query().Get("include_terminal") == "true" |
| 106 | focus := r.URL.Query().Get("focus") |
| 107 | depth := defaultFocusDepth |
| 108 | if d := r.URL.Query().Get("depth"); d != "" { |
| 109 | if n, err := strconv.Atoi(d); err == nil { |
| 110 | depth = n |
| 111 | } |
| 112 | } |
| 113 | if depth < 1 { |
| 114 | depth = 1 |
| 115 | } |
| 116 | if depth > maxFocusDepth { |
| 117 | depth = maxFocusDepth |
| 118 | } |
| 119 | |
| 120 | visibleIDs, err := s.visibleCollectionIDs(r, workspaceID) |
| 121 | if err != nil { |
| 122 | writeInternalError(w, err) |
| 123 | return |
| 124 | } |
| 125 | fullCollIDs, grantedItemIDs, err := s.guestResourceFilter(r, workspaceID) |
| 126 | if err != nil { |
| 127 | writeInternalError(w, err) |
| 128 | return |
| 129 | } |
| 130 | collIDs := visibleIDs |
| 131 | var itemIDs []string |
| 132 | if len(grantedItemIDs) > 0 { |
| 133 | collIDs = fullCollIDs |
| 134 | itemIDs = grantedItemIDs |
| 135 | } |
| 136 | |
| 137 | items, err := s.store.ListItems(workspaceID, models.ItemListParams{CollectionIDs: collIDs, ItemIDs: itemIDs}) |
| 138 | if err != nil { |
| 139 | writeInternalError(w, err) |
| 140 | return |
| 141 | } |
| 142 | |
| 143 | // Done-context map from ALL workspace collections (not the |
| 144 | // visibility-filtered set) so item-level grants from hidden |
| 145 | // collections still evaluate against their own done rules — same |
| 146 | // reasoning as buildDashboardResponse. |
| 147 | allCollections, err := s.store.ListCollectionsMinimal(workspaceID) |
| 148 | if err != nil { |
| 149 | writeInternalError(w, err) |
| 150 | return |
| 151 | } |
| 152 | ctxMap := buildDoneContextMap(allCollections) |
| 153 | |
| 154 | links, err := s.store.ListWorkspaceGraphLinks(workspaceID) |
| 155 | if err != nil { |
| 156 | writeInternalError(w, err) |
| 157 | return |
nothing calls this directly
no test coverage detected