Skip to content

Commit

Permalink
Bugfix/live 8698 Manager API v2 breaking changes adaptations (#4896)
Browse files Browse the repository at this point in the history
* fix(common/manager/listAppsV2): handle breaking change in /v2/apps/hash

* fix(lld,llm/featureflags): replace listAppsV2 by listAppsV2dot1

* fix(lld,llm/featureflags): replace listAppsV2dot1 by listAppsV2minot1

* fix(common/types-live): default feature val for listAppsV2minor1

* docs(llc/manager/api): change comment on getAppsByHash

* fix(common/manager/api): add MANAGER_API_BASE env to caching key extractor

* fix(common/apps/polyfill): same currencyId polyfill logic in v1 and v2

* fix(llm/InstalledAppsModal): UninstallDependenciesModal not opening

* style(llm, common): lint

* fix(llm/InstalledAppsModal): layout issues when too many apps

* refacto(llm/manager): replace prop drilling hell by context

* refactor(llm/manager): type fix & stateless install/uninstall modals

* fix(llm/InstallAppDependenciesModal): styling

* refacto(common/listapps/v2): reorder without breaking + document

* style(llm, common): lint

* style(llm): rename action installAppFirstTime to setHasInstalledAnyApp

* fix(llm): dispatch setHasInstalledAnyApp in installAppWithDependencies

* chore: changeset

* fix(manager): using correct dispatch

* docs(common/listApps): fix typos

* refactor(manager/api): clearer String(array)

* docs: remove outdated todo

---------

Co-authored-by: OlivierFreyssinet <olivier.freyssinet@gmail.com>
  • Loading branch information
1 parent 63657e5 commit 95cf52e
Show file tree
Hide file tree
Showing 25 changed files with 325 additions and 300 deletions.
9 changes: 9 additions & 0 deletions .changeset/fresh-squids-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@ledgerhq/types-live": patch
"@ledgerhq/live-common": patch
"ledger-live-desktop": patch
"live-mobile": patch
---

Feature flag listAppsV2 replaced by listAppsV2minor1
Fix listApps v2 logic: adapt to breaking changes in the API and fix "polyfilling" logic of data of apps
8 changes: 8 additions & 0 deletions .changeset/poor-cobras-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"live-mobile": patch
---

Fix interaction between "InstalledAppsModal" and "UninstallDependenciesModal", the later one was not getting opened in case an app with dependents was getting uninstalled from the first one, due to a bad usage of drawers (not using QueuedDrawer).
Refactor prop drilling nightmare of setAppInstallWithDependencies/setAppUninstallWithDependencies with a simple React.Context.
Refactor InstalledAppDependenciesModal and UninstallAppDependenciesModal to have no business logic inside
Rename action creator installAppFirstTime to setHasInstalledAnyApp for more clarity
2 changes: 1 addition & 1 deletion apps/ledger-live-desktop/src/renderer/Default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default function Default() {
useFetchCurrencyFrom();
const discoverDB = useDiscoverDB();

const listAppsV2 = useFeature("listAppsV2");
const listAppsV2 = useFeature("listAppsV2minor1");
useEffect(() => {
if (!listAppsV2) return;
enableListAppsV2(listAppsV2.enabled);
Expand Down
6 changes: 3 additions & 3 deletions apps/ledger-live-mobile/src/actions/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
SettingsHideNftCollectionPayload,
SettingsImportDesktopPayload,
SettingsImportPayload,
SettingsInstallAppFirstTimePayload,
SettingsSetHasInstalledAnyAppPayload,
SettingsLastSeenDeviceInfoPayload,
SettingsLastSeenDevicePayload,
SettingsRemoveStarredMarketcoinsPayload,
Expand Down Expand Up @@ -115,8 +115,8 @@ export const clearLastSeenCustomImage = () =>
export const completeOnboarding = createAction<SettingsCompleteOnboardingPayload>(
SettingsActionTypes.SETTINGS_COMPLETE_ONBOARDING,
);
export const installAppFirstTime = createAction<SettingsInstallAppFirstTimePayload>(
SettingsActionTypes.SETTINGS_INSTALL_APP_FIRST_TIME,
export const setHasInstalledAnyApp = createAction<SettingsSetHasInstalledAnyAppPayload>(
SettingsActionTypes.SETTINGS_SET_HAS_INSTALLED_ANY_APP,
);
export const switchCountervalueFirst = createAction(
SettingsActionTypes.SETTINGS_SWITCH_COUNTERVALUE_FIRST,
Expand Down
6 changes: 3 additions & 3 deletions apps/ledger-live-mobile/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ export enum SettingsActionTypes {
SETTINGS_SET_SELECTED_TIME_RANGE = "SETTINGS_SET_SELECTED_TIME_RANGE",
SETTINGS_COMPLETE_ONBOARDING = "SETTINGS_COMPLETE_ONBOARDING",
SETTINGS_COMPLETE_CUSTOM_IMAGE_FLOW = "SETTINGS_COMPLETE_CUSTOM_IMAGE_FLOW",
SETTINGS_INSTALL_APP_FIRST_TIME = "SETTINGS_INSTALL_APP_FIRST_TIME",
SETTINGS_SET_HAS_INSTALLED_ANY_APP = "SETTINGS_SET_HAS_INSTALLED_ANY_APP",
SETTINGS_SET_READONLY_MODE = "SETTINGS_SET_READONLY_MODE",
SETTINGS_SET_EXPERIMENTAL_USB_SUPPORT = "SETTINGS_SET_EXPERIMENTAL_USB_SUPPORT",
SETTINGS_SWITCH_COUNTERVALUE_FIRST = "SETTINGS_SWITCH_COUNTERVALUE_FIRST",
Expand Down Expand Up @@ -297,7 +297,7 @@ export type SettingsSetCountervaluePayload = SettingsState["counterValue"];
export type SettingsSetOrderAccountsPayload = SettingsState["orderAccounts"];
export type SettingsSetPairsPayload = { pairs: Array<Pair> };
export type SettingsSetSelectedTimeRangePayload = SettingsState["selectedTimeRange"];
export type SettingsInstallAppFirstTimePayload = SettingsState["hasInstalledAnyApp"];
export type SettingsSetHasInstalledAnyAppPayload = SettingsState["hasInstalledAnyApp"];
export type SettingsSetReadOnlyModePayload = SettingsState["readOnlyModeEnabled"];
export type SettingsHideEmptyTokenAccountsPayload = SettingsState["hideEmptyTokenAccounts"];
export type SettingsFilterTokenOperationsZeroAmountPayload =
Expand Down Expand Up @@ -388,7 +388,7 @@ export type SettingsPayload =
| SettingsSetOrderAccountsPayload
| SettingsSetPairsPayload
| SettingsSetSelectedTimeRangePayload
| SettingsInstallAppFirstTimePayload
| SettingsSetHasInstalledAnyAppPayload
| SettingsSetReadOnlyModePayload
| SettingsHideEmptyTokenAccountsPayload
| SettingsShowTokenPayload
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function RootNavigator() {
const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector);
const goToOnboarding = !hasCompletedOnboarding && !Config.SKIP_ONBOARDING;

const listAppsV2 = useFeature("listAppsV2");
const listAppsV2 = useFeature("listAppsV2minor1");
useEffect(() => {
if (!listAppsV2) return;
enableListAppsV2(listAppsV2.enabled);
Expand Down
6 changes: 3 additions & 3 deletions apps/ledger-live-mobile/src/reducers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import type {
SettingsHideNftCollectionPayload,
SettingsImportDesktopPayload,
SettingsImportPayload,
SettingsInstallAppFirstTimePayload,
SettingsSetHasInstalledAnyAppPayload,
SettingsLastSeenDeviceInfoPayload,
SettingsPayload,
SettingsRemoveStarredMarketcoinsPayload,
Expand Down Expand Up @@ -304,9 +304,9 @@ const handlers: ReducerMap<SettingsState, SettingsPayload> = {
};
},

[SettingsActionTypes.SETTINGS_INSTALL_APP_FIRST_TIME]: (state, action) => ({
[SettingsActionTypes.SETTINGS_SET_HAS_INSTALLED_ANY_APP]: (state, action) => ({
...state,
hasInstalledAnyApp: (action as Action<SettingsInstallAppFirstTimePayload>).payload,
hasInstalledAnyApp: (action as Action<SettingsSetHasInstalledAnyAppPayload>).payload,
}),

[SettingsActionTypes.SETTINGS_SET_READONLY_MODE]: (state, action) => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { App } from "@ledgerhq/types-live";
import React, { useContext } from "react";

/**
* Represents an installed app that depends on other installed apps.
* For instance:
* `{ app: polygonApp, dependents: [ethereumApp] }`
*/
export type AppWithDependencies = {
app: App;
dependencies: App[];
};

/**
* Represents an installed app that has other installed apps depending on it.
* For instance:
* `{ app: ethereumApp, dependents: [polygonApp] }`
*/
export type AppWithDependents = {
app: App;
dependents: App[];
};

type AppsInstallUninstallWithDependenciesValue = {
setAppWithDependenciesToInstall: (appWithDependencies: AppWithDependencies | null) => void;
setAppWithDependentsToUninstall: (appWithDependents: AppWithDependents | null) => void;
};

/**
* Defines setters for apps to install with their dependencies or apps to
* uninstall with their dependents.
* This context was introduced to avoid prop drilling.
*/
const AppsInstallUninstallWithDependenciesContext = React.createContext<
AppsInstallUninstallWithDependenciesValue | undefined
>(undefined);

export const AppsInstallUninstallWithDependenciesContextProvider =
AppsInstallUninstallWithDependenciesContext.Provider;

export function useSetAppsWithDependenciesToInstallUninstall() {
const contextValue = useContext(AppsInstallUninstallWithDependenciesContext);
if (contextValue === undefined)
throw new Error(
"useAppsInstallUninstallWithDependencies must be used within a context provider",
);
return contextValue;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import { useAppInstallNeedsDeps } from "@ledgerhq/live-common/apps/react";
import styled from "styled-components/native";
import { IconsLegacy, Box } from "@ledgerhq/native-ui";
import { hasInstalledAnyAppSelector } from "../../../reducers/settings";
import { installAppFirstTime } from "../../../actions/settings";
import { setHasInstalledAnyApp } from "../../../actions/settings";
import { useSetAppsWithDependenciesToInstallUninstall } from "../AppsInstallUninstallWithDependenciesContext";

type Props = {
app: App;
state: State;
dispatch: (_: Action) => void;
notEnoughMemoryToInstall: boolean;
setAppInstallWithDependencies: (_: { app: App; dependencies: App[] }) => void;
storageWarning: (_: string) => void;
};

Expand All @@ -34,7 +34,6 @@ export default function AppInstallButton({
state,
dispatch: dispatchProps,
notEnoughMemoryToInstall,
setAppInstallWithDependencies,
storageWarning,
}: Props) {
const dispatch = useDispatch();
Expand All @@ -46,6 +45,8 @@ export default function AppInstallButton({

const needsDependencies = useAppInstallNeedsDeps(state, app);

const { setAppWithDependenciesToInstall } = useSetAppsWithDependenciesToInstallUninstall();

const disabled = useMemo(
() => !canBeInstalled || updateAllQueue.length > 0,
[canBeInstalled, updateAllQueue.length],
Expand All @@ -57,21 +58,21 @@ export default function AppInstallButton({
storageWarning(name);
return;
}
if (needsDependencies && setAppInstallWithDependencies) {
setAppInstallWithDependencies(needsDependencies);
if (needsDependencies) {
setAppWithDependenciesToInstall(needsDependencies);
} else {
dispatchProps({ type: "install", name });
}
if (!hasInstalledAnyApp) {
dispatch(installAppFirstTime(true));
dispatch(setHasInstalledAnyApp(true));
}
}, [
disabled,
dispatch,
dispatchProps,
name,
needsDependencies,
setAppInstallWithDependencies,
setAppWithDependenciesToInstall,
hasInstalledAnyApp,
notEnoughMemoryToInstall,
storageWarning,
Expand Down
14 changes: 1 addition & 13 deletions apps/ledger-live-mobile/src/screens/Manager/AppsList/AppRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ type Props = {
app: App;
state: State;
dispatch: (_: Action) => void;
setAppInstallWithDependencies: (_: { app: App; dependencies: App[] }) => void;
setAppUninstallWithDependencies: (_: { dependents: App[]; app: App }) => void;
setStorageWarning: (value: string | null) => void;
optimisticState: State;
};
Expand Down Expand Up @@ -52,15 +50,7 @@ const VersionContainer = styled(Flex).attrs({
marginTop: 2,
})``;

const AppRow = ({
app,
state,
dispatch,
setAppInstallWithDependencies,
setAppUninstallWithDependencies,
setStorageWarning,
optimisticState,
}: Props) => {
const AppRow = ({ app, state, dispatch, setStorageWarning, optimisticState }: Props) => {
const { name, bytes, version: appVersion, displayName } = app;
const { installed, deviceInfo } = state;
const canBeInstalled = useMemo(() => manager.canHandleInstall(app), [app]);
Expand Down Expand Up @@ -111,8 +101,6 @@ const AppRow = ({
dispatch={dispatch}
notEnoughMemoryToInstall={notEnoughMemoryToInstall}
isInstalled={!!isInstalled}
setAppInstallWithDependencies={setAppInstallWithDependencies}
setAppUninstallWithDependencies={setAppUninstallWithDependencies}
storageWarning={onSizePress}
/>
</RowContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ type Props = {
dispatch: (_: Action) => void;
notEnoughMemoryToInstall: boolean;
isInstalled: boolean;
setAppInstallWithDependencies: (_: { app: App; dependencies: App[] }) => void;
setAppUninstallWithDependencies: (_: { dependents: App[]; app: App }) => void;
storageWarning: (appName: string) => void;
};

Expand All @@ -34,8 +32,6 @@ const AppStateButton = ({
dispatch,
notEnoughMemoryToInstall,
isInstalled,
setAppInstallWithDependencies,
setAppUninstallWithDependencies,
storageWarning,
}: Props) => {
const { installed, installQueue, uninstallQueue, updateAllQueue } = state;
Expand Down Expand Up @@ -63,22 +59,14 @@ const AppStateButton = ({
case canUpdate:
return <AppUpdateButton app={app} state={state} dispatch={dispatch} />;
case isInstalled:
return (
<AppUninstallButton
app={app}
state={state}
dispatch={dispatch}
setAppUninstallWithDependencies={setAppUninstallWithDependencies}
/>
);
return <AppUninstallButton app={app} state={state} dispatch={dispatch} />;
default:
return (
<AppInstallButton
state={state}
dispatch={dispatch}
app={app}
notEnoughMemoryToInstall={notEnoughMemoryToInstall}
setAppInstallWithDependencies={setAppInstallWithDependencies}
storageWarning={storageWarning}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import type { Action, State } from "@ledgerhq/live-common/apps/index";

import styled from "styled-components/native";
import { IconsLegacy, Box } from "@ledgerhq/native-ui";
import { useSetAppsWithDependenciesToInstallUninstall } from "../AppsInstallUninstallWithDependenciesContext";

type Props = {
app: App;
state: State;
dispatch: (_: Action) => void;
setAppUninstallWithDependencies: (_: { dependents: App[]; app: App }) => void;
size?: number;
};

Expand All @@ -23,17 +23,14 @@ const ButtonContainer = styled(Box).attrs({
justifyContent: "center",
})``;

const AppUninstallButton = ({
app,
state,
dispatch,
setAppUninstallWithDependencies,
size = 48,
}: Props) => {
const AppUninstallButton = ({ app, state, dispatch, size = 48 }: Props) => {
const { name } = app;

const needsDependencies = useAppUninstallNeedsDeps(state, app);

const { setAppWithDependentsToUninstall: setAppUninstallWithDependencies } =
useSetAppsWithDependenciesToInstallUninstall();

const uninstallApp = useCallback(() => {
if (needsDependencies && setAppUninstallWithDependencies)
setAppUninstallWithDependencies(needsDependencies);
Expand Down
17 changes: 1 addition & 16 deletions apps/ledger-live-mobile/src/screens/Manager/AppsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ type NavigationProps = BaseComposite<
type Props = {
state: State;
dispatch: (_: Action) => void;
setAppInstallWithDependencies: (_: { app: App; dependencies: App[] }) => void;
setAppUninstallWithDependencies: (_: { dependents: App[]; app: App }) => void;
setStorageWarning: (value: string | null) => void;
deviceId: string;
initialDeviceName?: string | null;
Expand All @@ -76,8 +74,6 @@ type Props = {
const AppsScreen = ({
state,
dispatch,
setAppInstallWithDependencies,
setAppUninstallWithDependencies,
setStorageWarning,
updateModalOpened,
deviceId,
Expand Down Expand Up @@ -232,20 +228,11 @@ const AppsScreen = ({
app={item}
state={state}
dispatch={dispatch}
setAppInstallWithDependencies={setAppInstallWithDependencies}
setAppUninstallWithDependencies={setAppUninstallWithDependencies}
setStorageWarning={setStorageWarning}
optimisticState={optimisticState}
/>
),
[
state,
dispatch,
setAppInstallWithDependencies,
setAppUninstallWithDependencies,
setStorageWarning,
optimisticState,
],
[state, dispatch, setStorageWarning, optimisticState],
);

const lastSeenDevice = useSelector(lastSeenDeviceSelector);
Expand All @@ -267,7 +254,6 @@ const AppsScreen = ({
initialDeviceName={initialDeviceName}
pendingInstalls={pendingInstalls}
deviceInfo={deviceInfo}
setAppUninstallWithDependencies={setAppUninstallWithDependencies}
dispatch={dispatch}
device={device}
appList={deviceApps}
Expand Down Expand Up @@ -325,7 +311,6 @@ const AppsScreen = ({
initialDeviceName,
pendingInstalls,
deviceInfo,
setAppUninstallWithDependencies,
dispatch,
device,
deviceApps,
Expand Down
Loading

1 comment on commit 95cf52e

@vercel
Copy link

@vercel vercel bot commented on 95cf52e Oct 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.