From 8ce78c302db021218a324205499bb92cf95cce82 Mon Sep 17 00:00:00 2001 From: Ben Schumacher Date: Thu, 27 Mar 2025 12:47:19 +0100 Subject: [PATCH] [MM-63534] Show errors from Support Packet generation in System Console (#30535) --- .../commercial_support_modal.test.tsx.snap | 36 ++++---- .../commercial_support_modal.scss | 10 ++ .../commercial_support_modal.test.tsx | 92 +++++++++++++++++-- .../commercial_support_modal.tsx | 15 ++- 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/webapp/channels/src/components/commercial_support_modal/__snapshots__/commercial_support_modal.test.tsx.snap b/webapp/channels/src/components/commercial_support_modal/__snapshots__/commercial_support_modal.test.tsx.snap index 62c963d8ae..55bd21b256 100644 --- a/webapp/channels/src/components/commercial_support_modal/__snapshots__/commercial_support_modal.test.tsx.snap +++ b/webapp/channels/src/components/commercial_support_modal/__snapshots__/commercial_support_modal.test.tsx.snap @@ -60,22 +60,6 @@ exports[`components/CommercialSupportModal should match snapshot 1`] = ` } } /> - - } - mode="info" - onDismiss={[Function]} - />
@@ -86,6 +70,26 @@ exports[`components/CommercialSupportModal should match snapshot 1`] = ` />
+
+ + + + +
diff --git a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.scss b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.scss index 31655eb01f..94c91dbd75 100644 --- a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.scss +++ b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.scss @@ -24,3 +24,13 @@ font-family: Metropolis, sans-serif; font-weight: 600 !important; } + +.CommercialSupportModal__error { + margin-top: 12px; + + .error-text { + display: inline-block; + color: var(--error-text); + word-break: break-word; + } +} diff --git a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.test.tsx b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.test.tsx index 2954d0d2c2..dc0a4e68be 100644 --- a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.test.tsx +++ b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.test.tsx @@ -4,22 +4,94 @@ import {shallow} from 'enzyme'; import React from 'react'; +import {Client4} from 'mattermost-redux/client'; + import CommercialSupportModal from 'components/commercial_support_modal/commercial_support_modal'; import {TestHelper} from 'utils/test_helper'; describe('components/CommercialSupportModal', () => { + beforeAll(() => { + // Mock getSystemRoute to return a valid URL + jest.spyOn(Client4, 'getSystemRoute').mockImplementation(() => 'http://localhost:8065/api/v4/system'); + + // Mock createObjectURL + window.URL.createObjectURL = jest.fn().mockReturnValue('mock-url'); + }); + + afterAll(() => { + jest.restoreAllMocks(); + + // @ts-expect-error - TS doesn't like deleting built-in methods + delete window.URL.createObjectURL; + }); + + const baseProps = { + onExited: jest.fn(), + showBannerWarning: false, + isCloud: false, + currentUser: TestHelper.getUserMock(), + packetContents: [ + {id: 'basic.server.logs', label: 'Server Logs', selected: true, mandatory: true}, + ], + }; + test('should match snapshot', () => { - const mockUser = TestHelper.getUserMock(); - const wrapper = shallow( - , - ); + const wrapper = shallow(); expect(wrapper).toMatchSnapshot(); }); + + test('should show error message when download fails', async () => { + const errorMessage = 'Failed to download'; + const detailedError = 'Permission denied'; + + // Mock the fetch call to return an error + global.fetch = jest.fn().mockImplementation(() => + Promise.resolve({ + ok: false, + json: () => Promise.resolve({ + message: errorMessage, + detailed_error: detailedError, + }), + }), + ); + + const wrapper = shallow(); + + // Trigger download + const instance = wrapper.instance(); + await instance.downloadSupportPacket(); + wrapper.update(); + + // Verify error message is shown + const errorDiv = wrapper.find('.CommercialSupportModal__error'); + expect(errorDiv.exists()).toBe(true); + expect(errorDiv.find('.error-text').text()).toBe(`${errorMessage}: ${detailedError}`); + + // Verify loading state is reset + expect(wrapper.state('loading')).toBe(false); + }); + + test('should clear error when starting new download', async () => { + // Mock the fetch call to succeed + global.fetch = jest.fn().mockImplementation(() => + Promise.resolve({ + ok: true, + blob: () => Promise.resolve(new Blob()), + headers: {get: () => null}, + }), + ); + + const wrapper = shallow(); + + // Set initial error state + wrapper.setState({error: 'Previous error'}); + + // Start download + const instance = wrapper.instance(); + await instance.downloadSupportPacket(); + + // Verify error is cleared + expect(wrapper.state('error')).toBeUndefined(); + }); }); diff --git a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx index e7f1d2c87d..63d7aa1837 100644 --- a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx +++ b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx @@ -39,6 +39,7 @@ type State = { showBannerWarning: boolean; packetContents: SupportPacketContent[]; loading: boolean; + error?: string; }; export default class CommercialSupportModal extends React.PureComponent { @@ -106,11 +107,18 @@ export default class CommercialSupportModal extends React.PureComponent { - this.setState({loading: true}); + this.setState({loading: true, error: undefined}); const res = await fetch(this.genereateDownloadURLWithParams(), { method: 'GET', headers: {'Content-Type': 'application/zip'}, }); + if (!res.ok) { + const data = await res.json(); + const error = data.message + ': ' + data.detailed_error; + this.setState({loading: false, error}); + return; + } + const blob = await res.blob(); this.setState({loading: false}); @@ -214,6 +222,11 @@ export default class CommercialSupportModal extends React.PureComponent ))}
+ {this.state.error && ( +
+ {this.state.error} +
+ )}