13 KiB
rooms-ui Specification
Purpose
The Rooms page: how room data is laid out, filtered, paged, refreshed and linked, built from the shared UI building blocks and driven by the URL state rules of the shell; the Room detail page is locked in CE.
Requirements
Requirement: Rooms page URL state
Edition: CE. /rooms SHALL read its whole state from the query parameters status, q, features, nodeId,
from, to, tz, sort, order, cursor and limit as the shell's URL-state rules describe: defaults
status=all, sort=createdAt, order=desc, the global range and the stored page size; the range always applies to
the start time; invalid values fall back silently; any change of filter, search, range, sort or page size drops
cursor and creates a history entry.
Scenario: Deep link reproduces the view
- GIVEN
/rooms?status=closed&q=demo&features=egress,agent&from=now-7d&to=now&tz=UTC&sort=endedAt&order=asc&limit=50 - WHEN it is opened in a new browser session
- THEN the status segment shows Closed, the search box reads
demo, the Egress and Agent feature chips are selected, the range picker shows the 7-day preset in UTC, the table lists rooms started in that range sorted by Ended ascending and shows 50 rows
Scenario: Filter change drops the cursor
- GIVEN the list on its third page
- WHEN the user selects the Active status
- THEN the URL has
status=active, nocursor, and Back returns to the third page
Requirement: Summary tiles
Edition: CE. The Rooms page SHALL show four KPI tiles from the summary endpoint above the filters: Active rooms, Rooms in range, Participant sessions and Active participants; approximate values carry a tooltip saying the range exceeds the exact-count limit, and the tiles keep their last value while refreshing.
Scenario: Tiles after load
- GIVEN the summary answers
{ activeRooms: 7, roomsInRange: 120, participantSessions: 900, activeParticipants: 31, approximate: false } - WHEN the page renders
- THEN the tiles read 7, 120, 900 and 31 with tabular figures and no approximation hint
Scenario: Approximate counts
- GIVEN a 30-day range and
approximate: true - WHEN the tiles render
- THEN Rooms in range and Participant sessions show a "≈" prefix and the tooltip explains the counts are hour-aligned rollup sums
Requirement: Status, search and feature filters
Edition: CE. The Rooms page SHALL offer a status segment (Active, Closed, All), the shared list search box labelled
"Room name or SID" for a room name prefix or an RM_ SID, and a multi-select of feature chips (Egress, Ingress, Agent);
an exact SID shows only that room ignoring the range and every filter, and Enter on it opens the room keeping the
range. SIP is not offered as a feature chip nor shown as a room feature.
Scenario: Short search text
- GIVEN the user typed
d - WHEN the debounce elapses
- THEN
qis not written, the list is unchanged and the box shows the hint "Type at least 2 characters"
Scenario: Exact SID
- GIVEN the user typed
RM_ab12cd, the room exists and the status filter is Active - WHEN the result arrives
- THEN the table shows that one room regardless of range and status, and the box shows the hint "Exact ID: range and filters ignored · Enter opens it"
Scenario: Enter on an exact SID
- GIVEN the box reads
RM_ab12cd - WHEN the user presses Enter
- THEN the application navigates to
/rooms/RM_ab12cdkeepingfrom,toandtz
Scenario: Feature chips
- WHEN the user selects Egress and Agent
- THEN the URL reads
features=egress,agent,cursoris dropped and the table shows rooms with either flag
Scenario: SIP hidden
- GIVEN a room with
features.sip: trueand no other feature - WHEN the Rooms page renders
- THEN the feature chips offer Egress, Ingress and Agent only and the room's Features cell is empty
Requirement: Rooms table
Edition: CE. The Rooms table SHALL render, in order, the columns SID (detail link with copy button), Name (copy
button), Status (estimated and stale cues), Started, Ended, Duration (live), Unique identities (participants.unique),
Active, Data up / down, Features (badges E, I, A) and Node (hidden by default); the sortable headers are Started
(createdAt, the default), Ended (endedAt), Duration (duration), Unique identities (uniqueIdentities) and Active
(active).
Scenario: Row of an active room
- GIVEN an active room
demo-room/RM_ab12cdwith 6 unique identities, 7 sessions, 5 active, 12 MB up, 48 MB down, an egress and an agent - WHEN the row renders
- THEN it shows, in order,
RM_ab12cdonce, as a link to/rooms/RM_ab12cdwith its copy button,demo-roomwith its copy button, the active badge without a LIVE chip, the start time, a dash for Ended, a live duration, 6, 5, "↑ 12.0 MB ↓ 48.0 MB" and the E and A badges, under headers that include "Unique identities" and "Data up / down"
Scenario: Sort by Ended
- GIVEN
status=alland the default 24 h range - WHEN the user activates the Ended header
- THEN the URL gets
sort=endedAt&order=descwithoutcursor, the list holds the rooms started in the range, and the active rooms, which have no end yet, come first
Scenario: Sort by unique identities
- GIVEN the default 24 h range
- WHEN the user activates the Unique identities header
- THEN the URL gets
sort=uniqueIdentities&order=descwithoutcursorand the rooms with the most distinct STANDARD identities come first
Scenario: Reconciler-closed room
- GIVEN a room with
closedBy: "reconciler" - WHEN the row renders
- THEN the status badge has the dotted outline and the Ended cell carries the tooltip "Closed by the reconciler: the end time is estimated"
Scenario: Room of a node without media statistics
- GIVEN a room item with
mediaStats: false - WHEN the row renders
- THEN the Data up / down cell reads "—" with the tooltip "Not reported: this room's server does not report media statistics" instead of "↑ 0 B ↓ 0 B"
Requirement: Rooms pagination
Edition: CE. The Rooms page SHALL use the cursor paginator with Prev/Next bound to prevCursor/nextCursor for every
sort key, the page size select bound to limit (10, 25, 50, 100) and "Showing x–y of total" when total is present.
Scenario: Next page
- GIVEN a response with
nextCursor: "abc" - WHEN the user presses Next
- THEN the URL gets
cursor=abc, the table shows the next page and Prev becomes enabled
Scenario: Long range without total
- GIVEN a 30-day range
- WHEN the paginator renders
- THEN it reads "Showing 1–25" without a total
Scenario: Next page of a ranked sort
- GIVEN
sort=durationand a response withnextCursor: "def" - WHEN the user presses Next
- THEN the URL gets
cursor=defand keepssort=duration, and the request carries both
Requirement: Rooms live refresh
Edition: CE. The Rooms page SHALL be a live view following the shell's auto-refresh policy (default 10 s): each tick
reloads the summary and the current page in place; an active row that the list response marks stale: true carries
the stale cue on its status badge, judged by the API with its own clock and never by the browser; refresh pauses while
the tab is hidden and skips ticks while a request is in flight.
Scenario: In-place refresh
- GIVEN the list showing 25 rooms with the scroll at row 20
- WHEN a refresh completes with a changed participant count
- THEN the rows update without skeletons, the scroll position is kept and no row flashes
Scenario: Stale active room
- GIVEN an active room that the list response marks
stale: true, withlastStatsAtat 12:31:05 - WHEN the row renders
- THEN its status badge carries the clock cue with the tooltip "No stats since 12:31:05"
Scenario: Fresh room under a long interval
- GIVEN the auto-refresh at 5 min and an active room without
stalein the last list response - WHEN four minutes pass without a new response
- THEN its status badge carries no stale cue
Requirement: Rooms page states
Edition: CE. The Rooms page SHALL show skeleton rows equal to the page size on first load only, the shared list empty state "No rooms match" with "Clear filters" and "Widen range" when no row matches, "Room was not found" with "Clear search" when an exact SID matches nothing, and the error banner with retry and request id while keeping the previous rows when a load fails.
Scenario: Empty filtered list
- GIVEN
?status=active&q=zzz - WHEN the list answers no items
- THEN the empty state reads "No rooms match" with the hint "Change the filters or widen the time range." and offers
"Clear filters" (removes
status,q,featuresandnodeId) and "Widen range" (opens the range picker)
Scenario: Failed refresh
- GIVEN rows from the previous load
- WHEN the next request fails with
500 - THEN the rows stay visible under the error banner showing the
X-Request-Idand a Retry action
Scenario: Unknown SID
- GIVEN the search box reads
RM_missing - WHEN the list answers no items
- THEN the empty state reads "Room RM_missing was not found" with "Clear search", which removes
q
Requirement: Room detail route and CE lock
Edition: CE. /rooms/:roomSid SHALL be registered in CE as a timed route that is not range-scoped and declares the
feature room-detail, and in CE render the breadcrumbs, a title (room name, or SID) with its copy button and the
status badge, filled from the list cache or else from GET /api/v1/rooms?q=<sid>, and the full-page lock over a
silhouette of three tiles and a block, with no other header row, no refresh control and no PRO request.
Scenario: Locked from the list
- GIVEN CE and the user follows the
RM_ab12cdlink from the list - WHEN the page renders
- THEN the breadcrumbs read
Rooms / RM_ab12cd, the title readsdemo-roomwith its copy button followed by the status badge from the list data, no SID chip, start time or other row is shown, the header has no refresh control, the silhouette behind the lock shows three tiles and one block, the lock card reads "Room detail is available in OpenVidu PRO" with "Learn about OpenVidu PRO" and "Back to rooms", and no request to/api/v1/rooms/RM_ab12cdis sent
Scenario: Locked deep link
- GIVEN CE and
/rooms/RM_ab12cdopened directly - WHEN the page renders
- THEN the header is filled from
GET /api/v1/rooms?q=RM_ab12cdand the lock card is shown
Scenario: Locked room not in the list
- GIVEN CE and
/rooms/RM_ab12cdopened directly for a room that the list lookup does not return - WHEN the page renders
- THEN the title reads
RM_ab12cdwith its copy button, no status badge is shown and the lock card is shown
Requirement: Rooms ranked sort limit
Edition: CE. The Ended, Duration, Unique identities and Active sorts of the Rooms table SHALL be offered only while the
resolved range is at most limits.rankedSortMaxRangeMs of GET /api/v1/info (7 days by default); beyond it their
headers SHALL be disabled with the tooltip "Narrow the range to to sort by ", and a URL asking for one of
them SHALL fall back silently to Started descending. Started is sortable with any range.
Scenario: Range within the limit
- GIVEN the default 24 h range and
limits.rankedSortMaxRangeMsof 7 days - WHEN the user activates the Duration header
- THEN the URL gets
sort=duration&order=descwithoutcursorand the list request carriessort=duration
Scenario: Range beyond the limit
- GIVEN a 30-day range and
limits.rankedSortMaxRangeMsof 7 days - WHEN the table renders
- THEN the Ended, Duration, Unique identities and Active headers are disabled, hovering Duration shows "Narrow the range to to sort by Duration" with naming the 7-day limit, and Started stays sortable
Scenario: Deep link beyond the limit
- GIVEN
/rooms?sort=active&from=now-30d&to=now - WHEN the page loads
- THEN no error is shown, the list request carries
sort=createdAtand the table is sorted by Started descending
Requirement: Rooms node filter
Edition: CE. Without the per-node-breakdown feature the Rooms page SHALL show the Node select disabled on "All nodes"
with a lock icon whose tooltip says filtering by node is available in OpenVidu PRO, SHALL ignore nodeId and SHALL
NOT request the scopes.
Scenario: Node filter in CE
- GIVEN
featureswithoutper-node-breakdown - WHEN the Rooms page renders
- THEN the Node select reads "All nodes", is disabled with the lock icon and its tooltip, and no request to
/api/v1/analytics/scopesis sent
Scenario: Node in a CE URL
- GIVEN
featureswithoutper-node-breakdownand/rooms?nodeId=a - WHEN the page loads
- THEN the list request carries no
nodeId