diff --git a/src/components/explanation/explanation.tsx b/src/components/explanation/explanation.tsx index a2237cf5ec..95c6a7dc32 100644 --- a/src/components/explanation/explanation.tsx +++ b/src/components/explanation/explanation.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { RiBook2Fill } from '@remixicon/react'; +import React from 'react'; import { classNames } from '@/util/utils'; @@ -8,14 +8,15 @@ import styles from './explanation.module.css'; export interface ExplanationProps { className?: string; title: React.ReactNode; - children: React.ReactNode; + children?: React.ReactNode; + hasDescription: boolean; } /** * Component implementing this Figma: * https://www.figma.com/design/akGPTH0WwNFDfSWSs3qAnh/OBI---UX-Summer-2025?node-id=183-8506&p=f&t=wvidSlAofObM72zC-0 */ -export function Explanation({ className, title, children }: ExplanationProps) { +export function Explanation({ className, title, children, hasDescription }: ExplanationProps) { const [open, setOpen] = React.useState(false); if (open) @@ -35,10 +36,12 @@ export function Explanation({ className, title, children }: ExplanationProps) { return (
{title}
- + {hasDescription && ( + + )}
); } diff --git a/src/entity-configuration/domain/model/e-model.ts b/src/entity-configuration/domain/model/e-model.ts index 9eb3dabcec..87dccd38c9 100644 --- a/src/entity-configuration/domain/model/e-model.ts +++ b/src/entity-configuration/domain/model/e-model.ts @@ -1,11 +1,12 @@ import { getCellMorphology } from '@/api/entitycore/queries'; import { getEModel, getEModels } from '@/api/entitycore/queries/model/e-model'; -import type { IEModel } from '@/api/entitycore/types/entities/e-model'; import { EntityTypeDict } from '@/api/entitycore/types/entity-type'; import { ExtendedEntitiesTypeDict } from '@/api/entitycore/types/extended-entity-type'; import { DetailViewSectionsDict } from '@/entity-configuration/definitions/types'; import { EntityTypeGroup } from '@/entity-configuration/domain/group'; import { EntitySlug } from '@/entity-configuration/domain/slug'; + +import type { IEModel } from '@/api/entitycore/types/entities/e-model'; import type { EntityCoreTypeConfig } from '@/entity-configuration/domain/types'; export const Emodel: EntityCoreTypeConfig = { diff --git a/src/entity-configuration/domain/model/me-model.ts b/src/entity-configuration/domain/model/me-model.ts index b0887c3dc2..ae9ff1d761 100644 --- a/src/entity-configuration/domain/model/me-model.ts +++ b/src/entity-configuration/domain/model/me-model.ts @@ -1,10 +1,11 @@ import { createMEModel, getMEModel, getMEModels } from '@/api/entitycore/queries/model/me-model'; -import type { IMEModel } from '@/api/entitycore/types/entities/me-model'; import { EntityTypeDict } from '@/api/entitycore/types/entity-type'; import { ExtendedEntitiesTypeDict } from '@/api/entitycore/types/extended-entity-type'; import { DetailViewSectionsDict } from '@/entity-configuration/definitions/types'; import { EntityTypeGroup } from '@/entity-configuration/domain/group'; import { EntitySlug } from '@/entity-configuration/domain/slug'; + +import type { IMEModel } from '@/api/entitycore/types/entities/me-model'; import type { EntityCoreTypeConfig } from '@/entity-configuration/domain/types'; export const MEmodel: EntityCoreTypeConfig = { diff --git a/src/features/model-analysis/explorer/container.tsx b/src/features/model-analysis/explorer/container.tsx index 201d25b518..a173f09202 100644 --- a/src/features/model-analysis/explorer/container.tsx +++ b/src/features/model-analysis/explorer/container.tsx @@ -1,22 +1,25 @@ 'use client'; import { LoadingOutlined } from '@ant-design/icons'; -import { useParams } from 'next/navigation'; import { Spin } from 'antd'; +import { useParams } from 'next/navigation'; -import { useInputResistance } from './use-input-resistance'; - +import { getEntityByCoreType } from '@/entity-configuration/domain/helpers'; import { useAnalysis } from '@/features/model-analysis/explorer/use-analysis'; +import { useInputResistance } from '@/features/model-analysis/explorer/use-input-resistance'; import { ViewerContainer } from '@/features/model-analysis/viewer/container/container'; import { useWorkspace } from '@/ui/hooks/use-workspace'; -export default function Analysis() { +import type { TRetrieveEntityOutput } from '@/entity-configuration/domain/requests'; + +export default function Analysis({ entity }: { entity: TRetrieveEntityOutput }) { const workspace = useWorkspace(); const { id } = useParams<{ id: string }>(); const { data, error, isLoading } = useAnalysis({ workspace, id }); - const rin = useInputResistance(id); + const { data: rin, isLoading: loadingRin } = useInputResistance({ entity }); + const entityConfig = getEntityByCoreType({ type: entity.type }); - if (isLoading) { + if (isLoading || loadingRin) { return (
} size="large" /> @@ -28,7 +31,7 @@ export default function Analysis() { if (error) { return (
- Error loading ME-Model analysis + Error loading {entityConfig?.title} analysis
); } @@ -48,5 +51,5 @@ export default function Analysis() { ); } - return ; + return ; } diff --git a/src/features/model-analysis/explorer/use-analysis.ts b/src/features/model-analysis/explorer/use-analysis.ts index 949f632f71..5c54d760ff 100644 --- a/src/features/model-analysis/explorer/use-analysis.ts +++ b/src/features/model-analysis/explorer/use-analysis.ts @@ -1,10 +1,10 @@ 'use client'; -import { useEffect } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; +import { useEffect } from 'react'; -import { getValidationResults } from '@/api/entitycore/queries/general/validation-result'; import { getAssets } from '@/api/entitycore/queries/assets'; +import { getValidationResults } from '@/api/entitycore/queries/general/validation-result'; import { EntityTypeDict } from '@/api/entitycore/types'; import { DEFAULT_PAGE_XSMALL_SIZE } from '@/constants'; import { keyBuilder } from '@/ui/use-query-keys/data'; @@ -38,8 +38,7 @@ export function useAnalysis({ workspace, id }: { id: string; workspace: Workspac if (query.hasNextPage && !query.isFetchingNextPage) { query.fetchNextPage(); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [query.hasNextPage, query.isFetchingNextPage, query.data]); + }, [query.hasNextPage, query.isFetchingNextPage, query.fetchNextPage]); return query; } @@ -51,7 +50,11 @@ function makeQueryFn(workspace: { virtualLabId: string; projectId: string }, id: return async ({ pageParam = 1 }) => { const response = await getValidationResults({ context: workspace, - filters: { validated_entity_id: id, page: pageParam, page_size: DEFAULT_PAGE_XSMALL_SIZE }, + filters: { + validated_entity_id: id, + page: pageParam, + page_size: DEFAULT_PAGE_XSMALL_SIZE, + }, }); const data = ( await Promise.allSettled( diff --git a/src/features/model-analysis/explorer/use-input-resistance.tsx b/src/features/model-analysis/explorer/use-input-resistance.tsx index 6fcd053528..5e5599093c 100644 --- a/src/features/model-analysis/explorer/use-input-resistance.tsx +++ b/src/features/model-analysis/explorer/use-input-resistance.tsx @@ -1,19 +1,22 @@ import { useQuery } from '@tanstack/react-query'; import { getMEModel } from '@/api/entitycore/queries'; -import { keyBuilder } from '@/ui/use-query-keys/data'; +import { EntityTypeDict } from '@/api/entitycore/types'; import { useWorkspace } from '@/ui/hooks/use-workspace'; +import { keyBuilder } from '@/ui/use-query-keys/data'; + +import type { TRetrieveEntityOutput } from '@/entity-configuration/domain/requests'; -export function useInputResistance(entityId: string): number | undefined { +export function useInputResistance({ entity }: { entity: TRetrieveEntityOutput }) { const { projectId, virtualLabId } = useWorkspace(); - const { isPending, error, data } = useQuery({ - queryKey: keyBuilder.meModel({ projectId, virtualLabId, entityId }), + const { isLoading, error, data } = useQuery({ + queryKey: keyBuilder.meModel({ projectId, virtualLabId, entityId: entity.id }), queryFn: async () => { - const model = await getMEModel({ context: { projectId, virtualLabId }, id: entityId }); + const model = await getMEModel({ context: { projectId, virtualLabId }, id: entity.id }); return model.calibration_result.rin; }, + enabled: entity.type === EntityTypeDict.Memodel, }); - if (isPending || error) return undefined; - return data; + return { data, isLoading, error }; } diff --git a/src/features/model-analysis/viewer/container/container.tsx b/src/features/model-analysis/viewer/container/container.tsx index 00a5a1af70..f55d193537 100644 --- a/src/features/model-analysis/viewer/container/container.tsx +++ b/src/features/model-analysis/viewer/container/container.tsx @@ -1,19 +1,24 @@ import { useState } from 'react'; -import type { TValidationResultNonUndefined } from '@/features/model-analysis/explorer/use-analysis'; + import { useFlatValidationResults, useSelectedValidationResults } from './hooks'; import { SelectAnalysis } from './select-analysis'; import { ValidationExplanation } from './validation-explanation'; import { ValidationResultCard } from './validation-result-card'; +import type { TRetrieveEntityOutput } from '@/entity-configuration/domain/requests'; +import type { TValidationResultNonUndefined } from '@/features/model-analysis/explorer/use-analysis'; + type Props = { rin: number | undefined; validationResults: TValidationResultNonUndefined; + entity: TRetrieveEntityOutput; }; -export function ViewerContainer({ rin, validationResults }: Props) { +export function ViewerContainer({ rin, validationResults, entity }: Props) { const [selectedId, setSelectedId] = useState('all'); const flatValidationResults = useFlatValidationResults(validationResults, rin); const selectedValidationResults = useSelectedValidationResults(flatValidationResults, selectedId); + if (flatValidationResults.length === 0) return
No validation results found
; const passed = flatValidationResults.reduce( @@ -23,7 +28,7 @@ export function ViewerContainer({ rin, validationResults }: Props) { return ( <> - + {selectedValidationResults.map((result) => ( diff --git a/src/features/model-analysis/viewer/container/validation-explanation/validation-explanation.tsx b/src/features/model-analysis/viewer/container/validation-explanation/validation-explanation.tsx index 743364b7ff..09149ba161 100644 --- a/src/features/model-analysis/viewer/container/validation-explanation/validation-explanation.tsx +++ b/src/features/model-analysis/viewer/container/validation-explanation/validation-explanation.tsx @@ -1,21 +1,42 @@ -import React from 'react'; - +import { EntityTypeDict } from '@/api/entitycore/types'; +import { Explanation } from '@/components/explanation'; +import { getEntityByCoreType } from '@/entity-configuration/domain/helpers'; import { classNames } from '@/util/utils'; -import { Explanation } from '@/components/explanation'; +import type { TRetrieveEntityOutput } from '@/entity-configuration/domain/requests'; + import styles from './validation-explanation.module.css'; export interface ValidationExplanationProps { className?: string; passed: boolean; + entity: TRetrieveEntityOutput; } -export function ValidationExplanation({ className, passed }: ValidationExplanationProps) { +export function ValidationExplanation({ className, passed, entity }: ValidationExplanationProps) { + const entityConfig = getEntityByCoreType({ type: entity.type }); + + if (entityConfig?.type === EntityTypeDict.Emodel) + return ( + +
{entityConfig?.title} Validation
+
+ {passed ? 'passed' : 'failed'} +
+ + } + className={classNames(styles.validationDescription, className)} + hasDescription={false} + /> + ); return ( -
ME-Model Validation
+
{entityConfig?.title} Validation
{passed ? 'passed' : 'failed'}
diff --git a/src/ui/segments/detail-view/analysis.tsx b/src/ui/segments/detail-view/analysis.tsx index add1e07bb8..97d3cb1f5b 100644 --- a/src/ui/segments/detail-view/analysis.tsx +++ b/src/ui/segments/detail-view/analysis.tsx @@ -28,7 +28,7 @@ export default async function Configuration({ extendedType === ExtendedEntitiesTypeDict.Memodel || extendedType === ExtendedEntitiesTypeDict.Emodel ) - return ; + return ; return notFound(); }