From ceec2340b319430f5d3d5dee4f09844099bdaf3b Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Tue, 2 Sep 2025 08:07:11 +0300 Subject: [PATCH] Provisioning: Fix rule of hooks violations (#110414) --- .betterer.results | 12 ------------ .../provisioning/GettingStarted/Sidebar.tsx | 4 ++-- .../provisioning/GettingStarted/SidebarItem.tsx | 1 + .../app/features/provisioning/Job/JobContent.tsx | 14 +++++++------- .../app/features/provisioning/Job/RecentJobs.tsx | 10 +++++----- 5 files changed, 15 insertions(+), 26 deletions(-) diff --git a/.betterer.results b/.betterer.results index 11294995287..d1b8ef95b28 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2736,18 +2736,6 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], - "public/app/features/provisioning/GettingStarted/Sidebar.tsx:5381": [ - [0, 0, 0, "React Hook \\"useStyles2\\" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?", "0"] - ], - "public/app/features/provisioning/GettingStarted/SidebarItem.tsx:5381": [ - [0, 0, 0, "Add noMargin prop to Card components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"] - ], - "public/app/features/provisioning/Job/JobContent.tsx:5381": [ - [0, 0, 0, "React Hook \\"useEffect\\" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?", "0"] - ], - "public/app/features/provisioning/Job/RecentJobs.tsx:5381": [ - [0, 0, 0, "React Hook \\"useMemo\\" is called conditionally. React Hooks must be called in the exact same order in every component render.", "0"] - ], "public/app/features/query/components/QueryEditorRow.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], diff --git a/public/app/features/provisioning/GettingStarted/Sidebar.tsx b/public/app/features/provisioning/GettingStarted/Sidebar.tsx index 7e53b7242b1..08be8662430 100644 --- a/public/app/features/provisioning/GettingStarted/Sidebar.tsx +++ b/public/app/features/provisioning/GettingStarted/Sidebar.tsx @@ -9,12 +9,12 @@ interface Props { } export const Sidebar = ({ steps, currentStep, onStepClick }: Props) => { + const stepItemStyles = useStyles2(getStepItemStyles); + if (steps.length === 0 || steps.length === 1) { return null; } - const stepItemStyles = useStyles2(getStepItemStyles); - return ( diff --git a/public/app/features/provisioning/GettingStarted/SidebarItem.tsx b/public/app/features/provisioning/GettingStarted/SidebarItem.tsx index d1489e4ab73..924862355b2 100644 --- a/public/app/features/provisioning/GettingStarted/SidebarItem.tsx +++ b/public/app/features/provisioning/GettingStarted/SidebarItem.tsx @@ -49,6 +49,7 @@ export const SidebarItem = ({ step, index, currentStep, onStepClick, styles }: P return ( diff --git a/public/app/features/provisioning/Job/JobContent.tsx b/public/app/features/provisioning/Job/JobContent.tsx index 8234a1b4378..3e3a05f80f5 100644 --- a/public/app/features/provisioning/Job/JobContent.tsx +++ b/public/app/features/provisioning/Job/JobContent.tsx @@ -21,13 +21,9 @@ export interface JobContentProps { export function JobContent({ jobType, job, isFinishedJob = false, onStatusChange }: JobContentProps) { const errorSetRef = useRef(false); - if (!job?.status) { - return null; - } - - const { state, message, progress, summary, errors } = job.status; - const repoName = job.metadata?.labels?.['provisioning.grafana.app/repository']; - const pullRequestURL = job.status?.url?.newPullRequestURL; + const { state, message, progress, summary, errors } = job?.status || {}; + const repoName = job?.metadata?.labels?.['provisioning.grafana.app/repository']; + const pullRequestURL = job?.status?.url?.newPullRequestURL; // Update step status based on job state useEffect(() => { @@ -72,6 +68,10 @@ export function JobContent({ jobType, job, isFinishedJob = false, onStatusChange } }, [state, message, errors, onStatusChange]); + if (!job?.status) { + return null; + } + return ( diff --git a/public/app/features/provisioning/Job/RecentJobs.tsx b/public/app/features/provisioning/Job/RecentJobs.tsx index 550511b5069..e6265d804b0 100644 --- a/public/app/features/provisioning/Job/RecentJobs.tsx +++ b/public/app/features/provisioning/Job/RecentJobs.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { intervalToAbbreviatedDurationString, TraceKeyValuePair } from '@grafana/data'; -import { Trans, t } from '@grafana/i18n'; +import { t, Trans } from '@grafana/i18n'; import { Alert, Badge, Box, Card, InteractiveTable, Spinner, Stack, Text } from '@grafana/ui'; import { Job, Repository, SyncStatus } from 'app/api/clients/provisioning/v0alpha1'; import KeyValuesTable from 'app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable'; @@ -95,10 +95,6 @@ function ExpandedRow({ row }: ExpandedRowProps) { const hasErrors = Boolean(row.status?.errors?.length); const hasSpec = Boolean(row.spec); - if (!hasSummary && !hasErrors && !hasSpec) { - return null; - } - // the action is already showing const data = useMemo(() => { const v: TraceKeyValuePair[] = []; @@ -116,6 +112,10 @@ function ExpandedRow({ row }: ExpandedRowProps) { return v; }, [row.spec]); + if (!hasSummary && !hasErrors && !hasSpec) { + return null; + } + return (