Skip to content

Commit 785b9cb

Browse files
committed
feat: handle no simbridge connection, sb port setting, refresh button
1 parent c9c1bf7 commit 785b9cb

File tree

6 files changed

+155
-61
lines changed

6 files changed

+155
-61
lines changed

src/instruments/src/EFB/apps/Files/Sidebar.tsx

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import ScrollContainer from "react-indiana-drag-scroll";
77
import { Files } from ".";
88

99
type SidebarProps = {
10+
simbridgeAvailable: boolean
1011
files?: Files;
1112
selected?: string;
1213
onSelect: (name: string) => void;
1314
ofpSelected: boolean;
1415
onSelectOfp: () => void;
16+
onRefresh: () => void;
1517
};
1618

17-
export const Sidebar: FC<SidebarProps> = ({ files, selected, onSelect, ofpSelected, onSelectOfp }) => {
19+
export const Sidebar: FC<SidebarProps> = ({ simbridgeAvailable, files, selected, onSelect, ofpSelected, onSelectOfp, onRefresh }) => {
1820
const getFileTypeIcon = (name: string, props: { fill: string; size: number }) => {
1921
if (name.endsWith(".pdf")) {
2022
return <BsFiletypePdf {...props} />;
@@ -31,46 +33,67 @@ export const Sidebar: FC<SidebarProps> = ({ files, selected, onSelect, ofpSelect
3133
<Title>Files</Title>
3234
<Category>
3335
<div>SimBrief</div>
34-
<AiOutlineCloudDownload size={33} fill="#4FA0FC" />
36+
<AiOutlineCloudDownload size={33} fill="#4FA0FC" onClick={onSelectOfp} />
3537
</Category>
3638
<Entry selected={ofpSelected} onClick={onSelectOfp}>
3739
<BsFileEarmark fill={ofpSelected ? "white" : "#4FA0FC"} size={32} />
3840
<div>OFP</div>
3941
</Entry>
40-
<ScrollContainer style={{ width: "100%" }}>
41-
{files?.pdfs.length !== 0 && (
42-
<>
43-
<Category>
44-
<div>Local Documents</div>
45-
<IoIosRefresh size={32} fill="#4FA0FC" />
46-
</Category>
47-
{files?.pdfs?.map((file, i) => (
48-
<Entry selected={selected === file} key={i} onClick={() => onSelect(file)}>
49-
{getFileTypeIcon(file, { fill: selected === file ? "white" : "#4FA0FC", size: 32 })}
50-
<div>{file}</div>
51-
</Entry>
52-
))}
53-
</>
54-
)}
55-
{files?.images.length !== 0 && (
56-
<>
57-
<Category>
58-
<div>Local Images</div>
59-
<IoIosRefresh size={32} fill="#4FA0FC" />
60-
</Category>
61-
{files?.images.map((image, i) => (
62-
<Entry selected={selected === image} key={i} onClick={() => onSelect(image)}>
63-
{getFileTypeIcon(image, { fill: selected === image ? "white" : "#4FA0FC", size: 32 })}
64-
<div>{image}</div>
65-
</Entry>
66-
))}
67-
</>
68-
)}
69-
</ScrollContainer>
42+
{simbridgeAvailable ? (
43+
<ScrollContainer style={{ width: "100%" }}>
44+
{files?.pdfs.length !== 0 && (
45+
<>
46+
<Category>
47+
<div>Local Documents</div>
48+
<IoIosRefresh size={32} fill="#4FA0FC" onClick={onRefresh} />
49+
</Category>
50+
{files?.pdfs?.map((file, i) => (
51+
<Entry selected={selected === file} key={i} onClick={() => onSelect(file)}>
52+
{getFileTypeIcon(file, { fill: selected === file ? "white" : "#4FA0FC", size: 32 })}
53+
<div>{file}</div>
54+
</Entry>
55+
))}
56+
</>
57+
)}
58+
{files?.images.length !== 0 && (
59+
<>
60+
<Category>
61+
<div>Local Images</div>
62+
<IoIosRefresh size={32} fill="#4FA0FC" onClick={onRefresh} />
63+
</Category>
64+
{files?.images.map((image, i) => (
65+
<Entry selected={selected === image} key={i} onClick={() => onSelect(image)}>
66+
{getFileTypeIcon(image, { fill: selected === image ? "white" : "#4FA0FC", size: 32 })}
67+
<div>{image}</div>
68+
</Entry>
69+
))}
70+
</>
71+
)}
72+
</ScrollContainer>
73+
) : (
74+
<SimbridgeUnavailable>
75+
<div>SimBridge not connected</div>
76+
<IoIosRefresh size={32} fill="lightgray" onClick={onRefresh} />
77+
</SimbridgeUnavailable>
78+
)}
7079
</StyledSidebar>
7180
);
7281
};
7382

83+
const SimbridgeUnavailable = styled.div`
84+
width: 100%;
85+
flex: 1;
86+
display: flex;
87+
flex-direction: column;
88+
justify-content: center;
89+
align-items: center;
90+
color: lightgray;
91+
92+
* {
93+
margin: 5px;
94+
}
95+
`;
96+
7497
const Entry = styled.div<{ selected: boolean }>`
7598
display: flex;
7699
align-items: center;
@@ -108,6 +131,7 @@ const StyledSidebar = styled.div`
108131
color: black;
109132
font-size: 24px;
110133
border-right: 1px solid lightgray;
134+
flex-shrink: 0;
111135
`;
112136

113137
const Title = styled.div`

src/instruments/src/EFB/apps/Files/index.tsx

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { DocumentLoading } from "../../components/charts/DocumentLoading";
99
import ScrollContainer from "react-indiana-drag-scroll";
1010
import { useSetting } from "../../hooks/useSettings";
1111
import { FilesContext } from "./FilesContext";
12+
import { SettingsContext } from "../Settings/SettingsContext";
13+
import { useSimBridge } from "../../hooks/useSimBridge";
1214

1315
export type View = {
1416
name: string;
@@ -21,15 +23,19 @@ export type Files = { pdfs: string[]; images: string[] };
2123

2224
export const Files: FC = () => {
2325
const [documentLoading, setDocumentLoading] = useState<boolean>(false);
26+
const [simbridgeConnection, setSimbridgeConnection] = useState<boolean>(false);
2427

2528
const { setModal } = useContext(ModalContext);
2629
const { view, setView, files, setFiles, ofp, setOfp, ofpSelected, setOfpSelected } = useContext(FilesContext);
30+
const { simbridgePort } = useContext(SettingsContext);
31+
32+
const simbridge = useSimBridge();
2733

2834
const contentSectionRef = useRef<HTMLDivElement>(null);
2935

3036
const [simbriefUsername] = useSetting("boeingMsfsSimbriefUsername");
3137

32-
const getFiles = async () => setFiles({ pdfs: await SimBridge.getPDFList(), images: await SimBridge.getImageList() });
38+
const getFiles = async () => setFiles({ pdfs: await simbridge.getPDFList(), images: await simbridge.getImageList() });
3339

3440
const handleSelect = async (name: string) => {
3541
setOfpSelected(false);
@@ -39,8 +45,8 @@ export const Files: FC = () => {
3945
try {
4046
setView(
4147
files?.images.includes(name)
42-
? { name, blob: await SimBridge.getImage(name) }
43-
: { name, blob: await SimBridge.getPDFPage(name, 1), pages: await SimBridge.getPDFPageNum(name), currentPage: 1 }
48+
? { name, blob: await simbridge.getImage(name) }
49+
: { name, blob: await simbridge.getPDFPage(name, 1), pages: await simbridge.getPDFPageNum(name), currentPage: 1 }
4450
);
4551
} catch (e: unknown) {
4652
e instanceof Error && setModal(<InfoModal title="Error" description={e.message} />);
@@ -51,7 +57,7 @@ export const Files: FC = () => {
5157

5258
const handlePageChange = async (page: number) => {
5359
try {
54-
view && setView({ ...view, blob: await SimBridge.getPDFPage(view.name, page), currentPage: page });
60+
view && setView({ ...view, blob: await simbridge.getPDFPage(view.name, page), currentPage: page });
5561
} catch (e: unknown) {
5662
e instanceof Error && setModal(<InfoModal title="Error" description={e.message} />);
5763
}
@@ -76,18 +82,27 @@ export const Files: FC = () => {
7682
setDocumentLoading(false);
7783
};
7884

85+
const checkHealth = async () => {
86+
if (await simbridge.getHealth()) {
87+
setSimbridgeConnection(true);
88+
!files && getFiles();
89+
}
90+
};
91+
7992
useEffect(() => {
80-
!files && getFiles();
93+
checkHealth();
8194
}, []);
8295

8396
return (
8497
<Container>
8598
<Sidebar
99+
simbridgeAvailable={simbridgeConnection}
86100
files={files}
87101
selected={view?.name}
88102
onSelect={handleSelect}
89103
ofpSelected={ofpSelected}
90104
onSelectOfp={handleSelectOfp}
105+
onRefresh={() => simbridgeConnection ? getFiles() : checkHealth()}
91106
/>
92107
<ContentSection ref={contentSectionRef}>
93108
{!view && !ofpSelected && !documentLoading && <SelectAFile>Select a file</SelectAFile>}

src/instruments/src/EFB/apps/Settings/Aircraft.tsx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { FC } from "react";
1+
import React, { FC, useContext } from "react";
22

33
import { ContentPageContainer } from "./components/ContentPageContainer";
44
import { usePersistentProperty } from "@instruments/common/persistence";
@@ -9,24 +9,55 @@ import { SelectableItem } from "./components/SelectableItem";
99

1010
import { BoeingAutoFuelMode, BoeingIrsAlignTimeMode, BoeingNdHdgTrkUpMode } from "../../lib/settings";
1111
import { useSetting } from "../../hooks/useSettings";
12+
import { SettingsContext } from "./SettingsContext";
13+
import { ListItem } from "../../components/ListItem";
14+
import { Input } from "../../components/Input";
15+
import { ModalContext } from "../..";
16+
import { InfoModal } from "../../components/InfoModal";
1217

1318
export const Aircraft: FC = () => {
19+
const { simbridgePort, setSimbridgePort } = useContext(SettingsContext);
20+
const { setModal } = useContext(ModalContext);
21+
1422
const [trkUp, setTrkUp] = useSetting("boeingMsfsNdHdgTrkUpMode");
1523
const [autoFuelManagement, setAutoFuelManagement] = useSetting("boeingMsfsAutoFuelManagement");
1624

25+
const handlePort = (val: string) => {
26+
const parsed = parseInt(val);
27+
if (!isNaN(parsed) && parsed.toString().length <= 5) {
28+
setSimbridgePort(parsed);
29+
} else {
30+
setModal(<InfoModal title="Error" description="Invalid port"/>)
31+
}
32+
};
33+
1734
return (
1835
<ContentPageContainer title="Aircraft">
1936
<ItemGroup>
20-
<Toggle label="ND Track Up"
21-
enabled={trkUp === BoeingNdHdgTrkUpMode.TRK}
22-
onClick={(enabled) => setTrkUp(enabled ? BoeingNdHdgTrkUpMode.HDG : BoeingNdHdgTrkUpMode.TRK)}
37+
<Toggle
38+
label="ND Track Up"
39+
enabled={trkUp === BoeingNdHdgTrkUpMode.TRK}
40+
onClick={(enabled) => setTrkUp(enabled ? BoeingNdHdgTrkUpMode.HDG : BoeingNdHdgTrkUpMode.TRK)}
2341
/>
2442
<Toggle
2543
label="Automatic Fuel Management"
2644
enabled={autoFuelManagement === BoeingAutoFuelMode.ON}
2745
onClick={(enabled) => setAutoFuelManagement(enabled ? BoeingAutoFuelMode.OFF : BoeingAutoFuelMode.ON)}
2846
/>
2947
</ItemGroup>
48+
<ItemGroup>
49+
<ListItem>
50+
<div className="side">SimBridge Port</div>
51+
<Input
52+
placeholder={simbridgePort.toString()}
53+
centerPlaceholder={false}
54+
placeholderAlign="right"
55+
style={{ borderBottom: "none", textAlign: "right", margin: "0 15px", fontSize: "26px" }}
56+
onFocusOut={handlePort}
57+
clearOnFocusOut
58+
/>
59+
</ListItem>
60+
</ItemGroup>
3061
<ItemGroup>
3162
<NavigationItem name="IRS Alignment Time" path="/settings/irs-alignment" />
3263
<NavigationItem name="Pilot Visibility" path="/settings/pilot-visibility" />

src/instruments/src/EFB/apps/Settings/SettingsContext.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ type SettingsContextProps = {
99
setTafSource: (source: TafSource) => void;
1010
atisSource: AtisSource;
1111
setAtisSource: (source: AtisSource) => void;
12+
simbridgePort: number;
13+
setSimbridgePort: (port: number) => void;
1214
};
1315

14-
const defaults: Pick<SettingsContextProps, "metarSource" | "tafSource" | "atisSource"> = {
16+
const defaults: Pick<SettingsContextProps, "metarSource" | "tafSource" | "atisSource" | "simbridgePort"> = {
1517
metarSource: "msfs",
1618
tafSource: "met",
1719
atisSource: "vatsim",
20+
simbridgePort: 8380,
1821
};
1922

2023
export const SettingsContext = React.createContext<SettingsContextProps>({
@@ -24,6 +27,8 @@ export const SettingsContext = React.createContext<SettingsContextProps>({
2427
setTafSource: () => {},
2528
atisSource: defaults.atisSource,
2629
setAtisSource: () => {},
30+
simbridgePort: defaults.simbridgePort,
31+
setSimbridgePort: () => {},
2732
});
2833

2934
export const SettingsContextProvider: FC<{ children: ReactNode | ReactNode[] }> = ({ children }) => {
@@ -40,6 +45,7 @@ export const SettingsContextProvider: FC<{ children: ReactNode | ReactNode[] }>
4045
(s: AtisSource) => void
4146
];
4247

48+
const [simbridgePort, setSimbridgePort] = usePersistentPropertyWithDefault("SALTY_SIMBRIDGE_PORT", defaults.simbridgePort.toString());
4349
return (
4450
<SettingsContext.Provider
4551
value={{
@@ -49,6 +55,8 @@ export const SettingsContextProvider: FC<{ children: ReactNode | ReactNode[] }>
4955
setTafSource,
5056
atisSource,
5157
setAtisSource,
58+
simbridgePort: parseInt(simbridgePort),
59+
setSimbridgePort,
5260
}}
5361
>
5462
{children}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useContext } from "react";
2+
import { SettingsContext } from "../apps/Settings/SettingsContext";
3+
import { SimBridge } from "../lib/simbridge";
4+
5+
export const useSimBridge = () => {
6+
const { simbridgePort } = useContext(SettingsContext);
7+
8+
const simbridge = new SimBridge(simbridgePort);
9+
10+
return simbridge;
11+
};

0 commit comments

Comments
 (0)