(tools: readonly ToolRow[])
| 262 | }; |
| 263 | |
| 264 | const buildConnectionGroups = (tools: readonly ToolRow[]): readonly ToolkitConnectionGroup[] => { |
| 265 | const groups = new Map<string, ToolkitConnectionGroup & { tools: ToolRow[] }>(); |
| 266 | for (const tool of tools) { |
| 267 | const owner = toolOwner(tool); |
| 268 | const key = `${owner}:${tool.integration}:${toolConnectionName(tool)}`; |
| 269 | const existing = groups.get(key); |
| 270 | if (existing) { |
| 271 | existing.tools.push(tool); |
| 272 | continue; |
| 273 | } |
| 274 | groups.set(key, { |
| 275 | id: key, |
| 276 | owner, |
| 277 | integration: String(tool.integration), |
| 278 | connection: toolConnectionName(tool), |
| 279 | patterns: [], |
| 280 | tools: [tool], |
| 281 | }); |
| 282 | } |
| 283 | return [...groups.values()] |
| 284 | .map((group) => { |
| 285 | const sortedTools = [...group.tools].sort(compareTools); |
| 286 | return { |
| 287 | ...group, |
| 288 | patterns: reducePolicyPatterns(sortedTools.map(connectionPatternForTool)), |
| 289 | tools: sortedTools, |
| 290 | }; |
| 291 | }) |
| 292 | .sort(compareConnectionGroups); |
| 293 | }; |
| 294 | |
| 295 | const compareTools = (a: ToolRow, b: ToolRow): number => |
| 296 | String(a.name).localeCompare(String(b.name)) || toolMatchId(a).localeCompare(toolMatchId(b)); |
no test coverage detected