Skip to content

Commit

Permalink
Merge pull request #341 from Chia-Network/refactor/core-registry-chil…
Browse files Browse the repository at this point in the history
…d-app-adjustments

Refactor/core registry child app adjustments
  • Loading branch information
wwills2 authored Nov 12, 2024
2 parents 82a0488 + db0dad2 commit 15e5d0e
Show file tree
Hide file tree
Showing 18 changed files with 337 additions and 45 deletions.
132 changes: 113 additions & 19 deletions src/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,80 @@ import { IntlProvider } from 'react-intl';
import { loadLocaleData } from '@/translations';
import '@/App.css';
import { AppNavigator } from '@/routes';
import { resetApiHost, setConfigFileLoaded, setCoreRegistryMode, setHost, setLocale } from '@/store/slices/app';
import {
resetApiHost,
setConfigLoaded,
setCoreRegistryMode,
setHost,
setIsCoreRegistryUiApp,
setLocale,
} from '@/store/slices/app';
import { ComponentCenteredSpinner } from '@/components';
import { useGetHealthQuery, useGetThemeColorsQuery, useGetUiConfigQuery } from '@/api';
import {
getParentSettings,
isIframe,
notifyParentOfAppLoad,
ParentSettings,
reconcileSavedUrl,
} from '@/utils/unified-ui-utils';

/**
* @returns app react component to be rendered by electron as the UI
*/
function App() {
const isCoreRegistryUiChildApp = isIframe();
let settingsFromParentApp: ParentSettings | null = null;
if (isCoreRegistryUiChildApp) {
settingsFromParentApp = getParentSettings();
}

reconcileSavedUrl();

const dispatch = useDispatch();
const appStore = useSelector((state: any) => state.app);
const [translationTokens, setTranslationTokens] = useState<object>();
const [appLoading, setAppLoading] = useState(true);
const { data: fetchedConfig, isLoading: configFileLoading } = useGetUiConfigQuery();
const { data: fetchedThemeColors, isLoading: themeColorsFileLoading } = useGetThemeColorsQuery();
const { data: healthData, isLoading: healthDataLoading } = useGetHealthQuery(
{
apiHost: appStore?.apiHost,
apiKey: appStore?.apiKey,
},
{ skip: !appStore?.apiHost },
);
const { data: fetchedConfig, isLoading: configFileLoading } = useGetUiConfigQuery(undefined, {
skip: isCoreRegistryUiChildApp,
});
const { data: fetchedThemeColors, isLoading: themeColorsFileLoading } = useGetThemeColorsQuery(undefined, {
skip: isCoreRegistryUiChildApp,
});

if (isCoreRegistryUiChildApp !== appStore.isCoreRegistryUiApp) {
dispatch(setIsCoreRegistryUiApp({ isCoreRegistryUiApp: isCoreRegistryUiChildApp }));
}

const setThemeColors = (colors: any) => {
// apply loaded theme colors via changing css property values (see App.css)
Object.entries(colors).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--color-${key}`, value as string);
});
};

const setConfig = ({ apiHost, apiKey }: { apiHost: string; apiKey?: string }) => {
if (apiHost) {
if (apiKey) {
dispatch(setHost({ apiHost, apiKey }));
} else {
dispatch(setHost({ apiHost }));
}
dispatch(setConfigLoaded({ configLoaded: true }));
} else if (appStore.configFileLoaded) {
dispatch(resetApiHost());
dispatch(setConfigLoaded({ configLoaded: false }));
}
};

useEffect(() => notifyParentOfAppLoad(), []);

useEffect(() => {
if (Boolean(healthData?.coreRegistryMode) != appStore.coreRegistryMode) {
Expand All @@ -34,12 +87,7 @@ function App() {

useEffect(() => {
if (appStore.locale) {
const processTranslationTokens = async () => {
const tokens = loadLocaleData(appStore.locale);
setTranslationTokens(tokens);
};

processTranslationTokens();
setTranslationTokens(loadLocaleData(appStore.locale));
} else {
dispatch(setLocale(navigator.language));
}
Expand All @@ -54,22 +102,68 @@ function App() {
}
}, [fetchedThemeColors]);

// handle messages from parent
useEffect(() => {
if (fetchedConfig) {
if (fetchedConfig?.apiHost) {
dispatch(setHost({ apiHost: fetchedConfig.apiHost }));
const parentAppMessageListener = (event: MessageEvent) => {
if (event.origin === window.origin) {
const message = event.data;
if (message?.selectedLocale && message.selectedLocale !== appStore.locale) {
console.log('selected locale', message.selectedLocale);
dispatch(setLocale(message.selectedLocale));
}
}
dispatch(setConfigFileLoaded({ configFileLoaded: true }));
} else if (!configFileLoading && !fetchedConfig && appStore.configFileLoaded) {
dispatch(resetApiHost());
dispatch(setConfigFileLoaded({ configFileLoaded: false }));
};

window.addEventListener('message', parentAppMessageListener);

return () => window.removeEventListener('message', parentAppMessageListener);
}, [appStore.locale, dispatch]);

/*
2 different loading scenarios:
- as a stand-alone app fetching files
- as a child app getting connection settings from parent local storage. in this case the config file is ignored
*/

// handle setting the theme colors when fetched as standalone app
useEffect(() => {
if (fetchedThemeColors && !isCoreRegistryUiChildApp) {
setThemeColors(fetchedThemeColors);
}
}, [fetchedThemeColors, isCoreRegistryUiChildApp]);

// handle setting the config when fetched as standalone app
useEffect(() => {
if (!configFileLoading && fetchedConfig?.apiHost && !isCoreRegistryUiChildApp) {
setConfig({ apiHost: fetchedConfig?.apiHost });
}
}, [appStore.apiHost, appStore.configFileLoaded, fetchedConfig, configFileLoading, dispatch]);
}, [configFileLoading, fetchedConfig /* do not add setConfig */]);

//handle setting theme colors when loaded as child app
useEffect(() => {
if (isCoreRegistryUiChildApp && settingsFromParentApp?.colors) {
setThemeColors(settingsFromParentApp.colors);
}
}, [isCoreRegistryUiChildApp, settingsFromParentApp?.colors]);

//handle setting config when loaded as child app
useEffect(() => {
if (isCoreRegistryUiChildApp && settingsFromParentApp?.apiHost) {
setConfig({ apiHost: settingsFromParentApp?.apiHost, apiKey: settingsFromParentApp.apiKey });
}
}, [
isCoreRegistryUiChildApp,
settingsFromParentApp?.apiHost,
settingsFromParentApp?.apiKey,
/* do not add setConfig */
]);

useEffect(() => {
// give the setConfigFileLoaded action time to dispatch
if (!configFileLoading) setTimeout(() => setAppLoading(false), 400);
}, [configFileLoading]);
if (!configFileLoading || isCoreRegistryUiChildApp) {
setTimeout(() => setAppLoading(false), 400);
}
}, [configFileLoading, isCoreRegistryUiChildApp]);

if (!translationTokens || configFileLoading || themeColorsFileLoading || healthDataLoading || appLoading) {
return <ComponentCenteredSpinner />;
Expand Down
8 changes: 5 additions & 3 deletions src/renderer/components/blocks/buttons/ConnectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { useGetHealthQuery } from '@/api';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '@/store';
import { resetApiHost } from '@/store/slices/app';
import { reloadApplication } from '@/utils/unified-ui-utils';

const ConnectButton: React.FC = () => {
const location = useLocation();
const dispatch = useDispatch();
const [isActive, setActive] = useUrlHash('connect');
const { configFileLoaded } = useSelector((state: RootState) => state.app);
const { configFileLoaded, isCoreRegistryUiApp } = useSelector((state: RootState) => state.app);

const { data: serverHealth, isLoading, refetch } = useGetHealthQuery({});

Expand All @@ -32,18 +33,19 @@ const ConnectButton: React.FC = () => {

const handleDisconnect = () => {
dispatch(resetApiHost());
setTimeout(() => window.location.reload(), 0);
setTimeout(() => reloadApplication());
};

const onClose = () => {
refetch();
setTimeout(() => setActive(false));
setTimeout(() => window.location.reload(), 0);
setTimeout(() => reloadApplication());
};

return (
<>
<Button
disabled={isCoreRegistryUiApp}
color="none"
onClick={() => {
!serverHealth?.isHealthy ? setActive(true) : handleDisconnect();
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/components/blocks/forms/ConnectForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { FormattedMessage, IntlShape, useIntl } from 'react-intl';
import { useUrlHash } from '@/hooks';
import { useSelector } from 'react-redux';
import { RootState } from '@/store';
import { reloadApplication } from '@/utils/unified-ui-utils';

const validationSchema = yup.object({
apiHost: yup
Expand Down Expand Up @@ -53,7 +54,7 @@ const ConnectForm: React.FC<FormProps> = ({ onSubmit, hasServerError, onClearErr

const handleRetry = useCallback(() => {
setIsActive(false);
window.location.reload();
reloadApplication();
}, [setIsActive]);

return (
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/blocks/layout/LeftNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const LeftNav = () => {
<Sidebar.Item
style={{ cursor: 'pointer' }}
active={isActive(ROUTES.CREATE_TOKENS)}
onClick={() => navigate(ROUTES.CREATE_TOKENS)}
onClick={() => !isActive(ROUTES.CREATE_TOKENS) && navigate(ROUTES.CREATE_TOKENS)}
>
<p className="capitalize">
<FormattedMessage id="create-tokens" />
Expand All @@ -56,7 +56,7 @@ const LeftNav = () => {
<Sidebar.Item
style={{ cursor: 'pointer' }}
active={isActive(ROUTES.REVERT_TOKENS)}
onClick={() => navigate(ROUTES.REVERT_TOKENS)}
onClick={() => !isActive(ROUTES.REVERT_TOKENS) && navigate(ROUTES.REVERT_TOKENS)}
>
<p className="capitalize">
<FormattedMessage id="revert-tokens" />
Expand Down
8 changes: 7 additions & 1 deletion src/renderer/components/blocks/layout/Template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { ErrorBoundary } from '@/pages';
import { LeftNav } from './LeftNav';
import { Outlet } from 'react-router-dom';
import { Header } from '@/components';
import { useManageSavedLocation } from '@/hooks';
import { useSelector } from 'react-redux';
import { RootState } from '@/store';

const Template = () => {
const isCoreRegistryUiApp = useSelector((state: RootState) => state.app.isCoreRegistryUiApp);
useManageSavedLocation();

return (
<ErrorBoundary>
<div id="app" className="dark:bg-gray-800 w-full h-dvh">
Expand All @@ -12,7 +18,7 @@ const Template = () => {
<LeftNav />
<div id="content" className="w-full relative dark:text-white">
<ErrorBoundary>
<div style={{ height: 'calc(100vh - 64px)' }}>
<div style={{ height: isCoreRegistryUiApp ? '100vh' : 'calc(100vh - 64px)' }}>
<Outlet />
</div>
</ErrorBoundary>
Expand Down
28 changes: 21 additions & 7 deletions src/renderer/components/blocks/modals/ConnectModal.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import React, { useState } from 'react';
import { ConnectForm, Modal } from '@/components';
import { FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { setHost } from '@/store/slices/app';
import { useGetHealthImmediateMutation } from '@/api';
import { useUrlHash } from '@/hooks';

// @ts-ignore
import { BaseQueryResult, FetchBaseQueryError, SerializedError } from '@reduxjs/toolkit/dist/query/baseQueryTypes';
import { RootState } from '@/store';
import { reloadApplication } from '@/utils/unified-ui-utils';

interface ConnectModalProps {
onClose: () => void;
}

const ConnectModal: React.FC<ConnectModalProps> = ({ onClose }: ConnectModalProps) => {
const dispatch = useDispatch();
const appStore = useSelector((state: RootState) => state.app);
const [getHealth] = useGetHealthImmediateMutation();
const [serverNotFound, setServerNotFound] = useState(false);
const [, setActive] = useUrlHash('connect');
Expand All @@ -29,7 +32,7 @@ const ConnectModal: React.FC<ConnectModalProps> = ({ onClose }: ConnectModalProp

dispatch(setHost({ apiHost, apiKey }));
setActive(false);
setTimeout(() => window.location.reload(), 0);
setTimeout(() => reloadApplication(), 0);
onClose();
};

Expand All @@ -41,11 +44,22 @@ const ConnectModal: React.FC<ConnectModalProps> = ({ onClose }: ConnectModalProp
</p>
</Modal.Header>
<Modal.Body>
<ConnectForm
onSubmit={handleSubmit}
hasServerError={serverNotFound}
onClearError={() => setServerNotFound(false)}
/>
{appStore?.isCoreRegistryUiApp ? (
<div>
<p>
<FormattedMessage id="cannot-connect-to-registry-api-with-current-settings" />.
</p>
<p>
<FormattedMessage id="please-disconnect-to-edit-the-api-url-and-api-key" />.
</p>
</div>
) : (
<ConnectForm
onSubmit={handleSubmit}
hasServerError={serverNotFound}
onClearError={() => setServerNotFound(false)}
/>
)}
</Modal.Body>
</Modal>
);
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/blocks/widgets/SyncIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { useLocation } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { projectsByIdsTag, projectsTag, tokenizedUnitsTag, untokenizedUnitsTag } from '@/api/tokenization-engine';
import { reloadApplication } from '@/utils/unified-ui-utils';

interface SyncIndicatorProps {
detailed: boolean;
orgUid?: string;
}

/**
Expand Down Expand Up @@ -43,7 +43,7 @@ const SyncIndicator: React.FC<SyncIndicatorProps> = ({ detailed }: SyncIndicator

const handleRefreshClick = () => {
// Trigger hard refresh of the app here
window.location.reload();
reloadApplication();
};

return (
Expand Down
14 changes: 14 additions & 0 deletions src/renderer/components/layout/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import React from 'react';
import { AppLogo, ConnectButton } from '@/components';
import { useSelector } from 'react-redux';
import { RootState } from '@/store';

const Header: React.FC = () => {
const isCoreRegistryUiApp = useSelector((state: RootState) => state.app.isCoreRegistryUiApp);

if (isCoreRegistryUiApp) {
// if running as a child app, the parent app provides the header.
// return hidden connect button to show connect message if unable to connect
return (
<div className="hidden">
<ConnectButton />
</div>
);
}

return (
<div style={{ height: '64px' }}>
<div className="pt-1 pb-1 w-screen h-16 bg-[#6e7d7f] dark:bg-gray-800 dark:border-gray-600">
Expand Down
1 change: 1 addition & 0 deletions src/renderer/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './useQueryParamState';
export * from './useColumnOrder';
export * from './useWildCardUrlHash';
export * from './useGetProjectOptionsList';
export * from './useManageSavedLocation';
Loading

0 comments on commit 15e5d0e

Please sign in to comment.