From 0374d85cc89ff368c90e62d130697956295f5651 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 12:49:11 +0300 Subject: [PATCH 01/10] #24: refine crossmatch details page --- src/pages/RecordCrossmatchDetails.tsx | 39 ++++++++++++++++----------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/pages/RecordCrossmatchDetails.tsx b/src/pages/RecordCrossmatchDetails.tsx index a2ab362..923ee1a 100644 --- a/src/pages/RecordCrossmatchDetails.tsx +++ b/src/pages/RecordCrossmatchDetails.tsx @@ -4,7 +4,6 @@ import { AladinViewer } from "../components/ui/aladin"; import { Loading } from "../components/ui/loading"; import { ErrorPage, - ErrorPageBackButton, ErrorPageHomeButton, } from "../components/ui/error-page"; import { CatalogData } from "../components/ui/catalog-data"; @@ -22,19 +21,12 @@ import { } from "../clients/backend/types.gen"; import { getResource } from "../resources/resources"; -function backToResultsHandler(navigate: NavigateFunction) { - return function f() { - navigate(-1); - }; -} - function renderNotFound(navigate: NavigateFunction) { return ( - navigate("/")} /> ); @@ -107,14 +99,31 @@ function convertRecordToPgcObject(record: RecordCrossmatch): PgcObject { }; } -function convertCandidatesToAdditionalSources(candidates: PgcCandidate[]) { - return candidates +function convertCandidatesToAdditionalSources( + candidates: PgcCandidate[], + mainRecord: RecordCrossmatch, +) { + const candidateSources = candidates .filter((candidate) => candidate.catalogs?.coordinates?.equatorial) .map((candidate) => ({ ra: candidate.catalogs!.coordinates!.equatorial.ra, dec: candidate.catalogs!.coordinates!.equatorial.dec, label: `PGC ${candidate.pgc}`, })); + + const mainRecordSource = mainRecord.catalogs?.coordinates?.equatorial + ? { + ra: mainRecord.catalogs.coordinates.equatorial.ra, + dec: mainRecord.catalogs.coordinates.equatorial.dec, + label: + mainRecord.catalogs.designation?.name || + `Record ${mainRecord.record_id}`, + } + : null; + + return mainRecordSource + ? [mainRecordSource, ...candidateSources] + : candidateSources; } function renderCrossmatchDetails( @@ -123,7 +132,10 @@ function renderCrossmatchDetails( const { crossmatch, candidates, schema } = data; const recordObject = convertRecordToPgcObject(crossmatch); const backendSchema = convertAdminSchemaToBackendSchema(schema); - const candidateSources = convertCandidatesToAdditionalSources(candidates); + const candidateSources = convertCandidatesToAdditionalSources( + candidates, + crossmatch, + ); return (
@@ -138,11 +150,6 @@ function renderCrossmatchDetails( className="w-96 h-96" additionalSources={candidateSources} /> - {candidateSources.length > 0 && ( -

- White labels show crossmatch candidates -

- )}
)}
From f9019afd5e2e6289f6ae8edbd2fc1e2d24af2232 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 13:15:55 +0300 Subject: [PATCH 02/10] change coordinate formatting --- src/components/ui/catalog-data.tsx | 71 ++++++++++++++------------- src/pages/RecordCrossmatchDetails.tsx | 32 ++++++------ 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/src/components/ui/catalog-data.tsx b/src/components/ui/catalog-data.tsx index d8f9876..2320291 100644 --- a/src/components/ui/catalog-data.tsx +++ b/src/components/ui/catalog-data.tsx @@ -13,47 +13,50 @@ export function CatalogData({ }: CatalogDataProps): ReactElement { if (!object || !schema) return
; + function formatCoordinate( + value: number | undefined, + error: number | undefined, + unit: string | undefined, + ): string { + if (value === undefined) return "NULL"; + const formattedValue = value.toFixed(2); + const formattedError = error?.toFixed(2) || "0.00"; + const unitStr = unit || "deg"; + return `${formattedValue} ${unitStr} +- ${formattedError} ${unitStr}`; + } + const coordinatesColumns = [ - { name: "Parameter" }, - { name: "Value" }, - { name: "Unit" }, - { name: "Error" }, - { name: "Error unit" }, + { name: "Type" }, + { name: "RA / l" }, + { name: "Dec / b" }, ]; const coordinatesData = [ { - Parameter: "Right ascension", - Value: object.catalogs?.coordinates?.equatorial?.ra?.toFixed(6) || "NULL", - Unit: schema.units.coordinates?.equatorial?.ra || "NULL", - Error: - object.catalogs?.coordinates?.equatorial?.e_ra?.toFixed(6) || "NULL", - "Error unit": schema.units.coordinates?.equatorial?.e_ra || "NULL", - }, - { - Parameter: "Declination", - Value: - object.catalogs?.coordinates?.equatorial?.dec?.toFixed(6) || "NULL", - Unit: schema.units.coordinates?.equatorial?.dec || "NULL", - Error: - object.catalogs?.coordinates?.equatorial?.e_dec?.toFixed(6) || "NULL", - "Error unit": schema.units.coordinates?.equatorial?.e_dec || "NULL", - }, - { - Parameter: "Galactic longitude", - Value: object.catalogs?.coordinates?.galactic?.lon?.toFixed(6) || "NULL", - Unit: schema.units.coordinates?.galactic?.lon || "NULL", - Error: - object.catalogs?.coordinates?.galactic?.e_lon?.toFixed(6) || "NULL", - "Error unit": schema.units.coordinates?.galactic?.e_lon || "NULL", + Type: "Equatorial", + "RA / l": formatCoordinate( + object.catalogs?.coordinates?.equatorial?.ra, + object.catalogs?.coordinates?.equatorial?.e_ra, + schema.units.coordinates?.equatorial?.ra, + ), + "Dec / b": formatCoordinate( + object.catalogs?.coordinates?.equatorial?.dec, + object.catalogs?.coordinates?.equatorial?.e_dec, + schema.units.coordinates?.equatorial?.dec, + ), }, { - Parameter: "Galactic latitude", - Value: object.catalogs?.coordinates?.galactic?.lat?.toFixed(6) || "NULL", - Unit: schema.units.coordinates?.galactic?.lat || "NULL", - Error: - object.catalogs?.coordinates?.galactic?.e_lat?.toFixed(6) || "NULL", - "Error unit": schema.units.coordinates?.galactic?.e_lat || "NULL", + Type: "Galactic", + "RA / l": formatCoordinate( + object.catalogs?.coordinates?.galactic?.lon, + object.catalogs?.coordinates?.galactic?.e_lon, + schema.units.coordinates?.galactic?.lon, + ), + "Dec / b": formatCoordinate( + object.catalogs?.coordinates?.galactic?.lat, + object.catalogs?.coordinates?.galactic?.e_lat, + schema.units.coordinates?.galactic?.lat, + ), }, ]; diff --git a/src/pages/RecordCrossmatchDetails.tsx b/src/pages/RecordCrossmatchDetails.tsx index 923ee1a..831437f 100644 --- a/src/pages/RecordCrossmatchDetails.tsx +++ b/src/pages/RecordCrossmatchDetails.tsx @@ -1,17 +1,18 @@ import { ReactElement, useEffect, useState } from "react"; -import { NavigateFunction, useNavigate, useParams } from "react-router-dom"; +import { + Link, + NavigateFunction, + useNavigate, + useParams, +} from "react-router-dom"; import { AladinViewer } from "../components/ui/aladin"; import { Loading } from "../components/ui/loading"; -import { - ErrorPage, - ErrorPageHomeButton, -} from "../components/ui/error-page"; +import { ErrorPage, ErrorPageHomeButton } from "../components/ui/error-page"; import { CatalogData } from "../components/ui/catalog-data"; import { getRecordCrossmatchAdminApiV1RecordCrossmatchGet } from "../clients/admin/sdk.gen"; import { GetRecordCrossmatchResponse, RecordCrossmatch, - RecordCrossmatchStatus, PgcCandidate, Schema as AdminSchema, } from "../clients/admin/types.gen"; @@ -32,10 +33,6 @@ function renderNotFound(navigate: NavigateFunction) { ); } -function getStatusLabel(status: RecordCrossmatchStatus): string { - return getResource(`crossmatch.status.${status}`).Title; -} - function convertAdminSchemaToBackendSchema( adminSchema: AdminSchema, ): BackendSchema { @@ -156,11 +153,17 @@ function renderCrossmatchDetails(

Record ID: {crossmatch.record_id}

-

- Status: {getStatusLabel(crossmatch.status)} +

+ Status:{" "} + {getResource(`crossmatch.status.${crossmatch.status}`).Title}

{crossmatch.metadata.pgc && ( -

PGC: {crossmatch.metadata.pgc}

+

+ PGC:{" "} + + {crossmatch.metadata.pgc} + +

)}
@@ -178,7 +181,8 @@ function renderCrossmatchDetails( return (

- Candidate {index + 1}: PGC {candidate.pgc} + Candidate {index + 1}: PGC{" "} + {candidate.pgc}

From c4e7bcd9398ff077c794ec79f5e3ba55e4aabe84 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 13:35:13 +0300 Subject: [PATCH 03/10] refactor catalog data component --- src/components/ui/catalog-data.tsx | 156 +++++++++++++++++--------- src/pages/RecordCrossmatchDetails.tsx | 92 ++++++--------- 2 files changed, 133 insertions(+), 115 deletions(-) diff --git a/src/components/ui/catalog-data.tsx b/src/components/ui/catalog-data.tsx index 2320291..1fab8e4 100644 --- a/src/components/ui/catalog-data.tsx +++ b/src/components/ui/catalog-data.tsx @@ -1,30 +1,46 @@ import { ReactElement } from "react"; import { CommonTable } from "./common-table"; -import { PgcObject, Schema } from "../../clients/backend/types.gen"; +import { Catalogs, Schema } from "../../clients/backend/types.gen"; interface CatalogDataProps { - object: PgcObject; - schema: Schema | null; + catalogs: Catalogs; + schema: Schema; } -export function CatalogData({ - object, - schema, -}: CatalogDataProps): ReactElement { - if (!object || !schema) return
; - - function formatCoordinate( - value: number | undefined, - error: number | undefined, - unit: string | undefined, - ): string { - if (value === undefined) return "NULL"; - const formattedValue = value.toFixed(2); - const formattedError = error?.toFixed(2) || "0.00"; - const unitStr = unit || "deg"; - return `${formattedValue} ${unitStr} +- ${formattedError} ${unitStr}`; - } +function formatCoordinate( + value: number | undefined, + error: number | undefined, + unit: string | undefined, +): string { + if (value === undefined) return "NULL"; + const formattedValue = value.toFixed(2); + const formattedError = error?.toFixed(2) || "0.00"; + const unitStr = unit || "deg"; + return `${formattedValue} ${unitStr} +- ${formattedError} ${unitStr}`; +} + +function CatalogHeader({ + title, + description, +}: { + title: string; + description: string; +}): ReactElement { + return ( + <> +

{title}

+

{description}

+ + ); +} +function CoordinatesCatalog({ + catalogs, + schema, +}: { + catalogs: Catalogs; + schema: Schema; +}): ReactElement { const coordinatesColumns = [ { name: "Type" }, { name: "RA / l" }, @@ -35,31 +51,42 @@ export function CatalogData({ { Type: "Equatorial", "RA / l": formatCoordinate( - object.catalogs?.coordinates?.equatorial?.ra, - object.catalogs?.coordinates?.equatorial?.e_ra, + catalogs?.coordinates?.equatorial?.ra, + catalogs?.coordinates?.equatorial?.e_ra, schema.units.coordinates?.equatorial?.ra, ), "Dec / b": formatCoordinate( - object.catalogs?.coordinates?.equatorial?.dec, - object.catalogs?.coordinates?.equatorial?.e_dec, + catalogs?.coordinates?.equatorial?.dec, + catalogs?.coordinates?.equatorial?.e_dec, schema.units.coordinates?.equatorial?.dec, ), }, { Type: "Galactic", "RA / l": formatCoordinate( - object.catalogs?.coordinates?.galactic?.lon, - object.catalogs?.coordinates?.galactic?.e_lon, + catalogs?.coordinates?.galactic?.lon, + catalogs?.coordinates?.galactic?.e_lon, schema.units.coordinates?.galactic?.lon, ), "Dec / b": formatCoordinate( - object.catalogs?.coordinates?.galactic?.lat, - object.catalogs?.coordinates?.galactic?.e_lat, + catalogs?.coordinates?.galactic?.lat, + catalogs?.coordinates?.galactic?.e_lat, schema.units.coordinates?.galactic?.lat, ), }, ]; + return ( + + + + ); +} + +function RedshiftCatalog({ catalogs }: { catalogs: Catalogs }): ReactElement { const redshiftColumns = [ { name: "Parameter" }, { name: "Value" }, @@ -69,11 +96,25 @@ export function CatalogData({ const redshiftData = [ { Parameter: "z", - Value: object.catalogs?.redshift?.z?.toFixed(6) || "NULL", - Error: object.catalogs?.redshift?.e_z?.toFixed(6) || "NULL", + Value: catalogs?.redshift?.z?.toFixed(6) || "NULL", + Error: catalogs?.redshift?.e_z?.toFixed(6) || "NULL", }, ]; + return ( + + + + ); +} + +function VelocityCatalog({ + catalogs, + schema, +}: { + catalogs: Catalogs; + schema: Schema; +}): ReactElement { const velocityColumns = [ { name: "Parameter" }, { name: "Value" }, @@ -85,57 +126,60 @@ export function CatalogData({ const velocityData = [ { Parameter: "Heliocentric", - Value: object.catalogs?.velocity?.heliocentric?.v?.toFixed(2) || "NULL", + Value: catalogs?.velocity?.heliocentric?.v?.toFixed(2) || "NULL", Unit: schema.units.velocity?.heliocentric?.v || "NULL", - Error: object.catalogs?.velocity?.heliocentric?.e_v?.toFixed(2) || "NULL", + Error: catalogs?.velocity?.heliocentric?.e_v?.toFixed(2) || "NULL", "Error unit": schema.units.velocity?.heliocentric?.e_v || "NULL", }, { Parameter: "Local Group", - Value: object.catalogs?.velocity?.local_group?.v?.toFixed(2) || "NULL", + Value: catalogs?.velocity?.local_group?.v?.toFixed(2) || "NULL", Unit: schema.units.velocity?.local_group?.v || "NULL", - Error: object.catalogs?.velocity?.local_group?.e_v?.toFixed(2) || "NULL", + Error: catalogs?.velocity?.local_group?.e_v?.toFixed(2) || "NULL", "Error unit": schema.units.velocity?.local_group?.e_v || "NULL", }, { Parameter: "CMB (old)", - Value: object.catalogs?.velocity?.cmb_old?.v?.toFixed(2) || "NULL", + Value: catalogs?.velocity?.cmb_old?.v?.toFixed(2) || "NULL", Unit: schema.units.velocity?.cmb_old?.v || "NULL", - Error: object.catalogs?.velocity?.cmb_old?.e_v?.toFixed(2) || "NULL", + Error: catalogs?.velocity?.cmb_old?.e_v?.toFixed(2) || "NULL", "Error unit": schema.units.velocity?.cmb_old?.e_v || "NULL", }, { Parameter: "CMB", - Value: object.catalogs?.velocity?.cmb?.v?.toFixed(2) || "NULL", + Value: catalogs?.velocity?.cmb?.v?.toFixed(2) || "NULL", Unit: schema.units.velocity?.cmb?.v || "NULL", - Error: object.catalogs?.velocity?.cmb?.e_v?.toFixed(2) || "NULL", + Error: catalogs?.velocity?.cmb?.e_v?.toFixed(2) || "NULL", "Error unit": schema.units.velocity?.cmb?.e_v || "NULL", }, ]; + return ( + + + + ); +} + +export function CatalogData({ + catalogs, + schema, +}: CatalogDataProps): ReactElement { + if (!catalogs) return
; + return (
- {object.catalogs?.coordinates && ( - -

Coordinates

-

Celestial coordinates of the object

-
+ {catalogs?.coordinates && ( + )} - {object.catalogs?.redshift && ( - -

Redshift

-

Redshift measurements

-
- )} + {catalogs?.redshift && } - {object.catalogs?.velocity && ( - -

Velocity

-

- Velocity measurements with respect to different apexes -

-
+ {catalogs?.velocity && ( + )}
); diff --git a/src/pages/RecordCrossmatchDetails.tsx b/src/pages/RecordCrossmatchDetails.tsx index 831437f..81f14de 100644 --- a/src/pages/RecordCrossmatchDetails.tsx +++ b/src/pages/RecordCrossmatchDetails.tsx @@ -1,10 +1,5 @@ import { ReactElement, useEffect, useState } from "react"; -import { - Link, - NavigateFunction, - useNavigate, - useParams, -} from "react-router-dom"; +import { NavigateFunction, useNavigate, useParams } from "react-router-dom"; import { AladinViewer } from "../components/ui/aladin"; import { Loading } from "../components/ui/loading"; import { ErrorPage, ErrorPageHomeButton } from "../components/ui/error-page"; @@ -16,11 +11,9 @@ import { PgcCandidate, Schema as AdminSchema, } from "../clients/admin/types.gen"; -import { - PgcObject, - Schema as BackendSchema, -} from "../clients/backend/types.gen"; +import { Schema as BackendSchema } from "../clients/backend/types.gen"; import { getResource } from "../resources/resources"; +import { Link } from "../components/ui/link"; function renderNotFound(navigate: NavigateFunction) { return ( @@ -33,6 +26,7 @@ function renderNotFound(navigate: NavigateFunction) { ); } +// TODO: remove when admin api uses the same structures as data api function convertAdminSchemaToBackendSchema( adminSchema: AdminSchema, ): BackendSchema { @@ -82,20 +76,6 @@ function convertAdminSchemaToBackendSchema( }; } -function convertToPgcObject(candidate: PgcCandidate): PgcObject { - return { - pgc: candidate.pgc, - catalogs: candidate.catalogs, - }; -} - -function convertRecordToPgcObject(record: RecordCrossmatch): PgcObject { - return { - pgc: record.metadata.pgc || 0, - catalogs: record.catalogs, - }; -} - function convertCandidatesToAdditionalSources( candidates: PgcCandidate[], mainRecord: RecordCrossmatch, @@ -127,7 +107,7 @@ function renderCrossmatchDetails( data: GetRecordCrossmatchResponse, ): ReactElement { const { crossmatch, candidates, schema } = data; - const recordObject = convertRecordToPgcObject(crossmatch); + const recordCatalogs = crossmatch.catalogs; const backendSchema = convertAdminSchemaToBackendSchema(schema); const candidateSources = convertCandidatesToAdditionalSources( candidates, @@ -138,56 +118,50 @@ function renderCrossmatchDetails(
{crossmatch.catalogs?.coordinates?.equatorial && ( -
- -
+ )}
-

- Record ID: {crossmatch.record_id} -

+ {crossmatch.catalogs?.designation?.name && ( +

+ {crossmatch.catalogs.designation.name} +

+ )}

Status:{" "} {getResource(`crossmatch.status.${crossmatch.status}`).Title}

- {crossmatch.metadata.pgc && ( -

- PGC:{" "} - - {crossmatch.metadata.pgc} - -

- )}

Record Catalog Data

- +
{candidates.length > 0 && (

Crossmatch Candidates

- {candidates.map((candidate, index) => { - const candidateObject = convertToPgcObject(candidate); - return ( -
-

- Candidate {index + 1}: PGC{" "} - {candidate.pgc} -

- -
- ); - })} + {candidates.map((candidate, index) => ( +
+

+ Candidate {index + 1}:{" "} + {`PGC ${candidate.pgc}`} +

+ +
+ ))}
)}
From 4776520c178ba077d68a83c1978078642ec9bdea Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 13:51:52 +0300 Subject: [PATCH 04/10] merge link button and link --- src/components/ui/footer.tsx | 10 ++++++++-- src/components/ui/link-button.tsx | 19 ------------------- src/components/ui/link.tsx | 22 ++++++++++++++++------ src/pages/CrossmatchResults.tsx | 23 +++++++++++------------ src/pages/ObjectDetails.tsx | 3 +-- src/pages/TableDetails.tsx | 7 +++++-- 6 files changed, 41 insertions(+), 43 deletions(-) delete mode 100644 src/components/ui/link-button.tsx diff --git a/src/components/ui/footer.tsx b/src/components/ui/footer.tsx index fa3947a..e99c5ef 100644 --- a/src/components/ui/footer.tsx +++ b/src/components/ui/footer.tsx @@ -7,10 +7,16 @@ import { MdKeyboardArrowDown, MdKeyboardArrowUp } from "react-icons/md"; const footerContent = (
- Information: + Information:{" "} + + The next generation of the HyperLeda database +
- Original version: + Original version:{" "} + + OHP Mirror +
); diff --git a/src/components/ui/link-button.tsx b/src/components/ui/link-button.tsx deleted file mode 100644 index e09d040..0000000 --- a/src/components/ui/link-button.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { ReactElement, ReactNode } from "react"; -import { MdOpenInNew } from "react-icons/md"; -import { Link } from "./link"; - -interface LinkButtonProps { - children?: ReactNode; - to: string; -} - -export function LinkButton(props: LinkButtonProps): ReactElement { - return ( -
-
{props.children}
- - - -
- ); -} diff --git a/src/components/ui/link.tsx b/src/components/ui/link.tsx index 7999d88..a4b37c6 100644 --- a/src/components/ui/link.tsx +++ b/src/components/ui/link.tsx @@ -1,25 +1,35 @@ -import { ReactElement } from "react"; +import { ReactElement, ReactNode } from "react"; +import { MdOpenInNew } from "react-icons/md"; interface LinkProps { - children?: ReactElement | string; + children?: ReactNode; href: string; className?: string; + external?: boolean; } export function Link(props: LinkProps): ReactElement { - const content = props.children ?? props.href; + const content = props.children; const baseClass = "text-green-500 hover:text-green-600 transition-colors"; const className = props.className ? `${baseClass} ${props.className}` : baseClass; + + const linkProps = props.external + ? { + target: "_blank", + rel: "noopener noreferrer", + } + : {}; + return ( {content} + {props.external && } ); } diff --git a/src/pages/CrossmatchResults.tsx b/src/pages/CrossmatchResults.tsx index c232026..0c8b6b3 100644 --- a/src/pages/CrossmatchResults.tsx +++ b/src/pages/CrossmatchResults.tsx @@ -20,7 +20,7 @@ import { getResource } from "../resources/resources"; import { Button } from "../components/ui/button"; import { Loading } from "../components/ui/loading"; import { ErrorPage, ErrorPageHomeButton } from "../components/ui/error-page"; -import { LinkButton } from "../components/ui/link-button"; +import { Link } from "../components/ui/link"; export function CrossmatchResultsPage(): ReactElement { const [searchParams, setSearchParams] = useSearchParams(); @@ -121,9 +121,9 @@ export function CrossmatchResultsPage(): ReactElement { function getRecordName(record: RecordCrossmatch): ReactElement { const displayName = record.catalogs.designation?.name || record.record_id; return ( - + {displayName} - + ); } @@ -224,15 +224,14 @@ export function CrossmatchResultsPage(): ReactElement {

Crossmatch results

- - - + + PGC: {object.pgc}

- - +
); } diff --git a/src/pages/TableDetails.tsx b/src/pages/TableDetails.tsx index 75c1b53..4343f2f 100644 --- a/src/pages/TableDetails.tsx +++ b/src/pages/TableDetails.tsx @@ -38,7 +38,10 @@ function renderBibliography(bib: Bibliography): ReactElement { return (
- {bib.bibcode} | {authors}: "{bib.title}" + + {bib.bibcode} + {" "} + | {authors}: "{bib.title}"
); @@ -220,7 +223,7 @@ function ColumnInfo(props: ColumnInfoProps): ReactElement {

Unified Content Descriptor. Describes astronomical quantities in a structured way. For more information see{" "} - + IVOA Recommendation . From 1531f6670833dc9d9fe47e778e20ff756e8721d8 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 13:58:18 +0300 Subject: [PATCH 05/10] add link to the original object in OHP --- src/pages/ObjectDetails.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/ObjectDetails.tsx b/src/pages/ObjectDetails.tsx index d79d672..bb2fa16 100644 --- a/src/pages/ObjectDetails.tsx +++ b/src/pages/ObjectDetails.tsx @@ -9,6 +9,7 @@ import { ErrorPageHomeButton, } from "../components/ui/error-page"; import { CatalogData } from "../components/ui/catalog-data"; +import { Link } from "../components/ui/link"; import { querySimpleApiV1QuerySimpleGet } from "../clients/backend/sdk.gen"; import { PgcObject, Schema } from "../clients/backend/types.gen"; @@ -59,6 +60,12 @@ function renderObjectDetails( {object.catalogs?.designation?.name || `PGC ${object.pgc}`}

PGC: {object.pgc}

+ + OHP Mirror + From 685b33f54a91015262b7ac3e0ee21be36f4b8367 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 14:16:49 +0300 Subject: [PATCH 06/10] merge errors with values --- src/components/ui/catalog-data.tsx | 88 ++++++++++++++++-------------- src/pages/ObjectDetails.tsx | 4 +- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/components/ui/catalog-data.tsx b/src/components/ui/catalog-data.tsx index 1fab8e4..205a1e2 100644 --- a/src/components/ui/catalog-data.tsx +++ b/src/components/ui/catalog-data.tsx @@ -7,16 +7,22 @@ interface CatalogDataProps { schema: Schema; } -function formatCoordinate( +function formatValueWithError( value: number | undefined, error: number | undefined, - unit: string | undefined, + unit?: string, + decimalPlaces: number = 0, ): string { if (value === undefined) return "NULL"; - const formattedValue = value.toFixed(2); - const formattedError = error?.toFixed(2) || "0.00"; - const unitStr = unit || "deg"; - return `${formattedValue} ${unitStr} +- ${formattedError} ${unitStr}`; + const formattedValue = value.toFixed(decimalPlaces); + const formattedError = + error?.toFixed(decimalPlaces) || "0".padEnd(decimalPlaces + 1, "0"); + + if (!unit) { + return `${formattedValue} +- ${formattedError}`; + } + + return `${formattedValue} ${unit} +- ${formattedError} ${unit}`; } function CatalogHeader({ @@ -50,28 +56,32 @@ function CoordinatesCatalog({ const coordinatesData = [ { Type: "Equatorial", - "RA / l": formatCoordinate( + "RA / l": formatValueWithError( catalogs?.coordinates?.equatorial?.ra, catalogs?.coordinates?.equatorial?.e_ra, schema.units.coordinates?.equatorial?.ra, + 2, ), - "Dec / b": formatCoordinate( + "Dec / b": formatValueWithError( catalogs?.coordinates?.equatorial?.dec, catalogs?.coordinates?.equatorial?.e_dec, schema.units.coordinates?.equatorial?.dec, + 2, ), }, { Type: "Galactic", - "RA / l": formatCoordinate( + "RA / l": formatValueWithError( catalogs?.coordinates?.galactic?.lon, catalogs?.coordinates?.galactic?.e_lon, schema.units.coordinates?.galactic?.lon, + 2, ), - "Dec / b": formatCoordinate( + "Dec / b": formatValueWithError( catalogs?.coordinates?.galactic?.lat, catalogs?.coordinates?.galactic?.e_lat, schema.units.coordinates?.galactic?.lat, + 2, ), }, ]; @@ -87,17 +97,17 @@ function CoordinatesCatalog({ } function RedshiftCatalog({ catalogs }: { catalogs: Catalogs }): ReactElement { - const redshiftColumns = [ - { name: "Parameter" }, - { name: "Value" }, - { name: "Error" }, - ]; + const redshiftColumns = [{ name: "Parameter" }, { name: "Value" }]; const redshiftData = [ { Parameter: "z", - Value: catalogs?.redshift?.z?.toFixed(6) || "NULL", - Error: catalogs?.redshift?.e_z?.toFixed(6) || "NULL", + Value: formatValueWithError( + catalogs?.redshift?.z, + catalogs?.redshift?.e_z, + undefined, + 5, + ), }, ]; @@ -115,42 +125,40 @@ function VelocityCatalog({ catalogs: Catalogs; schema: Schema; }): ReactElement { - const velocityColumns = [ - { name: "Parameter" }, - { name: "Value" }, - { name: "Unit" }, - { name: "Error" }, - { name: "Error unit" }, - ]; + const velocityColumns = [{ name: "Parameter" }, { name: "Value" }]; const velocityData = [ { Parameter: "Heliocentric", - Value: catalogs?.velocity?.heliocentric?.v?.toFixed(2) || "NULL", - Unit: schema.units.velocity?.heliocentric?.v || "NULL", - Error: catalogs?.velocity?.heliocentric?.e_v?.toFixed(2) || "NULL", - "Error unit": schema.units.velocity?.heliocentric?.e_v || "NULL", + Value: formatValueWithError( + catalogs?.velocity?.heliocentric?.v, + catalogs?.velocity?.heliocentric?.e_v, + schema.units.velocity?.heliocentric?.v, + ), }, { Parameter: "Local Group", - Value: catalogs?.velocity?.local_group?.v?.toFixed(2) || "NULL", - Unit: schema.units.velocity?.local_group?.v || "NULL", - Error: catalogs?.velocity?.local_group?.e_v?.toFixed(2) || "NULL", - "Error unit": schema.units.velocity?.local_group?.e_v || "NULL", + Value: formatValueWithError( + catalogs?.velocity?.local_group?.v, + catalogs?.velocity?.local_group?.e_v, + schema.units.velocity?.local_group?.v, + ), }, { Parameter: "CMB (old)", - Value: catalogs?.velocity?.cmb_old?.v?.toFixed(2) || "NULL", - Unit: schema.units.velocity?.cmb_old?.v || "NULL", - Error: catalogs?.velocity?.cmb_old?.e_v?.toFixed(2) || "NULL", - "Error unit": schema.units.velocity?.cmb_old?.e_v || "NULL", + Value: formatValueWithError( + catalogs?.velocity?.cmb_old?.v, + catalogs?.velocity?.cmb_old?.e_v, + schema.units.velocity?.cmb_old?.v, + ), }, { Parameter: "CMB", - Value: catalogs?.velocity?.cmb?.v?.toFixed(2) || "NULL", - Unit: schema.units.velocity?.cmb?.v || "NULL", - Error: catalogs?.velocity?.cmb?.e_v?.toFixed(2) || "NULL", - "Error unit": schema.units.velocity?.cmb?.e_v || "NULL", + Value: formatValueWithError( + catalogs?.velocity?.cmb?.v, + catalogs?.velocity?.cmb?.e_v, + schema.units.velocity?.cmb?.v, + ), }, ]; diff --git a/src/pages/ObjectDetails.tsx b/src/pages/ObjectDetails.tsx index bb2fa16..e18cb12 100644 --- a/src/pages/ObjectDetails.tsx +++ b/src/pages/ObjectDetails.tsx @@ -46,7 +46,7 @@ function renderObjectDetails( return (
- {object.catalogs?.coordinates?.equatorial && ( + {object.catalogs?.coordinates && ( {object.catalogs?.designation?.name || `PGC ${object.pgc}`} -

PGC: {object.pgc}

+

PGC: {object.pgc}

Date: Wed, 17 Sep 2025 15:37:35 +0300 Subject: [PATCH 07/10] added markers to aladin widget --- src/components/ui/aladin.tsx | 45 ++++++++++++++++++--------- src/pages/RecordCrossmatchDetails.tsx | 23 +++++++++++++- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/components/ui/aladin.tsx b/src/components/ui/aladin.tsx index be88b98..e835e58 100644 --- a/src/components/ui/aladin.tsx +++ b/src/components/ui/aladin.tsx @@ -5,14 +5,14 @@ interface AdditionalSource { ra: number; dec: number; label: string; + description?: string; } interface AladinViewerProps { - ra?: number; - dec?: number; + ra: number; + dec: number; fov?: number; survey?: string; - target?: string; className?: string; additionalSources?: AdditionalSource[]; } @@ -22,7 +22,6 @@ export function AladinViewer({ dec, fov = 0.5, survey = "P/DSS2/color", - target, className = "w-full h-96", additionalSources, }: AladinViewerProps) { @@ -42,23 +41,33 @@ export function AladinViewer({ showCooGridControl: false, }); - if (target) { - aladin.gotoObject(target); - } else if (ra !== undefined && dec !== undefined) { - aladin.gotoRaDec(ra, dec); - } + aladin.gotoRaDec(ra, dec); if (additionalSources && additionalSources.length > 0) { - const catalog = window.A.catalog({ + const nameCatalog = window.A.catalog({ labelColumn: "name", displayLabel: true, labelColor: "#fff", labelFont: "14px sans-serif", }); - aladin.addCatalog(catalog); + const descrCatalog = window.A.catalog({ + sourceSize: 8, + displayLabel: true, + }); + aladin.addCatalog(nameCatalog); + aladin.addCatalog(descrCatalog); additionalSources.forEach((source) => { - catalog.addSources( + if (source.description) { + descrCatalog.addSources([ + window.A.marker(source.ra, source.dec, { + name: source.label, + popupTitle: source.label, + popupDesc: source.description, + }), + ]); + } + nameCatalog.addSources( window.A.source(source.ra, source.dec, { name: source.label }), ); }); @@ -66,19 +75,19 @@ export function AladinViewer({ } catch (error) { console.error("Error initializing Aladin:", error); } - }, [ra, dec, fov, survey, target, additionalSources]); + }, [ra, dec, fov, survey, additionalSources]); return
; } interface AladinCatalog { - addSources: (sources: AladinSource) => void; + addSources: (sources: AladinSource | AladinSource[]) => void; } interface AladinSource { ra: number; dec: number; - properties?: { name?: string }; + properties?: { name?: string; popupTitle?: string; popupDesc?: string }; } declare global { @@ -105,12 +114,18 @@ declare global { displayLabel?: boolean; labelColor?: string; labelFont?: string; + sourceSize?: number; }) => AladinCatalog; source: ( ra: number, dec: number, properties?: { name?: string }, ) => AladinSource; + marker: ( + ra: number, + dec: number, + properties?: { name?: string; popupTitle?: string; popupDesc?: string }, + ) => AladinSource; }; } } diff --git a/src/pages/RecordCrossmatchDetails.tsx b/src/pages/RecordCrossmatchDetails.tsx index 81f14de..77885a4 100644 --- a/src/pages/RecordCrossmatchDetails.tsx +++ b/src/pages/RecordCrossmatchDetails.tsx @@ -76,6 +76,23 @@ function convertAdminSchemaToBackendSchema( }; } +function createDescription( + velocity?: { v: number; e_v: number } | null, + redshift?: { z: number; e_z: number } | null, +): string { + const parts = []; + + if (velocity) { + parts.push(`v: ${velocity.v.toFixed(1)} ± ${velocity.e_v.toFixed(1)} km/s`); + } + + if (redshift) { + parts.push(`z: ${redshift.z.toFixed(4)} ± ${redshift.e_z.toFixed(4)}`); + } + + return parts.join(", "); +} + function convertCandidatesToAdditionalSources( candidates: PgcCandidate[], mainRecord: RecordCrossmatch, @@ -86,6 +103,10 @@ function convertCandidatesToAdditionalSources( ra: candidate.catalogs!.coordinates!.equatorial.ra, dec: candidate.catalogs!.coordinates!.equatorial.dec, label: `PGC ${candidate.pgc}`, + description: createDescription( + candidate.catalogs?.velocity?.heliocentric, + candidate.catalogs?.redshift, + ), })); const mainRecordSource = mainRecord.catalogs?.coordinates?.equatorial @@ -93,7 +114,7 @@ function convertCandidatesToAdditionalSources( ra: mainRecord.catalogs.coordinates.equatorial.ra, dec: mainRecord.catalogs.coordinates.equatorial.dec, label: - mainRecord.catalogs.designation?.name || + mainRecord.catalogs?.designation?.name || `Record ${mainRecord.record_id}`, } : null; From 71db7b74a3ce64c20b75926b50a63e3d8be5ede3 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 15:44:39 +0300 Subject: [PATCH 08/10] aladin styling --- src/components/ui/aladin.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/ui/aladin.tsx b/src/components/ui/aladin.tsx index e835e58..8d46cc1 100644 --- a/src/components/ui/aladin.tsx +++ b/src/components/ui/aladin.tsx @@ -46,13 +46,15 @@ export function AladinViewer({ if (additionalSources && additionalSources.length > 0) { const nameCatalog = window.A.catalog({ labelColumn: "name", + shape: "cross", + color: "black", displayLabel: true, - labelColor: "#fff", + labelColor: "lightgrey", labelFont: "14px sans-serif", }); const descrCatalog = window.A.catalog({ - sourceSize: 8, - displayLabel: true, + color: "black", + shape: "cross", }); aladin.addCatalog(nameCatalog); aladin.addCatalog(descrCatalog); @@ -115,6 +117,8 @@ declare global { labelColor?: string; labelFont?: string; sourceSize?: number; + shape?: string; + color?: string; }) => AladinCatalog; source: ( ra: number, From 90c2967f6cb9525fda103424e38c2106201a0d1b Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 16:34:49 +0300 Subject: [PATCH 09/10] compact tables --- src/components/ui/catalog-data.tsx | 251 ++++++++++---------------- src/components/ui/common-table.tsx | 2 +- src/components/ui/hint.tsx | 4 +- src/pages/RecordCrossmatchDetails.tsx | 5 +- 4 files changed, 99 insertions(+), 163 deletions(-) diff --git a/src/components/ui/catalog-data.tsx b/src/components/ui/catalog-data.tsx index 205a1e2..8aa7467 100644 --- a/src/components/ui/catalog-data.tsx +++ b/src/components/ui/catalog-data.tsx @@ -19,176 +19,115 @@ function formatValueWithError( error?.toFixed(decimalPlaces) || "0".padEnd(decimalPlaces + 1, "0"); if (!unit) { - return `${formattedValue} +- ${formattedError}`; + return `${formattedValue} ± ${formattedError}`; } - return `${formattedValue} ${unit} +- ${formattedError} ${unit}`; + return `${formattedValue} ${unit} ± ${formattedError} ${unit}`; } -function CatalogHeader({ - title, - description, -}: { - title: string; - description: string; -}): ReactElement { - return ( - <> -

{title}

-

{description}

- - ); +function CatalogHeader({ title }: { title: string }): ReactElement { + return

{title}

; } -function CoordinatesCatalog({ +export function CatalogData({ catalogs, schema, -}: { - catalogs: Catalogs; - schema: Schema; -}): ReactElement { - const coordinatesColumns = [ - { name: "Type" }, - { name: "RA / l" }, - { name: "Dec / b" }, - ]; - - const coordinatesData = [ - { - Type: "Equatorial", - "RA / l": formatValueWithError( - catalogs?.coordinates?.equatorial?.ra, - catalogs?.coordinates?.equatorial?.e_ra, - schema.units.coordinates?.equatorial?.ra, - 2, - ), - "Dec / b": formatValueWithError( - catalogs?.coordinates?.equatorial?.dec, - catalogs?.coordinates?.equatorial?.e_dec, - schema.units.coordinates?.equatorial?.dec, - 2, - ), - }, - { - Type: "Galactic", - "RA / l": formatValueWithError( - catalogs?.coordinates?.galactic?.lon, - catalogs?.coordinates?.galactic?.e_lon, - schema.units.coordinates?.galactic?.lon, - 2, - ), - "Dec / b": formatValueWithError( - catalogs?.coordinates?.galactic?.lat, - catalogs?.coordinates?.galactic?.e_lat, - schema.units.coordinates?.galactic?.lat, - 2, - ), - }, - ]; - - return ( - - - - ); -} +}: CatalogDataProps): ReactElement { + if (!catalogs) return
; -function RedshiftCatalog({ catalogs }: { catalogs: Catalogs }): ReactElement { - const redshiftColumns = [{ name: "Parameter" }, { name: "Value" }]; + const columns = [{ name: "Parameter" }, { name: "Value" }]; + + const data = []; + + if (catalogs?.coordinates) { + data.push( + { + Parameter: "Equatorial RA", + Value: formatValueWithError( + catalogs.coordinates.equatorial?.ra, + catalogs.coordinates.equatorial?.e_ra, + schema.units.coordinates?.equatorial?.ra, + 2, + ), + }, + { + Parameter: "Equatorial Dec", + Value: formatValueWithError( + catalogs.coordinates.equatorial?.dec, + catalogs.coordinates.equatorial?.e_dec, + schema.units.coordinates?.equatorial?.dec, + 2, + ), + }, + { + Parameter: "Galactic l", + Value: formatValueWithError( + catalogs.coordinates.galactic?.lon, + catalogs.coordinates.galactic?.e_lon, + schema.units.coordinates?.galactic?.lon, + 2, + ), + }, + { + Parameter: "Galactic b", + Value: formatValueWithError( + catalogs.coordinates.galactic?.lat, + catalogs.coordinates.galactic?.e_lat, + schema.units.coordinates?.galactic?.lat, + 2, + ), + }, + ); + } - const redshiftData = [ - { - Parameter: "z", + if (catalogs?.redshift) { + data.push({ + Parameter: "Redshift z", Value: formatValueWithError( - catalogs?.redshift?.z, - catalogs?.redshift?.e_z, + catalogs.redshift.z, + catalogs.redshift.e_z, undefined, 5, ), - }, - ]; - - return ( - - - - ); -} - -function VelocityCatalog({ - catalogs, - schema, -}: { - catalogs: Catalogs; - schema: Schema; -}): ReactElement { - const velocityColumns = [{ name: "Parameter" }, { name: "Value" }]; - - const velocityData = [ - { - Parameter: "Heliocentric", - Value: formatValueWithError( - catalogs?.velocity?.heliocentric?.v, - catalogs?.velocity?.heliocentric?.e_v, - schema.units.velocity?.heliocentric?.v, - ), - }, - { - Parameter: "Local Group", - Value: formatValueWithError( - catalogs?.velocity?.local_group?.v, - catalogs?.velocity?.local_group?.e_v, - schema.units.velocity?.local_group?.v, - ), - }, - { - Parameter: "CMB (old)", - Value: formatValueWithError( - catalogs?.velocity?.cmb_old?.v, - catalogs?.velocity?.cmb_old?.e_v, - schema.units.velocity?.cmb_old?.v, - ), - }, - { - Parameter: "CMB", - Value: formatValueWithError( - catalogs?.velocity?.cmb?.v, - catalogs?.velocity?.cmb?.e_v, - schema.units.velocity?.cmb?.v, - ), - }, - ]; - - return ( - - - - ); -} - -export function CatalogData({ - catalogs, - schema, -}: CatalogDataProps): ReactElement { - if (!catalogs) return
; - - return ( -
- {catalogs?.coordinates && ( - - )} + }); + } - {catalogs?.redshift && } + if (catalogs?.velocity) { + data.push( + { + Parameter: "Heliocentric Velocity", + Value: formatValueWithError( + catalogs.velocity.heliocentric?.v, + catalogs.velocity.heliocentric?.e_v, + schema.units.velocity?.heliocentric?.v, + ), + }, + { + Parameter: "Local Group Velocity", + Value: formatValueWithError( + catalogs.velocity.local_group?.v, + catalogs.velocity.local_group?.e_v, + schema.units.velocity?.local_group?.v, + ), + }, + { + Parameter: "CMB (old) Velocity", + Value: formatValueWithError( + catalogs.velocity.cmb_old?.v, + catalogs.velocity.cmb_old?.e_v, + schema.units.velocity?.cmb_old?.v, + ), + }, + { + Parameter: "CMB Velocity", + Value: formatValueWithError( + catalogs.velocity.cmb?.v, + catalogs.velocity.cmb?.e_v, + schema.units.velocity?.cmb?.v, + ), + }, + ); + } - {catalogs?.velocity && ( - - )} -
- ); + return ; } diff --git a/src/components/ui/common-table.tsx b/src/components/ui/common-table.tsx index b8df151..0061498 100644 --- a/src/components/ui/common-table.tsx +++ b/src/components/ui/common-table.tsx @@ -52,7 +52,7 @@ export function CommonTable({ {children && (
diff --git a/src/components/ui/hint.tsx b/src/components/ui/hint.tsx index 513e2e1..879182e 100644 --- a/src/components/ui/hint.tsx +++ b/src/components/ui/hint.tsx @@ -1,10 +1,10 @@ import { Tooltip } from "flowbite-react"; -import { ReactElement } from "react"; +import { ReactElement, ReactNode } from "react"; import { MdHelpOutline } from "react-icons/md"; interface HintProps { children: ReactElement; - hintContent: ReactElement; + hintContent: ReactNode; className?: string; } diff --git a/src/pages/RecordCrossmatchDetails.tsx b/src/pages/RecordCrossmatchDetails.tsx index 77885a4..a25d59a 100644 --- a/src/pages/RecordCrossmatchDetails.tsx +++ b/src/pages/RecordCrossmatchDetails.tsx @@ -161,10 +161,7 @@ function renderCrossmatchDetails(
-
-

Record Catalog Data

- -
+ {candidates.length > 0 && (
From d0cc6bb440ac285aa55d8dcc4e5f425265957824 Mon Sep 17 00:00:00 2001 From: Artyom Zaporozhets Date: Wed, 17 Sep 2025 19:55:27 +0300 Subject: [PATCH 10/10] add name to catalogs data --- src/components/ui/catalog-data.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/ui/catalog-data.tsx b/src/components/ui/catalog-data.tsx index 8aa7467..f66134e 100644 --- a/src/components/ui/catalog-data.tsx +++ b/src/components/ui/catalog-data.tsx @@ -25,10 +25,6 @@ function formatValueWithError( return `${formattedValue} ${unit} ± ${formattedError} ${unit}`; } -function CatalogHeader({ title }: { title: string }): ReactElement { - return

{title}

; -} - export function CatalogData({ catalogs, schema, @@ -39,6 +35,13 @@ export function CatalogData({ const data = []; + if (catalogs?.designation?.name) { + data.push({ + Parameter: "Name", + Value: catalogs.designation.name, + }); + } + if (catalogs?.coordinates) { data.push( {