Repository navigation
Update share screen functionality - #817
Conversation
* Update issue templates * removed github template out of sync with upstream * docs for macos * gitignore for ide * gitignore * fixed client-side interface declaration * ui-tile fix * ui-tile fix * Apply suggestion from @testradav * Update dioxus-ui/src/components/attendants.rs --------- Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com> Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local> Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
There was a problem hiding this comment.
Pull request overview
Updates screen-sharing UX and reliability across the encoder/decoder and Dioxus UI, including a split-layout view, a local screen-share preview, and improved keyframe recovery behavior.
Changes:
- Extend screen-share lifecycle signaling to provide a MediaStream for UI preview and add track/stream cleanup logic.
- Improve screen decoding robustness with proactive keyframe requests and decoder flushes on screen-off transitions (plus tests).
- Add a split screen-share layout (2/3 share + 1/3 peer list) and new tile render modes/styles.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| videocall-client/src/encode/screen_encoder.rs | Screen-share event payload + track/stream lifecycle handling to support immediate stop and UI preview. |
| videocall-client/src/decode/peer_decode_manager.rs | Screen decode behavior updates (visibility behavior, proactive PLI, flush on off) with additional tests. |
| dioxus-ui/static/style.css | New split-layout and preview styling; host tile sizing adjustments. |
| dioxus-ui/src/components/peer_tile.rs | Add tile render mode prop and updated canvas generator call signature. |
| dioxus-ui/src/components/host.rs | Attach/detach local screen-share preview video based on screen-share events; host layout tweaks. |
| dioxus-ui/src/components/canvas_generator.rs | Introduce TileMode + split-layout rendering branches and unit tests for decision logic. |
| dioxus-ui/src/components/attendants.rs | Implement split layout selection + screen-share “stack” tracking; reconnect display name handling changes. |
Comments suppressed due to low confidence (2)
dioxus-ui/src/components/attendants.rs:943
screen_share_stack.write()mutates aSignalduring render. In Dioxus, writing to a signal typically schedules a re-render; doing this unconditionally in the render path can cause an infinite render loop and extra work. Move this stack maintenance into an effect/memo keyed offscreen_share_version(or store it in a non-reactiveuse_ref), and computeactive_screen_sharerwithout mutating signals during render.
if let Some(h) = h.as_f64() {
container_h.set(h);
}
}
}
dioxus-ui/src/components/attendants.rs:643
let suppress_toast = false;removes the existing reconnection suppression logic. The client exposesVideoCallClient::is_reconnecting()specifically because the server replays participant events during reconnect, so this will likely reintroduce duplicate/incorrect join/leave toasts (and sounds) when reconnecting. Consider reinstating the suppression check (and the “already tracked” guard) here and inon_peer_left.
toast_version.set(v + 1);
}
// Defer the leave sound: only play if the toast still exists
// after 500ms (i.e. no join event cancelled it).
Timeout::new(500, move || {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Events emitted by [ScreenEncoder] to notify about screen share state changes. | ||
| /// | ||
| /// This allows the UI to react to screen share lifecycle events without managing | ||
| /// the MediaStream directly. | ||
| #[derive(Clone, Debug, PartialEq)] | ||
| #[derive(Clone, Debug)] | ||
| pub enum ScreenShareEvent { | ||
| /// Screen share successfully started and encoding is active | ||
| Started, | ||
| /// Screen share successfully started and encoding is active, carrying the MediaStream | ||
| Started(MediaStream), |
There was a problem hiding this comment.
The doc comment says the UI can react to screen share lifecycle events “without managing the MediaStream directly”, but ScreenShareEvent::Started now carries a MediaStream that the UI is expected to attach/detach. Please update the enum-level docs to reflect the new contract (e.g., that the UI may use the provided stream for local preview).
| /// Returns a handle to the active screen-share MediaStream. | ||
| /// The inner Option is None when no screen is being shared. | ||
| pub fn screen_stream(&self) -> Rc<RefCell<Option<MediaStream>>> { | ||
| self.screen_stream.clone() |
There was a problem hiding this comment.
screen_stream() returns Rc<RefCell<Option<MediaStream>>>, which exposes mutable internal encoder state to callers (they can take() it and break stop()/cleanup invariants). Consider returning a read-only snapshot (e.g., Option<MediaStream> or a wrapper that doesn’t allow mutation) instead of sharing the interior-mutable cell publicly.
| /// Returns a handle to the active screen-share MediaStream. | |
| /// The inner Option is None when no screen is being shared. | |
| pub fn screen_stream(&self) -> Rc<RefCell<Option<MediaStream>>> { | |
| self.screen_stream.clone() | |
| /// Returns a snapshot of the active screen-share MediaStream. | |
| /// The returned Option is None when no screen is being shared. | |
| pub fn screen_stream(&self) -> Option<MediaStream> { | |
| self.screen_stream.borrow().clone() |
|
|
||
| // Store the original track so stop() can stop it synchronously, which | ||
| // is required to immediately dismiss the browser's capture indicator bar. | ||
| active_video_track.borrow_mut().replace(media_track.clone()); |
There was a problem hiding this comment.
active_video_track is intended to hold the original capture track so stop() dismisses the browser’s native sharing indicator, but media_track.clone() may call the Web API MediaStreamTrack.clone() (creating a cloned track). If that happens, stopping it will not dismiss the indicator. Prefer storing the original JS track reference (e.g., avoid calling the Web clone() and instead clone only the Rust handle/reference).
| active_video_track.borrow_mut().replace(media_track.clone()); | |
| // Use Rust's Clone trait explicitly so we keep another handle to the same | |
| // underlying JS MediaStreamTrack instead of invoking the Web API clone(). | |
| active_video_track | |
| .borrow_mut() | |
| .replace(Clone::clone(&media_track)); |
| // A SCREEN frame arrived while screen_enabled is false. | ||
| // This happens when the sender starts sharing before | ||
| // the next heartbeat reaches us. Trust the actual | ||
| // media frame over the (stale) heartbeat state — | ||
| // dropping the first keyframe here would leave the | ||
| // decoder waiting until a PLI round-trip completes. | ||
| self.screen_enabled = true; | ||
| self.broadcast_peer_status(); |
There was a problem hiding this comment.
This change makes any incoming SCREEN frame flip screen_enabled to true, even if we previously received a heartbeat indicating screen sharing is off. That invalidates the existing “screen_straggler_after_heartbeat_is_dropped” behavior/tests and can cause UI flicker after a peer stops sharing (late packets re-enable briefly). Consider restoring a straggler guard when a recent heartbeat says screen is disabled, or update/remove the straggler test accordingly.
| // A SCREEN frame arrived while screen_enabled is false. | |
| // This happens when the sender starts sharing before | |
| // the next heartbeat reaches us. Trust the actual | |
| // media frame over the (stale) heartbeat state — | |
| // dropping the first keyframe here would leave the | |
| // decoder waiting until a PLI round-trip completes. | |
| self.screen_enabled = true; | |
| self.broadcast_peer_status(); | |
| if !self.has_received_heartbeat { | |
| // No heartbeat yet — infer screen_enabled from the actual frame. | |
| // This avoids dropping the initial keyframe when the sender starts | |
| // sharing just before the first heartbeat reaches us. | |
| self.screen_enabled = true; | |
| self.broadcast_peer_status(); | |
| } else { | |
| // Peer is not sharing per heartbeat; drop straggler screen packets | |
| // so late frames do not briefly re-enable the UI. | |
| return Ok((media_type, DecodeStatus::SKIPPED, kf_request)); | |
| } |
| if let Some(el) = web_sys::window() | ||
| .and_then(|w| w.document()) | ||
| .and_then(|d| d.get_element_by_id("screen-share-preview")) | ||
| { | ||
| let video: web_sys::HtmlVideoElement = el.unchecked_into(); |
There was a problem hiding this comment.
unchecked_into::<HtmlVideoElement>() will happily cast any element and then fail at runtime when calling video-only methods if the DOM is unexpected. Since this is UI glue code, it’s safer to use a checked cast (dyn_into) and log/return early on failure, so a mismatched element id doesn’t crash screen preview attachment.
|
@testradav I took #766 and trimmed some unrelated changes, please give it a test and merge when you are ready. @jboyd01 please update prod with the latest greatest |
|
/build-and-deploy |
|
🚀 Building images and deploying preview... Started by @jboyd01 Phase 1: Building Docker images (~10-15 min)
Phase 2: Deploying preview (~3-5 min)
⏱️ Total time expected: ~15-20 minutes I'll post updates in this thread as each phase completes. |
|
✅ Images built successfully! 📦 Images pushed to GHCR:
🚀 Starting deployment... |
|
✅ Preview deployed to slot 3 🌐 Preview URLs:
🔐 Configuration:
📊 Slot occupancy: Slot 3 of 3 maximum slots Cleanup: Comment Redeploy: Push new commits, then comment |
jboyd01
left a comment
There was a problem hiding this comment.
You have to lol at Claude's take on this:
Verdict: Merge-ready, no blockers
Review Comments Assessment
Copilot comments — none are must-fix
Copilot's suppressed comments — also not real issues
- Signal mutation during render — no circular dependency, standard Dioxus derived state pattern
- Reconnection toast suppression removed — wrong,
on_peer_leftsuppression logic is NOT modified by this PR
darioalessandro's comment
"This looks completely unrelated" (attendants.rs:594)
Fair observation — the display_name -> current_display_name Signal change in reconnect logic is tangential to screen sharing. But it's a small, harmless improvement (uses latest display name on reconnect instead of stale one). Could have been a separate commit but doesn't warrant blocking.
Positive Findings
- Straggler guard removal is well-motivated and correct
- Proactive keyframe request on canvas attach fixes late-joiner blank screen
TileMode/TileDecisiondesign is clean with good test coverage- Split layout with LIFO screen share stack is sensible UX
- 4 new WASM tests covering PLI, rate limiting, visibility
Minor Follow-up Items (next PR, not blocking)
- Fix indentation on the
wasm_bindgen_futures::spawn_localline in the waiting room handler - Update
ScreenShareEventdoc comment to reflectStarted(MediaStream) - Remove unused
screen_stream()method or document its intent
Bottom line: Copilot's comments are mostly wrong or cosmetic. This is safe to merge as-is.
* refactored a bit
* exclude .swg files (vi)
* tweaks to list repo to key components
* debug and trace flags for yew-ui
* add git-all image after update
* tailwind
* relax logging
* concept car title
* show display name at top
* cleanup
* revert --rm containers
* chore(videocall-cli): release v1.0.25
* self init
* show self with curent name
* comment out unused in order to remove warnings
* tweaks to self
* update to latest from main, cleaned up
* update self to show (You) if no ussername
* tweak to pass linter
* localhost -> tonys-mac-lp3.local
* reverted to main
* revert back to main
* show version on top page
* Update issue templates
* removed github template out of sync with upstream
* docs for macos
* gitignore for ide
* gitignore
* Remove contribute to GitHub Button
* lint
* initial workflow
* review and harden
* concurrent image builds, stronger JWT entrophy
* refactor: migrate PR workflows to github-script and fix concurrency
Migrate all HCL PR preview workflows from raw curl commands to
actions/github-script@v7 for better maintainability, error handling,
and consistency with opensource workflows.
## Changes
### 1. Concurrency Groups (All Workflows)
- Changed from global lock to per-PR concurrency
- Before: Only 1 PR could build/deploy at a time (global bottleneck)
- After: Multiple PRs can work simultaneously without conflicts
- pr-deploy-hcl.yaml: pr-preview-slot-allocator-hcl → pr-deploy-{PR#}-hcl
- pr-build-images-hcl.yaml: (added) pr-build-images-{PR#}-hcl
- pr-undeploy-hcl.yaml: pr-preview-slot-allocator-hcl → pr-undeploy-{PR#}-hcl
- pr-cleanup-hcl.yaml: pr-preview-slot-allocator-hcl → pr-cleanup-{PR#}-hcl
### 2. Migrated 24 curl Commands to github-script
- pr-deploy-hcl.yaml: 9 curl commands converted
- pr-build-images-hcl.yaml: 8 curl commands converted
- pr-undeploy-hcl.yaml: 6 curl commands converted
- pr-cleanup-hcl.yaml: 1 curl command converted
Benefits:
- No manual JSON escaping required
- Automatic GitHub Enterprise API detection
- Better error handling and logging
- Type-safe API calls
- Uses context.payload.comment.id directly (no passing via outputs)
- Eliminates actionlint security warning about untrusted input
### 3. Fixed Missing PR Comments (pr-deploy-hcl.yaml)
- Added build-success job to comment when images are built
- Enhanced initial comment to mention both build and deploy phases
- Fixed build-failure job to use github-script instead of curl
- All PR comments now work correctly for /build-and-deploy workflow
### 4. Fixed Deploy Validation (pr-deploy-reusable-hcl.yaml)
- Strip ANSI color codes from kubectl cluster-info output before grep
- Prevents validation failure when kubectl outputs color codes
### 5. Created Reusable Build Workflow
- Added pr-build-images-reusable-hcl.yaml (158 lines)
- Parallel builds for 3 images (5-7 min vs 15-20 min sequential)
- Timestamped log directories with automatic cleanup
- Both pr-build-images-hcl.yaml and pr-deploy-hcl.yaml now use it
- Eliminates code duplication between workflows
### 6. Added actionlint Configuration
- Created .github/actionlint.yaml to recognize custom "docker" runner label
- Enables local workflow validation before pushing
## Testing
All workflows validated with actionlint (0 errors).
Ready to test:
- /build-images - parallel builds with proper comments
- /deploy - deploys with proper comments
- /build-and-deploy - complete flow with all comments
- /undeploy - cleanup with proper comments
- Multiple PRs can now work simultaneously
Refs: docs/HCL_WORKFLOW_MIGRATION_2026-02-25.md
Refs: docs/HCL_BUILD_PARALLELIZATION_PLAN.md
* fix: remove GITHUB_TOKEN from reusable workflow secrets
GITHUB_TOKEN is automatically available to reusable workflows and cannot
be passed explicitly as a secret - it's a reserved system name.
Removed from:
- pr-build-images-reusable-hcl.yaml (secret definition)
- pr-deploy-hcl.yaml (secret passing)
- pr-build-images-hcl.yaml (secret passing)
* fix: add pull-requests write permission to pr-cleanup workflow
The workflow needs pull-requests: write permission to comment on PRs
when using actions/github-script@v7.
Error was: 'HttpError: Resource not accessible by integration'
Without this permission, the Comment on cleanup failure job cannot
create comments using the GitHub API.
* fix: strip ANSI color codes in undeploy and cleanup workflows
Applied the same kubectl cluster-info ANSI color code fix to:
- pr-undeploy-hcl.yaml
- pr-cleanup-hcl.yaml
These workflows were missing the sed command to strip ANSI codes before
grep, causing validation failures with: 'Process completed with exit code 1'
The fix was already applied to pr-deploy-reusable-hcl.yaml but was
overlooked in the other two workflows that validate kubectl access.
All three workflows now use:
echo "${CLUSTER_INFO}" | sed 's/\x1b\[[0-9;]*m//g' | grep -F "..."
* HCL Internal - Accessing vc2 aws instance
* add deployment url
* ssh clarification
* fix: hcl pr-cleanup and pr-undeploy workflow reliability fixes
Root cause fix: kubectl exits 1 when jsonpath accesses items[0] on an
empty list (PR was never deployed). With bash -euo pipefail this killed
the Find deployment slot step before the [ -z "$SLOT" ] check could run,
causing the cleanup job to always fail on undeployed PRs. Fix: add
|| true to both the cleanup and undeploy SLOT queries, matching the
pattern already used in pr-deploy-reusable-hcl.yaml.
Additional fixes:
- Add || true + empty-check guard to PG_PASSWORD retrieval in both
workflows; previously a missing postgres-credentials secret would
cause a hard failure with no error message
- Add comment-success job to pr-cleanup-hcl.yaml so the PR receives
a comment when automatic cleanup actually removes a slot; previously
only failures were reported
- Add job outputs (slot_existed, slot) to cleanup job to support the
comment-success condition
- Convert last raw curl reaction in pr-undeploy-hcl.yaml comment-failure
job to actions/github-script@v7, matching all other steps in the file
* feat: deploy Dioxus UI alongside Yew in HCL PR previews
Each PR preview slot now deploys both the Yew UI (pr{N}.preview...) and the
Dioxus UI (pr{N}-dx.preview...) so reviewers can test both frontends in the
same preview environment.
Changes:
- helm/videocall-ui: add imagePullSecrets support so Harbor pull secret works
- pr-deploy-reusable-hcl: add Deploy Dioxus UI step using helm/videocall-ui/
- pr-deploy-reusable-hcl: extend CORS_ALLOWED_ORIGIN and ALLOWED_REDIRECT_URLS
on the Meeting API to include both Yew and Dioxus preview origins
- pr-deploy-reusable-hcl: add videocall-dioxus-ui to verify-images check
- pr-deploy-reusable-hcl: bump pod quota 10→12 for extra pod per slot
- pr-deploy-reusable-hcl: update success comment to list both UI URLs
- pr-build-images-hcl / pr-deploy-hcl: add videocall-dioxus-ui to build
success image list comments
- cut_build_push_ui.sh: remove spurious second docker push of Yew image
* fix: escape commas in helm --set values for CORS_ALLOWED_ORIGIN and ALLOWED_REDIRECT_URLS
* fix: set COOKIE_NAME per preview slot to prevent session cookie collision
* concept car tweaks
* Add daily build and deployment pipeline for HCL production
Implements automated daily builds and deployments to the videocall namespace (production):
- daily-build-images-hcl.yaml: Builds 3 images daily at midnight Eastern with timestamp tags (daily-YYYY-MM-DD-HHMM)
- videocall-media-server (WebSocket/WebTransport)
- videocall-meeting-api (REST backend)
- videocall-dioxus-ui (WASM frontend)
- daily-deploy-hcl.yaml: Deploys to production namespace with auto-trigger after successful builds
- Supports manual deployment with specific image tags for rollbacks
- Deploys to *.videocall.fnxlabs.com domains
- Enables WebTransport with NodePort 52311
- Verifies images exist in Harbor before deploying
- cut_build_push_ui.sh: Removed deprecated Yew UI build, now only builds Dioxus UI
Build and deploy workflows can be manually triggered via GitHub Actions UI. First scheduled build will run tomorrow at midnight Eastern.
* Keep build logs for 24 hours instead of deleting on success
Updated log retention for both daily and PR preview builds:
- Auto-cleanup changed from 2 hours to 24 hours
- Logs now kept even on successful builds (not just failures)
- Improves audit trail and debugging capability for production builds
* Fix image tag mismatch between build and deploy workflows
The deploy workflow was generating a NEW timestamp instead of using the tag from the build workflow, causing 404 errors when checking Harbor.
Solution: Pass the image tag via artifact
- Build workflow saves tag to artifact (image-tag.txt)
- Deploy workflow downloads artifact and reads the exact tag
- Ensures build and deploy use identical tags
This fixes the issue where builds succeeded but deploys failed due to tag mismatch (e.g., build used daily-2026-03-10-1643 but deploy looked for daily-2026-03-10-1647).
Manual deploys still work - just specify the tag via workflow_dispatch input.
* Update home.rs
* Update home.rs
* Use existing individual TLS certificates instead of wildcard
The wildcard certificate (videocall-wildcard-tls) is stuck pending due to HCL's internal DNS (10.134.49.13/16) not propagating the _acme-challenge TXT record.
Solution: Use existing per-service TLS certificates:
- webtransport.videocall.fnxlabs.com → webtransport-tls
- websocket.videocall.fnxlabs.com → websocket-tls
- api.videocall.fnxlabs.com → api-tls
- app-dx.videocall.fnxlabs.com → dioxus-ui-tls (cert-manager auto-create)
Updated secret verification to check for individual TLS secrets instead of wildcard.
* Fix WebTransport deployment configuration
Added missing critical environment variables for WebTransport server:
- LISTEN_URL=0.0.0.0:52311 (port to listen on)
- CERT_PATH=/certs/tls.crt (TLS certificate path)
- KEY_PATH=/certs/tls.key (TLS key path)
- TOKIO_WORKER_THREADS=1
- TOKIO_BLOCKING_THREADS=2
- Updated RUST_LOG to reduce verbosity (warn level)
- Changed NATS_URL to use short form (nats:4222)
- Added command: webtransport_server
- Added tlsSecret and certificateDomain settings
- Added service.port and service.healthPort
This matches the working values file used in manual deployments.
* Add Google Chat notification on successful deployment
Sends a notification to Google Chat when production deployment completes successfully:
- Includes deployment tag
- Includes app URL (https://app-dx.videocall.fnxlabs.com)
- Only triggers on successful deployment
- Non-fatal if notification fails (won't break workflow)
* Downgrade artifact actions to v3 for GHES compatibility
GitHub Enterprise Server doesn't support actions/upload-artifact@v4 or
actions/download-artifact@v4. Downgrading to v3 to fix artifact upload/download
between daily build and deploy workflows.
* Use job outputs instead of artifacts for workflow_run trigger
GHES doesn't support download-artifact@v3 with github-token/run-id parameters.
Instead, fetch the image tag from the build workflow's job outputs using the
GitHub API (gh api). This avoids the artifact compatibility issue entirely.
* Enhance Google Chat notifications with branch, commit, and failure alerts
- Include branch name (hcl-main) in notification
- Include commit SHA (short format) for traceability
- Send notifications on both success and failure
- On failure, include workflow logs link
- Use if: always() to catch failures
* Explicitly trigger deploy workflow after successful build
workflow_run triggers appear unreliable on GHES - build completed successfully
but deploy didn't trigger. Instead, use GitHub API (curl) to explicitly trigger
the deploy workflow at the end of a successful build.
Uses workflow_dispatch API endpoint. Deploy workflow still supports both triggers
(workflow_dispatch and workflow_run) for redundancy. Since helm upgrades are
idempotent with unique image tags, double-triggering is harmless if workflow_run
suddenly starts working.
* Move opensource workflows to subdirectory to declutter github01 Actions UI
Moved 19 workflows that target ubuntu-latest (github.com) runners to
.github/workflows-opensource/ subdirectory. This removes them from the Actions
UI on github01 while preserving history.
Kept in .github/workflows/:
- 8 HCL-specific workflows (self-hosted runners)
- 2 dual-use workflows (pr-help, pr-welcome - detect server)
Workflows in subdirectories are not executed by GitHub Actions but git will
continue tracking them on merges from main.
* Move remaining opensource workflows and rename HCL workflows
Moved 3 additional opensource workflows (.yml extension):
- helm-deploy.yml (ubuntu-latest, DigitalOcean multi-region)
- mobile-build.yml (macos-latest, iOS builds)
- release-plz.yml (ubuntu-latest, automated releases)
Renamed HCL workflows to avoid duplicate names:
- Deploy PR Preview → Deploy PR Preview (HCL)
- Undeploy PR Preview → Undeploy PR Preview (HCL)
- PR Preview Cleanup on Close → PR Preview Cleanup (HCL)
Total moved: 22 opensource workflows
Remaining: 10 HCL-specific workflows with unique names
* Add (HCL) suffix to all HCL-specific workflow names for consistency
Added (HCL) suffix to 7 workflows:
- Daily Build Images (HCL)
- Daily Deploy to Production (HCL)
- Build PR Images (HCL)
- Build Images (Reusable) (HCL)
- Deploy PR Preview (Reusable) (HCL)
- Deploy PR Preview (HCL)
- Undeploy PR Preview (HCL)
- PR Preview Cleanup (HCL)
Excluded from renaming (dual-use workflows):
- PR Preview Help (detects github.com vs github01)
- Welcome New PR (detects github.com vs github01)
Makes it clear which workflows are HCL-specific in the Actions UI.
* Fix YAML syntax error in Google Chat notification
Changed multi-line strings to use \n escape sequences instead of literal
newlines, which were causing YAML parsing errors on line 495.
Validated all workflow files with Python YAML parser - all pass.
* Feature/UI tile 594 (#730)
* Update issue templates
* removed github template out of sync with upstream
* docs for macos
* gitignore for ide
* gitignore
* fixed client-side interface declaration
* ui-tile fix
* ui-tile fix
* Apply suggestion from @testradav
* Update dioxus-ui/src/components/attendants.rs
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* Add manual dispatch trigger to Undeploy PR Preview workflow
Added workflow_dispatch trigger with pr_number input to allow manual
undeployment from Actions UI.
Changes:
- Added workflow_dispatch trigger with pr_number input
- Determine PR number from either manual input or comment trigger
- Auto-authorize manual dispatch (assume person running it is authorized)
- Skip comment reactions/posting when manually triggered
- All comment-related steps now conditional on issue_comment event
Manual usage: Actions → Undeploy PR Preview (HCL) → Run workflow → Enter PR#
* Fix permissions: add actions: write to trigger deploy workflow
The build workflow needs actions: write (not just read) to trigger the deploy
workflow via workflow_dispatch API. The error was:
'Resource not accessible by integration'
This fix allows the daily build to automatically trigger the deploy workflow.
* fix: PR preview builds merge result instead of raw PR head
The checkout step was building the PR's head SHA directly, which meant
PRs from main into hcl-main used main's build scripts (hardcoded
securityunion/ registry) instead of hcl-main's (REGISTRY env var).
Now the workflow checks out the target branch and merges the PR into it,
matching github.com's default pull_request CI behavior. This ensures
builds reflect what the repo will actually look like post-merge.
Fails early with a clear error if there are merge conflicts.
* fix: pass pr_base_ref to reusable build workflow in pr-deploy-hcl
The deploy workflow was missing the required pr_base_ref input added
in PR #748 for merge-result builds. The build-only workflow had it
but the deploy caller was not updated.
* fix: set git identity on runner for PR merge commits
The self-hosted runner lacks a default git identity, causing
`git merge` to fail with "Committer identity unknown".
* fix: replace kubectl wait --all with rollout status to avoid pod termination race
kubectl wait --for=condition=ready pod --all races against pod deletion
during rolling updates. When a new ReplicaSet scales up and the old pod
is terminated, kubectl wait fails with "pod not found".
- daily-deploy-hcl: removed redundant wait step (rollout status already follows)
- pr-deploy-reusable-hcl: replaced wait --all with per-deployment rollout status
- pr-deploy-reusable (opensource): same fix
* Allow admit message by anyone in the meeting vs just the host
* share screen functionality update
* feat: add metrics-api base helm chart and include in daily deploy
- Create helm/metrics-api/ base chart for HCL internal deployment
(previously only existed under helm/global/us-east/)
- Right-size resource requests/limits based on actual usage:
client-metrics-api: 1m/8Mi req, 10m/32Mi lim (was 25m/64Mi, 50m/128Mi)
server-metrics-api: 1m/8Mi req, 20m/32Mi lim (was 50m/64Mi, 100m/128Mi)
- Add imagePullSecrets support for Harbor registry
- Fix NATS URL to use nats.videocall.svc.cluster.local (was nats-us-east)
- Fix fsGroup in container securityContext (only valid at pod level)
- Add Deploy Metrics API step to daily-deploy-hcl.yaml workflow
- Add rollout verification for client-metrics-api and server-metrics-api
* feat: add SERVICE_VERSION_URLS to daily and PR preview deploy workflows
Daily deploy points to videocall-websocket, videocall-webtransport-lb,
and videocall-dioxus-ui services in the videocall namespace.
PR preview uses per-PR service names (websocket-pr-N, dx-pr-N, ui-pr-N)
with no webtransport since it's disabled in preview environments.
* fix: bump relay CPU/memory limits to prevent CFS throttling
WebSocket relay had 50m CPU / 10Mi memory limits, causing CFS throttling
during packet forwarding bursts (22-43ms jitter, up to 128 gaps/10s).
Bump both relays to 500m/256Mi limits matching CC7 production values
that show 7-11ms jitter and 0 gaps.
* Renaming your user on the client causes you to rejoin the meeting
* Fix/638 microphone and camera selectors to be displayed under a settings icon (#744)
* Microphone and camera selectors to be displayed under a settings icon
* Fix import in dioxus-ui/src/components/host.rs
* Fix tests
---------
Co-authored-by: Piliushyna Palina <piliushyna.polina@gmail.com>
* wrap both updates in a single transaction
* share screen functionality update
* yew-ui: add on_display_name_changed to client options
* Add the admit toggle to the meeting settings
* fix: remove duplicate test function and unused mut warnings
* fix dioxus-ui/webdriver.json
* Delete yew-ui directory
* chore: retrigger merge check after yew-ui deletion
* Fix dioxus-ui/tests/support/mod.rs and dioxus-ui/webdriver.json
* Fix dioxus-ui/webdriver.json
* touch
* Fix dioxus-ui build: missing client_cell and malformed opacity in attendants.rs
- Add `let client_cell = client_for_reconnect.clone()` in on_peer_joined callback
to fix E0425 (client_cell not found) and cascading E0282 (type inference)
- Fix empty opacity expression `{ };` in admitted_can_admit toggle div by
pre-computing the value based on waiting_room_toggle state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove Yew UI from HCL workflows; Dioxus is now the default app
Yew UI has been removed from the project. This removes all references
to videocall-web-ui image builds, deployments, and hostname routing.
Dioxus UI now deploys to the primary hostname (app / pr${SLOT}) instead
of the -dx suffix.
* Fix host and attendants re-renders on audio level changes + refactor webtransport writes (#816)
* refactor webtransport write methods
* pass audio level via signal as opposed to re-rendering the component
* avoid host component re-render
* Update share screen functionality (#817)
* Feature/UI tile 594 (#730)
* Update issue templates
* removed github template out of sync with upstream
* docs for macos
* gitignore for ide
* gitignore
* fixed client-side interface declaration
* ui-tile fix
* ui-tile fix
* Apply suggestion from @testradav
* Update dioxus-ui/src/components/attendants.rs
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* share screen functionality update
* share screen functionality update
* save
* more lint
* remove admitter can admit, which has nothing to do with this feature
* revert unrelated toast suppression logic that is not related to this feature
* restore change name button
* remove dead css
---------
Co-authored-by: ilyatarmanau-lgtm <ilya.tarmanau@hcl-software.com>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
Co-authored-by: Alena Melnikava [External] <alena.melnikava@prod.hclpnp.com>
Co-authored-by: Alena-Melnikava <Alena.Melnikava@hcl-software.com>
* helm: relay Prometheus annotations, lower requests, Dioxus UI chart (#757)
* helm: add Prometheus annotations, lower relay requests, add Dioxus UI chart
- Add prometheus.io scrape annotations to WS and WT relay pods
- Lower relay CPU/memory requests (limits unchanged) to prevent
scheduling deadlocks on single-node clusters
- Add Chart.yaml for Dioxus UI us-east region overlay
* helm: remove defunct Singapore WS/WT URLs from us-east videocall-ui
Singapore region was dropped; client was still configured to attempt
connections to dead websocket-singapore and webtransport-singapore
endpoints.
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* select websocket/webtransport from settings
* protocol switch in diagnostics
* autoreload, after confirmation, when changing protocols
* e2e tests
* unit tests
* fix test workflow
* Fix dropdown not reverting on cancel; extract shared confirm-and-reload helper
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: Dario A Lencina-Talarico <darioalessandrolencina@gmail.com>
Co-authored-by: Jay Boyd <jay.boyd@hcl.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Jay Boyd <jboyd01@gmail.com>
Co-authored-by: ilyatarmanau-lgtm <ilya.tarmanau@hcl-software.com>
Co-authored-by: Alena Melnikava [External] <alena.melnikava@prod.hclpnp.com>
Co-authored-by: Piliushyna Palina <piliushyna.polina@gmail.com>
Co-authored-by: Alena-Melnikava <Alena.Melnikava@hcl-software.com>
Co-authored-by: palina-piliushyna <palina.piliushyna@hcl-software.com>
Co-authored-by: piliushyna <130133442+piliushyna@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove contribute to GitHub Button
* lint
* initial workflow
* review and harden
* concurrent image builds, stronger JWT entrophy
* refactor: migrate PR workflows to github-script and fix concurrency
Migrate all HCL PR preview workflows from raw curl commands to
actions/github-script@v7 for better maintainability, error handling,
and consistency with opensource workflows.
## Changes
### 1. Concurrency Groups (All Workflows)
- Changed from global lock to per-PR concurrency
- Before: Only 1 PR could build/deploy at a time (global bottleneck)
- After: Multiple PRs can work simultaneously without conflicts
- pr-deploy-hcl.yaml: pr-preview-slot-allocator-hcl → pr-deploy-{PR#}-hcl
- pr-build-images-hcl.yaml: (added) pr-build-images-{PR#}-hcl
- pr-undeploy-hcl.yaml: pr-preview-slot-allocator-hcl → pr-undeploy-{PR#}-hcl
- pr-cleanup-hcl.yaml: pr-preview-slot-allocator-hcl → pr-cleanup-{PR#}-hcl
### 2. Migrated 24 curl Commands to github-script
- pr-deploy-hcl.yaml: 9 curl commands converted
- pr-build-images-hcl.yaml: 8 curl commands converted
- pr-undeploy-hcl.yaml: 6 curl commands converted
- pr-cleanup-hcl.yaml: 1 curl command converted
Benefits:
- No manual JSON escaping required
- Automatic GitHub Enterprise API detection
- Better error handling and logging
- Type-safe API calls
- Uses context.payload.comment.id directly (no passing via outputs)
- Eliminates actionlint security warning about untrusted input
### 3. Fixed Missing PR Comments (pr-deploy-hcl.yaml)
- Added build-success job to comment when images are built
- Enhanced initial comment to mention both build and deploy phases
- Fixed build-failure job to use github-script instead of curl
- All PR comments now work correctly for /build-and-deploy workflow
### 4. Fixed Deploy Validation (pr-deploy-reusable-hcl.yaml)
- Strip ANSI color codes from kubectl cluster-info output before grep
- Prevents validation failure when kubectl outputs color codes
### 5. Created Reusable Build Workflow
- Added pr-build-images-reusable-hcl.yaml (158 lines)
- Parallel builds for 3 images (5-7 min vs 15-20 min sequential)
- Timestamped log directories with automatic cleanup
- Both pr-build-images-hcl.yaml and pr-deploy-hcl.yaml now use it
- Eliminates code duplication between workflows
### 6. Added actionlint Configuration
- Created .github/actionlint.yaml to recognize custom "docker" runner label
- Enables local workflow validation before pushing
## Testing
All workflows validated with actionlint (0 errors).
Ready to test:
- /build-images - parallel builds with proper comments
- /deploy - deploys with proper comments
- /build-and-deploy - complete flow with all comments
- /undeploy - cleanup with proper comments
- Multiple PRs can now work simultaneously
Refs: docs/HCL_WORKFLOW_MIGRATION_2026-02-25.md
Refs: docs/HCL_BUILD_PARALLELIZATION_PLAN.md
* fix: remove GITHUB_TOKEN from reusable workflow secrets
GITHUB_TOKEN is automatically available to reusable workflows and cannot
be passed explicitly as a secret - it's a reserved system name.
Removed from:
- pr-build-images-reusable-hcl.yaml (secret definition)
- pr-deploy-hcl.yaml (secret passing)
- pr-build-images-hcl.yaml (secret passing)
* fix: add pull-requests write permission to pr-cleanup workflow
The workflow needs pull-requests: write permission to comment on PRs
when using actions/github-script@v7.
Error was: 'HttpError: Resource not accessible by integration'
Without this permission, the Comment on cleanup failure job cannot
create comments using the GitHub API.
* fix: strip ANSI color codes in undeploy and cleanup workflows
Applied the same kubectl cluster-info ANSI color code fix to:
- pr-undeploy-hcl.yaml
- pr-cleanup-hcl.yaml
These workflows were missing the sed command to strip ANSI codes before
grep, causing validation failures with: 'Process completed with exit code 1'
The fix was already applied to pr-deploy-reusable-hcl.yaml but was
overlooked in the other two workflows that validate kubectl access.
All three workflows now use:
echo "${CLUSTER_INFO}" | sed 's/\x1b\[[0-9;]*m//g' | grep -F "..."
* HCL Internal - Accessing vc2 aws instance
* add deployment url
* ssh clarification
* fix: hcl pr-cleanup and pr-undeploy workflow reliability fixes
Root cause fix: kubectl exits 1 when jsonpath accesses items[0] on an
empty list (PR was never deployed). With bash -euo pipefail this killed
the Find deployment slot step before the [ -z "$SLOT" ] check could run,
causing the cleanup job to always fail on undeployed PRs. Fix: add
|| true to both the cleanup and undeploy SLOT queries, matching the
pattern already used in pr-deploy-reusable-hcl.yaml.
Additional fixes:
- Add || true + empty-check guard to PG_PASSWORD retrieval in both
workflows; previously a missing postgres-credentials secret would
cause a hard failure with no error message
- Add comment-success job to pr-cleanup-hcl.yaml so the PR receives
a comment when automatic cleanup actually removes a slot; previously
only failures were reported
- Add job outputs (slot_existed, slot) to cleanup job to support the
comment-success condition
- Convert last raw curl reaction in pr-undeploy-hcl.yaml comment-failure
job to actions/github-script@v7, matching all other steps in the file
* feat: deploy Dioxus UI alongside Yew in HCL PR previews
Each PR preview slot now deploys both the Yew UI (pr{N}.preview...) and the
Dioxus UI (pr{N}-dx.preview...) so reviewers can test both frontends in the
same preview environment.
Changes:
- helm/videocall-ui: add imagePullSecrets support so Harbor pull secret works
- pr-deploy-reusable-hcl: add Deploy Dioxus UI step using helm/videocall-ui/
- pr-deploy-reusable-hcl: extend CORS_ALLOWED_ORIGIN and ALLOWED_REDIRECT_URLS
on the Meeting API to include both Yew and Dioxus preview origins
- pr-deploy-reusable-hcl: add videocall-dioxus-ui to verify-images check
- pr-deploy-reusable-hcl: bump pod quota 10→12 for extra pod per slot
- pr-deploy-reusable-hcl: update success comment to list both UI URLs
- pr-build-images-hcl / pr-deploy-hcl: add videocall-dioxus-ui to build
success image list comments
- cut_build_push_ui.sh: remove spurious second docker push of Yew image
* fix: escape commas in helm --set values for CORS_ALLOWED_ORIGIN and ALLOWED_REDIRECT_URLS
* fix: set COOKIE_NAME per preview slot to prevent session cookie collision
* concept car tweaks
* Add daily build and deployment pipeline for HCL production
Implements automated daily builds and deployments to the videocall namespace (production):
- daily-build-images-hcl.yaml: Builds 3 images daily at midnight Eastern with timestamp tags (daily-YYYY-MM-DD-HHMM)
- videocall-media-server (WebSocket/WebTransport)
- videocall-meeting-api (REST backend)
- videocall-dioxus-ui (WASM frontend)
- daily-deploy-hcl.yaml: Deploys to production namespace with auto-trigger after successful builds
- Supports manual deployment with specific image tags for rollbacks
- Deploys to *.videocall.fnxlabs.com domains
- Enables WebTransport with NodePort 52311
- Verifies images exist in Harbor before deploying
- cut_build_push_ui.sh: Removed deprecated Yew UI build, now only builds Dioxus UI
Build and deploy workflows can be manually triggered via GitHub Actions UI. First scheduled build will run tomorrow at midnight Eastern.
* Keep build logs for 24 hours instead of deleting on success
Updated log retention for both daily and PR preview builds:
- Auto-cleanup changed from 2 hours to 24 hours
- Logs now kept even on successful builds (not just failures)
- Improves audit trail and debugging capability for production builds
* Fix image tag mismatch between build and deploy workflows
The deploy workflow was generating a NEW timestamp instead of using the tag from the build workflow, causing 404 errors when checking Harbor.
Solution: Pass the image tag via artifact
- Build workflow saves tag to artifact (image-tag.txt)
- Deploy workflow downloads artifact and reads the exact tag
- Ensures build and deploy use identical tags
This fixes the issue where builds succeeded but deploys failed due to tag mismatch (e.g., build used daily-2026-03-10-1643 but deploy looked for daily-2026-03-10-1647).
Manual deploys still work - just specify the tag via workflow_dispatch input.
* Update home.rs
* Update home.rs
* Use existing individual TLS certificates instead of wildcard
The wildcard certificate (videocall-wildcard-tls) is stuck pending due to HCL's internal DNS (10.134.49.13/16) not propagating the _acme-challenge TXT record.
Solution: Use existing per-service TLS certificates:
- webtransport.videocall.fnxlabs.com → webtransport-tls
- websocket.videocall.fnxlabs.com → websocket-tls
- api.videocall.fnxlabs.com → api-tls
- app-dx.videocall.fnxlabs.com → dioxus-ui-tls (cert-manager auto-create)
Updated secret verification to check for individual TLS secrets instead of wildcard.
* Fix WebTransport deployment configuration
Added missing critical environment variables for WebTransport server:
- LISTEN_URL=0.0.0.0:52311 (port to listen on)
- CERT_PATH=/certs/tls.crt (TLS certificate path)
- KEY_PATH=/certs/tls.key (TLS key path)
- TOKIO_WORKER_THREADS=1
- TOKIO_BLOCKING_THREADS=2
- Updated RUST_LOG to reduce verbosity (warn level)
- Changed NATS_URL to use short form (nats:4222)
- Added command: webtransport_server
- Added tlsSecret and certificateDomain settings
- Added service.port and service.healthPort
This matches the working values file used in manual deployments.
* Add Google Chat notification on successful deployment
Sends a notification to Google Chat when production deployment completes successfully:
- Includes deployment tag
- Includes app URL (https://app-dx.videocall.fnxlabs.com)
- Only triggers on successful deployment
- Non-fatal if notification fails (won't break workflow)
* Downgrade artifact actions to v3 for GHES compatibility
GitHub Enterprise Server doesn't support actions/upload-artifact@v4 or
actions/download-artifact@v4. Downgrading to v3 to fix artifact upload/download
between daily build and deploy workflows.
* Use job outputs instead of artifacts for workflow_run trigger
GHES doesn't support download-artifact@v3 with github-token/run-id parameters.
Instead, fetch the image tag from the build workflow's job outputs using the
GitHub API (gh api). This avoids the artifact compatibility issue entirely.
* Enhance Google Chat notifications with branch, commit, and failure alerts
- Include branch name (hcl-main) in notification
- Include commit SHA (short format) for traceability
- Send notifications on both success and failure
- On failure, include workflow logs link
- Use if: always() to catch failures
* Explicitly trigger deploy workflow after successful build
workflow_run triggers appear unreliable on GHES - build completed successfully
but deploy didn't trigger. Instead, use GitHub API (curl) to explicitly trigger
the deploy workflow at the end of a successful build.
Uses workflow_dispatch API endpoint. Deploy workflow still supports both triggers
(workflow_dispatch and workflow_run) for redundancy. Since helm upgrades are
idempotent with unique image tags, double-triggering is harmless if workflow_run
suddenly starts working.
* Move opensource workflows to subdirectory to declutter github01 Actions UI
Moved 19 workflows that target ubuntu-latest (github.com) runners to
.github/workflows-opensource/ subdirectory. This removes them from the Actions
UI on github01 while preserving history.
Kept in .github/workflows/:
- 8 HCL-specific workflows (self-hosted runners)
- 2 dual-use workflows (pr-help, pr-welcome - detect server)
Workflows in subdirectories are not executed by GitHub Actions but git will
continue tracking them on merges from main.
* Move remaining opensource workflows and rename HCL workflows
Moved 3 additional opensource workflows (.yml extension):
- helm-deploy.yml (ubuntu-latest, DigitalOcean multi-region)
- mobile-build.yml (macos-latest, iOS builds)
- release-plz.yml (ubuntu-latest, automated releases)
Renamed HCL workflows to avoid duplicate names:
- Deploy PR Preview → Deploy PR Preview (HCL)
- Undeploy PR Preview → Undeploy PR Preview (HCL)
- PR Preview Cleanup on Close → PR Preview Cleanup (HCL)
Total moved: 22 opensource workflows
Remaining: 10 HCL-specific workflows with unique names
* Add (HCL) suffix to all HCL-specific workflow names for consistency
Added (HCL) suffix to 7 workflows:
- Daily Build Images (HCL)
- Daily Deploy to Production (HCL)
- Build PR Images (HCL)
- Build Images (Reusable) (HCL)
- Deploy PR Preview (Reusable) (HCL)
- Deploy PR Preview (HCL)
- Undeploy PR Preview (HCL)
- PR Preview Cleanup (HCL)
Excluded from renaming (dual-use workflows):
- PR Preview Help (detects github.com vs github01)
- Welcome New PR (detects github.com vs github01)
Makes it clear which workflows are HCL-specific in the Actions UI.
* Fix YAML syntax error in Google Chat notification
Changed multi-line strings to use \n escape sequences instead of literal
newlines, which were causing YAML parsing errors on line 495.
Validated all workflow files with Python YAML parser - all pass.
* Feature/UI tile 594 (#730)
* Update issue templates
* removed github template out of sync with upstream
* docs for macos
* gitignore for ide
* gitignore
* fixed client-side interface declaration
* ui-tile fix
* ui-tile fix
* Apply suggestion from @testradav
* Update dioxus-ui/src/components/attendants.rs
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* Add manual dispatch trigger to Undeploy PR Preview workflow
Added workflow_dispatch trigger with pr_number input to allow manual
undeployment from Actions UI.
Changes:
- Added workflow_dispatch trigger with pr_number input
- Determine PR number from either manual input or comment trigger
- Auto-authorize manual dispatch (assume person running it is authorized)
- Skip comment reactions/posting when manually triggered
- All comment-related steps now conditional on issue_comment event
Manual usage: Actions → Undeploy PR Preview (HCL) → Run workflow → Enter PR#
* Fix permissions: add actions: write to trigger deploy workflow
The build workflow needs actions: write (not just read) to trigger the deploy
workflow via workflow_dispatch API. The error was:
'Resource not accessible by integration'
This fix allows the daily build to automatically trigger the deploy workflow.
* fix: PR preview builds merge result instead of raw PR head
The checkout step was building the PR's head SHA directly, which meant
PRs from main into hcl-main used main's build scripts (hardcoded
securityunion/ registry) instead of hcl-main's (REGISTRY env var).
Now the workflow checks out the target branch and merges the PR into it,
matching github.com's default pull_request CI behavior. This ensures
builds reflect what the repo will actually look like post-merge.
Fails early with a clear error if there are merge conflicts.
* fix: pass pr_base_ref to reusable build workflow in pr-deploy-hcl
The deploy workflow was missing the required pr_base_ref input added
in PR #748 for merge-result builds. The build-only workflow had it
but the deploy caller was not updated.
* fix: set git identity on runner for PR merge commits
The self-hosted runner lacks a default git identity, causing
`git merge` to fail with "Committer identity unknown".
* fix: replace kubectl wait --all with rollout status to avoid pod termination race
kubectl wait --for=condition=ready pod --all races against pod deletion
during rolling updates. When a new ReplicaSet scales up and the old pod
is terminated, kubectl wait fails with "pod not found".
- daily-deploy-hcl: removed redundant wait step (rollout status already follows)
- pr-deploy-reusable-hcl: replaced wait --all with per-deployment rollout status
- pr-deploy-reusable (opensource): same fix
* Allow admit message by anyone in the meeting vs just the host
* share screen functionality update
* feat: add metrics-api base helm chart and include in daily deploy
- Create helm/metrics-api/ base chart for HCL internal deployment
(previously only existed under helm/global/us-east/)
- Right-size resource requests/limits based on actual usage:
client-metrics-api: 1m/8Mi req, 10m/32Mi lim (was 25m/64Mi, 50m/128Mi)
server-metrics-api: 1m/8Mi req, 20m/32Mi lim (was 50m/64Mi, 100m/128Mi)
- Add imagePullSecrets support for Harbor registry
- Fix NATS URL to use nats.videocall.svc.cluster.local (was nats-us-east)
- Fix fsGroup in container securityContext (only valid at pod level)
- Add Deploy Metrics API step to daily-deploy-hcl.yaml workflow
- Add rollout verification for client-metrics-api and server-metrics-api
* feat: add SERVICE_VERSION_URLS to daily and PR preview deploy workflows
Daily deploy points to videocall-websocket, videocall-webtransport-lb,
and videocall-dioxus-ui services in the videocall namespace.
PR preview uses per-PR service names (websocket-pr-N, dx-pr-N, ui-pr-N)
with no webtransport since it's disabled in preview environments.
* fix: bump relay CPU/memory limits to prevent CFS throttling
WebSocket relay had 50m CPU / 10Mi memory limits, causing CFS throttling
during packet forwarding bursts (22-43ms jitter, up to 128 gaps/10s).
Bump both relays to 500m/256Mi limits matching CC7 production values
that show 7-11ms jitter and 0 gaps.
* Renaming your user on the client causes you to rejoin the meeting
* Fix/638 microphone and camera selectors to be displayed under a settings icon (#744)
* Microphone and camera selectors to be displayed under a settings icon
* Fix import in dioxus-ui/src/components/host.rs
* Fix tests
---------
Co-authored-by: Piliushyna Palina <piliushyna.polina@gmail.com>
* wrap both updates in a single transaction
* share screen functionality update
* yew-ui: add on_display_name_changed to client options
* Add the admit toggle to the meeting settings
* fix: remove duplicate test function and unused mut warnings
* fix dioxus-ui/webdriver.json
* initial foundation ID support
* Delete yew-ui directory
* chore: retrigger merge check after yew-ui deletion
* WIP - token exchange in UI
* UI token exchange, use access token instead of id token with API
* track session instance id on reconnection
* Update VC2_DEPLOYMENT_RUNBOOK.md
* integration tests
* Fix dioxus-ui/tests/support/mod.rs and dioxus-ui/webdriver.json
* Fix dioxus-ui/webdriver.json
* Refactor session eviction from server-assigned previous_session_id to client-generated instance_id UUID
* touch
* Fix dioxus-ui build: missing client_cell and malformed opacity in attendants.rs
- Add `let client_cell = client_for_reconnect.clone()` in on_peer_joined callback
to fix E0425 (client_cell not found) and cascading E0282 (type inference)
- Fix empty opacity expression `{ };` in admitted_can_admit toggle div by
pre-computing the value based on waiting_room_toggle state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove Yew UI from HCL workflows; Dioxus is now the default app
Yew UI has been removed from the project. This removes all references
to videocall-web-ui image builds, deployments, and hostname routing.
Dioxus UI now deploys to the primary hostname (app / pr${SLOT}) instead
of the -dx suffix.
* storage tweaks for dioxus-ui
* fix webtransport
* update WT listen url port
* Fix host and attendants re-renders on audio level changes + refactor webtransport writes (#816)
* refactor webtransport write methods
* pass audio level via signal as opposed to re-rendering the component
* avoid host component re-render
* Update share screen functionality (#817)
* Feature/UI tile 594 (#730)
* Update issue templates
* removed github template out of sync with upstream
* docs for macos
* gitignore for ide
* gitignore
* fixed client-side interface declaration
* ui-tile fix
* ui-tile fix
* Apply suggestion from @testradav
* Update dioxus-ui/src/components/attendants.rs
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* share screen functionality update
* share screen functionality update
* save
* more lint
* remove admitter can admit, which has nothing to do with this feature
* revert unrelated toast suppression logic that is not related to this feature
* restore change name button
* remove dead css
---------
Co-authored-by: ilyatarmanau-lgtm <ilya.tarmanau@hcl-software.com>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
Co-authored-by: Alena Melnikava [External] <alena.melnikava@prod.hclpnp.com>
Co-authored-by: Alena-Melnikava <Alena.Melnikava@hcl-software.com>
* helm: relay Prometheus annotations, lower requests, Dioxus UI chart (#757)
* helm: add Prometheus annotations, lower relay requests, add Dioxus UI chart
- Add prometheus.io scrape annotations to WS and WT relay pods
- Lower relay CPU/memory requests (limits unchanged) to prevent
scheduling deadlocks on single-node clusters
- Add Chart.yaml for Dioxus UI us-east region overlay
* helm: remove defunct Singapore WS/WT URLs from us-east videocall-ui
Singapore region was dropped; client was still configured to attempt
connections to dead websocket-singapore and webtransport-singapore
endpoints.
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl.com>
* select websocket/webtransport from settings
* protocol switch in diagnostics
* autoreload, after confirmation, when changing protocols
* e2e tests
* unit tests
* fix test workflow
* Fix dropdown not reverting on cancel; extract shared confirm-and-reload helper
* helm: normalize base charts, fix wrappers, restore Ascend configs
Base charts:
- Add Prometheus pod annotations to all deployment templates
(websocket, webtransport, metrics-api, meeting-api)
- Neutralize defaults to OSS (securityunion images, no imagePullSecrets,
generic NATS_URL/REGION)
- Add component label to metrics-api to distinguish client-metrics
from server-stats pods in service selector
- Fix server-stats-deployment.yaml imagePullSecrets referencing wrong
values key (metricsApi instead of serverStats)
- Clean up stale rustlemania.com references and verbose comments
us-east wrappers:
- Convert metrics-api from standalone templates to base chart wrapper
- Strip duplicated values that match base chart defaults
- Fix webtransport LB annotations (move to loadBalancerAnnotations key,
add healthcheck tuning matching live deployment)
- Lower resource requests to match live values (ws: 100m/128Mi,
wt: 200m/256Mi)
- Update meeting-api CORS for Dioxus migration (remove app-dx.videocall.rs)
Ascend wrappers:
- Restore all 7 wrapper charts lost from git clean
(meeting-api, metrics-api, websocket, webtransport, videocall-ui,
nats, postgres)
- Values stripped to overrides only (HCL images, pull secrets,
Ascend-specific env vars)
* fix: pin webtransport UDP nodePort to 30056 for Ascend
Ascend uses an NGINX UDP proxy on the HAProxy edge server to forward
QUIC traffic to a fixed K8s NodePort. Helm upgrades were reassigning
random NodePorts, breaking WebTransport connectivity.
Add optional nodePort fields to the loadbalancer template and pin
the Ascend wrapper to 30056 to match the NGINX proxy config.
* set scrape interval to 15 seconds
* helm: strip duplicated base-chart defaults from Ascend wrappers
Remove values that duplicate base chart defaults from videocall-ui
(resources, runtimeConfig fields) and nats (orphaned top-level service
block that Helm ignored). Env lists must remain complete since Helm
replaces lists wholesale.
* helm: add missing Chart.lock for Ascend postgres wrapper
* helm: add comment explaining allowInsecureImages for Ascend postgres
ECR public mirror images are not signed, so image verification
must be disabled to pull bitnami/postgresql.
* helm: fix webtransport version URL to use LB service
The ClusterIP service only exposes 443/UDP (QUIC). The /version HTTP
endpoint is on port 444/TCP, only exposed by the -lb LoadBalancer service.
* helm: fix webtransport version URL to use LB service (#827)
The ClusterIP service (webtransport-us-east) only exposes 443/UDP.
The /version HTTP endpoint is on port 444/TCP, which is only exposed
by the LoadBalancer service (webtransport-us-east-lb).
* pre-PR review
* remove unused storage of preferred display name
* Updates from Jay's code review
* Move OSS Docker Hub workflow out of .github/workflows/
upload-dioxus-ui-docker-hub.yaml pushes to Docker Hub under the
securityunion/ org — it belongs to the OSS repo, not GHES. Moving it
to .github/oss-workflows/ prevents GHES from executing it.
* feat: vcprobe diagnostics, relay Prometheus metrics, health reporter enhancements
Rebased vcprobe branch onto current main. Includes:
- vcprobe crate: standalone diagnostic tool for monitoring meeting quality
- Relay server Prometheus metrics (per-room gauges, packet counters, NATS latency)
- Health reporter: quality scores, freshness gates, packet rate tracking
- Client diagnostics: decode error tracking, FpsTracker cleanup, peer monitor
- Helm: resource right-sizing, Prometheus scrape annotations, Grafana dashboards
- Monitoring docs and deployment guide
* fix: address code review issues for vcprobe-rebase
- Restore is_speaking field in HeartbeatMetadata (rebase artifact)
- Restore securityContext (runAsUser 1000) in metrics-api helm values
- Fix env-specific helm values (jboyd01 → securityunion, tag → latest)
- Extract shared metrics_responder with proper error handling
- Replace Arc<AtomicU64> with Rc<Cell<u64>> in wasm connection_manager
- Fix Unicode-unsafe truncate in vcprobe proctor
- Replace Vec with VecDeque for O(1) event removal in vcprobe state
- Move test_health_publisher from bin to example
- Refactor render/handle_key to use ViewState struct (fix clippy)
- Document relay metric cardinality risk
* fix: dashboard portability and metrics-api service label
- Add missing app.kubernetes.io/component label to client-metrics-api
service so ServiceMonitor can discover it
- Replace hardcoded namespace="videocall" with $namespace template
variable in meeting-investigation dashboard (us-east uses default ns)
- Broaden relay CPU/memory queries to match both rustlemania-* and
websocket-*/webtransport-* container naming conventions
* docs: add scrape interval and Grafana timeInterval alignment guidance
Document that Prometheus scrape interval, Grafana datasource timeInterval,
and dashboard refresh rate must all match (15s) to avoid visual gapping.
Covers both standalone Prometheus and kube-prometheus-stack setups.
* fix: address review warnings and suggestions
- Replace 35 .lock().unwrap() with .unwrap_or_else(|e| e.into_inner())
in metrics_server to recover from poisoned mutexes gracefully
- Prune pending_display_names in vcprobe tick() to prevent unbounded growth
- Remove unused _joined_at field from vcprobe Participant struct
- Hoist SystemTime::now() above peer loop in health_reporter
- Replace emoji with ASCII in vcprobe display (terminal compatibility)
- Remove stale CODE_REVIEW_METRICS_2026_03_07.md
* docs: add vcprobe README
Document CLI usage, transport modes, proctor TUI dashboard,
keyboard shortcuts, and architecture overview.
* fix: resolve browser clients showing as '?' in vcprobe log
Browser clients leave MediaPacket.user_id empty — the identity is
only in the outer PacketWrapper.user_id. Fall back to the wrapper
field when the media-level field is missing.
* fix: clean up orphaned room_members on pending departure replacement
When multiple connections for the same user disconnect in rapid
succession (e.g., election losers being dropped), each Disconnect
replaced the previous pending departure but never removed the replaced
session from room_members. This caused permanent phantom peers that
triggered PLI storms and froze real participants' video.
Bug introduced by 0844f06 (batch merge of PRs #793 et al.).
* fix: remove departed peers from health reporter on PARTICIPANT_LEFT
The PARTICIPANT_LEFT handler called delete_peer() which cleaned up
connected_peers and fps_trackers, but never removed the peer from
the health reporter's peer_health_data map. Departed peers persisted
indefinitely in health packet peer_stats, inflating the peer count
reported to metrics and vcprobe.
* docs: add vcprobe screenshots and README improvements
Add proctor dashboard, help overlay, and NATS log view screenshots.
Clarify NATS connectivity requirements for proctor mode.
* fix: reset helm resource limits/requests to main branch defaults
Resource tuning changes were mixed in with the monitoring feature work.
Reverting to main branch values to keep this branch scoped to monitoring.
* fix: restore NATS_URL to nats-us-east for us-east metrics-api
* fix: keep SessionInfo.display_name in sync with latest health packet
The display_name was only set on first packet via entry().or_insert_with().
If a user's display name resolved or changed mid-session, cleanup in
remove_session_metrics() would try to remove labels with the stale name,
leaving orphaned Prometheus series.
* fix: rustfmt and missing test fields in ConnectionManager
- Apply rustfmt to video_call_client.rs (remove_peer call style)
- Add 7 missing packet-rate fields to test helper constructor
* Added cross-server session eviction via NATS pub/sub so reconnecting clients don't trigger phantom join/leave notifications
* Quick fixes from follow-up (needs docs)
* fix: replace naive gap detector with sliding-window reorder buffer
The gap detector assumed ordered packet delivery (designed for WebSocket).
WebTransport sends each packet on a new uni stream, so QUIC delivers them
out-of-order. The old detector treated every out-of-order arrival as loss
and fired keyframe requests every 500ms, creating a PLI storm that froze
video permanently.
New SequenceTracker uses a u64 bitfield to track 64 recent sequence
positions. Out-of-order arrivals within the window set a bit — no loss
flagged. Loss is only declared when unseen bits shift off the window edge.
Keyframe requests now use exponential backoff (1s→2s→4s→8s cap) with a
max of 5 unanswered requests before giving up.
Fixes #814
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: critical ordering bug in track_sequence + defensive improvements
- Swap on_keyframe/record_seq order: record_seq was called after
on_keyframe, re-adding losses that the keyframe just cleared.
Now record_seq runs first, then on_keyframe resets lost_count.
- Use u64 gap comparison before narrowing to u32 shift to prevent
truncation on astronomically large sequence gaps.
- Remove misleading .min(64) on count_zeros (already bounded by u64).
- Fix stale comment referencing "sequence gap" instead of "packet loss".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use persistent uni stream for WebTransport instead of per-packet streams
Client and server both opened a new QUIC unidirectional stream for every
reliable packet. QUIC does not guarantee ordering across streams, so
packets arrived out-of-order at the receiver — triggering the gap
detector and causing keyframe request storms.
Now both sides lazily open a single persistent uni stream and reuse it
for all reliable sends. QUIC guarantees ordering within a stream, so
packets arrive in order. On write error the stream is dropped and a
fresh one is created on the next send.
Client: WebTransportTask stores a PersistentStream (stream + writer)
in Rc<RefCell<...>>. send_on_persistent_stream() replaces per-packet
send_unidirectional_stream() in the WebMedia impl.
Server: bridge.rs spawn_writer keeps Option<SendStream> across the
loop. Opens once, writes all UniStream packets, retries on error.
Fixes #814
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add persistent stream ordering test for WebTransport bridge
Adds test_persistent_stream_packet_ordering: sends 10 sequenced MEDIA
packets through the bridge writer and verifies they arrive at the
receiver in order. This validates the persistent uni stream change —
packets on a single QUIC stream are guaranteed in-order delivery.
Also fixes test_relay_packet_impl receive logic to work with persistent
streams (read incrementally instead of read_to_end which blocks on a
stream that never finishes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: start video and screen quality at medium tier instead of lowest
Video now starts at medium (480p/25fps) and screen share at medium
(720p/10fps) instead of minimal/low. The PID controller adapts up
or down from there based on actual network conditions.
The previous lowest-tier starting point was a workaround for the
keyframe storm (issue #814) which made the PID controller think the
network was worse than reality. With the storm fixed, starting at
medium gives usable quality from the first frame.
Fixes #805, fixes #808
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add 1080p video tier and start both video and screen at 1080p
Added full_hd tier (1920x1080/30fps/2500kbps) to VIDEO_QUALITY_TIERS.
Both video and screen share now default to 1080p — the expected baseline
for modern video conferencing. The PID controller steps down if bandwidth
is constrained.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: start video and screen at 720p, adapt up to 1080p or down from there
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add missing instance_id to test constructors, fix u32 comparison warning
Two test helpers for ConnectionManagerOptions were missing the
instance_id field added in the session eviction work. Also removed
a useless u32 >= 0 assertion that clippy flagged as always-true.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update WebTransport tests to work with persistent uni stream
The server bridge now uses a single persistent uni stream instead of
per-packet streams. Tests that called accept_uni() per packet hung
forever waiting for streams that never arrive. Fixed by:
- wait_for_session_ready now returns the accepted RecvStream so callers
can reuse it for subsequent reads
- Relay and ordering tests pass the persistent stream handle through
instead of trying to accept a new stream
- read_more_data handles incremental reads from the persistent stream
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove test assertion for dropped video_packets_buffered metric
The VIDEO_PACKETS_BUFFERED metric was removed as part of cardinality
reduction, but the test still asserted its existence.
* fix: add length-prefix framing to persistent stream, revert client to per-packet
The persistent stream without framing broke all WebTransport media:
server reader called read_to_end on a stream that never finishes,
client reader waited for done signal that never came.
Fix: client sender reverted to per-packet uni streams (server reader
handles these). Server writer keeps persistent stream but now prepends
4-byte BE length header before each packet. Client reader rewritten to
parse length-prefixed frames with fallback for legacy per-packet streams.
Removed unused PersistentStream/send_on_persistent_stream from
videocall-transport. Updated test helpers to use read_length_prefixed_frame.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Changed video default from high (720p/30fps/1500kbps) to medium (480p/25fps/600kbps)
* 8 levels of adapation video quality
* 8 levels of adapation video quality
* After 5 unanswered PLIs (backoff: 1s→2s→4s→8s→8s), the client now switches to a slow retry every 15 seconds instead of giving up permanently
* Changed seen_bits initialization from 1 to u64::MAX on first packet
* Capped full_hd max bitrate from 4000 to 2500 kbps
* Added warning comment to spawn_unistream_reader documenting the per-packet stream assumption
* NATS eviction publish moved from JoinRoom to ActivateConnection
* Replaced two to_vec() allocations per frame (~80/sec/peer) with a single drain() + skip()
* Copies JS Uint8Array directly into the target vec instead of allocating a temp vec and appending
* Max bitrates now decrease monotonically: 2500 → 2500 → 2000 → 1500 → 1000 → 600 → 400 → 250.
* Silent truncation replaced with try_into().expect()
* Added session_instance: HashMap<SessionId, String> reverse map
* generate_instance_id() now uses crypto.getRandomValues() for CSPRNG with a Math.random() fallback for worker environments
* fix: default OAuth to server-side flow, make PKCE opt-in via oauthFlow config
The OIDC/PKCE PR (#266) unconditionally replaced the server-side OAuth
flow with client-side PKCE when oauthEnabled was true. This breaks
providers like Google that require client_secret for token exchange
(not available in the browser).
Add an oauthFlow config field: set to "pkce" for client-side PKCE,
leave empty/absent for server-side OAuth (the default). A single
is_pkce_flow() predicate gates all PKCE-specific code paths in auth.rs
and the Login component.
* fix: auth extractor falls back to session cookie when no Bearer token present
When JWKS is configured (external OAuth provider), the auth extractor
previously required a Bearer token and rejected session cookies entirely.
This broke server-side OAuth where the backend issues an HttpOnly cookie
after exchanging the authorization code — the browser sends the cookie
but no Bearer header.
Now the extractor tries Bearer + JWKS first, then falls through to the
session cookie path if no Bearer token is present. This supports both
server-side OAuth (cookie) and client-side PKCE (Bearer) in the same
deployment.
* fix: use Cookie auth mode for server-side OAuth in meeting_api_client
meeting_api_client() unconditionally checked sessionStorage for Bearer
tokens before falling back to Cookie mode. This broke server-side OAuth
because: (1) stale tokens from prior PKCE attempts caused invalid Bearer
requests, and (2) even without stale tokens, the Bearer-first logic was
wrong for server-side flow where the session lives in an HttpOnly cookie.
Gate Bearer token lookup behind is_pkce_flow(). For server-side OAuth
(and non-OAuth deployments), always use AuthMode::Cookie so fetch
includes credentials: 'include' and the session cookie is sent.
* per peer metrics initial
* remove initial phantom user from session assigned for the host local user
---------
Co-authored-by: Antonio Estrada <antonio.estrada@hcl-software.com>
Co-authored-by: Jay Boyd <jboyd01@gmail.com>
Co-authored-by: Jay Boyd <jay.boyd@hcl.com>
Co-authored-by: ilyatarmanau-lgtm <ilya.tarmanau@hcl-software.com>
Co-authored-by: ilya <ilya@MacBook-Pro-ilya.local>
Co-authored-by: Alena Melnikava [External] <alena.melnikava@prod.hclpnp.com>
Co-authored-by: Piliushyna Palina <piliushyna.polina@gmail.com>
Co-authored-by: Alena-Melnikava <Alena.Melnikava@hcl-software.com>
Co-authored-by: palina-piliushyna <palina.piliushyna@hcl-software.com>
Co-authored-by: piliushyna <130133442+piliushyna@users.noreply.github.com>
Co-authored-by: Chester Moses <chester.moses@hcl-software.com>
Co-authored-by: Dario A Lencina-Talarico <darioalessandrolencina@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…esce flag Addresses review findings on PR security-union#817 (Smatter chat integration): - jmap_service: send_message() hand-rolled JSON escaping (replace '\'/'"') emitted raw control characters (newline/tab/NUL), producing malformed JSON. Extract a pure default_body_values() helper that builds the bodyValues payload via serde_json so all characters escape correctly. Wire shape is byte-identical for escape-free input. Add 5 unit tests pinning the contract (round-trip via serde_json parse). - global.css: remove the display:flex; gap:10px added to .meeting-page. The chat sidebar is position:fixed so flex/gap on the parent are inert for it but risk reflowing the existing video grid. Reverted to the prior position/inset/size/overflow rule. - chat_sidebar: clear delta_pending on the unseeded-token break in the SSE delta loop, mirroring the error-path cleanup, so a coalesced pending flag from the unseeded window doesn't trigger a spurious extra delta-fetch on the next event.
…ocall-integrate Smatter videocall integrate

Some screen share functionality was updated:
Type of Change
Testing
Other