Skip to content

Commit 5f2d63c

Browse files
committed
Improve hub primary tag selection using doc-level tags
The SignalR OpenAPI plugin now determines each hub's primary tag based on the document-level tags array, ensuring the connection bar appears above the first visible tag section in Swagger UI. A fallback is provided for tags not listed in the array. An integration test was added to verify this behavior.
1 parent 87ebeb4 commit 5f2d63c

2 files changed

Lines changed: 44 additions & 4 deletions

File tree

src/SignalR.OpenApi.SwaggerUi/Resources/signalr-openapi-plugin.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ var SignalROpenApiPlugin = function (system) {
454454
}
455455

456456
var tagMap = {};
457-
var hubPrimaryTag = {};
458457
var pathsIm = specIm.get("paths");
459458
if (pathsIm) {
460459
pathsIm.keySeq().forEach(function (path) {
@@ -483,16 +482,38 @@ var SignalROpenApiPlugin = function (system) {
483482
var tagStr = typeof tag === "string" ? tag : (tag.get ? tag.get("name") || tag : tag);
484483
if (typeof tagStr === "string" && !tagMap[tagStr]) {
485484
tagMap[tagStr] = hubPath;
486-
if (!hubPrimaryTag[hubPath]) {
487-
hubPrimaryTag[hubPath] = tagStr;
488-
}
489485
}
490486
});
491487
}
492488
}
493489
});
494490
}
495491

492+
// Determine the primary tag per hub using the document-level tags
493+
// array, which defines the order SwaggerUI renders tag sections.
494+
// This ensures the connection bar appears above the first visible
495+
// tag section for each hub, not at a path-scan-order position.
496+
var hubPrimaryTag = {};
497+
var docTagsIm = specIm.get("tags");
498+
if (docTagsIm) {
499+
docTagsIm.forEach(function (tagObj) {
500+
var name = tagObj && typeof tagObj.get === "function"
501+
? tagObj.get("name")
502+
: (typeof tagObj === "string" ? tagObj : null);
503+
if (name && tagMap[name] && !hubPrimaryTag[tagMap[name]]) {
504+
hubPrimaryTag[tagMap[name]] = name;
505+
}
506+
});
507+
}
508+
509+
// Fallback for tags not listed in the document-level tags array
510+
Object.keys(tagMap).forEach(function (tag) {
511+
var hp = tagMap[tag];
512+
if (!hubPrimaryTag[hp]) {
513+
hubPrimaryTag[hp] = tag;
514+
}
515+
});
516+
496517
_cachedTagHubMapVersion = specIm;
497518
_cachedTagHubMap = tagMap;
498519
_cachedHubPrimaryTag = hubPrimaryTag;

test/SignalR.OpenApi.Tests/SwaggerUiIntegrationTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,25 @@ public async Task PluginJs_ContainsPrimaryTagDeduplication()
566566
Assert.IsTrue(content.Contains("_cachedHubPrimaryTag"), "Plugin JS should cache the primary tag per hub path");
567567
}
568568

569+
/// <summary>
570+
/// Verifies that the plugin JS determines the primary tag per hub using
571+
/// the document-level tags array so the connection bar renders above
572+
/// the first visible tag section in SwaggerUI.
573+
/// </summary>
574+
/// <returns>A <see cref="Task"/> representing the asynchronous test.</returns>
575+
[TestMethod]
576+
public async Task PluginJs_DeterminesPrimaryTagFromDocumentTagsArray()
577+
{
578+
using var host = await CreateTestHost();
579+
using var client = host.GetTestClient();
580+
581+
using var response = await client.GetAsync("/signalr-swagger/_resources/signalr-openapi-plugin.js");
582+
var content = await response.Content.ReadAsStringAsync();
583+
584+
Assert.IsTrue(content.Contains("specIm.get(\"tags\")"), "Plugin JS should read the document-level tags array for primary tag ordering");
585+
Assert.IsTrue(content.Contains("tagObj.get(\"name\")"), "Plugin JS should extract tag names from the document tags array");
586+
}
587+
569588
/// <summary>
570589
/// Verifies that the CSS contains connection bar styles.
571590
/// </summary>

0 commit comments

Comments
 (0)