Skip to content

Go Live Window Refactor.#5958

Open
michelinewu wants to merge 71 commits into
masterfrom
mw_gl_ui_3
Open

Go Live Window Refactor.#5958
michelinewu wants to merge 71 commits into
masterfrom
mw_gl_ui_3

Conversation

@michelinewu

@michelinewu michelinewu commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Go Live Window Refactor

Summary

A broad refactor of the Go Live window: rebuilt UI components, a new theming system, consolidated feature-availability logic, and a batch of correctness fixes around Stream Shift, dual output, and per-platform settings. The goal is a cleaner, more consistent Go Live experience with a single, predictable source of truth for what is enabled/disabled/hidden across the many user states (Ultra vs. non-Ultra, dual output, Stream Shift, mid-stream, Patreon, etc.). The new theming system should allow for faster UI updates since the Go Live Window themes are now independent.

What changed

UI components

  • Reworked the core Go Live components: GoLiveWindow, GoLiveSettings, DestinationSwitchers, PlatformSettings, PrimaryChatSwitcher, EditStreamWindow.
  • Added new components: SwitcherCard, CustomFieldsCheckbox, shared AnimatedWrapper, and refactored shared Tabs, RadioInput, InfoBadge, Tooltip, and ButtonHighlighted.
  • Removed the obsolete AdvancedSettingsSwitch.
  • Refactored TikTok tabs into a reusable "filled tabs" subtype and added missing Twitch fields to the stream info form.

Theming & styling

  • Added dedicated Go Live theme stylesheets:
    golive-day-theme, golive-night-theme, golive-prime-dark,
    golive-prime-light (lazy-loaded), plus updates to themes.g.less,
    colors.less, and a new top-level go-live.less.
  • Migrated component styling into co-located *.m.less modules and fixed a range of styling issues: platform logo colors, Ultra button/banner styling, primary button hover colors, recording tooltip, Stream Shift toggle alignment (non-Ultra) TikTok form, Edit Stream margins, and non-Ultra settings height.

Stream Shift

  • Moved the Stream Shift "is live" check into the Go Live window and consolidated Stream Shift toggling into a single path.
  • Refactored the is-live handling to remove a race condition; fixed tooltip and non-Ultra toggle behavior.
  • Restored the Patreon / Stream Shift limitation.

Platform & dual-output fixes

  • Fixed Twitch dual-stream enhanced broadcasting state and the YouTube dual-stream UI race condition.
  • Clear YouTube monetization on broadcast change without incorrectly updating state.
  • Fixed dual output mode handling and the display selector interaction with Patreon and Stream Shift.
  • Surfaced previously swallowed errors for Patreon and Kick; added error handling for platform toggling and corrected enable/disable logic for non-Ultra users.

Recording / AI Highlighter

  • Restyled the Recording switcher and AI Highlighter toggle; consolidated the recording disabled/tooltip states.

Services

  • Updates across streaming, streaming-view, restream, customization, user, platform services (patreon, kick, youtube), and settings services to support the above.

Tests

  • Added/updated Go Live window tests, AI Highlighter tests, and Stream Shift tests (events + live status), plus supporting test helpers for radio/form modules and streaming.

Notes for reviewers

  • Large diff is dominated by styling migration (~20 .less files) and the four new theme stylesheets; the substantive logic changes are concentrated in the Go Live components, useGoLiveSettings, and the streaming/platform services.
  • Please pay particular attention to the Stream Shift consolidation and the dual-output / non-Ultra enable-disable paths, which touch cross-window state.

@bundlemon

bundlemon Bot commented Jun 3, 2026

Copy link
Copy Markdown

BundleMon

Files updated (2)
Status Path Size Limits
renderer.(hash).js
10.35MB (+2.49MB +31.75%) -
vendors~renderer.(hash).js
4.67MB (+1.23KB +0.03%) -
Unchanged files (2)
Status Path Size Limits
updater.js
115.29KB -
guest-api.js
40.23KB -

Total files change +2.5MB +19.69%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 106 out of 106 changed files in this pull request and generated 3 comments.

Comment thread test/helpers/webdriver/user.ts
Comment thread app/services/streaming/streaming-view.ts
Comment thread app/services/streaming/streaming.ts Outdated
Comment on lines +1638 to +1640
// The horizontal stream has started but the vertical stream status is still Starting. Update the status here, instead of
// when the vertical stream actually starts, to prevent a race condition where the UI might show all streams as Live when
// they are still starting.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 106 out of 106 changed files in this pull request and generated 2 comments.

Comment thread app/services/restream.ts Outdated
Comment on lines +126 to +131
emitIsLiveForTest(isLive: boolean): void {
if (!Utils.isTestMode()) return;
this.streamSettingsService.setGoLiveSettings({ streamShift: true });
this.SET_STREAM_SWITCHER_STATUS('pending');
this.isLive.next(isLive);
}
Comment on lines +80 to +94
const onChange = useCallback(
(val: string) => {
const updatedDisplay = val as TDisplayOutput;
if (p.platform) {
updatePlatformDisplayAndSaveSettings(p.platform, updatedDisplay);
} else {
if (updatedDisplay === 'both') {
// There's no UI that would allow for this, but just in case
throw new Error('Attempted to update custom display for dual stream, this is impossible');
}
updateCustomDestinationDisplayAndSaveSettings(p.index, updatedDisplay as TDisplayType);
}
updateCustomDestinationDisplayAndSaveSettings(p.index, val as TDisplayType);
}
};
},
[p.platform, p.index],
);

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 108 out of 108 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

app/components-react/windows/go-live/useGoLiveSettings.ts:291

  • The non-Ultra prepopulate pruning only considers enabledPlatforms.length > 2, but it does not consider enabled custom destinations. If a user previously saved settings with custom destinations enabled (or >2 total targets) and later loses Ultra, the Go Live window can start with more than 2 targets enabled, bypassing the non-Ultra limit. Consider pruning/disable extra enabled custom destinations here as well so the initial state always satisfies the 2-target limit.

await waitForSettingsWindowLoaded();
await clickButton('Close');

await addDummyAccount('kick');
Comment thread test/regular/streaming/dual-output.ts Outdated
Comment on lines 283 to 287
/**
* A shortcut for useForm().assertFormContains()
* The second argument can be an assertion message (a string containing spaces)
* or the indexKey for field lookup.
*/
Comment on lines +254 to 266
const handleGoLive = useCallback(async () => {
if (!isPrime) {
// Check to see if the user has a valid display assignment
if (!hasValidDisplayAssignment) {
alertInfo({
name: 'dual-output-info-alert',
text: $t(
'To use Dual Output you must stream to at least one horizontal and one vertical platform.',
),
});

return;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior is intentional. Dual output as a mode will be removed after this new go live window UI is merged

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 109 out of 109 changed files in this pull request and generated 17 comments.

Comment on lines +38 to +42
async function installHighlighter() {
await showPage('Highlighter');
await clickIfDisplayed('[name="installHighlighter"]');
await waitForDisplayed('h3=Installing...', { timeout: 60000 });
}
Comment on lines +111 to +118
export async function isTooltipDisplayed(
hoverSelector: string,
tooltipSelector: string,
duration?: number,
): Promise<boolean> {
await hoverElement(hoverSelector, duration);
return isDisplayed(tooltipSelector);
}
Comment on lines 47 to 52
if (scope === 'relog') {
skipCheckingErrorsInLog();

t.true(
await isDisplayed('div=Failed to update TikTok account', { timeout: 3000 }),
'TikTok remerge error shown',
);
await isDisplayed('span=Failed to update TikTok account', {
timeout: 3000,
timeoutMsg: 'TikTok remerge error not shown for relog scope',
});
return;
Comment thread test/regular/streaming/tiktok.ts Outdated
Comment on lines 61 to 63
await waitForDisplayed('div[data-name="tiktok-settings"]');
await isTabActive('Streamlabs Access', 'tiktokLiveAccess');

Comment thread test/regular/streaming/tiktok.ts Outdated
Comment on lines +72 to +76
await clickTab('Stream with TikTok Stream Key', 'tiktokStreamKey');
await isDisplayed('[data-name="tiktokStreamForm"]', {
timeout: 3000,
timeoutMsg: 'TikTok stream key form not shown for approved scope',
});
Comment thread test/regular/streaming/multistream.ts Outdated
Comment on lines +353 to +354
// Default tooltip
await isTooltipDisplayed('i.icon-information', '[data-name="explanation"]', 1000);
Comment thread test/regular/streaming/multistream.ts Outdated
Comment on lines +356 to +358
// Default tooltip stays the same when multiple platforms are enabled
await fillForm({ youtube: true });
await isTooltipDisplayed('i.icon-information', '[data-name="explanation"]', 1000);
Comment thread test/regular/streaming/multistream.ts Outdated
Comment on lines +360 to +362
// Dual output tooltip
await fillForm({ youtubeDisplay: 'vertical' });
await isTooltipDisplayed('i.icon-information', '[data-name="dual-output"]', 1000);
Comment on lines +391 to +393
await fillForm({ patreon: true });
await isTooltipDisplayed('i.icon-information', '[data-name="patreon"]', 1000);
await assertFormContains({ streamShift: false });
Comment on lines +396 to +398
await fillForm({ patreon: false });
await isTooltipDisplayed('i.icon-information', '[data-name="explanation"]', 1000);
await assertFormContains({ streamShift: true });

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

test/regular/streaming/youtube.ts:51

  • logInYouTubeEnabledAccount is used as a boolean flag (retried) but can return void when retries === 0, forcing callers into boolean | void and making the result ambiguous. Return a boolean in all paths (or throw) so call sites can rely on the type/value.

Comment on lines +119 to 123
function DefaultAddDestinationButton(p: IAddDestinationButtonProps) {
return (
<Button
data-name="default-add-destination"
name="default-add-destination"
className={cx(styles.addDestinationBtn, styles.defaultOutputBtn, p.className)}
Comment on lines +133 to +137
function SmallAddDestinationButton(p: IAddDestinationButtonProps) {
return (
<Button
data-name="default-add-destination"
className={cx(styles.addDestinationBtn, styles.smallBtn, p.className)}
name="default-add-destination"
className={cx(styles.smallBtn, p.className)}
Comment on lines +147 to +148
[settings, updatePlatform],
);
Comment thread app/services/restream.ts
Comment on lines +842 to +849
async forceStreamShiftGoLive() {
this.streamSettingsService.setGoLiveSettings({ streamShift: false });
await this.deleteTargets();
this.SET_STREAM_SWITCHER_STATUS('inactive');
this.SET_STREAM_SWITCHER_STREAM_ID();
this.SET_STREAM_SWITCHER_TARGETS([]);
this.SET_STREAM_SWITCHER_FORCE_GO_LIVE(true);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intended

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 110 out of 110 changed files in this pull request and generated 5 comments.

Comment on lines +29 to +33
// Ultra banner should be visible for non-prime users
await isDisplayed('[name="banner-add-destination"]');

// Add destination button should be below the platform card if there is only one target
await isDisplayed('[name="bottom-add-destination"]');
Comment on lines +35 to +36
// Stream shift should be disabled and tooltip should be visible
await isDisplayed('[data-name="shift-ultra-icon"]');
Comment on lines +57 to +58
// Add destination button should be above the platform card if there are multiple targets
await isDisplayed('[name="top-add-destination"]');
Comment on lines +49 to +68
// Memoize the values of `hasDescription` to avoid unnecessary re-renders of the component
// but it never needs to be updated after the first render because supported fields for platforms
// can't change without updating the service
const hasDescription = useMemo(
() =>
p.platform
? Services.StreamingService.views.supports('description', [p.platform])
: Services.StreamingService.views.supports('description'),
[],
);

// Same as above for `title`
const title = useMemo(
() => (hasDescription ? $t('Use different title and description') : $t('Use different title')),
[],
);

const showCheckbox = useMemo(() => {
return p.enabledPlatformsCount && p.enabledPlatformsCount > 1;
}, [p.enabledPlatformsCount]);
Comment on lines 40 to +43
async function logInYouTubeEnabledAccount(
t: TExecutionContext,
retries: number = 3,
): Promise<void> {
): Promise<boolean | void> {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants