diff --git a/src/components/builds/BuildDebuggingInformation.tsx b/src/components/builds/BuildDebuggingInformation.tsx index 0eb0eacef..7f6975747 100644 --- a/src/components/builds/BuildDebuggingInformation.tsx +++ b/src/components/builds/BuildDebuggingInformation.tsx @@ -1,18 +1,32 @@ import React from 'react'; import { CardContent } from '@mui/material'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; import Typography from '@mui/material/Typography'; import Card from '@mui/material/Card'; -import { BuildDebuggingInformation_build } from './__generated__/BuildDebuggingInformation_build.graphql'; +import { BuildDebuggingInformation_build$key } from './__generated__/BuildDebuggingInformation_build.graphql'; import InlineLogs from '../logs/InlineLogs'; interface Props { - build: BuildDebuggingInformation_build; + build: BuildDebuggingInformation_build$key; } -function BuildDebuggingInformation(props: Props) { - let { build } = props; +export default function BuildDebuggingInformation(props: Props) { + let build = useFragment( + graphql` + fragment BuildDebuggingInformation_build on Build { + parsingResult { + rawYamlConfig + rawStarlarkConfig + processedYamlConfig + outputLogs + environment + affectedFiles + } + } + `, + props.build, + ); if (!build.parsingResult) { return null; @@ -39,18 +53,3 @@ function BuildDebuggingInformation(props: Props) { ); } - -export default createFragmentContainer(BuildDebuggingInformation, { - build: graphql` - fragment BuildDebuggingInformation_build on Build { - parsingResult { - rawYamlConfig - rawStarlarkConfig - processedYamlConfig - outputLogs - environment - affectedFiles - } - } - `, -}); diff --git a/src/components/builds/BuildDetails.tsx b/src/components/builds/BuildDetails.tsx index 022350bf2..c03ca8f6e 100644 --- a/src/components/builds/BuildDetails.tsx +++ b/src/components/builds/BuildDetails.tsx @@ -5,15 +5,14 @@ import CardActions from '@mui/material/CardActions'; import CardContent from '@mui/material/CardContent'; import Paper from '@mui/material/Paper'; import { graphql } from 'babel-plugin-relay/macro'; -import React, { useEffect } from 'react'; -import { commitMutation, createFragmentContainer, requestSubscription } from 'react-relay'; -import environment from '../../createRelayEnvironment'; +import React, { useMemo } from 'react'; +import { useFragment, useSubscription, useMutation } from 'react-relay'; import { hasWritePermissions } from '../../utils/permissions'; import BuildCreatedChip from '../chips/BuildCreatedChip'; import BuildStatusChip from '../chips/BuildStatusChip'; import CirrusFavicon from '../common/CirrusFavicon'; import TaskList from '../tasks/TaskList'; -import { BuildDetails_build } from './__generated__/BuildDetails_build.graphql'; +import { BuildDetails_build$key } from './__generated__/BuildDetails_build.graphql'; import { Helmet as Head } from 'react-helmet'; import Refresh from '@mui/icons-material/Refresh'; import Check from '@mui/icons-material/Check'; @@ -26,32 +25,24 @@ import { BugReport, Cancel, Dehaze, Functions } from '@mui/icons-material'; import Tooltip from '@mui/material/Tooltip'; import DebuggingInformation from './BuildDebuggingInformation'; import { HookType } from '../hooks/HookType'; -import { BuildDetailsApproveBuildMutationVariables } from './__generated__/BuildDetailsApproveBuildMutation.graphql'; -import { BuildDetailsReTriggerMutationVariables } from './__generated__/BuildDetailsReTriggerMutation.graphql'; -import { BuildDetailsReRunMutationVariables } from './__generated__/BuildDetailsReRunMutation.graphql'; -import { BuildDetailsCancelMutationVariables } from './__generated__/BuildDetailsCancelMutation.graphql'; +import { + BuildDetailsApproveBuildMutation, + BuildDetailsApproveBuildMutationVariables, +} from './__generated__/BuildDetailsApproveBuildMutation.graphql'; +import { + BuildDetailsReTriggerMutation, + BuildDetailsReTriggerMutationVariables, +} from './__generated__/BuildDetailsReTriggerMutation.graphql'; +import { + BuildDetailsReRunMutation, + BuildDetailsReRunMutationVariables, +} from './__generated__/BuildDetailsReRunMutation.graphql'; +import { + BuildDetailsCancelMutation, + BuildDetailsCancelMutationVariables, +} from './__generated__/BuildDetailsCancelMutation.graphql'; import CommitMessage from '../common/CommitMessage'; -const buildApproveMutation = graphql` - mutation BuildDetailsApproveBuildMutation($input: BuildApproveInput!) { - approve(input: $input) { - build { - ...BuildDetails_build - } - } - } -`; - -const buildReTriggerMutation = graphql` - mutation BuildDetailsReTriggerMutation($input: BuildReTriggerInput!) { - retrigger(input: $input) { - build { - ...BuildDetails_build - } - } - } -`; - const buildSubscription = graphql` subscription BuildDetailsSubscription($buildID: ID!) { build(id: $buildID) { @@ -72,28 +63,6 @@ const buildSubscription = graphql` } `; -const taskBatchReRunMutation = graphql` - mutation BuildDetailsReRunMutation($input: TasksReRunInput!) { - batchReRun(input: $input) { - newTasks { - build { - ...BuildDetails_build - } - } - } - } -`; - -const taskCancelMutation = graphql` - mutation BuildDetailsCancelMutation($input: TaskAbortInput!) { - abortTask(input: $input) { - abortedTask { - id - } - } - } -`; - const useStyles = makeStyles(theme => { return { gap: { @@ -116,25 +85,72 @@ const useStyles = makeStyles(theme => { }); interface Props { - build: BuildDetails_build; + build: BuildDetails_build$key; } -function BuildDetails(props: Props) { - useEffect(() => { - let variables = { buildID: props.build.id }; +export default function BuildDetails(props: Props) { + let build = useFragment( + graphql` + fragment BuildDetails_build on Build { + id + branch + status + changeIdInRepo + changeMessageTitle + ...BuildCreatedChip_build + ...BuildBranchNameChip_build + ...BuildStatusChip_build + notifications { + message + ...Notification_notification + } + ...ConfigurationWithIssues_build + ...BuildDebuggingInformation_build + latestGroupTasks { + id + localGroupId + requiredGroups + scheduledTimestamp + executingTimestamp + finalStatusTimestamp + status + ...TaskListRow_task + } + repository { + ...RepositoryNameChip_repository + cloneUrl + viewerPermission + } + hooks { + timestamp + ...HookListRow_hook + } + } + `, + props.build, + ); - const subscription = requestSubscription(environment, { + const buildSubscriptionConfig = useMemo( + () => ({ + variables: { buildID: build.id }, subscription: buildSubscription, - variables: variables, - }); - return () => { - subscription.dispose(); - }; - }, [props.build.id]); - const { build } = props; + }), + [build.id], + ); + useSubscription(buildSubscriptionConfig); + let classes = useStyles(); const repository = build.repository; + const [commitBuildApproveMutation] = useMutation(graphql` + mutation BuildDetailsApproveBuildMutation($input: BuildApproveInput!) { + approve(input: $input) { + build { + ...BuildDetails_build + } + } + } + `); function approveBuild() { const variables: BuildDetailsApproveBuildMutationVariables = { input: { @@ -143,13 +159,21 @@ function BuildDetails(props: Props) { }, }; - commitMutation(environment, { - mutation: buildApproveMutation, + commitBuildApproveMutation({ variables: variables, onError: err => console.error(err), }); } + const [commitBuildReTriggerMutation] = useMutation(graphql` + mutation BuildDetailsReTriggerMutation($input: BuildReTriggerInput!) { + retrigger(input: $input) { + build { + ...BuildDetails_build + } + } + } + `); function reTriggerBuild() { const variables: BuildDetailsReTriggerMutationVariables = { input: { @@ -158,39 +182,56 @@ function BuildDetails(props: Props) { }, }; - commitMutation(environment, { - mutation: buildReTriggerMutation, + commitBuildReTriggerMutation({ variables: variables, onError: err => console.error(err), }); } + const [commitTaskBatchReRunMutation] = useMutation(graphql` + mutation BuildDetailsReRunMutation($input: TasksReRunInput!) { + batchReRun(input: $input) { + newTasks { + build { + ...BuildDetails_build + } + } + } + } + `); function batchReRun(taskIds) { const variables: BuildDetailsReRunMutationVariables = { input: { - clientMutationId: 'batch-rerun-' + props.build.id, + clientMutationId: 'batch-rerun-' + build.id, taskIds: taskIds, }, }; - commitMutation(environment, { - mutation: taskBatchReRunMutation, + commitTaskBatchReRunMutation({ variables: variables, onError: err => console.error(err), }); } + const [commitTaskCancelMutation] = useMutation(graphql` + mutation BuildDetailsCancelMutation($input: TaskAbortInput!) { + abortTask(input: $input) { + abortedTask { + id + } + } + } + `); function batchCancellation(taskIds: string[]) { taskIds.forEach(id => { const variables: BuildDetailsCancelMutationVariables = { input: { - clientMutationId: `batch-cancellation-${props.build.id}-${id}`, + clientMutationId: `batch-cancellation-${build.id}-${id}`, taskId: id, }, }; - commitMutation(environment, { - mutation: taskCancelMutation, + commitTaskCancelMutation({ variables: variables, onError: err => console.error(err), }); @@ -326,43 +367,3 @@ function BuildDetails(props: Props) { ); } - -export default createFragmentContainer(BuildDetails, { - build: graphql` - fragment BuildDetails_build on Build { - id - branch - status - changeIdInRepo - changeMessageTitle - ...BuildCreatedChip_build - ...BuildBranchNameChip_build - ...BuildStatusChip_build - notifications { - message - ...Notification_notification - } - ...ConfigurationWithIssues_build - ...BuildDebuggingInformation_build - latestGroupTasks { - id - localGroupId - requiredGroups - scheduledTimestamp - executingTimestamp - finalStatusTimestamp - status - ...TaskListRow_task - } - repository { - ...RepositoryNameChip_repository - cloneUrl - viewerPermission - } - hooks { - timestamp - ...HookListRow_hook - } - } - `, -}); diff --git a/src/components/builds/ConfigurationWithIssues.tsx b/src/components/builds/ConfigurationWithIssues.tsx index f57b05677..69116b243 100644 --- a/src/components/builds/ConfigurationWithIssues.tsx +++ b/src/components/builds/ConfigurationWithIssues.tsx @@ -1,9 +1,9 @@ import React, { ReactNode } from 'react'; import { Alert } from '@mui/material'; import { makeStyles } from '@mui/styles'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import { ConfigurationWithIssues_build } from './__generated__/ConfigurationWithIssues_build.graphql'; +import { ConfigurationWithIssues_build$key } from './__generated__/ConfigurationWithIssues_build.graphql'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; @@ -48,11 +48,29 @@ const useStyles = makeStyles(theme => { }); interface Props { - build: ConfigurationWithIssues_build; + build: ConfigurationWithIssues_build$key; } -function ConfigurationWithIssues(props: Props) { - let { build } = props; +export default function ConfigurationWithIssues(props: Props) { + let build = useFragment( + graphql` + fragment ConfigurationWithIssues_build on Build { + parsingResult { + rawStarlarkConfig + processedYamlConfig + issues { + level + message + path + line + column + } + } + } + `, + props.build, + ); + let classes = useStyles(); if (!build.parsingResult || build.parsingResult.issues.length === 0) { @@ -194,21 +212,3 @@ function ConfigurationWithIssues(props: Props) { ); } - -export default createFragmentContainer(ConfigurationWithIssues, { - build: graphql` - fragment ConfigurationWithIssues_build on Build { - parsingResult { - rawStarlarkConfig - processedYamlConfig - issues { - level - message - path - line - column - } - } - } - `, -}); diff --git a/src/components/chips/BuildCreatedChip.tsx b/src/components/chips/BuildCreatedChip.tsx index 8628a43b5..ff69223b3 100644 --- a/src/components/chips/BuildCreatedChip.tsx +++ b/src/components/chips/BuildCreatedChip.tsx @@ -7,20 +7,29 @@ import Icon from '@mui/material/Icon'; import { useTaskStatusColor } from '../../utils/colors'; import { taskStatusIconName } from '../../utils/status'; import { roundAndPresentDuration } from '../../utils/time'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import { BuildCreatedChip_build } from './__generated__/BuildCreatedChip_build.graphql'; +import { BuildCreatedChip_build$key } from './__generated__/BuildCreatedChip_build.graphql'; import { useTheme } from '@mui/material'; interface Props { - build: BuildCreatedChip_build; + build: BuildCreatedChip_build$key; className?: string; } -let BuildCreatedChip = (props: Props) => { +export default function BuildCreatedChip(props: Props) { + let build = useFragment( + graphql` + fragment BuildCreatedChip_build on Build { + id + buildCreatedTimestamp + } + `, + props.build, + ); let theme = useTheme(); - const creationTimestamp = props.build.buildCreatedTimestamp; + const creationTimestamp = build.buildCreatedTimestamp; const [durationAgoInSeconds, setDurationAgoInSeconds] = React.useState((Date.now() - creationTimestamp) / 1000); useEffect(() => { @@ -51,13 +60,4 @@ let BuildCreatedChip = (props: Props) => { /> ); -}; - -export default createFragmentContainer(BuildCreatedChip, { - build: graphql` - fragment BuildCreatedChip_build on Build { - id - buildCreatedTimestamp - } - `, -}); +} diff --git a/src/scenes/Build/BuildById.tsx b/src/scenes/Build/BuildById.tsx index c843615ee..a0c5a46ff 100644 --- a/src/scenes/Build/BuildById.tsx +++ b/src/scenes/Build/BuildById.tsx @@ -1,11 +1,9 @@ import React from 'react'; -import { QueryRenderer } from 'react-relay'; +import { useLazyLoadQuery } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import environment from '../../createRelayEnvironment'; import BuildDetails from '../../components/builds/BuildDetails'; -import CirrusLinearProgress from '../../components/common/CirrusLinearProgress'; import NotFound from '../NotFound'; import { BuildByIdQuery } from './__generated__/BuildByIdQuery.graphql'; import { useParams } from 'react-router-dom'; @@ -13,35 +11,29 @@ import AppBreadcrumbs from '../../components/common/AppBreadcrumbs'; export default function BuildById(): JSX.Element { let { buildId } = useParams(); - return ( - - environment={environment} - variables={{ buildId }} - query={graphql` - query BuildByIdQuery($buildId: ID!) { - build(id: $buildId) { - ...BuildDetails_build - ...AppBreadcrumbs_build - } - viewer { - ...AppBreadcrumbs_viewer - } - } - `} - render={({ error, props }) => { - if (!props) { - return ; + + const response = useLazyLoadQuery( + graphql` + query BuildByIdQuery($buildId: ID!) { + build(id: $buildId) { + ...BuildDetails_build + ...AppBreadcrumbs_build } - if (!props.build) { - return ; + viewer { + ...AppBreadcrumbs_viewer } - return ( - <> - - - - ); - }} - /> + } + `, + { buildId }, + ); + + if (!response.build) { + return ; + } + return ( + <> + + + ); } diff --git a/src/scenes/Build/BuildBySHA.tsx b/src/scenes/Build/BuildBySHA.tsx index ee0bb1b6b..2b3d0f580 100644 --- a/src/scenes/Build/BuildBySHA.tsx +++ b/src/scenes/Build/BuildBySHA.tsx @@ -1,11 +1,9 @@ import React from 'react'; -import { QueryRenderer } from 'react-relay'; +import { useLazyLoadQuery } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import environment from '../../createRelayEnvironment'; import BuildDetails from '../../components/builds/BuildDetails'; -import CirrusLinearProgress from '../../components/common/CirrusLinearProgress'; import NotFound from '../NotFound'; import { BuildBySHAQuery } from './__generated__/BuildBySHAQuery.graphql'; import * as queryString from 'query-string'; @@ -14,42 +12,36 @@ import AppBreadcrumbs from '../../components/common/AppBreadcrumbs'; export default function BuildBySHA() { let { owner, name, SHA } = useParams(); - return ( - - environment={environment} - variables={{ owner, name, SHA }} - query={graphql` - query BuildBySHAQuery($owner: String!, $name: String!, $SHA: String) { - searchBuilds(repositoryOwner: $owner, repositoryName: $name, SHA: $SHA) { - branch - ...BuildDetails_build - ...AppBreadcrumbs_build - } - viewer { - ...AppBreadcrumbs_viewer - } - } - `} - render={({ error, props }) => { - if (!props) { - return ; - } - if (!props.searchBuilds || props.searchBuilds.length === 0) { - return ; + + const response = useLazyLoadQuery( + graphql` + query BuildBySHAQuery($owner: String!, $name: String!, $SHA: String) { + searchBuilds(repositoryOwner: $owner, repositoryName: $name, SHA: $SHA) { + branch + ...BuildDetails_build + ...AppBreadcrumbs_build } - const selectedBranch = queryString.parse(window.location.search).branch; - for (let build of props.searchBuilds) { - if (build.branch === selectedBranch) { - return ; - } + viewer { + ...AppBreadcrumbs_viewer } - return ( - <> - - - - ); - }} - /> + } + `, + { owner, name, SHA }, + ); + + if (!response.searchBuilds || response.searchBuilds.length === 0) { + return ; + } + const selectedBranch = queryString.parse(window.location.search).branch; + for (let build of response.searchBuilds) { + if (build.branch === selectedBranch) { + return ; + } + } + return ( + <> + + + ); }