Skip to content

Commit

Permalink
fix(client-electron): handle missing source file
Browse files Browse the repository at this point in the history
fixes #277
  • Loading branch information
marcincichocki committed Oct 11, 2022
1 parent a5bbb5d commit 6e5c55b
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 103 deletions.
5 changes: 4 additions & 1 deletion src/electron/renderer/components/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ export const LinkButton = styled.button`
border: none;
padding: 0;
color: var(--accent);
text-decoration: underline;
cursor: pointer;
font-family: Rajdhani;
font-size: 1rem;
font-weight: 500;
&:hover {
text-decoration: underline;
}
`;

export const ClearButton = styled.button`
Expand Down
62 changes: 15 additions & 47 deletions src/electron/renderer/components/TypesFragmentStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,5 @@
import type { BreachProtocolTypesFragmentResult } from '@/core';
import { MdWarning } from '@react-icons/all-files/md/MdWarning';
import { useContext } from 'react';
import styled from 'styled-components';
import { RouterExtContext } from '../router-ext';
import { LinkButton } from './Buttons';
import { Col, Row } from './Flex';

const WarningTitle = styled.h3`
margin: 0;
font-weight: 600;
color: var(--accent);
text-transform: uppercase;
`;

const WarningSubTitle = styled.h4`
margin: 0;
font-weight: 600;
color: var(--primary);
`;

const WarningLink = styled(LinkButton)`
color: var(--primary);
font-weight: 600;
`;
import { Warning } from './Warning';

interface TypesFragmentStatusProps {
types: BreachProtocolTypesFragmentResult;
Expand All @@ -31,29 +8,20 @@ interface TypesFragmentStatusProps {
export const TypesFragmentStatus = ({ types }: TypesFragmentStatusProps) => {
if (!types || types.isValid) return null;

const { navigateToSetting } = useContext(RouterExtContext);

return (
<Col>
<Row style={{ alignItems: 'center' }}>
<MdWarning size="2rem" color="var(--accent)" />
<WarningTitle>Warning: unknown types</WarningTitle>
</Row>
<WarningSubTitle>
Select correct{' '}
<WarningLink onClick={() => navigateToSetting('gameLang')}>
game language
</WarningLink>
, change{' '}
<WarningLink onClick={() => navigateToSetting('thresholdTypesAuto')}>
threshold
</WarningLink>{' '}
or{' '}
<WarningLink onClick={() => navigateToSetting('skipTypesFragment')}>
disable this feature
</WarningLink>
.
</WarningSubTitle>
</Col>
<Warning
title={<Warning.Title>Warning: unknown types</Warning.Title>}
body={
<Warning.Body>
Select correct{' '}
<Warning.Link setting="gameLang">game language</Warning.Link>, change{' '}
<Warning.Link setting="thresholdTypesAuto">threshold</Warning.Link> or{' '}
<Warning.Link setting="skipTypesFragment">
disable this feature
</Warning.Link>
.
</Warning.Body>
}
/>
);
};
60 changes: 60 additions & 0 deletions src/electron/renderer/components/Warning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { AppSettings } from '@/electron/common';
import { MdWarning } from '@react-icons/all-files/md/MdWarning';
import { PropsWithChildren, ReactElement, useContext } from 'react';
import styled from 'styled-components';
import { RouterExtContext } from '../router-ext';
import { LinkButton } from './Buttons';
import { Col, Row } from './Flex';

const Title = styled.h3`
margin: 0;
font-weight: 600;
color: var(--accent);
text-transform: uppercase;
`;

const Body = styled.h4`
margin: 0;
font-weight: 600;
color: var(--primary);
`;

const Link = styled(
({
setting,
children,
}: PropsWithChildren<{ setting: keyof AppSettings }>) => {
const { navigateToSetting } = useContext(RouterExtContext);

return (
<LinkButton onClick={() => navigateToSetting(setting)}>
{children}
</LinkButton>
);
}
)`
color: var(--primary);
font-weight: 600;
`;

interface WarningProps {
title: ReactElement;
body: ReactElement;
className?: string;
}

export const Warning = ({ title, body, className }: WarningProps) => {
return (
<Col className={className}>
<Row style={{ alignItems: 'center' }}>
<MdWarning size="2rem" color="var(--accent)" />
{title}
</Row>
{body}
</Col>
);
};

Warning.Title = Title;
Warning.Body = Body;
Warning.Link = Link;
26 changes: 20 additions & 6 deletions src/electron/renderer/pages/Calibrate.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { Outlet } from 'react-router-dom';
import styled from 'styled-components';
import {
Expand All @@ -20,14 +20,27 @@ const Heading = styled.h1`
`;

function useContainerInit(fileName: string) {
const [ready, setReady] = useState(false);
const hasSource = useMemo(() => api.existsSync(fileName), [fileName]);

useEffect(() => {
// FIXME: tiny race condition. Disable button until fragments are ready.
dispatchAsyncRequest({ type: 'TEST_THRESHOLD_INIT', data: fileName });
if (hasSource) {
dispatchAsyncRequest({
type: 'TEST_THRESHOLD_INIT',
data: fileName,
}).then(() => setReady(true));
}

return () => {
dispatchAsyncRequest({ type: 'TEST_THRESHOLD_DISPOSE' });
if (hasSource) {
dispatchAsyncRequest({ type: 'TEST_THRESHOLD_DISPOSE' }).then(() =>
setReady(false)
);
}
};
}, []);

return { ready, hasSource };
}

export const Calibrate = () => {
Expand All @@ -40,7 +53,8 @@ export const Calibrate = () => {
label: fromCamelCase(id),
}));
useNavigation({ items, from: `/history/${entry.uuid}` });
useContainerInit(entry.fileName);

const { ready, hasSource } = useContainerInit(entry.fileName);
const { time, distance } = transformTimestamp(entry.startedAt);

return (
Expand All @@ -50,7 +64,7 @@ export const Calibrate = () => {
{time} - {distance}
</Heading>
</Row>
<Outlet context={entry} />
<Outlet context={{ entry, ready, hasSource }} />
</Col>
);
};
118 changes: 82 additions & 36 deletions src/electron/renderer/pages/CalibrateFragment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
HEX_CODES,
} from '@/core';
import {
BreachProtocolStatus,
HistoryEntry,
TestThresholdData,
UpdateSettingsAction,
Expand All @@ -29,6 +30,7 @@ import {
Switch,
useField,
} from '../components';
import { Warning } from '../components/Warning';

const Title = styled.h3`
color: var(--primary);
Expand All @@ -44,10 +46,6 @@ interface CalibrateFormValues {
testThreshold: number;
}

interface CalibrateFragmentProps {
entry: HistoryEntry;
}

const ThresholdUpdater = ({
threshold,
}: {
Expand Down Expand Up @@ -118,8 +116,46 @@ const hexCodeValidator: JSONValidator = (value) => {
return true;
};

const CalibrateWarning = styled(
({ entry, className }: { entry: HistoryEntry; className?: string }) => {
return (
<Warning
className={className}
title={<Warning.Title>Source file does not exist</Warning.Title>}
body={
<Warning.Body>
<>Calibration is not possible without the source file. </>
{entry.status === BreachProtocolStatus.Resolved &&
!entry.settings.preserveSourceOnSuccess ? (
<>
It wasn't saved for this entry. You can change this in the{' '}
<Warning.Link setting="preserveSourceOnSuccess">
settings
</Warning.Link>
.
</>
) : (
<>It was renamed or deleted.</>
)}
</Warning.Body>
}
/>
);
}
)`
align-items: flex-end;
max-width: 50%;
text-align: right;
`;

interface CalibrateOuletContext {
entry: HistoryEntry;
ready: boolean;
hasSource: boolean;
}

export const CalibrateFragment = () => {
const entry = useOutletContext<HistoryEntry>();
const { entry, ready, hasSource } = useOutletContext<CalibrateOuletContext>();
const { fragmentId } = useParams<{ fragmentId: FragmentId }>();
const FragmentJSONTree = FragmentJSONTrees[fragmentId];
const { fileName } = entry;
Expand Down Expand Up @@ -188,32 +224,40 @@ export const CalibrateFragment = () => {
</RawDataStatusMessage>
</FragmentJSONTree>
</Col>
<Form<CalibrateFormValues>
initialValues={{ showBoxes, testThreshold }}
onSubmit={handleSubmit}
>
<Field name="showBoxes" onValueChange={setShowBoxes}>
<Label>Show boxes</Label>
<Switch disabled={isBufferSize} />
</Field>
<Field name="testThreshold" onValueChange={onTestThreshold}>
<Label>Test threshold</Label>
<RangeSlider
min={0}
max={255}
disabled={loading || isExperimental}
/>
<ThresholdUpdater threshold={testThreshold} />
</Field>
<FlatButton
type="submit"
disabled={!testResult.isValid || loading || isExperimental}
color="accent"
style={{ alignSelf: 'flex-end' }}
>
Update {fromCamelCase(fragmentId)} threshold
</FlatButton>
</Form>
<Row style={{ justifyContent: 'flex-end' }}>
{hasSource ? (
<Form<CalibrateFormValues>
initialValues={{ showBoxes, testThreshold }}
onSubmit={handleSubmit}
>
<Field name="showBoxes" onValueChange={setShowBoxes}>
<Label>Show boxes</Label>
<Switch disabled={!ready || isBufferSize} />
</Field>
<Field name="testThreshold" onValueChange={onTestThreshold}>
<Label>Test threshold</Label>
<RangeSlider
min={0}
max={255}
disabled={!ready || loading || isExperimental}
/>
<ThresholdUpdater threshold={testThreshold} />
</Field>
<FlatButton
type="submit"
disabled={
!ready || !testResult.isValid || loading || isExperimental
}
color="accent"
style={{ alignSelf: 'flex-end' }}
>
Update {fromCamelCase(fragmentId)} threshold
</FlatButton>
</Form>
) : (
<CalibrateWarning entry={entry} />
)}
</Row>
</Col>
<Col style={{ width: '600px', flexShrink: 0 }}>
<Title>Fragment preview</Title>
Expand All @@ -228,11 +272,13 @@ export const CalibrateFragment = () => {
{loading ? (
<Spinner />
) : (
<FragmentPreview
image={testResult.image}
boxes={testResult.source?.boxes}
showBoxes={showBoxes}
/>
<>
<FragmentPreview
image={testResult.image}
boxes={testResult.source?.boxes}
showBoxes={showBoxes}
/>
</>
)}
</Col>
</Col>
Expand Down

0 comments on commit 6e5c55b

Please sign in to comment.