Skip to content

Commit

Permalink
Merge branch 'master' into feature/move-to-home
Browse files Browse the repository at this point in the history
  • Loading branch information
Saschl authored Oct 13, 2024
2 parents 6f52131 + 775494d commit 330a460
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 439 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "fbw-installer",
"productName": "FlyByWire Installer",
"version": "3.4.0-dev.1",
"version": "3.4.2-dev.1",
"description": "Desktop application to install and customize FlyByWire addons",
"configUrls": {
"production": "https://cdn.flybywiresim.com/installer/config/production.json",
Expand Down Expand Up @@ -103,7 +103,7 @@
"webpack-dev-server": "^4.4.0"
},
"dependencies": {
"@flybywiresim/fragmenter": "^0.7.4",
"@flybywiresim/fragmenter": "^0.8.0",
"@reduxjs/toolkit": "^1.7.1",
"@sentry/cli": "^2.31.0",
"@sentry/electron": "^4.23.0",
Expand Down
15 changes: 6 additions & 9 deletions src/renderer/components/AddonSection/Configure/TrackSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,25 @@ type TrackProps = {
};

export const Track: React.FC<TrackProps> = ({ isSelected, isInstalled, handleSelected, addon, track }) => {
const latestVersionName = useSelector<InstallerStore, string>(
(state) => state.latestVersionNames[addon.key]?.[track.key]?.name ?? '<unknown>',
const latestVersionName = useSelector<InstallerStore, string | undefined>(
(state) => state.latestVersionNames[addon.key]?.[track.key]?.name,
);

return (
<div
className={twMerge(
`relative flex w-60 cursor-pointer flex-row items-center rounded-sm-md border-2 border-transparent bg-navy-dark text-white transition-all duration-200 hover:border-navy-lightest hover:text-gray-300`,
`flex w-60 h-24 cursor-pointer flex-col rounded-sm-md border-2 border-transparent bg-navy-dark text-white transition-all duration-200 hover:border-navy-lightest hover:text-gray-300`,
isSelected && 'border-2 border-cyan text-cyan',
)}
onClick={() => handleSelected(track)}
>
<div
className={`h-12 w-1 rounded-r-xl transition-all duration-200${isSelected ? 'scale-y-100' : 'scale-y-50'}`}
/>
<div className="flex flex-col px-3 py-2.5">
<span className="text-xl text-current">{track.name}</span>
<span className="mt-0.5 font-manrope text-3xl font-medium tracking-wider text-current">
{latestVersionName}
<span className="mt-0.5 flex justify-between font-manrope text-3xl font-medium tracking-wider text-current">
{latestVersionName ?? <span className="mt-1.5 block h-7 w-32 animate-pulse bg-navy-light"></span>}
{isInstalled && <Check className={`-mt-3.5 stroke-current text-cyan`} strokeWidth={3} />}
</span>
</div>
{isInstalled && <Check className={`absolute right-4 stroke-current text-cyan`} strokeWidth={3} />}
</div>
);
};
12 changes: 6 additions & 6 deletions src/renderer/components/AddonSection/Configure/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import rehypeRaw from 'rehype-raw';
export interface ConfigureProps {
routeAspectKey: string;
selectedAddon: Addon;
selectedTrack: AddonTrack;
installedTrack: AddonTrack;
selectedTrack: AddonTrack | null;
installedTrack: AddonTrack | null;
onTrackSelection: (track: AddonTrack) => void;
}

Expand Down Expand Up @@ -41,8 +41,8 @@ export const Configure: FC<ConfigureProps> = ({
addon={selectedAddon}
key={track.key}
track={track}
isSelected={selectedTrack === track}
isInstalled={installedTrack === track}
isSelected={selectedTrack?.key === track.key}
isInstalled={installedTrack?.key === track.key}
handleSelected={() => onTrackSelection(track)}
/>
))}
Expand All @@ -58,8 +58,8 @@ export const Configure: FC<ConfigureProps> = ({
addon={selectedAddon}
key={track.key}
track={track}
isSelected={selectedTrack === track}
isInstalled={installedTrack === track}
isSelected={selectedTrack?.key === track.key}
isInstalled={installedTrack?.key === track.key}
handleSelected={() => onTrackSelection(track)}
/>
))}
Expand Down
95 changes: 11 additions & 84 deletions src/renderer/components/AddonSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ import React, { FC, useCallback, useEffect, useState } from 'react';
import { setupInstallPath } from 'renderer/actions/install-path.utils';
import { DownloadItem } from 'renderer/redux/types';
import { useSelector } from 'react-redux';
import { getCurrentInstall } from '@flybywiresim/fragmenter';
import { InstallerStore, useAppDispatch, useAppSelector } from '../../redux/store';
import { Addon, AddonCategoryDefinition, AddonTrack } from 'renderer/utils/InstallerConfiguration';
import { Directories } from 'renderer/utils/Directories';
import { NavLink, Redirect, Route, useHistory, useParams } from 'react-router-dom';
import { Gear, InfoCircle, JournalText, Sliders } from 'react-bootstrap-icons';
import settings, { useSetting } from 'renderer/rendererSettings';
import { ipcRenderer } from 'electron';
import { AddonBar, AddonBarItem } from '../App/AddonBar';
import { NoAvailableAddonsSection } from '../NoAvailableAddonsSection';
import { ReleaseNotes } from './ReleaseNotes';
import { setInstalledTrack } from 'renderer/redux/features/installedTrack';
import { InstallState, setInstallStatus } from 'renderer/redux/features/installStatus';
import { setSelectedTrack } from 'renderer/redux/features/selectedTrack';
import { PromptModal, useModals } from 'renderer/components/Modal';
import ReactMarkdown from 'react-markdown';
Expand Down Expand Up @@ -129,13 +125,6 @@ export const AddonSection = (): JSX.Element => {

const installedTrack = (installedTracks[selectedAddon.key] as AddonTrack) ?? null;

const setCurrentlyInstalledTrack = useCallback(
(newInstalledTrack: AddonTrack) => {
dispatch(setInstalledTrack({ addonKey: selectedAddon.key, installedTrack: newInstalledTrack }));
},
[dispatch, selectedAddon.key],
);

const setCurrentlySelectedTrack = useCallback(
(newSelectedTrack: AddonTrack) => {
dispatch(setSelectedTrack({ addonKey: selectedAddon.key, track: newSelectedTrack }));
Expand All @@ -145,79 +134,12 @@ export const AddonSection = (): JSX.Element => {

const selectedTrack = (selectedTracks[selectedAddon.key] as AddonTrack) ?? null;

const selectAndSetTrack = useCallback(
(key: string) => {
const newTrack = selectedAddon.tracks.find((track) => track.key === key);
setCurrentlySelectedTrack(newTrack);
},
[selectedAddon.tracks, setCurrentlySelectedTrack],
);

const getCurrentInstallStatus = (): InstallState => {
try {
return installStates[selectedAddon.key];
} catch (e) {
setCurrentInstallStatus({ status: InstallStatus.Unknown });
return { status: InstallStatus.Unknown };
}
};

const setCurrentInstallStatus = useCallback(
(new_state: InstallState) => {
dispatch(setInstallStatus({ addonKey: selectedAddon.key, installState: new_state }));
},
[dispatch, selectedAddon.key],
);

const findInstalledTrack = useCallback((): AddonTrack => {
if (!Directories.isFragmenterInstall(selectedAddon)) {
console.log('Not installed');
if (selectedTrack) {
selectAndSetTrack(selectedTrack.key);
return selectedTrack;
} else {
setCurrentlySelectedTrack(selectedAddon.tracks[0]);
return selectedAddon.tracks[0];
}
}

try {
const manifest = getCurrentInstall(Directories.inInstallLocation(selectedAddon.targetDirectory));
console.log('Currently installed', manifest);

let track = selectedAddon.tracks.find((track) => track.url.includes(manifest.source));
if (!track) {
track = selectedAddon.tracks.find((track) => track.alternativeUrls?.includes(manifest.source));
}

console.log('Currently installed', track);
setCurrentlyInstalledTrack(track);
if (selectedTrack) {
selectAndSetTrack(selectedTrack.key);
return selectedTrack;
} else {
setCurrentlySelectedTrack(track);
return track;
}
} catch (e) {
console.error(e);
console.log('Not installed');
if (selectedTrack) {
selectAndSetTrack(selectedTrack.key);
return selectedTrack;
} else {
setCurrentlySelectedTrack(selectedAddon.tracks[0]);
return selectedAddon.tracks[0];
}
}
}, [selectAndSetTrack, selectedAddon, selectedTrack, setCurrentlyInstalledTrack, setCurrentlySelectedTrack]);

const download: DownloadItem = useSelector((state: InstallerStore) =>
state.downloads.find((download) => download.id === selectedAddon.key),
);

const isDownloading = download?.progress.totalPercent >= 0;
const status = getCurrentInstallStatus()?.status;
const status = installStates[selectedAddon.key]?.status;
const isInstalling = InstallStatusCategories.installing.includes(status);
const isFinishingDependencyInstall = status === InstallStatus.InstallingDependencyEnding;

Expand Down Expand Up @@ -255,11 +177,10 @@ export const AddonSection = (): JSX.Element => {
}, [dispatch, publisherData, selectedAddon]);

useEffect(() => {
findInstalledTrack();
if (!isInstalling) {
InstallManager.determineAddonInstallState(selectedAddon).then(setCurrentInstallStatus);
void InstallManager.refreshAddonInstallState(selectedAddon);
}
}, [findInstalledTrack, isInstalling, selectedAddon, setCurrentInstallStatus]);
}, [isInstalling, selectedAddon]);

useEffect(() => {
if (download && isDownloading) {
Expand Down Expand Up @@ -288,13 +209,19 @@ export const AddonSection = (): JSX.Element => {
bodyText={track.warningContent}
confirmColor={ButtonType.Caution}
onConfirm={() => {
selectAndSetTrack(track.key);
setCurrentlySelectedTrack(track);

// Update install state
void InstallManager.refreshAddonInstallState(selectedAddon);
}}
dontShowAgainSettingName="mainSettings.disableExperimentalWarning"
/>,
);
} else {
selectAndSetTrack(track.key);
setCurrentlySelectedTrack(track);

// Update install state
void InstallManager.refreshAddonInstallState(selectedAddon);
}
}
};
Expand Down
69 changes: 10 additions & 59 deletions src/renderer/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,73 +4,21 @@ import SimpleBar from 'simplebar-react';
import { Logo } from 'renderer/components/Logo';
import { SettingsSection } from 'renderer/components/SettingsSection';
import { DebugSection } from 'renderer/components/DebugSection';
import { GitVersions } from '@flybywiresim/api-client';
import { DataCache } from '../../utils/DataCache';
import { InstallerUpdate } from 'renderer/components/InstallerUpdate';
import { WindowButtons } from 'renderer/components/WindowActionButtons';
import { Addon, AddonVersion } from 'renderer/utils/InstallerConfiguration';
import { AddonData } from 'renderer/utils/AddonData';
import { Addon } from 'renderer/utils/InstallerConfiguration';
import { ErrorModal } from '../ErrorModal';
import { NavBar, NavBarPublisher } from 'renderer/components/App/NavBar';
import { Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom';
import { store, useAppSelector } from 'renderer/redux/store';
import { setAddonAndTrackLatestReleaseInfo } from 'renderer/redux/features/latestVersionNames';
import { useAppSelector } from 'renderer/redux/store';
import settings from 'renderer/rendererSettings';
import './index.css';
import { ipcRenderer } from 'electron';
import channels from 'common/channels';
import { ModalContainer } from '../Modal';
import { PublisherSection } from 'renderer/components/PublisherSection';
import * as packageInfo from '../../../../package.json';

const releaseCache = new DataCache<AddonVersion[]>('releases', 1000 * 3600 * 24);

/**
* Obtain releases for a specific addon
*
* @param addon
*/
export const getAddonReleases = async (addon: Addon): Promise<AddonVersion[]> => {
const releases = (
await releaseCache.fetchOrCompute(async (): Promise<AddonVersion[]> => {
return (await GitVersions.getReleases(addon.repoOwner, addon.repoName))
.filter((r) => /v\d/.test(r.name))
.map((r) => ({ title: r.name, date: r.publishedAt, type: 'minor' }));
})
).map((r) => ({ ...r, date: new Date(r.date) })); // Local Data cache returns a string instead of Date

releases.forEach((version, index) => {
const currentVersionTitle = version.title;
const otherVersionTitle = index === releases.length - 1 ? releases[index - 1].title : releases[index + 1].title;

if (currentVersionTitle[1] !== otherVersionTitle[1]) {
releases[index].type = 'major';
} else if (currentVersionTitle[3] !== otherVersionTitle[3]) {
releases[index].type = 'minor';
} else if (currentVersionTitle[5] !== otherVersionTitle[5] && index === releases.length - 1) {
releases[index].type = 'minor';
} else if (currentVersionTitle[5] !== otherVersionTitle[5]) {
releases[index].type = 'patch';
}
});

return releases;
};

export const fetchLatestVersionNames = async (addon: Addon): Promise<void> => {
const dispatch = store.dispatch;

for (const track of addon.tracks) {
const trackLatestVersionName = await AddonData.latestVersionForTrack(addon, track);
dispatch(
setAddonAndTrackLatestReleaseInfo({
addonKey: addon.key,
trackKey: track.key,
info: trackLatestVersionName,
}),
);
}
};
import { InstallManager } from 'renderer/utils/InstallManager';

const App = () => {
const history = useHistory();
Expand All @@ -86,8 +34,9 @@ const App = () => {
);

useEffect(() => {
addons.forEach(AddonData.configureInitialAddonState);
addons.forEach(fetchLatestVersionNames);
for (const addon of addons) {
void InstallManager.refreshAddonInstallState(addon).then(() => void InstallManager.checkForUpdates(addon));
}

if (settings.get('cache.main.lastShownSection')) {
history.push(settings.get('cache.main.lastShownSection'));
Expand All @@ -103,8 +52,10 @@ const App = () => {
const updateCheck = setInterval(
() => {
ipcRenderer.send(channels.checkForInstallerUpdate);
addons.forEach(AddonData.checkForUpdates);
addons.forEach(fetchLatestVersionNames);

for (const addon of addons) {
void InstallManager.checkForUpdates(addon);
}
},
5 * 60 * 1000,
);
Expand Down
Loading

0 comments on commit 330a460

Please sign in to comment.