feat(gui): add knip for checking for unused dead code, remove dead code

This commit is contained in:
Binarybaron 2025-11-05 19:08:43 +01:00
parent 5948a40c8d
commit 2f5f521009
23 changed files with 104 additions and 237 deletions

View file

@ -113,6 +113,10 @@ check_gui_eslint:
check_gui_tsc: check_gui_tsc:
cd src-gui && yarn run tsc --noEmit cd src-gui && yarn run tsc --noEmit
# Check for unused code in the GUI frontend
check_gui_unused_code:
cd src-gui && npx knip
test test_name: test test_name:
cargo test --test {{test_name}} -- --nocapture cargo test --test {{test_name}} -- --nocapture

7
src-gui/knip.json Normal file
View file

@ -0,0 +1,7 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"entry": ["src/renderer/index.tsx", "index.html"],
"project": ["src/**/*.{ts,tsx,js,jsx}"],
"ignoreExportsUsedInFile": true,
"tags": ["-lintignore"]
}

View file

@ -36,7 +36,6 @@
"boring-avatars": "^1.11.2", "boring-avatars": "^1.11.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"humanize-duration": "^3.32.1", "humanize-duration": "^3.32.1",
"jdenticon": "^3.3.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"multiaddr": "^10.0.1", "multiaddr": "^10.0.1",
"notistack": "^3.0.1", "notistack": "^3.0.1",

View file

@ -422,6 +422,7 @@ export function hasDescriptorProperty(
typeof response.wallet_descriptor === "object" && typeof response.wallet_descriptor === "object" &&
response.wallet_descriptor !== null && response.wallet_descriptor !== null &&
"descriptor" in response.wallet_descriptor && "descriptor" in response.wallet_descriptor &&
typeof (response.wallet_descriptor as { descriptor?: unknown }).descriptor === "string" typeof (response.wallet_descriptor as { descriptor?: unknown })
.descriptor === "string"
); );
} }

View file

@ -82,13 +82,62 @@ function InnerContent() {
}} }}
> >
<Routes> <Routes>
<Route path="/" element={<ErrorBoundary><MoneroWalletPage /></ErrorBoundary>} /> <Route
<Route path="/monero-wallet" element={<ErrorBoundary><MoneroWalletPage /></ErrorBoundary>} /> path="/"
<Route path="/swap" element={<ErrorBoundary><SwapPage /></ErrorBoundary>} /> element={
<Route path="/history" element={<ErrorBoundary><HistoryPage /></ErrorBoundary>} /> <ErrorBoundary>
<Route path="/bitcoin-wallet" element={<ErrorBoundary><WalletPage /></ErrorBoundary>} /> <MoneroWalletPage />
<Route path="/settings" element={<ErrorBoundary><SettingsPage /></ErrorBoundary>} /> </ErrorBoundary>
<Route path="/feedback" element={<ErrorBoundary><FeedbackPage /></ErrorBoundary>} /> }
/>
<Route
path="/monero-wallet"
element={
<ErrorBoundary>
<MoneroWalletPage />
</ErrorBoundary>
}
/>
<Route
path="/swap"
element={
<ErrorBoundary>
<SwapPage />
</ErrorBoundary>
}
/>
<Route
path="/history"
element={
<ErrorBoundary>
<HistoryPage />
</ErrorBoundary>
}
/>
<Route
path="/bitcoin-wallet"
element={
<ErrorBoundary>
<WalletPage />
</ErrorBoundary>
}
/>
<Route
path="/settings"
element={
<ErrorBoundary>
<SettingsPage />
</ErrorBoundary>
}
/>
<Route
path="/feedback"
element={
<ErrorBoundary>
<FeedbackPage />
</ErrorBoundary>
}
/>
</Routes> </Routes>
</Box> </Box>
); );

View file

@ -1,30 +0,0 @@
import React, { useEffect, useRef } from "react";
import * as jdenticon from "jdenticon";
interface IdentIconProps {
value: string;
size?: number | string;
className?: string;
}
function IdentIcon({ value, size = 40, className = "" }: IdentIconProps) {
const iconRef = useRef<SVGSVGElement>(null);
useEffect(() => {
if (iconRef.current) {
jdenticon.update(iconRef.current, value);
}
}, [value]);
return (
<svg
ref={iconRef}
width={size}
height={size}
className={className}
data-jdenticon-value={value}
/>
);
}
export default IdentIcon;

View file

@ -1,27 +0,0 @@
import { Button, Paper, Typography } from "@mui/material";
export default function PaperTextBox({ stdOut }: { stdOut: string }) {
function handleCopyLogs() {
throw new Error("Not implemented");
}
return (
<Paper
variant="outlined"
sx={{
overflow: "auto",
padding: 1,
marginTop: 1,
marginBottom: 1,
maxHeight: "10rem",
}}
>
<Typography component="pre" variant="body2">
{stdOut}
</Typography>
<Button onClick={handleCopyLogs} sx={{ marginTop: 1 }}>
Copy
</Button>
</Paper>
);
}

View file

@ -1,8 +1,9 @@
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/walletWithBitcoinAndMonero.png"; import imagePath from "assets/walletWithBitcoinAndMonero.png";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide01_GettingStarted(props: slideProps) { export default function Slide01_GettingStarted(props: IntroSlideProps) {
return ( return (
<SlideTemplate title="Getting Started" {...props} imagePath={imagePath}> <SlideTemplate title="Getting Started" {...props} imagePath={imagePath}>
<Typography variant="subtitle1"> <Typography variant="subtitle1">

View file

@ -1,8 +1,9 @@
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/mockMakerSelection.svg"; import imagePath from "assets/mockMakerSelection.svg";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide02_ChooseAMaker(props: slideProps) { export default function Slide02_ChooseAMaker(props: IntroSlideProps) {
return ( return (
<SlideTemplate <SlideTemplate
title="Choose a Maker" title="Choose a Maker"

View file

@ -1,8 +1,9 @@
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/mockConfigureSwap.svg"; import imagePath from "assets/mockConfigureSwap.svg";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide02_ChooseAMaker(props: slideProps) { export default function Slide02_ChooseAMaker(props: IntroSlideProps) {
return ( return (
<SlideTemplate <SlideTemplate
title="Prepare Swap" title="Prepare Swap"

View file

@ -1,8 +1,9 @@
import { Typography } from "@mui/material"; import { Typography } from "@mui/material";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/simpleSwapFlowDiagram.svg"; import imagePath from "assets/simpleSwapFlowDiagram.svg";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide02_ChooseAMaker(props: slideProps) { export default function Slide02_ChooseAMaker(props: IntroSlideProps) {
return ( return (
<SlideTemplate <SlideTemplate
title="Execute Swap" title="Execute Swap"

View file

@ -1,9 +1,10 @@
import { Link, Typography } from "@mui/material"; import { Link, SlideProps, Typography } from "@mui/material";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/mockHistoryPage.svg"; import imagePath from "assets/mockHistoryPage.svg";
import ExternalLink from "renderer/components/other/ExternalLink"; import ExternalLink from "renderer/components/other/ExternalLink";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide05_KeepAnEyeOnYourSwaps(props: slideProps) { export default function Slide05_KeepAnEyeOnYourSwaps(props: IntroSlideProps) {
return ( return (
<SlideTemplate <SlideTemplate
title="Monitor Your Swaps" title="Monitor Your Swaps"

View file

@ -1,15 +1,23 @@
import { Box, Typography, Paper, Button, Slide } from "@mui/material"; import {
Box,
Typography,
Paper,
Button,
Slide,
SlideProps,
} from "@mui/material";
import CardSelectionGroup from "renderer/components/inputs/CardSelection/CardSelectionGroup"; import CardSelectionGroup from "renderer/components/inputs/CardSelection/CardSelectionGroup";
import CardSelectionOption from "renderer/components/inputs/CardSelection/CardSelectionOption"; import CardSelectionOption from "renderer/components/inputs/CardSelection/CardSelectionOption";
import SlideTemplate from "./SlideTemplate"; import SlideTemplate from "./SlideTemplate";
import imagePath from "assets/currencyFetching.svg"; import imagePath from "assets/currencyFetching.svg";
import { IntroSlideProps } from "./SlideTypes";
const FiatPricePreferenceSlide = ({ const FiatPricePreferenceSlide = ({
handleContinue, handleContinue,
handlePrevious, handlePrevious,
showFiat, showFiat,
onChange, onChange,
}: slideProps & { }: IntroSlideProps & {
showFiat: boolean; showFiat: boolean;
onChange: (value: string) => void; onChange: (value: string) => void;
}) => { }) => {

View file

@ -4,8 +4,9 @@ import imagePath from "assets/groupWithChatbubbles.png";
import GitHubIcon from "@mui/icons-material/GitHub"; import GitHubIcon from "@mui/icons-material/GitHub";
import MatrixIcon from "renderer/components/icons/MatrixIcon"; import MatrixIcon from "renderer/components/icons/MatrixIcon";
import LinkIconButton from "renderer/components/icons/LinkIconButton"; import LinkIconButton from "renderer/components/icons/LinkIconButton";
import { IntroSlideProps } from "./SlideTypes";
export default function Slide02_ChooseAMaker(props: slideProps) { export default function Slide02_ChooseAMaker(props: IntroSlideProps) {
return ( return (
<SlideTemplate <SlideTemplate
title="Reach out" title="Reach out"

View file

@ -1,4 +1,4 @@
type slideProps = { export type IntroSlideProps = {
handleContinue: () => void; handleContinue: () => void;
handlePrevious: () => void; handlePrevious: () => void;
hidePreviousButton?: boolean; hidePreviousButton?: boolean;

View file

@ -1,22 +0,0 @@
import { IconButton } from "@mui/material";
import FeedbackIcon from "@mui/icons-material/Feedback";
import { useState } from "react";
import FeedbackDialog from "../../feedback/FeedbackDialog";
export default function FeedbackSubmitBadge() {
const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
return (
<>
{showFeedbackDialog && (
<FeedbackDialog
open={showFeedbackDialog}
onClose={() => setShowFeedbackDialog(false)}
/>
)}
<IconButton onClick={() => setShowFeedbackDialog(true)} size="large">
<FeedbackIcon />
</IconButton>
</>
);
}

View file

@ -13,7 +13,7 @@ interface State {
class ErrorBoundary extends Component<Props, State> { class ErrorBoundary extends Component<Props, State> {
public state: State = { public state: State = {
hasError: false, hasError: false,
error: null error: null,
}; };
public static getDerivedStateFromError(error: Error): State { public static getDerivedStateFromError(error: Error): State {
@ -30,13 +30,19 @@ class ErrorBoundary extends Component<Props, State> {
return ( return (
<div> <div>
<h1>Sorry.. there was an error</h1> <h1>Sorry.. there was an error</h1>
<pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}> <pre style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>
{this.state.error?.message} {this.state.error?.message}
</pre> </pre>
{this.state.error?.stack && ( {this.state.error?.stack && (
<details style={{ marginTop: '1rem' }}> <details style={{ marginTop: "1rem" }}>
<summary>Stack trace</summary> <summary>Stack trace</summary>
<pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', fontSize: '0.875rem' }}> <pre
style={{
whiteSpace: "pre-wrap",
wordBreak: "break-word",
fontSize: "0.875rem",
}}
>
{this.state.error.stack} {this.state.error.stack}
</pre> </pre>
</details> </details>

View file

@ -1,26 +0,0 @@
import Button, { ButtonProps } from "@mui/material/Button";
import CircularProgress from "@mui/material/CircularProgress";
import React from "react";
interface LoadingButtonProps extends ButtonProps {
loading: boolean;
}
const LoadingButton: React.FC<LoadingButtonProps> = ({
loading,
disabled,
children,
...props
}) => {
return (
<Button
disabled={loading || disabled}
{...props}
endIcon={loading && <CircularProgress size="1rem" />}
>
{children}
</Button>
);
};
export default LoadingButton;

View file

@ -1,5 +0,0 @@
import CircularProgressWithSubtitle from "renderer/components/pages/swap/swap/components/CircularProgressWithSubtitle";
export default function BitcoinRedeemedPage() {
return <CircularProgressWithSubtitle description="Redeeming your Monero" />;
}

View file

@ -1,51 +0,0 @@
import { Box, Button, Typography } from "@mui/material";
import SendIcon from "@mui/icons-material/Send";
import { useState } from "react";
import { SatsAmount } from "renderer/components/other/Units";
import { useAppSelector } from "store/hooks";
import BitcoinIcon from "../../icons/BitcoinIcon";
import InfoBox from "../swap/swap/components/InfoBox";
import WithdrawDialog from "../../modal/wallet/WithdrawDialog";
import WalletRefreshButton from "./WalletRefreshButton";
export default function WithdrawWidget() {
const walletBalance = useAppSelector((state) => state.bitcoinWallet.balance);
const [showDialog, setShowDialog] = useState(false);
function onShowDialog() {
setShowDialog(true);
}
return (
<>
<InfoBox
title={
<Box sx={{ alignItems: "center", display: "flex", gap: 0.5 }}>
Wallet Balance
<WalletRefreshButton />
</Box>
}
mainContent={
<Typography variant="h5">
<SatsAmount amount={walletBalance} />
</Typography>
}
icon={<BitcoinIcon />}
additionalContent={
<Button
variant="contained"
color="primary"
endIcon={<SendIcon />}
size="large"
onClick={onShowDialog}
disabled={walletBalance === null || walletBalance <= 0}
>
Withdraw
</Button>
}
loading={false}
/>
<WithdrawDialog open={showDialog} onClose={() => setShowDialog(false)} />
</>
);
}

View file

@ -1,5 +0,0 @@
import { createHash } from "crypto";
export function sha256(data: string): string {
return createHash("md5").update(data).digest("hex");
}

View file

@ -1,21 +0,0 @@
export class SingleTypeEventEmitter<T> {
private listeners: Array<(data: T) => void> = [];
// Method to add a listener for the event
on(listener: (data: T) => void) {
this.listeners.push(listener);
}
// Method to remove a listener
off(listener: (data: T) => void) {
const index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
}
// Method to emit the event
emit(data: T) {
this.listeners.forEach((listener) => listener(data));
}
}

View file

@ -531,7 +531,7 @@
integrity sha512-upzCtG6awpL6noEZlJ5Z01khZ9VnLNLaj7tb6iPbN6G97eYfUTs8e9OyPKy3rEms3VQWmVBfri7jzeaRxdFIzA== integrity sha512-upzCtG6awpL6noEZlJ5Z01khZ9VnLNLaj7tb6iPbN6G97eYfUTs8e9OyPKy3rEms3VQWmVBfri7jzeaRxdFIzA==
dependencies: dependencies:
"@babel/runtime" "^7.28.2" "@babel/runtime" "^7.28.2"
"@mui/material@^7.1.1": "@mui/material@^7.1.1":
version "7.3.1" version "7.3.1"
resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.3.1.tgz#bd1bf1344cc7a69b6e459248b544f0ae97945b1d" resolved "https://registry.yarnpkg.com/@mui/material/-/material-7.3.1.tgz#bd1bf1344cc7a69b6e459248b544f0ae97945b1d"
@ -1132,13 +1132,6 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.20.tgz#1ca77361d7363432d29f5e55950d9ec1e1c6ea93"
integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA== integrity sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==
"@types/node@*":
version "24.3.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-24.3.0.tgz#89b09f45cb9a8ee69466f18ee5864e4c3eb84dec"
integrity sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==
dependencies:
undici-types "~7.10.0"
"@types/node@^22.15.29": "@types/node@^22.15.29":
version "22.17.2" version "22.17.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.17.2.tgz#47a93d6f4b79327da63af727e7c54e8cab8c4d33" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.17.2.tgz#47a93d6f4b79327da63af727e7c54e8cab8c4d33"
@ -1643,13 +1636,6 @@ caniuse-lite@^1.0.30001735:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz#8292bb7591932ff09e9a765f12fdf5629a241ccc" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz#8292bb7591932ff09e9a765f12fdf5629a241ccc"
integrity sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw== integrity sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==
canvas-renderer@~2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/canvas-renderer/-/canvas-renderer-2.2.1.tgz#c1d131f78a9799aca8af9679ad0a005052b65550"
integrity sha512-RrBgVL5qCEDIXpJ6NrzyRNoTnXxYarqm/cS/W6ERhUJts5UQtt/XPEosGN3rqUkZ4fjBArlnCbsISJ+KCFnIAg==
dependencies:
"@types/node" "*"
chai@^5.1.2: chai@^5.1.2:
version "5.3.2" version "5.3.2"
resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.2.tgz#e2c35570b8fa23b5b7129b4114d5dc03b3fd3401" resolved "https://registry.yarnpkg.com/chai/-/chai-5.3.2.tgz#e2c35570b8fa23b5b7129b4114d5dc03b3fd3401"
@ -2785,13 +2771,6 @@ iterator.prototype@^1.1.4:
has-symbols "^1.1.0" has-symbols "^1.1.0"
set-function-name "^2.0.2" set-function-name "^2.0.2"
jdenticon@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/jdenticon/-/jdenticon-3.3.0.tgz#64bae9f9b3cf5c2a210e183648117afe3a89b367"
integrity sha512-DhuBRNRIybGPeAjMjdHbkIfiwZCCmf8ggu7C49jhp6aJ7DYsZfudnvnTY5/1vgUhrGA7JaDAx1WevnpjCPvaGg==
dependencies:
canvas-renderer "~2.2.0"
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -3989,11 +3968,6 @@ undici-types@~6.21.0:
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
undici-types@~7.10.0:
version "7.10.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350"
integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==
update-browserslist-db@^1.1.3: update-browserslist-db@^1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420"