Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: [M3-8216] - NodeBalancer Query Key Factory #10556

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tech Stories
---

NodeBalancer Query Key Factory ([#10556](https://github.com/linode/manager/pull/10556))
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NodeBalancer } from '@linode/api-v4';
import type { NodeBalancer } from '@linode/api-v4';
import { useTheme } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
import { useSnackbar } from 'notistack';
Expand All @@ -16,7 +16,7 @@ import {
useAddFirewallDeviceMutation,
useAllFirewallsQuery,
} from 'src/queries/firewalls';
import { queryKey } from 'src/queries/nodebalancers';
import { nodebalancerQueries } from 'src/queries/nodebalancers';
import { useGrants, useProfile } from 'src/queries/profile/profile';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
import { getEntityIdsByPermission } from 'src/utilities/grants';
Expand Down Expand Up @@ -73,12 +73,10 @@ export const AddNodebalancerDrawer = (props: Props) => {
enqueueSnackbar(`NodeBalancer ${label} successfully added`, {
variant: 'success',
});
queryClient.invalidateQueries([
queryKey,
'nodebalancer',
id,
'firewalls',
]);
queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(id)._ctx.firewalls
.queryKey,
});
return;
}
failedNodebalancers.push(selectedNodebalancers[index]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { FirewallDevice } from '@linode/api-v4';
import { useQueryClient } from '@tanstack/react-query';
import { useSnackbar } from 'notistack';
import * as React from 'react';
Expand All @@ -9,7 +8,9 @@ import { Typography } from 'src/components/Typography';
import { useRemoveFirewallDeviceMutation } from 'src/queries/firewalls';
import { queryKey as firewallQueryKey } from 'src/queries/firewalls';
import { queryKey as linodesQueryKey } from 'src/queries/linodes/linodes';
import { queryKey as nodebalancersQueryKey } from 'src/queries/nodebalancers';
import { nodebalancerQueries } from 'src/queries/nodebalancers';

import type { FirewallDevice } from '@linode/api-v4';

export interface Props {
device: FirewallDevice | undefined;
Expand All @@ -36,10 +37,16 @@ export const RemoveDeviceDialog = React.memo((props: Props) => {
const deviceDialog = deviceType === 'linode' ? 'Linode' : 'NodeBalancer';

const onDelete = async () => {
if (!device) {
return;
}

await mutateAsync();

const toastMessage = onService
? `Firewall ${firewallLabel} successfully unassigned`
: `${deviceDialog} ${device?.entity.label} successfully removed`;
: `${deviceDialog} ${device.entity.label} successfully removed`;

enqueueSnackbar(toastMessage, {
variant: 'success',
});
Expand All @@ -48,16 +55,22 @@ export const RemoveDeviceDialog = React.memo((props: Props) => {
enqueueSnackbar(error[0].reason, { variant: 'error' });
}

const queryKey =
deviceType === 'linode' ? linodesQueryKey : nodebalancersQueryKey;

// Since the linode was removed as a device, invalidate the linode-specific firewall query
queryClient.invalidateQueries([
queryKey,
deviceType,
device?.entity.id,
'firewalls',
]);
if (deviceType === 'linode') {
queryClient.invalidateQueries([
linodesQueryKey,
deviceType,
device.entity.id,
'firewalls',
]);
}

if (deviceType === 'nodebalancer') {
queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(device.entity.id)._ctx
.firewalls.queryKey,
});
}

queryClient.invalidateQueries([firewallQueryKey]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
useUpdateFirewallRulesMutation,
} from 'src/queries/firewalls';
import { queryKey as linodesQueryKey } from 'src/queries/linodes/linodes';
import { queryKey as nodebalancersQueryKey } from 'src/queries/nodebalancers';
import { nodebalancerQueries } from 'src/queries/nodebalancers';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';

import { FirewallRuleDrawer } from './FirewallRuleDrawer';
Expand Down Expand Up @@ -202,17 +202,24 @@ export const FirewallRulesLanding = React.memo((props: Props) => {
.then((_rules) => {
setSubmitting(false);
// Invalidate Firewalls assigned to NodeBalancers and Linodes.
// eslint-disable-next-line no-unused-expressions
devices?.forEach((device) =>
queryClient.invalidateQueries([
device.entity.type === 'linode'
? linodesQueryKey
: nodebalancersQueryKey,
device.entity.type,
device.entity.id,
'firewalls',
])
);
if (devices) {
for (const device of devices) {
if (device.entity.type === 'linode') {
queryClient.invalidateQueries([
linodesQueryKey,
device.entity.type,
device.entity.id,
'firewalls',
]);
}
if (device.entity.type === 'nodebalancer') {
queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(device.entity.id)
._ctx.firewalls.queryKey,
});
}
}
}

// Reset editor state.
inboundDispatch({ rules: _rules.inbound ?? [], type: 'RESET' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import {
useCreateFirewall,
} from 'src/queries/firewalls';
import { queryKey as linodesQueryKey } from 'src/queries/linodes/linodes';
import { queryKey as nodebalancersQueryKey } from 'src/queries/nodebalancers';
import { useGrants } from 'src/queries/profile/profile';
import { sendLinodeCreateFormStepEvent } from 'src/utilities/analytics/formEventAnalytics';
import { getErrorMap } from 'src/utilities/errorUtils';
Expand All @@ -50,6 +49,7 @@ import {
} from './constants';

import type { LinodeCreateType } from 'src/features/Linodes/LinodesCreate/types';
import { nodebalancerQueries } from 'src/queries/nodebalancers';

export const READ_ONLY_DEVICES_HIDDEN_MESSAGE =
'Only services you have permission to modify are shown.';
Expand Down Expand Up @@ -151,14 +151,12 @@ export const CreateFirewallDrawer = React.memo(

// Invalidate for NodeBalancers
if (payload.devices?.nodebalancers) {
payload.devices.nodebalancers.forEach((nodebalancerId) => {
queryClient.invalidateQueries([
nodebalancersQueryKey,
'nodebalancer',
nodebalancerId,
'firewalls',
]);
});
for (const id of payload.devices.nodebalancers) {
queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(id)._ctx.firewalls
.queryKey,
});
}
}

if (onFirewallCreated) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useDeleteFirewall, useMutateFirewall } from 'src/queries/firewalls';
import { queryKey as firewallQueryKey } from 'src/queries/firewalls';
import { useAllFirewallDevicesQuery } from 'src/queries/firewalls';
import { queryKey as linodesQueryKey } from 'src/queries/linodes/linodes';
import { queryKey as nodebalancersQueryKey } from 'src/queries/nodebalancers';
import { nodebalancerQueries } from 'src/queries/nodebalancers';
import { capitalize } from 'src/utilities/capitalize';

export type Mode = 'delete' | 'disable' | 'enable';
Expand Down Expand Up @@ -70,12 +70,20 @@ export const FirewallDialog = React.memo((props: Props) => {
// eslint-disable-next-line no-unused-expressions
devices?.forEach((device) => {
const deviceType = device.entity.type;
queryClient.invalidateQueries([
deviceType === 'linode' ? linodesQueryKey : nodebalancersQueryKey,
deviceType,
device.entity.id,
'firewalls',
]);
if (deviceType === 'linode') {
queryClient.invalidateQueries([
linodesQueryKey,
deviceType,
device.entity.id,
'firewalls',
]);
}
if (deviceType === 'nodebalancer') {
queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(device.entity.id)._ctx
.firewalls.queryKey,
});
}
});
if (mode === 'delete') {
queryClient.invalidateQueries([firewallQueryKey]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
WithQueryClientProps,
withQueryClient,
} from 'src/containers/withQueryClient.container';
import { queryKey } from 'src/queries/nodebalancers';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView';

Expand All @@ -63,6 +62,7 @@ import type {
NodeBalancerConfigNodeFields,
} from '../types';
import type { Grants } from '@linode/api-v4';
import { nodebalancerQueries } from 'src/queries/nodebalancers';

const StyledPortsSpan = styled('span', {
label: 'StyledPortsSpan',
Expand Down Expand Up @@ -411,12 +411,10 @@ class NodeBalancerConfigurations extends React.Component<
// actually delete a real config
deleteNodeBalancerConfig(Number(nodeBalancerId), config.id)
.then((_) => {
this.props.queryClient.invalidateQueries([
queryKey,
'nodebalancer',
Number(nodeBalancerId),
'configs',
]);
this.props.queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(Number(nodeBalancerId))
._ctx.configurations.queryKey,
});
// update config data
const newConfigs = clone(this.state.configs);
newConfigs.splice(idxToDelete, 1);
Expand Down Expand Up @@ -827,12 +825,10 @@ class NodeBalancerConfigurations extends React.Component<

createNodeBalancerConfig(Number(nodeBalancerId), configPayload)
.then((nodeBalancerConfig) => {
this.props.queryClient.invalidateQueries([
queryKey,
'nodebalancer',
Number(nodeBalancerId),
'configs',
]);
this.props.queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(Number(nodeBalancerId))
._ctx.configurations.queryKey,
});
// update config data
const newConfigs = clone(this.state.configs);
newConfigs[idx] = { ...nodeBalancerConfig, nodes: [] };
Expand Down Expand Up @@ -941,12 +937,10 @@ class NodeBalancerConfigurations extends React.Component<
configPayload
)
.then((nodeBalancerConfig) => {
this.props.queryClient.invalidateQueries([
queryKey,
'nodebalancer',
Number(nodeBalancerId),
'configs',
]);
this.props.queryClient.invalidateQueries({
queryKey: nodebalancerQueries.nodebalancer(Number(nodeBalancerId))
._ctx.configurations.queryKey,
});
// update config data
const newConfigs = clone(this.state.configs);
newConfigs[idx] = { ...nodeBalancerConfig, nodes: [] };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
import { Theme, useTheme } from '@mui/material/styles';
import { useTheme } from '@mui/material/styles';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import { useParams } from 'react-router-dom';

import PendingIcon from 'src/assets/icons/pending.svg';
import { AreaChart } from 'src/components/AreaChart/AreaChart';
import {
NodeBalancerConnectionsTimeData,
Point,
} from 'src/components/AreaChart/types';
import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { Paper } from 'src/components/Paper';
import { Typography } from 'src/components/Typography';
import { formatBitsPerSecond } from 'src/features/Longview/shared/utilities';
import {
NODEBALANCER_STATS_NOT_READY_API_MESSAGE,
useNodeBalancerQuery,
useNodeBalancerStats,
useNodeBalancerStatsQuery,
} from 'src/queries/nodebalancers';
import { useProfile } from 'src/queries/profile/profile';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
import { getUserTimezone } from 'src/utilities/getUserTimezone';
import { formatNumber, getMetrics } from 'src/utilities/statMetrics';

import type { Theme } from '@mui/material/styles';
import type {
NodeBalancerConnectionsTimeData,
Point,
} from 'src/components/AreaChart/types';

const NODEBALANCER_STATS_NOT_READY_API_MESSAGE =
'Stats are unavailable at this time.';
const STATS_NOT_READY_TITLE =
'Stats for this NodeBalancer are not available yet';

Expand All @@ -36,9 +39,8 @@ export const TablesPanel = () => {
const id = Number(nodeBalancerId);
const { data: nodebalancer } = useNodeBalancerQuery(id);

const { data: stats, error, isLoading } = useNodeBalancerStats(
nodebalancer?.id ?? -1,
nodebalancer?.created
const { data: stats, error, isLoading } = useNodeBalancerStatsQuery(
nodebalancer?.id ?? -1
);

const statsErrorString = error
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/hooks/useEventHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { firewallEventsHandler } from 'src/queries/firewalls';
import { imageEventsHandler } from 'src/queries/images';
import { diskEventHandler } from 'src/queries/linodes/events';
import { linodeEventsHandler } from 'src/queries/linodes/events';
import { nodebalanacerEventHandler } from 'src/queries/nodebalancers';
import { nodebalancerEventHandler } from 'src/queries/nodebalancers';
import { sshKeyEventHandler } from 'src/queries/profile/profile';
import { stackScriptEventHandler } from 'src/queries/stackscripts';
import { supportTicketEventHandler } from 'src/queries/support';
Expand Down Expand Up @@ -58,7 +58,7 @@ export const eventHandlers: {
},
{
filter: (event) => event.action.startsWith('nodebalancer'),
handler: nodebalanacerEventHandler,
handler: nodebalancerEventHandler,
},
{
filter: (event) => event.action.startsWith('oauth_client'),
Expand Down
Loading
Loading