From 5d7c3b52ed663ea9cadbb4becffdcc3fe46d6387 Mon Sep 17 00:00:00 2001 From: Nick Misasi Date: Tue, 24 Jun 2025 11:11:19 -0400 Subject: [PATCH] [CLD-9285] Add server version and edition (team vs ent) to ExternalLink component (#31783) * Add server version and edition (team vs ent) to ExternalLink component * fix: add proper Redux state setup to datetime_input.test.tsx The test was failing because the useExternalLink hook (added in this PR) requires access to config and license Redux state, but the datetime_input tests weren't providing proper initial state. This caused components to receive undefined values from Redux selectors, potentially affecting locale/date formatting behavior. Added defaultState with proper config and license structure to match what other tests in the codebase use, ensuring consistent test environment. Co-authored-by: Nick Misasi * Revert to master * Revert to master --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Nick Misasi --- .../about_build_modal.test.tsx | 27 ++++++++++++++----- .../billing/billing_history.test.tsx | 2 +- .../feature_discovery.test.tsx | 10 +++---- .../common/hooks/use_external_link.ts | 13 ++++++++- .../__snapshots__/external_link.test.tsx.snap | 2 +- .../external_link/external_link.test.tsx | 4 +-- ...d_outgoing_oauth_connections.test.tsx.snap | 2 +- .../overage_users_banner_notice.test.tsx | 4 +-- .../start_trial_form_modal.test.tsx.snap | 4 +-- .../team_access_tab/open_invite.test.tsx | 2 +- .../user_settings_notifications.test.tsx.snap | 12 ++++----- 11 files changed, 53 insertions(+), 29 deletions(-) diff --git a/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx b/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx index 4c64b1d8f3..993d7331b9 100644 --- a/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx +++ b/webapp/channels/src/components/about_build_modal/about_build_modal.test.tsx @@ -78,7 +78,7 @@ describe('components/AboutBuildModal', () => { expect(screen.getByTestId('aboutModalBuildNumber')).toHaveTextContent('Build Number: 123456'); expect(screen.getByText('Mattermost Enterprise Edition')).toBeInTheDocument(); expect(screen.getByText('Modern communication from behind your firewall.')).toBeInTheDocument(); - expect(screen.getByRole('link', {name: 'mattermost.com'})).toHaveAttribute('href', 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid='); + expect(screen.getByRole('link', {name: 'mattermost.com'})).toHaveAttribute('href', 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid=&edition=enterprise&server_version=3.6.0'); expect(screen.getByText('EE Build Hash: 0123456789abcdef', {exact: false})).toBeInTheDocument(); expect(screen.queryByText('Hostname: mock.localhost', {exact: false})).toBeInTheDocument(); @@ -100,7 +100,7 @@ describe('components/AboutBuildModal', () => { expect(screen.getByTestId('aboutModalBuildNumber')).toHaveTextContent('Build Number: 123456'); expect(screen.getByText('Mattermost Team Edition')).toBeInTheDocument(); expect(screen.getByText('All your team communication in one place, instantly searchable and accessible anywhere.')).toBeInTheDocument(); - expect(screen.getByRole('link', {name: 'mattermost.com/community/'})).toHaveAttribute('href', 'https://mattermost.com/community/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid='); + expect(screen.getByRole('link', {name: 'mattermost.com/community/'})).toHaveAttribute('href', 'https://mattermost.com/community/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid=&edition=team&server_version=3.6.0'); expect(screen.queryByText('EE Build Hash: 0123456789abcdef')).not.toBeInTheDocument(); expect(screen.queryByText('Hostname: disconnected', {exact: false})).toBeInTheDocument(); @@ -150,7 +150,7 @@ describe('components/AboutBuildModal', () => { expect(screen.getByTestId('aboutModalBuildNumber')).toHaveTextContent('Build Number: n/a'); expect(screen.getByText('Mattermost Team Edition')).toBeInTheDocument(); expect(screen.getByText('All your team communication in one place, instantly searchable and accessible anywhere.')).toBeInTheDocument(); - expect(screen.getByRole('link', {name: 'mattermost.com/community/'})).toHaveAttribute('href', 'https://mattermost.com/community/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid='); + expect(screen.getByRole('link', {name: 'mattermost.com/community/'})).toHaveAttribute('href', 'https://mattermost.com/community/?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=&sid=&edition=team&server_version=dev'); expect(screen.queryByText('EE Build Hash: 0123456789abcdef')).not.toBeInTheDocument(); expect(screen.queryByText('Hostname: server did not provide hostname', {exact: false})).toBeInTheDocument(); @@ -193,7 +193,7 @@ describe('components/AboutBuildModal', () => { const state = { entities: { general: { - config: {}, + config, license: { Cloud: 'false', }, @@ -213,9 +213,9 @@ describe('components/AboutBuildModal', () => { state, ); - expect(screen.getByRole('link', {name: 'Terms of Use'})).toHaveAttribute('href', `${AboutLinks.TERMS_OF_SERVICE}?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=currentUserId&sid=`); + expect(screen.getByRole('link', {name: 'Terms of Use'})).toHaveAttribute('href', `${AboutLinks.TERMS_OF_SERVICE}?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=currentUserId&sid=&edition=enterprise&server_version=3.6.0`); - expect(screen.getByRole('link', {name: 'Privacy Policy'})).toHaveAttribute('href', `${AboutLinks.PRIVACY_POLICY}?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=currentUserId&sid=`); + expect(screen.getByRole('link', {name: 'Privacy Policy'})).toHaveAttribute('href', `${AboutLinks.PRIVACY_POLICY}?utm_source=mattermost&utm_medium=in-product&utm_content=about_build_modal&uid=currentUserId&sid=&edition=enterprise&server_version=3.6.0`); expect(screen.getByRole('link', {name: 'Terms of Use'})).not.toHaveAttribute('href', config?.TermsOfServiceLink); expect(screen.getByRole('link', {name: 'Privacy Policy'})).not.toHaveAttribute('href', config?.PrivacyPolicyLink); @@ -282,6 +282,19 @@ describe('components/AboutBuildModal', () => { ...props, }; - return renderWithContext(); + // Create state with the config and license for useExternalLink hook to access + const state = { + entities: { + general: { + config: allProps.config, + license: allProps.license, + }, + users: { + currentUserId: '', + }, + }, + }; + + return renderWithContext(, state); } }); diff --git a/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx index 8eed69ca35..71eaaa93d9 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_history.test.tsx @@ -131,7 +131,7 @@ describe('components/admin_console/billing/billing_history', () => { expect(screen.queryByTestId(invoiceA.id)).not.toBeInTheDocument(); expect(screen.queryByTestId(invoiceB.id)).not.toBeInTheDocument(); - expect(screen.getByRole('link')).toHaveAttribute('href', CloudLinks.BILLING_DOCS + '?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=billing_history&uid=current_user_id&sid='); + expect(screen.getByRole('link')).toHaveAttribute('href', CloudLinks.BILLING_DOCS + '?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=billing_history&uid=current_user_id&sid=&edition=team&server_version='); expect(screen.getByRole('link')).toHaveTextContent('See how billing works'); expect(screen.getByTestId('no-invoices')).toHaveTextContent(NO_INVOICES_LEGEND); }); diff --git a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx index 946e40f41e..702a250a1a 100644 --- a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx +++ b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx @@ -65,10 +65,10 @@ describe('components/feature_discovery', () => { const featureLink = screen.getByTestId('featureDiscovery_secondaryCallToAction'); expect(featureLink).toBeInTheDocument(); - expect(featureLink).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid='); + expect(featureLink).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid=&edition=team&server_version='); expect(featureLink).toHaveTextContent('Learn more'); - expect(screen.getByText('Mattermost Software and Services License Agreement')).toHaveAttribute('href', 'https://mattermost.com/pl/software-and-services-license-agreement?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid='); - expect(screen.getByText('Privacy Policy')).toHaveAttribute('href', AboutLinks.PRIVACY_POLICY + '?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid='); + expect(screen.getByText('Mattermost Software and Services License Agreement')).toHaveAttribute('href', 'https://mattermost.com/pl/software-and-services-license-agreement?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid=&edition=team&server_version='); + expect(screen.getByText('Privacy Policy')).toHaveAttribute('href', AboutLinks.PRIVACY_POLICY + '?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid=&edition=team&server_version='); expect(getPrevTrialLicense).toHaveBeenCalled(); expect(getCloudSubscription).not.toHaveBeenCalled(); @@ -121,12 +121,12 @@ describe('components/feature_discovery', () => { //this option is visible only when it is cloud environment expect(screen.getByRole('button', {name: 'Contact sales'})).toBeInTheDocument(); - expect(screen.getByTestId('featureDiscovery_secondaryCallToAction')).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid='); + expect(screen.getByTestId('featureDiscovery_secondaryCallToAction')).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid=&edition=team&server_version='); const featureLink = screen.getByTestId('featureDiscovery_secondaryCallToAction'); expect(featureLink).toBeInTheDocument(); - expect(featureLink).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid='); + expect(featureLink).toHaveAttribute('href', 'https://test.mattermost.com/secondary/?utm_source=mattermost&utm_medium=in-product&utm_content=feature_discovery&uid=&sid=&edition=team&server_version='); expect(featureLink).toHaveTextContent('Learn more'); expect(getPrevTrialLicense).toHaveBeenCalled(); diff --git a/webapp/channels/src/components/common/hooks/use_external_link.ts b/webapp/channels/src/components/common/hooks/use_external_link.ts index b7bfc70e21..5125ce3845 100644 --- a/webapp/channels/src/components/common/hooks/use_external_link.ts +++ b/webapp/channels/src/components/common/hooks/use_external_link.ts @@ -19,6 +19,8 @@ export type ExternalLinkQueryParams = { export function useExternalLink(href: string, location: string = '', overwriteQueryParams: ExternalLinkQueryParams = {}): [string, Record] { const userId = useSelector(getCurrentUserId); + const config = useSelector(getConfig); + const license = useSelector(getLicense); const telemetryId = useSelector((state: GlobalState) => getConfig(state)?.TelemetryId || ''); const isCloud = useSelector((state: GlobalState) => getLicense(state)?.Cloud === 'true'); @@ -29,6 +31,13 @@ export function useExternalLink(href: string, location: string = '', overwriteQu const parsedUrl = new URL(href); + // Determine edition type (enterprise vs team) + const isEnterpriseReady = config?.BuildEnterpriseReady === 'true'; + const edition = isEnterpriseReady ? 'enterprise' : 'team'; + + // Determine server version + const serverVersion = config?.BuildNumber === 'dev' ? config.BuildNumber : (config?.Version || ''); + const existingURLSearchParams = parsedUrl.searchParams; const existingQueryParamsObj = Object.fromEntries(existingURLSearchParams.entries()); const queryParams = { @@ -37,11 +46,13 @@ export function useExternalLink(href: string, location: string = '', overwriteQu utm_content: location, uid: userId, sid: telemetryId, + edition, + server_version: serverVersion, ...overwriteQueryParams, ...existingQueryParamsObj, }; parsedUrl.search = Object.entries(queryParams).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&'); return [parsedUrl.toString(), queryParams]; - }, [href, isCloud, location, overwriteQueryParams, telemetryId, userId]); + }, [href, isCloud, location, overwriteQueryParams, telemetryId, userId, config, license]); } diff --git a/webapp/channels/src/components/external_link/__snapshots__/external_link.test.tsx.snap b/webapp/channels/src/components/external_link/__snapshots__/external_link.test.tsx.snap index 0e84096d24..a342da968d 100644 --- a/webapp/channels/src/components/external_link/__snapshots__/external_link.test.tsx.snap +++ b/webapp/channels/src/components/external_link/__snapshots__/external_link.test.tsx.snap @@ -18,7 +18,7 @@ exports[`components/external_link should match snapshot 1`] = ` location="test" > { expect(screen.queryByText('Click Me')).toHaveAttribute( 'href', - 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=test&uid=currentUserId&sid=&test=true', + 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=test&uid=currentUserId&sid=&edition=team&server_version=&test=true', ); }); @@ -191,7 +191,7 @@ describe('components/external_link', () => { expect(screen.queryByText('Click Me')).toHaveAttribute( 'href', - 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=test&uid=currentUserId&sid=#desktop', + 'https://mattermost.com/?utm_source=mattermost&utm_medium=in-product-cloud&utm_content=test&uid=currentUserId&sid=&edition=team&server_version=#desktop', ); }); }); diff --git a/webapp/channels/src/components/integrations/outgoing_oauth_connections/__snapshots__/installed_outgoing_oauth_connections.test.tsx.snap b/webapp/channels/src/components/integrations/outgoing_oauth_connections/__snapshots__/installed_outgoing_oauth_connections.test.tsx.snap index 1f2b67adf0..22efa61be0 100644 --- a/webapp/channels/src/components/integrations/outgoing_oauth_connections/__snapshots__/installed_outgoing_oauth_connections.test.tsx.snap +++ b/webapp/channels/src/components/integrations/outgoing_oauth_connections/__snapshots__/installed_outgoing_oauth_connections.test.tsx.snap @@ -194,7 +194,7 @@ exports[`components/integrations/InstalledOutgoingOAuthConnections should match location="installed_outgoing_oauth_connections" > { expect(screen.getByRole('link')).toHaveAttribute( 'href', LicenseLinks.CONTACT_SALES + - '?utm_source=mattermost&utm_medium=in-product&utm_content=overage_users_banner&uid=current_user&sid=', + '?utm_source=mattermost&utm_medium=in-product&utm_content=overage_users_banner&uid=current_user&sid=&edition=team&server_version=', ); expect(trackEvent).toBeCalledTimes(2); expect(trackEvent).toBeCalledWith('insights', 'click_true_up_error', { @@ -337,7 +337,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => { expect(screen.getByRole('link')).toHaveAttribute( 'href', LicenseLinks.CONTACT_SALES + - '?utm_source=mattermost&utm_medium=in-product&utm_content=overage_users_banner&uid=current_user&sid=', + '?utm_source=mattermost&utm_medium=in-product&utm_content=overage_users_banner&uid=current_user&sid=&edition=team&server_version=', ); expect(trackEvent).toBeCalledTimes(2); expect(trackEvent).toBeCalledWith('insights', 'click_true_up_error', { diff --git a/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap b/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap index 184236489d..47f2aa7c68 100644 --- a/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap +++ b/webapp/channels/src/components/start_trial_form_modal/__snapshots__/start_trial_form_modal.test.tsx.snap @@ -334,7 +334,7 @@ Object { > By selecting Start trial, I agree to the , { expect(title).toBeInTheDocument(); const externalLink = screen.getByText('Learn More'); expect(externalLink).toBeInTheDocument(); - expect(externalLink).toHaveAttribute('href', 'https://mattermost.com/pl/default-ldap-group-constrained-team-channel.html?utm_source=mattermost&utm_medium=in-product&utm_content=open_invite&uid=&sid='); + expect(externalLink).toHaveAttribute('href', 'https://mattermost.com/pl/default-ldap-group-constrained-team-channel.html?utm_source=mattermost&utm_medium=in-product&utm_content=open_invite&uid=&sid=&edition=team&server_version='); }); test('should render the checkbox when the team is not constrained and not checked', () => { diff --git a/webapp/channels/src/components/user_settings/notifications/__snapshots__/user_settings_notifications.test.tsx.snap b/webapp/channels/src/components/user_settings/notifications/__snapshots__/user_settings_notifications.test.tsx.snap index f71910fcff..0c3df0154d 100644 --- a/webapp/channels/src/components/user_settings/notifications/__snapshots__/user_settings_notifications.test.tsx.snap +++ b/webapp/channels/src/components/user_settings/notifications/__snapshots__/user_settings_notifications.test.tsx.snap @@ -56,7 +56,7 @@ Object { >