diff --git a/src/components/chips/TaskDurationChip.tsx b/src/components/chips/TaskDurationChip.tsx index c45714d7c..47df9ba04 100644 --- a/src/components/chips/TaskDurationChip.tsx +++ b/src/components/chips/TaskDurationChip.tsx @@ -2,13 +2,13 @@ import Avatar from '@mui/material/Avatar'; import Chip from '@mui/material/Chip'; import Icon from '@mui/material/Icon'; import { graphql } from 'babel-plugin-relay/macro'; -import React, { useEffect } from 'react'; -import { createFragmentContainer, requestSubscription } from 'react-relay'; +import React, { useEffect, useMemo } from 'react'; +import { useFragment, requestSubscription } from 'react-relay'; import environment from '../../createRelayEnvironment'; import { useTaskStatusColor } from '../../utils/colors'; import { isTaskFinalStatus, isTaskInProgressStatus, taskStatusIconName } from '../../utils/status'; import { formatDuration } from '../../utils/time'; -import { TaskDurationChip_task } from './__generated__/TaskDurationChip_task.graphql'; +import { TaskDurationChip_task$key } from './__generated__/TaskDurationChip_task.graphql'; import { useTheme } from '@mui/material'; const taskSubscription = graphql` @@ -20,19 +20,34 @@ const taskSubscription = graphql` `; interface Props { - task: TaskDurationChip_task; + task: TaskDurationChip_task$key; className?: string; } -function TaskDurationChip(props: Props) { +export default function TaskDurationChip(props: Props) { + let task = useFragment( + graphql` + fragment TaskDurationChip_task on Task { + id + status + creationTimestamp + scheduledTimestamp + executingTimestamp + durationInSeconds + } + `, + props.task, + ); + let theme = useTheme(); + const isFinalStatus = useMemo(() => isTaskFinalStatus(task.status), [task.status]); useEffect(() => { - if (isTaskFinalStatus(props.task.status)) { + if (isFinalStatus) { return; } - let variables = { taskID: props.task.id }; + let variables = { taskID: task.id }; const subscription = requestSubscription(environment, { subscription: taskSubscription, @@ -41,26 +56,26 @@ function TaskDurationChip(props: Props) { return () => { subscription.dispose(); }; - }, [props.task.id, props.task.status]); + }, [task.id, isFinalStatus]); const [now, setNow] = React.useState(Date.now()); useEffect(() => { - if (isTaskFinalStatus(props.task.status)) { + if (isFinalStatus) { return; } const timeoutId = setInterval(() => { setNow(Date.now()); }, 1_000); return () => clearInterval(timeoutId); - }, [now, props.task.status]); + }, [now, isFinalStatus]); - let { task, className } = props; + let { className } = props; let durationInSeconds = task.durationInSeconds; - if (!isTaskInProgressStatus(task.status) && !isTaskFinalStatus(task.status)) { + if (!isTaskInProgressStatus(task.status) && !isFinalStatus) { durationInSeconds = 0; - } else if (!isTaskFinalStatus(task.status)) { + } else if (!isFinalStatus) { let timestamp = Math.max(task.creationTimestamp, task.scheduledTimestamp, task.executingTimestamp); durationInSeconds = (Date.now() - timestamp) / 1000; } @@ -77,16 +92,3 @@ function TaskDurationChip(props: Props) { /> ); } - -export default createFragmentContainer(TaskDurationChip, { - task: graphql` - fragment TaskDurationChip_task on Task { - id - status - creationTimestamp - scheduledTimestamp - executingTimestamp - durationInSeconds - } - `, -}); diff --git a/src/components/compute-credits/BillingSettingsButton.tsx b/src/components/compute-credits/BillingSettingsButton.tsx index cf73b71bc..4fe138362 100644 --- a/src/components/compute-credits/BillingSettingsButton.tsx +++ b/src/components/compute-credits/BillingSettingsButton.tsx @@ -1,20 +1,31 @@ import React, { useState } from 'react'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; import AlarmOffIcon from '@mui/icons-material/AlarmOff'; import AlarmOnIcon from '@mui/icons-material/AlarmOn'; import Button from '@mui/material/Button'; import BillingSettingsDialog from './BillingSettingsDialog'; -import { BillingSettingsButton_info } from './__generated__/BillingSettingsButton_info.graphql'; +import { BillingSettingsButton_info$key } from './__generated__/BillingSettingsButton_info.graphql'; interface Props { - info: BillingSettingsButton_info; + info: BillingSettingsButton_info$key; className?: string; } -function BillingSettingsButton(props: Props) { +export default function BillingSettingsButton(props: Props) { + let info = useFragment( + graphql` + fragment BillingSettingsButton_info on OwnerInfo { + billingSettings { + enabled + ...BillingSettingsDialog_billingSettings + } + } + `, + props.info, + ); let [openDialog, setOpenDialog] = useState(false); - let { info, className } = props; + let { className } = props; if (!info) return null; let { billingSettings } = info; @@ -37,14 +48,3 @@ function BillingSettingsButton(props: Props) { ); } - -export default createFragmentContainer(BillingSettingsButton, { - info: graphql` - fragment BillingSettingsButton_info on OwnerInfo { - billingSettings { - enabled - ...BillingSettingsDialog_billingSettings - } - } - `, -}); diff --git a/src/components/compute-credits/BillingSettingsDialog.tsx b/src/components/compute-credits/BillingSettingsDialog.tsx index 3a59e8dfe..1cce1a1c1 100644 --- a/src/components/compute-credits/BillingSettingsDialog.tsx +++ b/src/components/compute-credits/BillingSettingsDialog.tsx @@ -13,13 +13,13 @@ import Switch from '@mui/material/Switch'; import Typography from '@mui/material/Typography'; import { graphql } from 'babel-plugin-relay/macro'; import React, { useState } from 'react'; -import { commitMutation, createFragmentContainer } from 'react-relay'; -import environment from '../../createRelayEnvironment'; +import { useMutation, useFragment } from 'react-relay'; import { + BillingSettingsDialogMutation, BillingSettingsDialogMutationResponse, BillingSettingsDialogMutationVariables, } from './__generated__/BillingSettingsDialogMutation.graphql'; -import { BillingSettingsDialog_billingSettings } from './__generated__/BillingSettingsDialog_billingSettings.graphql'; +import { BillingSettingsDialog_billingSettings$key } from './__generated__/BillingSettingsDialog_billingSettings.graphql'; import { Link } from '@mui/material'; const useStyles = makeStyles(theme => { @@ -33,31 +33,28 @@ const useStyles = makeStyles(theme => { }; }); -const saveBillingSettingsMutation = graphql` - mutation BillingSettingsDialogMutation($input: BillingSettingsInput!) { - saveBillingSettings(input: $input) { - settings { - ownerUid - enabled - billingCreditsLimit - billingEmailAddress - invoiceTemplate - } - } - } -`; - interface Props { - billingSettings: BillingSettingsDialog_billingSettings; + billingSettings: BillingSettingsDialog_billingSettings$key; onClose(...args: any[]): void; open: boolean; } -function BillingSettingsDialog(props: Props) { +export default function BillingSettingsDialog(props: Props) { + let billingSettings = useFragment( + graphql` + fragment BillingSettingsDialog_billingSettings on BillingSettings { + ownerUid + enabled + billingCreditsLimit + billingEmailAddress + invoiceTemplate + } + `, + props.billingSettings, + ); let classes = useStyles(); - const { billingSettings, ...other } = props; let [enabled, setEnabled] = useState(billingSettings.enabled); let [billingEmailAddress, setBillingEmailAddress] = useState(billingSettings.billingEmailAddress); let [invoiceTemplate, setInvoiceTemplate] = useState(billingSettings.invoiceTemplate); @@ -67,18 +64,30 @@ function BillingSettingsDialog(props: Props) { billingSettings.billingEmailAddress === billingEmailAddress && billingSettings.invoiceTemplate === invoiceTemplate; + const [commitSaveBillingSettingsMutation] = useMutation(graphql` + mutation BillingSettingsDialogMutation($input: BillingSettingsInput!) { + saveBillingSettings(input: $input) { + settings { + ownerUid + enabled + billingCreditsLimit + billingEmailAddress + invoiceTemplate + } + } + } + `); function updateSettings() { const variables: BillingSettingsDialogMutationVariables = { input: { - clientMutationId: 'save-billing-settings-' + props.billingSettings.ownerUid, - ownerUid: props.billingSettings.ownerUid, + clientMutationId: 'save-billing-settings-' + billingSettings.ownerUid, + ownerUid: billingSettings.ownerUid, enabled: enabled, billingEmailAddress: billingEmailAddress, invoiceTemplate: invoiceTemplate, }, }; - commitMutation(environment, { - mutation: saveBillingSettingsMutation, + commitSaveBillingSettingsMutation({ variables: variables, onCompleted: (response: BillingSettingsDialogMutationResponse, errors) => { if (errors) { @@ -95,7 +104,7 @@ function BillingSettingsDialog(props: Props) { } return ( - + Compute Credits Auto Pay @@ -147,15 +156,3 @@ function BillingSettingsDialog(props: Props) { ); } - -export default createFragmentContainer(BillingSettingsDialog, { - billingSettings: graphql` - fragment BillingSettingsDialog_billingSettings on BillingSettings { - ownerUid - enabled - billingCreditsLimit - billingEmailAddress - invoiceTemplate - } - `, -}); diff --git a/src/components/compute-credits/ComputeCreditsBase.tsx b/src/components/compute-credits/ComputeCreditsBase.tsx index 1e68d12a3..dd7da84e8 100644 --- a/src/components/compute-credits/ComputeCreditsBase.tsx +++ b/src/components/compute-credits/ComputeCreditsBase.tsx @@ -13,9 +13,9 @@ import { makeStyles } from '@mui/styles'; import classNames from 'classnames'; import React, { useState } from 'react'; import BillingSettingsButton from './BillingSettingsButton'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import { ComputeCreditsBase_info } from './__generated__/ComputeCreditsBase_info.graphql'; +import { ComputeCreditsBase_info$key } from './__generated__/ComputeCreditsBase_info.graphql'; import { Helmet as Head } from 'react-helmet'; import ComputeCreditsStripeDialog from './ComputeCreditsStripeDialog'; import { Link } from '@mui/material'; @@ -58,12 +58,21 @@ const useStyles = makeStyles(theme => { interface Props { transactionsComponent: JSX.Element; - info?: ComputeCreditsBase_info; + info?: ComputeCreditsBase_info$key; balanceInCredits?: string; ownerUid: string; } -function ComputeCreditsBase(props: Props) { +export default function ComputeCreditsBase(props: Props) { + let info = useFragment( + graphql` + fragment ComputeCreditsBase_info on OwnerInfo { + ...BillingSettingsButton_info + } + `, + props.info, + ); + let [expanded, setExpanded] = useState(false); let [openBuyCredits, setOpenBuyCredits] = useState(false); let classes = useStyles(); @@ -102,7 +111,7 @@ function ComputeCreditsBase(props: Props) { Add More Credits - + ); } - -export default createFragmentContainer(ComputeCreditsBase, { - info: graphql` - fragment ComputeCreditsBase_info on OwnerInfo { - ...BillingSettingsButton_info - } - `, -}); diff --git a/src/components/compute-credits/ComputeCreditsStripeDialog.tsx b/src/components/compute-credits/ComputeCreditsStripeDialog.tsx index d5755eb93..9efb8472c 100644 --- a/src/components/compute-credits/ComputeCreditsStripeDialog.tsx +++ b/src/components/compute-credits/ComputeCreditsStripeDialog.tsx @@ -5,11 +5,11 @@ import DialogContent from '@mui/material/DialogContent'; import FormControl from '@mui/material/FormControl'; import InputLabel from '@mui/material/InputLabel'; import Input from '@mui/material/Input'; -import { commitMutation } from 'react-relay'; +import { useMutation } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; -import environment from '../../createRelayEnvironment'; import { UnspecifiedCallbackFunction } from '../../utils/utility-types'; import { + ComputeCreditsStripeDialogMutation, ComputeCreditsStripeDialogMutationResponse, ComputeCreditsStripeDialogMutationVariables, } from './__generated__/ComputeCreditsStripeDialogMutation.graphql'; @@ -19,19 +19,6 @@ import DialogActions from '@mui/material/DialogActions'; import { StripeCardElementOptions, Token } from '@stripe/stripe-js'; import { FormHelperText } from '@mui/material'; -const computeCreditsBuyMutation = graphql` - mutation ComputeCreditsStripeDialogMutation($input: BuyComputeCreditsInput!) { - buyComputeCredits(input: $input) { - error - info { - uid - balanceInCredits - balanceInCredits - } - } - } -`; - const CARD_ELEMENT_OPTIONS: StripeCardElementOptions = { hidePostalCode: true, style: { @@ -98,6 +85,18 @@ function ComputeCreditsStripeDialog(props: Props) { } }; + const [commitComputeCreditsBuyMutation] = useMutation(graphql` + mutation ComputeCreditsStripeDialogMutation($input: BuyComputeCreditsInput!) { + buyComputeCredits(input: $input) { + error + info { + uid + balanceInCredits + balanceInCredits + } + } + } + `); const stripeTokenHandler = (token: Token) => { const variables: ComputeCreditsStripeDialogMutationVariables = { input: { @@ -110,8 +109,7 @@ function ComputeCreditsStripeDialog(props: Props) { }, }; - commitMutation(environment, { - mutation: computeCreditsBuyMutation, + commitComputeCreditsBuyMutation({ variables: variables, onCompleted: (response: ComputeCreditsStripeDialogMutationResponse, errors) => { if (errors) { diff --git a/src/components/compute-credits/OwnerComputeCredits.tsx b/src/components/compute-credits/OwnerComputeCredits.tsx index 2c5fec4a2..3dfd9168c 100644 --- a/src/components/compute-credits/OwnerComputeCredits.tsx +++ b/src/components/compute-credits/OwnerComputeCredits.tsx @@ -1,39 +1,23 @@ import { graphql } from 'babel-plugin-relay/macro'; import React from 'react'; -import { createPaginationContainer, RelayPaginationProp } from 'react-relay'; +import { useFragment } from 'react-relay'; import ComputeCreditsBase from './ComputeCreditsBase'; -import { OwnerComputeCredits_info } from './__generated__/OwnerComputeCredits_info.graphql'; +import { OwnerComputeCredits_info$key } from './__generated__/OwnerComputeCredits_info.graphql'; import ComputeCreditsTransactionsList from './ComputeCreditsTransactionsList'; interface Props { - relay: RelayPaginationProp; - info: OwnerComputeCredits_info; + info: OwnerComputeCredits_info$key; } -let OwnerComputeCredits = (props: Props) => { - return ( - edge.node)} /> - } - /> - ); -}; - -export default createPaginationContainer( - OwnerComputeCredits, - { - info: graphql` - fragment OwnerComputeCredits_info on OwnerInfo - @argumentDefinitions(count: { type: "Int", defaultValue: 50 }, cursor: { type: "String" }) { +export default function OwnerComputeCredits(props: Props) { + let info = useFragment( + graphql` + fragment OwnerComputeCredits_info on OwnerInfo { uid name balanceInCredits ...ComputeCreditsBase_info - transactions(last: $count, after: $cursor) @connection(key: "OwnerComputeCredits_transactions") { + transactions(last: 50) { edges { node { taskId @@ -43,33 +27,18 @@ export default createPaginationContainer( } } `, - }, - { - direction: 'forward', - getConnectionFromProps(props) { - return props.info && props.info.transactions; - }, - // This is also the default implementation of `getFragmentVariables` if it isn't provided. - getFragmentVariables(prevVars, totalCount) { - return { - ...prevVars, - count: totalCount, - }; - }, - getVariables(props: any, { count, cursor }, fragmentVariables) { - return { - count: count, - cursor: cursor, - platform: props.info.platform, - uid: props.info.uid, - }; - }, - query: graphql` - query OwnerComputeCreditsQuery($platform: String!, $uid: ID!, $count: Int!, $cursor: String) { - ownerInfo(platform: $platform, uid: $uid) { - ...OwnerComputeCredits_info @arguments(count: $count, cursor: $cursor) - } + + props.info, + ); + + return ( + edge.node)} /> } - `, - }, -); + /> + ); +} diff --git a/src/components/settings/OwnerSettings.tsx b/src/components/settings/OwnerSettings.tsx index 8c2961542..d8e9b02b2 100644 --- a/src/components/settings/OwnerSettings.tsx +++ b/src/components/settings/OwnerSettings.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { createFragmentContainer } from 'react-relay'; +import { useFragment } from 'react-relay'; import { graphql } from 'babel-plugin-relay/macro'; import Paper from '@mui/material/Paper'; import { makeStyles } from '@mui/styles'; @@ -10,7 +10,7 @@ import WebHookSettings from '../webhooks/WebHookSettings'; import OwnerApiSettings from './OwnerApiSettings'; import OwnerSecuredVariables from './OwnerSecuredVariables'; import OwnerPersistentWorkerPools from './OwnerPersistentWorkerPools'; -import { OwnerSettings_info } from './__generated__/OwnerSettings_info.graphql'; +import { OwnerSettings_info$key } from './__generated__/OwnerSettings_info.graphql'; import MarkdownTypography from '../common/MarkdownTypography'; import CardHeader from '@mui/material/CardHeader'; import { Card, CardActions, CardContent } from '@mui/material'; @@ -28,11 +28,34 @@ const useStyles = makeStyles(theme => { }); interface Props { - info: OwnerSettings_info; + info: OwnerSettings_info$key; } -function OwnerSettings(props: Props) { - let { info } = props; +export default function OwnerSettings(props: Props) { + let info = useFragment( + graphql` + fragment OwnerSettings_info on OwnerInfo { + platform + uid + name + viewerPermission + description { + message + actions { + title + link + } + } + ...OwnerComputeCredits_info + ...OwnerApiSettings_info + ...OwnerSecuredVariables_info + ...OwnerPersistentWorkerPools_info + ...WebHookSettings_info + } + `, + props.info, + ); + let classes = useStyles(); if (!info) { @@ -90,26 +113,3 @@ function OwnerSettings(props: Props) { ); } - -export default createFragmentContainer(OwnerSettings, { - info: graphql` - fragment OwnerSettings_info on OwnerInfo { - platform - uid - name - viewerPermission - description { - message - actions { - title - link - } - } - ...OwnerComputeCredits_info - ...OwnerApiSettings_info - ...OwnerSecuredVariables_info - ...OwnerPersistentWorkerPools_info - ...WebHookSettings_info - } - `, -}); diff --git a/src/scenes/Owner/OwnerSettingsRenderer.tsx b/src/scenes/Owner/OwnerSettingsRenderer.tsx index f89225111..ff604e1cb 100644 --- a/src/scenes/Owner/OwnerSettingsRenderer.tsx +++ b/src/scenes/Owner/OwnerSettingsRenderer.tsx @@ -1,10 +1,8 @@ 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 CirrusLinearProgress from '../../components/common/CirrusLinearProgress'; import OwnerSettings from '../../components/settings/OwnerSettings'; import { OwnerSettingsRendererQuery } from './__generated__/OwnerSettingsRendererQuery.graphql'; import { useParams } from 'react-router-dom'; @@ -13,41 +11,35 @@ import ManageAccountsIcon from '@mui/icons-material/ManageAccounts'; export default function OwnerSettingsRenderer(): JSX.Element { let { platform, name } = useParams(); - return ( - - environment={environment} - variables={{ platform, name }} - query={graphql` - query OwnerSettingsRendererQuery($platform: String!, $name: String!) { - ownerInfoByName(platform: $platform, name: $name) { - ...OwnerSettings_info - ...AppBreadcrumbs_info - } - viewer { - ...AppBreadcrumbs_viewer - } + + const response = useLazyLoadQuery( + graphql` + query OwnerSettingsRendererQuery($platform: String!, $name: String!) { + ownerInfoByName(platform: $platform, name: $name) { + ...OwnerSettings_info + ...AppBreadcrumbs_info } - `} - render={({ error, props }) => { - if (!props) { - return ; + viewer { + ...AppBreadcrumbs_viewer } - return ( - <> - - - - ); - }} - /> + } + `, + { platform, name }, + ); + + return ( + <> + + + ); }