Skip to content

Commit 93b2094

Browse files
authored
Merge pull request #84 from simonsobs/odds-and-ends
Odds and ends
2 parents 81c508b + 4ac6506 commit 93b2094

9 files changed

Lines changed: 84 additions & 159 deletions

File tree

‎src/App.tsx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { SearchResults } from './components/SearchResults';
99
import { ErrorBoundary } from './components/ErrorBoundary';
1010
import { ErrorBoundaryWrapper } from './components/ErrorBoundaryWrapper';
1111
import { Footer } from './Footer';
12+
import { IS_CROSSMATCH_ENABLED } from './configs/constants';
1213

1314
function App() {
1415
const location = useLocation();
@@ -35,8 +36,14 @@ function App() {
3536
<Route index element={null} />
3637
<Route path="/search/*" element={<SearchResults />} />
3738
<Route path="/source/:id" element={<Source />} />
38-
<Route path="/unassigned/" element={<UnassignedSourcesTable />} />
39-
<Route path="/unassigned/:id" element={<UnassignedSource />} />
39+
{/* Gated like the Cross Matcher nav button, so a disabled deployment can't reach these
40+
pages by URL either; they fall through to PageNotFound instead */}
41+
{IS_CROSSMATCH_ENABLED && (
42+
<>
43+
<Route path="/unassigned/" element={<UnassignedSourcesTable />} />
44+
<Route path="/unassigned/:id" element={<UnassignedSource />} />
45+
</>
46+
)}
4047
<Route path="*" element={<PageNotFound />} />
4148
</Routes>
4249
</ErrorBoundaryWrapper>

‎src/components/NearbySourcesSection.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,8 @@ export function NearbySourcesSection({
5252
{s.name}
5353
</Link>
5454
<p className="small-text">
55-
{angularSeparationDeg(
56-
sourceRa,
57-
sourceDec,
58-
s.ra,
59-
s.dec
55+
{(
56+
angularSeparationDeg(sourceRa, sourceDec, s.ra, s.dec) * 60
6057
).toFixed(2)}{' '}
6158
arcmin
6259
</p>

‎src/components/RangeInput.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export function RangeInput({
5151
onChange={handleChange}
5252
onMouseUp={handleCommit}
5353
onTouchEnd={handleCommit}
54+
onKeyUp={handleCommit}
5455
/>
5556
</div>
5657
);

‎src/components/SearchResults.tsx‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,23 +84,27 @@ export function SearchResults() {
8484
</h3>
8585
)}
8686
<Table
87+
className="themed-table"
8788
data={results}
8889
columns={
8990
[
9091
{
9192
header: 'Source ID',
9293
// Link to individual sources from the table
9394
cell: ({ row }) => (
94-
<Link to={`/source/${row.original.source_id}`}>
95+
<Link
96+
className="text-so-blue"
97+
to={`/source/${row.original.source_id}`}
98+
>
9599
{row.original.source_id}
96100
</Link>
97101
),
98102
size: 50,
99103
accessorFn: (row) => row.source_id,
100104
},
101105
{
102-
header: 'ra',
103-
// accessorFn: (row) => row.ra.toFixed(1),
106+
header: 'RA (deg)',
107+
accessorFn: (row) => row.ra,
104108
cell: ({ row }) => (
105109
<span title={String(row.original.ra)}>
106110
{row.original.ra.toFixed(3)}
@@ -109,8 +113,8 @@ export function SearchResults() {
109113
size: 125,
110114
},
111115
{
112-
header: 'dec',
113-
// accessorFn: (row) => row.dec.toFixed(1),
116+
header: 'Dec (deg)',
117+
accessorFn: (row) => row.dec,
114118
cell: ({ row }) => (
115119
<span title={String(row.original.dec)}>
116120
{row.original.dec.toFixed(3)}

‎src/components/Sources.tsx‎

Lines changed: 0 additions & 126 deletions
This file was deleted.

‎src/components/UnassignedSource.tsx‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -111,26 +111,30 @@ export function UnassignedSource() {
111111
STATUS_TO_EXCLUDE_SIMBAD_SEARCH.includes(data.source.status)
112112
)
113113
return { data: [], queryTimestamp: undefined };
114-
let matches: SimbadMatch[] = [];
114+
// Any failure here (network error, non-2xx status, or an unexpected response shape) is
115+
// surfaced in the SIMBAD card below rather than shown as an empty match list, which would
116+
// read as "nothing nearby" and could lead a reviewer to wrongly rule out an external match.
115117
const getSimbadHits = await fetch(
116118
SIMBAD_BASE_URL +
117119
'/cone' +
118120
`?ra=${toSimbadRa(data.source.ra)}&dec=${data.source.dec}&sr=${UNASSIGNED_BEAM_RADIUS_ARCMIN / 60}&verb=2&maxrec=10&responseformat=json&order_by=nb_ref&order_dir=desc`
119121
);
120-
try {
121-
const hitsJson = (await getSimbadHits.json()) as SimbadConeResponse;
122-
matches = hitsJson.data.map((row) => ({
123-
identifier: row[1] ?? 'SIMBAD object',
124-
objectType: row[4] ?? null,
125-
ra: row[2] ?? null,
126-
dec: row[3] ?? null,
127-
separationArcmin: row[0] != null ? row[0] * 60 : null,
128-
}));
129-
} catch {
130-
console.error(
131-
'An error occurred when querying for nearby SIMBAD sources.'
122+
if (!getSimbadHits.ok) {
123+
throw new Error(
124+
`SIMBAD returned ${getSimbadHits.status} ${getSimbadHits.statusText}`
132125
);
133126
}
127+
const hitsJson = (await getSimbadHits.json()) as SimbadConeResponse;
128+
if (!Array.isArray(hitsJson?.data)) {
129+
throw new Error('SIMBAD returned an unexpected response.');
130+
}
131+
const matches: SimbadMatch[] = hitsJson.data.map((row) => ({
132+
identifier: row[1] ?? 'SIMBAD object',
133+
objectType: row[4] ?? null,
134+
ra: row[2] ?? null,
135+
dec: row[3] ?? null,
136+
separationArcmin: row[0] != null ? row[0] * 60 : null,
137+
}));
134138
return {
135139
// ISO 8601, not a locale-formatted string: this doubles as the `queried_at` sent to the
136140
// server's external_evidence.queried_at (a datetime field) if the reviewer accepts one
@@ -244,10 +248,6 @@ export function UnassignedSource() {
244248
throw new Error(error.message);
245249
}
246250

247-
if (simbadError) {
248-
throw new Error(simbadError.message);
249-
}
250-
251251
return (
252252
<div className="unassigned-source-page-container">
253253
<ConfirmDialog
@@ -423,6 +423,11 @@ export function UnassignedSource() {
423423
>
424424
{isSimbadQueryActive ? (
425425
<p>Loading...</p>
426+
) : simbadError ? (
427+
<p className="small-text">
428+
The SIMBAD search failed, so potential matches couldn&rsquo;t be
429+
checked. Reload the page to try again.
430+
</p>
426431
) : (
427432
<>
428433
<p className="small-text">

‎src/components/UnassignedSourcesTable.tsx‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,13 @@ export function UnassignedSourcesTable() {
132132
<p className="small-text">
133133
{tableData.length}{' '}
134134
{statusFilter === INCLUDE_ALL_STATUSES
135-
? 'detected'
136-
: formatSourceStatus(statusFilter).toLowerCase()}{' '}
137-
sources awaiting review
135+
? 'sources'
136+
: statusFilter === 'unmatched'
137+
? 'sources awaiting review'
138+
: `${formatSourceStatus(statusFilter).toLowerCase()} sources`}
138139
</p>
139140
<Table
140-
className="unassigned-sources-table"
141+
className="unassigned-sources-table themed-table"
141142
data={tableData}
142143
columns={columns}
143144
/>

‎tests/App.test.tsx‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,17 @@ describe('App', () => {
3131
screen.getByRole('heading', { name: /page not found/i })
3232
).toBeInTheDocument();
3333
});
34+
35+
it('renders the not-found page for cross-match routes when cross-matching is disabled', () => {
36+
// VITE_CROSSMATCH_ENABLED isn't set in the test environment
37+
render(
38+
<MemoryRouter initialEntries={['/unassigned/some-source-id']}>
39+
<App />
40+
</MemoryRouter>
41+
);
42+
43+
expect(
44+
screen.getByRole('heading', { name: /page not found/i })
45+
).toBeInTheDocument();
46+
});
3447
});

‎tests/components/RangeInput.test.tsx‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,27 @@ describe('RangeInput', () => {
100100
expect(onFinalChange).toHaveBeenCalledTimes(1);
101101
expect(onFinalChange).toHaveBeenCalledWith(9);
102102
});
103+
104+
it('calls onFinalChange after a keyboard change', () => {
105+
const onFinalChange = vi.fn();
106+
107+
render(
108+
<RangeInput
109+
min={0}
110+
max={10}
111+
defaultValue={5}
112+
onFinalChange={onFinalChange}
113+
label="Radius"
114+
/>
115+
);
116+
117+
const slider = screen.getByRole('slider');
118+
// The browser fires change on keydown, then keyup once the key is released
119+
fireEvent.change(slider, { target: { value: '6' } });
120+
fireEvent.keyUp(slider, { key: 'ArrowRight' });
121+
vi.advanceTimersByTime(100);
122+
123+
expect(onFinalChange).toHaveBeenCalledTimes(1);
124+
expect(onFinalChange).toHaveBeenCalledWith(6);
125+
});
103126
});

0 commit comments

Comments
 (0)