diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index c9586f56c19..31bb09ea477 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -117,6 +117,7 @@ 1. [A380X/ND] Remove leading zeros from terrain elevation display - @BravoMike99 (bruno_pt99) 1. [A32NX/FWS] Fix autopilot instinctive disconnect button logic for 3D model - @flogross89 (floridude) 1. [A380X/EFIS] Fix VV pb indicator not turning on when TRK-FPA mode is selected - @heclak (Heclak) +1. [EFB] Added troubleshooting page, under about page, for advanced support - @tracernz (Mike) 1. [FMS] Transition altitude/level and RNP now come from navdata in MSFS2024 - @tracernz (Mike) 1. [ATSU] Fixed issues with the ALL-CALLSIGNS recipient on Hoppie - @CronixZero (CronixZero) 1. [A380X/MFD] Add ATCCOM D-ATIS page layout - @heclak (Heclak) diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js index a10fe135818..778f1c07259 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js @@ -199,6 +199,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, 0, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -231,6 +232,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, 0, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -300,6 +302,7 @@ class CDUAvailableArrivalsPage { } } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -343,6 +346,7 @@ class CDUAvailableArrivalsPage { } } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -373,6 +377,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, 0, false, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -400,6 +405,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, pageCurrent, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -563,6 +569,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, 0, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -627,6 +634,7 @@ class CDUAvailableArrivalsPage { CDUAvailableArrivalsPage.ShowPage(mcdu, airport, 0, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js index e28a3093c56..8d74ddb9424 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js @@ -136,6 +136,7 @@ class CDUAvailableDeparturesPage { CDUAvailableDeparturesPage.ShowPage(mcdu, airport, 0, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -177,6 +178,7 @@ class CDUAvailableDeparturesPage { CDUAvailableDeparturesPage.ShowPage(mcdu, airport, pageCurrent, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { @@ -216,6 +218,7 @@ class CDUAvailableDeparturesPage { CDUAvailableDeparturesPage.ShowPage(mcdu, airport, pageCurrent, true, forPlan, inAlternate); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); mcdu.eraseTemporaryFlightPlan(() => { diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_DirectToPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_DirectToPage.js index 5fab4f00f1f..281e83203b7 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_DirectToPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_DirectToPage.js @@ -62,6 +62,7 @@ class CDUDirectToPage { mcdu.directToWaypoint(w).then(() => { CDUDirectToPage.ShowPage(mcdu, w, wptsListIndex); }).catch(err => { + mcdu.logTroubleshootingError(err); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); console.error(err); }); @@ -119,6 +120,7 @@ class CDUDirectToPage { mcdu.directToLeg(legIndex).then(() => { CDUDirectToPage.ShowPage(mcdu, leg.terminationWaypoint(), wptsListIndex); }).catch(err => { + mcdu.logTroubleshootingError(err); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); console.error(err); }); diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_FlightPlanPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_FlightPlanPage.js index 744ec54ac5d..83ac475d4a0 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_FlightPlanPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_FlightPlanPage.js @@ -870,6 +870,7 @@ class CDUFlightPlanPage { console.log("deleting element"); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); scratchpadCallback(); } diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_InitPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_InitPage.js index 0ef2c9c2590..730a451edd0 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_InitPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_InitPage.js @@ -159,6 +159,7 @@ class CDUInitPage { } } catch (error) { console.error(error); + mcdu.logTroubleshootingError(error); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); } }; @@ -220,6 +221,7 @@ class CDUInitPage { } }).catch((error) => { console.error(error); + mcdu.logTroubleshootingError(error); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); }); }); diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_LateralRevisionPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_LateralRevisionPage.js index 758734b2a7f..fea05f597e4 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_LateralRevisionPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_LateralRevisionPage.js @@ -139,6 +139,7 @@ class CDULateralRevisionPage { await mcdu.flightPlanService.enableAltn(legIndexFP, cruiseLevel, forPlan); } catch (e) { console.error(e); + mcdu.logTroubleshootingError(e); mcdu.setScratchpadMessage(NXFictionalMessages.internalError); } diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_MainDisplay.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_MainDisplay.js index 5e7cd72ca3e..ade57f56ffb 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_MainDisplay.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_MainDisplay.js @@ -1594,5 +1594,9 @@ class A320_Neo_CDU_MainDisplay extends FMCMainDisplay { CDUInitPage.ShowPage2(this); } } + + logTroubleshootingError(msg) { + this.bus.pub('troubleshooting_log_error', msg, true, false); + } } registerInstrument("a320-neo-cdu-main-display", A320_Neo_CDU_MainDisplay); diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsInit.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsInit.tsx index 89d09968c69..bf2aba851a9 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsInit.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsInit.tsx @@ -16,7 +16,7 @@ import { import { Button, ButtonMenuItem } from 'instruments/src/MFD/pages/common/Button'; import { maxCertifiedAlt } from '@shared/PerformanceConstants'; import { FmsPage } from 'instruments/src/MFD/pages/common/FmsPage'; -import { NXDataStore } from '@flybywiresim/fbw-sdk'; +import { logTroubleshootingError, NXDataStore } from '@flybywiresim/fbw-sdk'; import { ISimbriefData } from '@flybywiresim/flypad'; import { SimBriefUplinkAdapter } from '@fmgc/flightplanning/uplink/SimBriefUplinkAdapter'; import { FmgcFlightPhase } from '@shared/flightphase'; @@ -210,12 +210,17 @@ export class MfdFmsInit extends FmsPage { this.simBriefOfp = await SimBriefUplinkAdapter.downloadOfpForUserID(navigraphUsername, overrideSimBriefUserID); - SimBriefUplinkAdapter.uplinkFlightPlanFromSimbrief( - this.props.fmcService.master, - this.props.fmcService.master.flightPlanService, - this.simBriefOfp, - { doUplinkProcedures: false }, - ); + try { + SimBriefUplinkAdapter.uplinkFlightPlanFromSimbrief( + this.props.fmcService.master, + this.props.fmcService.master.flightPlanService, + this.simBriefOfp, + { doUplinkProcedures: false }, + ); + } catch (e) { + console.error(e); + logTroubleshootingError(this.props.bus, e); + } } private async cityPairModified() { @@ -239,7 +244,12 @@ export class MfdFmsInit extends FmsPage { return; } - this.props.fmcService.master.flightPlanService.uplinkInsert(); + try { + this.props.fmcService.master.flightPlanService.uplinkInsert(); + } catch (e) { + console.error(e); + logTroubleshootingError(this.props.bus, e); + } this.props.fmcService.master?.acInterface.updateOansAirports(); this.props.fmcService.master.fmgc.data.atcCallsign.set(this.simBriefOfp?.callsign ?? '----------'); diff --git a/fbw-common/src/systems/instruments/src/EFB/Efb.tsx b/fbw-common/src/systems/instruments/src/EFB/Efb.tsx index 6480b24342b..99884eef629 100644 --- a/fbw-common/src/systems/instruments/src/EFB/Efb.tsx +++ b/fbw-common/src/systems/instruments/src/EFB/Efb.tsx @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 FlyByWire Simulations +// Copyright (c) 2023-2025 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { useContext, useEffect, useState } from 'react'; @@ -54,6 +54,9 @@ import { setFlightPlanProgress } from './Store/features/flightProgress'; import { Checklists, setAutomaticItemStates } from './Checklists/Checklists'; import { setAircraftChecklists, addTrackingChecklists } from './Store/features/checklists'; import { FlyPadPage } from './Settings/Pages/FlyPadPage'; +import { NavigraphAuthProvider } from '../react/navigraph'; +import { EventBus } from '@microsoft/msfs-sdk'; +import { TroubleshootingContextProvider } from './TroubleshootingContext'; // './Assets/Efb.scss' is imported by the aircraft EFB instrument the wraps this file import './Assets/Theme.css'; @@ -61,8 +64,6 @@ import './Assets/Slider.scss'; import 'react-toastify/dist/ReactToastify.css'; import './toast.css'; -import { NavigraphAuthProvider } from '../react/navigraph'; -import { EventBus } from '@microsoft/msfs-sdk'; export interface EfbWrapperProps { failures: FailureDefinition[]; // TODO: Move failure definition into VFS @@ -523,16 +524,18 @@ export const EfbInstrument: React.FC = ({ failures, aircraft const [err, setErr] = useState(false); return ( - - setErr(false)} resetKeys={[err]}> - - - - - - - - - + + + setErr(false)} resetKeys={[err]}> + + + + + + + + + + ); }; diff --git a/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json b/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json index dc4e3590348..14b4edef027 100644 --- a/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json +++ b/fbw-common/src/systems/instruments/src/EFB/Localization/data/en.json @@ -732,6 +732,9 @@ "ThrottleConfigurationReset": "Throttle Configuration Reset" }, "Title": "Settings", + "Troubleshooting": { + "Title": "Troubleshooting" + }, "Unrealistic": "Unrealistic", "flyPad": { "AutoBrightness": "Auto Brightness", diff --git a/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx index f0575801fed..27cd20ef2e8 100644 --- a/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx +++ b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/AboutPage.tsx @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 FlyByWire Simulations +// Copyright (c) 2023-2025 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 import React, { useEffect, useState } from 'react'; @@ -11,11 +11,15 @@ import { SENTRY_CONSENT_KEY, useSimVar, } from '@flybywiresim/fbw-sdk'; -import { t } from '@flybywiresim/flypad'; +import { PageLink, pathify, t, TabRoutes } from '@flybywiresim/flypad'; import { SettingsPage } from '../Settings'; // @ts-ignore import FbwTail from '../../Assets/FBW-Tail.svg'; import { useViewListenerEvent } from '../../Utils/listener'; +import { Link, Route, Switch } from 'react-router-dom'; +import { TroubleshootingPage } from './TroubleshootingPage'; + +const baseAboutRoute = `/settings/${pathify('About')}`; interface BuildInfoEntryProps { title: string; @@ -59,6 +63,10 @@ export const AboutPage = () => { const [version, setVersion] = useSessionStorage('SIM_VERSION', ''); const [sentryEnabled] = usePersistentProperty(SENTRY_CONSENT_KEY, SentryConsentState.Refused); + const subTabs: PageLink[] = [ + { alias: t('Settings.Troubleshooting.Title'), name: 'Troubleshooting', component: }, + ]; + // Callback function to set sBuildVersion from the community panel const onSetPlayerData = (data: CommunityPanelPlayerData) => { setVersion(data.sBuildVersion); @@ -72,43 +80,58 @@ export const AboutPage = () => { }, [process.env.AIRCRAFT_PROJECT_PREFIX]); return ( - -
-
-
+ + + +
- -

flyPadOS 3

+
+
+ +

flyPadOS 3

+
+ +

+ Made with love by contributors in Québec, Germany, the United States, Singapore, Indonesia, New + Zealand, Australia, Spain, the United Kingdom, France, the Netherlands, Sweden, and Switzerland! +

+
+
+
+

© 2020-2024 FlyByWire Simulations and its contributors, all rights reserved.

+

Licensed under the GNU General Public License Version 3

-

- Made with love by contributors in Québec, Germany, the United States, Singapore, Indonesia, New Zealand, - Australia, Spain, the United Kingdom, France, the Netherlands, Sweden, and Switzerland! -

-
-
-
-

© 2020-2024 FlyByWire Simulations and its contributors, all rights reserved.

-

Licensed under the GNU General Public License Version 3

-
- -
-

Build Info

-
- - - - - - - - - {sentryEnabled === SentryConsentState.Given && ( - - )} +
+

Build Info

+
+ + + + + + + + + {sentryEnabled === SentryConsentState.Given && ( + + )} +
+
+ +
+ + {t('Settings.Troubleshooting.Title')} + +
-
-
- + + + + ); }; diff --git a/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/TroubleshootingPage.tsx b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/TroubleshootingPage.tsx new file mode 100644 index 00000000000..4f1ce9f37e5 --- /dev/null +++ b/fbw-common/src/systems/instruments/src/EFB/Settings/Pages/TroubleshootingPage.tsx @@ -0,0 +1,43 @@ +// Copyright (c) 2025 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +import React, { useEffect, useState } from 'react'; +import { t } from '@flybywiresim/flypad'; +import { SettingsPage } from '../Settings'; +// @ts-ignore +import { useTroubleshooting } from '../../TroubleshootingContext'; +import { AiracCycleFormatter, FacilityLoader } from '@microsoft/msfs-sdk'; +import { AircraftGithubVersionChecker, BuildInfo } from '../../../../../shared/src/AircraftGithubVersionChecker'; +import { isMsfs2024 } from '../../../../../shared/src/MsfsDetect'; + +export const TroubleshootingPage = () => { + const errorLog = useTroubleshooting(); + const [navDates, setNavDates] = useState(''); + const [naviInstalled, setNaviInstalled] = useState(false); + const [buildInfo, setBuildInfo] = useState(undefined); + + useEffect(() => { + fetch('/VFS/scenery/fs-base-jep/scenery/world/airaccycle.bgl', { method: 'HEAD' }).then((r) => + setNaviInstalled(r.ok), + ); + + const formatter = AiracCycleFormatter.create('{eff({dd}{MON}{YY})}-{exp({dd}{MON}{YY})}({YYCC})'); + setNavDates(formatter(FacilityLoader.getDatabaseCycles().current)); + + AircraftGithubVersionChecker.getBuildInfo(process.env.AIRCRAFT_PROJECT_PREFIX).then((info) => setBuildInfo(info)); + }, []); + + return ( + +
+        Aircraft Version: {buildInfo?.version}
+        {'\n'}
+        MSFS2024: {isMsfs2024() ? 'True\n' : 'False\n'}
+        NavData Dates: {navDates + '\n'}
+        Navigraph NavData: {naviInstalled ? 'True\n' : 'False\n'}
+        {'\n'}
+        {errorLog.map((msg) => msg + '\n')}
+      
+
+ ); +}; diff --git a/fbw-common/src/systems/instruments/src/EFB/TroubleshootingContext.tsx b/fbw-common/src/systems/instruments/src/EFB/TroubleshootingContext.tsx new file mode 100644 index 00000000000..dd54535225a --- /dev/null +++ b/fbw-common/src/systems/instruments/src/EFB/TroubleshootingContext.tsx @@ -0,0 +1,34 @@ +// Copyright (c) 2025 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +import { EventBus } from '@microsoft/msfs-sdk'; +import React, { useContext, useEffect, useState } from 'react'; +import { TroubleshootingEvents } from '../../../shared/src/Troubleshooting'; + +const TroubleshootingContext = React.createContext(undefined as any); + +interface TroubleshootingContextProps { + eventBus: EventBus; +} + +export const TroubleshootingContextProvider: React.FC = ({ eventBus, children }) => { + const [errorLog, setErrorLog] = useState([] as string[]); + + useEffect(() => { + let log = []; + const sub = eventBus + .getSubscriber() + .on('troubleshooting_log_error') + .handle((err) => { + log = [`${new Date().toISOString()}: ${err}`, ...log]; + setErrorLog(log); + }); + return () => { + sub.destroy(); + }; + }, []); + + return {children}; +}; + +export const useTroubleshooting = () => useContext(TroubleshootingContext); diff --git a/fbw-common/src/systems/shared/src/Troubleshooting.ts b/fbw-common/src/systems/shared/src/Troubleshooting.ts new file mode 100644 index 00000000000..482588765e6 --- /dev/null +++ b/fbw-common/src/systems/shared/src/Troubleshooting.ts @@ -0,0 +1,22 @@ +// Copyright (c) 2025 FlyByWire Simulations +// SPDX-License-Identifier: GPL-3.0 + +import { EventBus } from '@microsoft/msfs-sdk'; + +/** Types for logging troubleshooting messages. */ +export interface TroubleshootingEvents { + /** + * Error log for errors that should be user visible for fault finding and FBW support team. + * Use vary sparingly, and only for user visible errors that need troubleshooting info e.g. INTERNAL ERROR in the FMS! + */ + troubleshooting_log_error: string; +} + +/** + * Logs a troubleshooting error message, for display on the EFB. + * @param bus EventBus to use. + * @param msg The message to log. + */ +export function logTroubleshootingError(bus: EventBus, msg: any): void { + bus.pub('troubleshooting_log_error', typeof msg === 'string' ? msg : String(msg), true, false); +} diff --git a/fbw-common/src/systems/shared/src/index.ts b/fbw-common/src/systems/shared/src/index.ts index febe87cba4a..cc1c6156044 100644 --- a/fbw-common/src/systems/shared/src/index.ts +++ b/fbw-common/src/systems/shared/src/index.ts @@ -44,4 +44,5 @@ export * from './simbridge'; export * from './simvar'; export * from './units'; export * from './GPUManagement'; +export * from './Troubleshooting'; export * from './types';