Skip to content

Commit

Permalink
add local integrity checks
Browse files Browse the repository at this point in the history
  • Loading branch information
Ross Bulat committed Mar 6, 2024
1 parent 31fb48b commit 1ac9632
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 31 deletions.
38 changes: 9 additions & 29 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,21 @@
// Copyright 2024 @rossbulat/console authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { Header } from 'library/Header';
import { ContextMenu } from 'library/ContextMenu';
import { Tabs } from 'library/Tabs';
import { HashRouter, Navigate, Route, Routes } from 'react-router-dom';
import { DefaultRoute } from 'screens/Default/Route';
import { SettingsRoute } from 'screens/Settings/Route';
import { HashRouter } from 'react-router-dom';
import { Entry } from 'library/Entry';
import { Tooltip } from 'library/Tooltip';
import { Router } from 'Router';

// The currently supported pages.
export type PageId = 'default' | 'settings';

const AppInner = () => (
// TODO: Get accent theme from active network, if any, otherwise default to `polkadot-relay`.
export const App = () => (
// TODO: Get accent theme from active network, if any, otherwise default to a new
// `developer-console` accent.
<Entry mode="light" theme={`polkadot-relay`}>
<ContextMenu />
<Tooltip />
<Header />
<Tabs />

<Routes>
<Route key={`route_default`} path={'/'} element={<DefaultRoute />} />
<Route
key={`route_settings`}
path={'/settings'}
element={<SettingsRoute />}
/>
{/* Fallback route to chain */}
<Route key="route_fallback" path="*" element={<Navigate to="/" />} />
</Routes>
<HashRouter basename="/">
<Router />
</HashRouter>
</Entry>
);

export const App = () => (
<HashRouter basename="/">
<AppInner />
</HashRouter>
);
export default App;
136 changes: 136 additions & 0 deletions src/IntegrityChecks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2024 @rossbulat/console authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { NetworkDirectory } from 'config/networks';
import * as localTabs from 'contexts/Tabs/Local';
import * as localTags from 'contexts/Tags/Local';
import * as localChainFilter from 'contexts/ChainFilter/Local';
import { defaultTagsConfig } from 'contexts/Tags/defaults';
import { defaultTabs } from 'contexts/Tabs/defaults';

// ------------------------------------------------------
// Tabs.
// ------------------------------------------------------

export const checkLocalTabs = () => {
// Use default tabs if activeTabs is empty.
const activeTabs = localTabs.getTabs() || defaultTabs;

const activeTabId = localTabs.getActiveTabId();
const activeTabIndex = localTabs.getActiveTabIndex();

// Check if `activeTabId` is among `activeTabs`, and clear `activeTabId` otherwise.
if (
activeTabs &&
activeTabId &&
!activeTabs.find(({ id }) => id === activeTabId)
) {
localStorage.removeItem('activeTabId');
}

// Check if `activeTabIndex` is a valid tab index, and clear `activeTabIndex` otherwise.
if (activeTabs && activeTabIndex && !activeTabs[activeTabIndex]) {
localStorage.removeItem('activeTabIndex');
}
};

// ------------------------------------------------------
// Tags.
// ------------------------------------------------------

export const checkLocalTags = () => {
const tags = localTags.getTags();
const tagsConfig = localTags.getTagsConfig();

// Check that each tag id in `tagsConfig` is present in `tags`, and delete the config otherwise.
if (tags && tagsConfig) {
const maybeUpdatedConfig = tagsConfig;
let updated = false;
Object.entries(tagsConfig).forEach(([tagId, chains]) => {
for (const chain of chains) {
if (!NetworkDirectory[chain]) {
// If error, fallback to defaults if exist, otherwise filter out the chain.
maybeUpdatedConfig[tagId] =
defaultTagsConfig[tagId] || chains.filter((c) => c !== chain);
updated = true;
}
}
});

if (JSON.stringify(maybeUpdatedConfig) === '{}') {
localStorage.removeItem('tagsConfig');
} else {
if (updated) {
localTags.setTagsConfig(maybeUpdatedConfig);
}
}
}
};

// ------------------------------------------------------
// Chain Filter.
// ------------------------------------------------------

// Check existing local storage and clear up if there are errors.
export const checkLocalChainFilter = () => {
// Use default tabs if activeTabs is empty.
const activeTabs = localTabs.getTabs() || defaultTabs;
const tags = localTags.getTags();
const searchTerms = localChainFilter.getSearchTerms();
const appliedTags = localChainFilter.getAppliedTags();

// Check if tabs exist for each search term, and remove the entry otherwise. Also remove empty
// strings.
if (searchTerms) {
const maybeUpdatedSearchTerms = searchTerms;
let updated = false;
Object.entries(searchTerms).forEach(([tabId, searchTerm]) => {
if (
!activeTabs?.find(({ id }) => id === Number(tabId)) ||
searchTerm === ''
) {
delete maybeUpdatedSearchTerms[Number(tabId)];
updated = true;
}
});

if (JSON.stringify(maybeUpdatedSearchTerms) === '{}') {
localStorage.removeItem('searchTerms');
} else {
if (updated) {
localChainFilter.setSearchTerms(maybeUpdatedSearchTerms);
}
}
}

// Check if tab index exists for each applied tag key, and remove otherwise.
if (appliedTags) {
const maybeUpdatedAppliedTags = appliedTags;
let updated = false;
Object.entries(appliedTags).forEach(([tabId, applied]) => {
if (!activeTabs?.find(({ id }) => id === Number(tabId))) {
delete maybeUpdatedAppliedTags[Number(tabId)];
updated = true;
} else {
// Check if each `applied` value is a valid tag id, and remove otherwise.
applied.forEach((tagId) => {
if (!tags?.[tagId]) {
maybeUpdatedAppliedTags[Number(tabId)].splice(
applied.indexOf(tagId),
1
);
updated = true;
}
});
}
});

if (JSON.stringify(maybeUpdatedAppliedTags) === '{}') {
localStorage.removeItem('appliedTags');
} else {
if (updated) {
localChainFilter.setAppliedTags(maybeUpdatedAppliedTags);
}
}
}
};
29 changes: 29 additions & 0 deletions src/Router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2024 @rossbulat/console authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { Navigate, Route, Routes } from 'react-router-dom';
import { DefaultRoute } from 'screens/Default/Route';
import { SettingsRoute } from 'screens/Settings/Route';
import { Header } from 'library/Header';
import { ContextMenu } from 'library/ContextMenu';
import { Tabs } from 'library/Tabs';
import { Tooltip } from 'library/Tooltip';

export const Router = () => (
<>
<ContextMenu />
<Tooltip />
<Header />
<Tabs />
<Routes>
<Route key={`route_default`} path={'/'} element={<DefaultRoute />} />
<Route
key={`route_settings`}
path={'/settings'}
element={<SettingsRoute />}
/>
{/* Fallback route to chain */}
<Route key="route_fallback" path="*" element={<Navigate to="/" />} />
</Routes>
</>
);
3 changes: 3 additions & 0 deletions src/contexts/ChainFilter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { useTags } from 'contexts/Tags';
import type { TagId, TagItem } from 'contexts/Tags/types';
import type { ChainId } from 'config/networks';
import * as local from './Local';
import { checkLocalChainFilter } from 'IntegrityChecks';

checkLocalChainFilter();

export const ChainFilter =
createContext<ChainFilterInterface>(defaultChainFilter);
Expand Down
5 changes: 3 additions & 2 deletions src/contexts/Tabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { defaultTabs, defaultTabsContext } from './defaults';
import * as local from './Local';
import { useSettings } from 'contexts/Settings';
import type { ChainId } from 'config/networks';
import { checkLocalTabs } from 'IntegrityChecks';

checkLocalTabs();

export const TabsContext =
createContext<TabsContextInterface>(defaultTabsContext);
Expand All @@ -17,8 +20,6 @@ export const useTabs = () => useContext(TabsContext);
export const TabsProvider = ({ children }: { children: ReactNode }) => {
const { autoConnect } = useSettings();

// TODO: Connect to the Polkadot Relay chain (first tab).

// Created tabs.
const [tabs, setTabsState] = useState<Tabs>(local.getTabs() || defaultTabs);

Expand Down
3 changes: 3 additions & 0 deletions src/contexts/Tags/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import type {
import { setStateWithRef } from '@w3ux/utils';
import type { ChainId } from 'config/networks';
import * as local from './Local';
import { checkLocalTags } from 'IntegrityChecks';

checkLocalTags();

export const TagsContext =
createContext<TagsContextInterface>(defaultTagsContext);
Expand Down

0 comments on commit 1ac9632

Please sign in to comment.