Skip to content

Commit 91bed6a

Browse files
committed
Redesign SignalR connection UI with toggle button
Replaces status label and separate Connect/Disconnect buttons with a single toggle button in SwaggerUI. Updates event log panel to use the same pattern. Removes old status CSS, adds new button styles matching SwaggerUI's Execute button. Adjusts connection bar layout for compactness. Updates documentation and integration tests to reflect the new UI. Adds doc maintenance note to copilot-instructions.md.
1 parent df89121 commit 91bed6a

6 files changed

Lines changed: 64 additions & 89 deletions

File tree

.github/copilot-instructions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,6 @@ Leverage ASP.NET Core built-in support:
8787
- **SwaggerUI component wrapping** — Props in `wrapComponents` may be **plain JS objects/arrays OR ImmutableJS** structures depending on the component and SwaggerUI version. Always use defensive access: `val.get ? val.get(0) : val[0]` for lists, `val.size != null ? val.size : val.length` for counts. The `parameters` component receives `pathMethod` (array/List) and `parameters` (ImmutableList). The "No parameters" section is hidden for SignalR operations since hub methods use request body, not URL parameters.
8888
- **SwaggerUI form-urlencoded** values are wrapped as `{fieldName: {value: "val", errors: []}}` — the JS plugin unwraps these and coerces types (string→number/boolean).
8989
- **Playwright tests** require browser binaries installed separately; they are excluded from CI via `[TestCategory("Playwright")]`.
90+
91+
### Documentation Maintenance
92+
- **README.md** is the primary user-facing documentation. When making changes to features, configuration options, UI behavior, CSS styling, or public API surface, always review and update `README.md` to keep it in sync with the implementation.

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ OpenAPI 3.1 specification generation and SwaggerUI support for ASP.NET Core Sign
2020
- Security scheme detection from `[Authorize]` / `[AllowAnonymous]`
2121
- JWT Bearer token support in SwaggerUI (header or query string)
2222
- Custom HTTP headers (static or user-enterable via SwaggerUI Authorize dialog)
23-
- Connection status indicator with automatic reconnection handling
23+
- Per-hub Connect / Disconnect toggle button with automatic reconnection handling
2424
- Automatic credential change detection with transparent reconnection
25-
- Per-hub Connect / Disconnect buttons in SwaggerUI
2625
- Form-urlencoded input mode for primitive and flat object parameters
2726
- Multiple named request/response examples via custom attributes
2827
- Enum schema generation (integer or string based on `JsonStringEnumConverter`)
@@ -143,22 +142,20 @@ When the stream completes, the state changes to `"completed"`. If an error occur
143142

144143
Client events (from `Hub<TClient>` interface methods) appear as **EVENT** operations. When you expand one, an event log panel shows:
145144

146-
- **Connection status**: Connected / Disconnected indicator
147-
- **Connect & Listen**: Button to establish hub connection and start receiving events
145+
- **Connect & Listen**: Toggle button to establish hub connection and start receiving events (shows "Connected" when active)
148146
- **Event log**: Real-time list of received events with timestamps and JSON payloads
149147
- **Clear Log**: Button to reset the event history
150148

151149
Events are automatically subscribed when connecting to a hub via any invoke or stream operation.
152150

153151
### Connection Management
154152

155-
Each hub tag section in SwaggerUI displays a connection control bar showing the current connection status with **Connect** and **Disconnect** buttons.
153+
Each hub tag section in SwaggerUI displays a connection control bar with a single toggle button:
156154

157-
| Status | Description |
158-
|--------|-------------|
159-
| **Connected** | Hub connection is active; a Disconnect button is available |
160-
| **Disconnected** | No active connection; a Connect button is available |
161-
| **Connecting…** | Connection is being established or reconnecting |
155+
| Button State | Description |
156+
|--------------|-------------|
157+
| **Connect** | No active connection; click to connect |
158+
| **Disconnect** | Hub connection is active; click to disconnect |
162159

163160
**Auto-connect on Execute**: Clicking Execute on any hub method automatically connects if not already connected — you do not need to click Connect first.
164161

samples/SignalR.OpenApi.Sample/Properties/launchSettings.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
"launchUrl": "signalr-swagger/",
77
"environmentVariables": {
88
"ASPNETCORE_ENVIRONMENT": "Development"
9-
},
10-
"applicationUrl": "https://localhost:57862;http://localhost:57863"
9+
}
1110
}
1211
}
13-
}
12+
}

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

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -600,33 +600,29 @@ var SignalROpenApiPlugin = function (system) {
600600

601601
var showConnecting = isConnecting || isManualConnecting;
602602

603-
var statusClass = isConnected
604-
? "signalr-status--connected"
605-
: showConnecting
606-
? "signalr-status--connecting"
607-
: "signalr-status--disconnected";
608-
609-
var statusText = isConnected
610-
? "Connected"
611-
: showConnecting
612-
? "Connecting\u2026"
613-
: "Disconnected";
603+
var buttonClass = isConnected
604+
? "btn signalr-disconnect-btn"
605+
: "btn signalr-connect-btn";
606+
607+
var buttonText = isConnected
608+
? "Disconnect"
609+
: "Connect";
610+
611+
var handleClick = isConnected
612+
? handleDisconnect
613+
: !showConnecting
614+
? handleConnect
615+
: undefined;
614616

615617
return React.createElement("div", {
616618
className: "signalr-hub-connection-bar",
617619
onClick: function (e) { e.stopPropagation(); },
618620
},
619-
React.createElement("span", {
620-
className: "signalr-status " + statusClass,
621-
}, statusText),
622-
!isConnected && !showConnecting && React.createElement("button", {
623-
className: "btn signalr-connect-btn",
624-
onClick: handleConnect,
625-
}, "Connect"),
626-
isConnected && React.createElement("button", {
627-
className: "btn signalr-disconnect-btn",
628-
onClick: handleDisconnect,
629-
}, "Disconnect")
621+
React.createElement("button", {
622+
className: buttonClass,
623+
onClick: handleClick,
624+
disabled: showConnecting,
625+
}, buttonText)
630626
);
631627
}
632628

@@ -682,14 +678,11 @@ var SignalROpenApiPlugin = function (system) {
682678
return React.createElement("div", { className: "opblock-body" },
683679
React.createElement("div", { className: "signalr-event-panel", style: { padding: "10px 20px" } },
684680
React.createElement("div", { style: { display: "flex", alignItems: "center", marginBottom: "10px" } },
685-
React.createElement("span", {
686-
className: "signalr-status " + (isConnected ? "signalr-status--connected" : "signalr-status--disconnected"),
687-
}, isConnected ? "Connected" : "Disconnected"),
688-
!isConnected && React.createElement("button", {
689-
className: "btn",
690-
style: { marginLeft: "10px", fontSize: "12px", padding: "4px 10px" },
691-
onClick: connectAndListen,
692-
}, "Connect & Listen"),
681+
React.createElement("button", {
682+
className: "btn " + (isConnected ? "signalr-disconnect-btn" : "signalr-connect-btn"),
683+
onClick: isConnected ? undefined : connectAndListen,
684+
disabled: isConnected,
685+
}, isConnected ? "Connected" : "Connect & Listen"),
693686
logs.length > 0 && React.createElement("button", {
694687
className: "btn",
695688
style: { marginLeft: "10px", fontSize: "12px", padding: "4px 10px" },

src/SignalR.OpenApi.SwaggerUi/Resources/signalr-openapi.css

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,41 @@
1717
background: #61affe;
1818
}
1919

20-
/* SignalR connection status indicator */
21-
.signalr-status {
22-
display: inline-block;
23-
padding: 2px 8px;
24-
border-radius: 3px;
25-
font-size: 12px;
26-
font-weight: 700;
27-
margin-left: 8px;
20+
/* SignalR connect/disconnect buttons styled like SwaggerUI Execute */
21+
.signalr-connect-btn,
22+
.signalr-disconnect-btn {
23+
font-size: 14px !important;
24+
font-weight: 700 !important;
25+
padding: 5px 23px !important;
26+
border: 2px solid !important;
27+
border-radius: 4px !important;
28+
cursor: pointer !important;
29+
font-family: sans-serif !important;
30+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
2831
}
2932

30-
.signalr-status--connected {
31-
background: #49cc90;
32-
color: #fff;
33+
/* Connect: matches the green Execute / Invoke style */
34+
.signalr-connect-btn {
35+
background: #fff !important;
36+
color: #49cc90 !important;
37+
border-color: #49cc90 !important;
3338
}
3439

35-
.signalr-status--disconnected {
36-
background: #f93e3e;
37-
color: #fff;
40+
.signalr-connect-btn:hover {
41+
background: #49cc90 !important;
42+
color: #fff !important;
3843
}
3944

40-
.signalr-status--connecting {
41-
background: #fca130;
42-
color: #fff;
45+
/* Disconnect: red variant */
46+
.signalr-disconnect-btn {
47+
background: #fff !important;
48+
color: #f93e3e !important;
49+
border-color: #f93e3e !important;
4350
}
4451

45-
.signalr-status--reconnecting {
46-
background: #fca130;
47-
color: #fff;
52+
.signalr-disconnect-btn:hover {
53+
background: #f93e3e !important;
54+
color: #fff !important;
4855
}
4956

5057
/* Stop Stream button styling */
@@ -93,33 +100,9 @@
93100
.signalr-hub-connection-bar {
94101
display: flex;
95102
align-items: center;
96-
padding: 6px 20px;
103+
padding: 6px 5px;
97104
background: #fafafa;
98105
border-bottom: 1px solid #e8e8e8;
99106
font-size: 13px;
100107
gap: 8px;
101108
}
102-
103-
.signalr-connect-btn {
104-
font-size: 12px !important;
105-
padding: 3px 10px !important;
106-
background: #49cc90 !important;
107-
color: #fff !important;
108-
border-color: #49cc90 !important;
109-
}
110-
111-
.signalr-connect-btn:hover {
112-
background: #3bb878 !important;
113-
}
114-
115-
.signalr-disconnect-btn {
116-
font-size: 12px !important;
117-
padding: 3px 10px !important;
118-
background: #f93e3e !important;
119-
color: #fff !important;
120-
border-color: #f93e3e !important;
121-
}
122-
123-
.signalr-disconnect-btn:hover {
124-
background: #e02020 !important;
125-
}

test/SignalR.OpenApi.Tests/SwaggerUiIntegrationTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public async Task EmbeddedResources_ServesCss()
222222

223223
Assert.AreEqual(System.Net.HttpStatusCode.OK, response.StatusCode);
224224
var content = await response.Content.ReadAsStringAsync();
225-
Assert.IsTrue(content.Contains("signalr-status"));
225+
Assert.IsTrue(content.Contains("signalr-connect-btn"));
226226
}
227227

228228
/// <summary>

0 commit comments

Comments
 (0)