diff --git a/packages/manager/.changeset/pr-10414-tech-stories-1714167805545.md b/packages/manager/.changeset/pr-10414-tech-stories-1714167805545.md new file mode 100644 index 00000000000..17ec96044cd --- /dev/null +++ b/packages/manager/.changeset/pr-10414-tech-stories-1714167805545.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tech Stories +--- + +Query Key Factory for Volumes ([#10414](https://github.com/linode/manager/pull/10414)) diff --git a/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts b/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts index 31bffd13a22..1d168718f81 100644 --- a/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts +++ b/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts @@ -131,6 +131,7 @@ describe('volumes', () => { id: randomNumber(), }); const newVolume = volumeFactory.build({ + linode_id: mockLinode.id, label: randomLabel(), }); diff --git a/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx b/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx index 74a4ec9c2cd..b61b2862a35 100644 --- a/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx +++ b/packages/manager/src/features/Linodes/LinodeEntityDetail.tsx @@ -11,7 +11,7 @@ import { useInProgressEvents } from 'src/queries/events/events'; import { useAllImagesQuery } from 'src/queries/images'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { useTypeQuery } from 'src/queries/types'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; +import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes'; import { formatStorageUnits } from 'src/utilities/formatStorageUnits'; import { LinodeEntityDetailBody } from './LinodeEntityDetailBody'; diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/ConfigRow.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/ConfigRow.tsx index 66611751a80..6310baecb29 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/ConfigRow.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/ConfigRow.tsx @@ -7,7 +7,7 @@ import { TableRow } from 'src/components/TableRow'; import { API_MAX_PAGE_SIZE } from 'src/constants'; import { useAllLinodeDisksQuery } from 'src/queries/linodes/disks'; import { useLinodeKernelQuery } from 'src/queries/linodes/linodes'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; +import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes'; import { InterfaceListItem } from './InterfaceListItem'; import { ConfigActionMenu } from './LinodeConfigActionMenu'; diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/LinodeConfigDialog.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/LinodeConfigDialog.tsx index 9f934c965fd..35b559b9e39 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/LinodeConfigDialog.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeConfigs/LinodeConfigDialog.tsx @@ -49,7 +49,7 @@ import { } from 'src/queries/linodes/linodes'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { vlanQueries } from 'src/queries/vlans'; -import { useAllVolumesQuery } from 'src/queries/volumes'; +import { useAllVolumesQuery } from 'src/queries/volumes/volumes'; import { vpcQueries } from 'src/queries/vpcs/vpcs'; import { DevicesAsStrings, diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeRescue/StandardRescueDialog.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeRescue/StandardRescueDialog.tsx index 83ccb886572..cb09d9ca5f8 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeRescue/StandardRescueDialog.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeRescue/StandardRescueDialog.tsx @@ -18,7 +18,7 @@ import { useLinodeRescueMutation, } from 'src/queries/linodes/linodes'; import { useGrants, useProfile } from 'src/queries/profile'; -import { useAllVolumesQuery } from 'src/queries/volumes'; +import { useAllVolumesQuery } from 'src/queries/volumes/volumes'; import { DevicesAsStrings, createDevicesFromStrings, diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeStorage/LinodeVolumes.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeStorage/LinodeVolumes.tsx index e5eb36b718a..dda1c4b2e5b 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeStorage/LinodeVolumes.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeStorage/LinodeVolumes.tsx @@ -29,7 +29,7 @@ import { useOrder } from 'src/hooks/useOrder'; import { usePagination } from 'src/hooks/usePagination'; import { useLinodeQuery } from 'src/queries/linodes/linodes'; import { useRegionsQuery } from 'src/queries/regions/regions'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; +import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes'; import { StyledRootGrid, StyledTypography } from './CommonLinodeStorage.styles'; export const preferenceKey = 'linode-volumes'; diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodesDetailHeader/UpgradeVolumesDialog.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodesDetailHeader/UpgradeVolumesDialog.tsx index 9f781f1e86f..1d5c479e392 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodesDetailHeader/UpgradeVolumesDialog.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodesDetailHeader/UpgradeVolumesDialog.tsx @@ -9,8 +9,10 @@ import { Typography } from 'src/components/Typography'; import { VolumeUpgradeCopy } from 'src/features/Volumes/UpgradeVolumeDialog'; import { getUpgradeableVolumeIds } from 'src/features/Volumes/utils'; import { useNotificationsQuery } from 'src/queries/account/notifications'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; -import { useVolumesMigrateMutation } from 'src/queries/volumesMigrations'; +import { + useLinodeVolumesQuery, + useVolumesMigrateMutation, +} from 'src/queries/volumes/volumes'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import type { Linode } from '@linode/api-v4'; diff --git a/packages/manager/src/features/Linodes/LinodesDetail/VolumesUpgradeBanner.tsx b/packages/manager/src/features/Linodes/LinodesDetail/VolumesUpgradeBanner.tsx index b261cb5609a..2d1a871b763 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/VolumesUpgradeBanner.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/VolumesUpgradeBanner.tsx @@ -9,7 +9,7 @@ import { Stack } from 'src/components/Stack'; import { Typography } from 'src/components/Typography'; import { getUpgradeableVolumeIds } from 'src/features/Volumes/utils'; import { useNotificationsQuery } from 'src/queries/account/notifications'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; +import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes'; interface Props { linodeId: number; diff --git a/packages/manager/src/features/Linodes/MigrateLinode/CautionNotice.tsx b/packages/manager/src/features/Linodes/MigrateLinode/CautionNotice.tsx index 2e101b4f8eb..6049904ce48 100644 --- a/packages/manager/src/features/Linodes/MigrateLinode/CautionNotice.tsx +++ b/packages/manager/src/features/Linodes/MigrateLinode/CautionNotice.tsx @@ -7,7 +7,7 @@ import { Link } from 'src/components/Link'; import { Notice } from 'src/components/Notice/Notice'; import { Typography } from 'src/components/Typography'; import { API_MAX_PAGE_SIZE } from 'src/constants'; -import { useLinodeVolumesQuery } from 'src/queries/volumes'; +import { useLinodeVolumesQuery } from 'src/queries/volumes/volumes'; interface Props { edgeRegionWarning?: string; diff --git a/packages/manager/src/features/Search/SearchLanding.tsx b/packages/manager/src/features/Search/SearchLanding.tsx index 161a6ec3bcd..0948d665bc3 100644 --- a/packages/manager/src/features/Search/SearchLanding.tsx +++ b/packages/manager/src/features/Search/SearchLanding.tsx @@ -23,7 +23,7 @@ import { } from 'src/queries/objectStorage'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { useSpecificTypes } from 'src/queries/types'; -import { useAllVolumesQuery } from 'src/queries/volumes'; +import { useAllVolumesQuery } from 'src/queries/volumes/volumes'; import { formatLinode } from 'src/store/selectors/getSearchEntities'; import { isFeatureEnabled } from 'src/utilities/accountCapabilities'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; diff --git a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx index 080162f9a02..4069ef30fd5 100644 --- a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx +++ b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx @@ -27,7 +27,7 @@ import { useAllFirewallsQuery } from 'src/queries/firewalls'; import { useAllKubernetesClustersQuery } from 'src/queries/kubernetes'; import { useAllLinodesQuery } from 'src/queries/linodes/linodes'; import { useAllNodeBalancersQuery } from 'src/queries/nodebalancers'; -import { useAllVolumesQuery } from 'src/queries/volumes'; +import { useAllVolumesQuery } from 'src/queries/volumes/volumes'; import { getAPIErrorOrDefault, getErrorMap, diff --git a/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx b/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx index 5f3a1624b2f..8e5d83a53d1 100644 --- a/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx +++ b/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx @@ -26,7 +26,7 @@ import { } from 'src/queries/objectStorage'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { useSpecificTypes } from 'src/queries/types'; -import { useAllVolumesQuery } from 'src/queries/volumes'; +import { useAllVolumesQuery } from 'src/queries/volumes/volumes'; import { formatLinode } from 'src/store/selectors/getSearchEntities'; import { isFeatureEnabled } from 'src/utilities/accountCapabilities'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; diff --git a/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx b/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx index eafaa9d5bda..65a60178bb5 100644 --- a/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx +++ b/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx @@ -14,7 +14,7 @@ import { LinodeSelect } from 'src/features/Linodes/LinodeSelect/LinodeSelect'; import { useEventsPollingActions } from 'src/queries/events/events'; import { useAllLinodeConfigsQuery } from 'src/queries/linodes/configs'; import { useGrants } from 'src/queries/profile'; -import { useAttachVolumeMutation } from 'src/queries/volumes'; +import { useAttachVolumeMutation } from 'src/queries/volumes/volumes'; import { getAPIErrorFor } from 'src/utilities/getAPIErrorFor'; interface Props { diff --git a/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx b/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx index f6c98de9dd9..2f54ad91c68 100644 --- a/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx +++ b/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx @@ -13,7 +13,7 @@ import { useGrants } from 'src/queries/profile'; import { useCloneVolumeMutation, useVolumeTypesQuery, -} from 'src/queries/volumes'; +} from 'src/queries/volumes/volumes'; import { handleFieldErrors, handleGeneralErrors, diff --git a/packages/manager/src/features/Volumes/DeleteVolumeDialog.tsx b/packages/manager/src/features/Volumes/DeleteVolumeDialog.tsx index 762c4bc97c6..d094eac48d5 100644 --- a/packages/manager/src/features/Volumes/DeleteVolumeDialog.tsx +++ b/packages/manager/src/features/Volumes/DeleteVolumeDialog.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Notice } from 'src/components/Notice/Notice'; import { TypeToConfirmDialog } from 'src/components/TypeToConfirmDialog/TypeToConfirmDialog'; import { useEventsPollingActions } from 'src/queries/events/events'; -import { useDeleteVolumeMutation } from 'src/queries/volumes'; +import { useDeleteVolumeMutation } from 'src/queries/volumes/volumes'; interface Props { onClose: () => void; diff --git a/packages/manager/src/features/Volumes/DetachVolumeDialog.tsx b/packages/manager/src/features/Volumes/DetachVolumeDialog.tsx index 6e9011a7cb7..6c72324fa7a 100644 --- a/packages/manager/src/features/Volumes/DetachVolumeDialog.tsx +++ b/packages/manager/src/features/Volumes/DetachVolumeDialog.tsx @@ -7,7 +7,7 @@ import { TypeToConfirmDialog } from 'src/components/TypeToConfirmDialog/TypeToCo import { Typography } from 'src/components/Typography'; import { useEventsPollingActions } from 'src/queries/events/events'; import { useLinodeQuery } from 'src/queries/linodes/linodes'; -import { useDetachVolumeMutation } from 'src/queries/volumes'; +import { useDetachVolumeMutation } from 'src/queries/volumes/volumes'; interface Props { onClose: () => void; diff --git a/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx b/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx index 88497be6dc7..365e2261029 100644 --- a/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx +++ b/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx @@ -9,7 +9,7 @@ import { Notice } from 'src/components/Notice/Notice'; import { TagsInput } from 'src/components/TagsInput/TagsInput'; import { TextField } from 'src/components/TextField'; import { useGrants } from 'src/queries/profile'; -import { useUpdateVolumeMutation } from 'src/queries/volumes'; +import { useUpdateVolumeMutation } from 'src/queries/volumes/volumes'; import { handleFieldErrors, handleGeneralErrors, diff --git a/packages/manager/src/features/Volumes/ResizeVolumeDrawer.tsx b/packages/manager/src/features/Volumes/ResizeVolumeDrawer.tsx index fa5714c6242..79a168ea377 100644 --- a/packages/manager/src/features/Volumes/ResizeVolumeDrawer.tsx +++ b/packages/manager/src/features/Volumes/ResizeVolumeDrawer.tsx @@ -12,7 +12,7 @@ import { useGrants } from 'src/queries/profile'; import { useResizeVolumeMutation, useVolumeTypesQuery, -} from 'src/queries/volumes'; +} from 'src/queries/volumes/volumes'; import { handleFieldErrors, handleGeneralErrors, diff --git a/packages/manager/src/features/Volumes/UpgradeVolumeDialog.tsx b/packages/manager/src/features/Volumes/UpgradeVolumeDialog.tsx index ab854121709..4747fbd8ffb 100644 --- a/packages/manager/src/features/Volumes/UpgradeVolumeDialog.tsx +++ b/packages/manager/src/features/Volumes/UpgradeVolumeDialog.tsx @@ -5,7 +5,7 @@ import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog'; import { Link } from 'src/components/Link'; import { Typography } from 'src/components/Typography'; -import { useVolumesMigrateMutation } from 'src/queries/volumesMigrations'; +import { useVolumesMigrateMutation } from 'src/queries/volumes/volumes'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import type { Volume } from '@linode/api-v4'; diff --git a/packages/manager/src/features/Volumes/VolumeCreate.tsx b/packages/manager/src/features/Volumes/VolumeCreate.tsx index 74d4bd5685f..6ac558e6f53 100644 --- a/packages/manager/src/features/Volumes/VolumeCreate.tsx +++ b/packages/manager/src/features/Volumes/VolumeCreate.tsx @@ -30,7 +30,7 @@ import { useRegionsQuery } from 'src/queries/regions/regions'; import { useCreateVolumeMutation, useVolumeTypesQuery, -} from 'src/queries/volumes'; +} from 'src/queries/volumes/volumes'; import { sendCreateVolumeEvent } from 'src/utilities/analytics'; import { getGDPRDetails } from 'src/utilities/formatRegion'; import { diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeAttachForm.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeAttachForm.tsx index 229c2da924f..3d75171ea14 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeAttachForm.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeAttachForm.tsx @@ -9,7 +9,7 @@ import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { Notice } from 'src/components/Notice/Notice'; import { useEventsPollingActions } from 'src/queries/events/events'; import { useGrants } from 'src/queries/profile'; -import { useAttachVolumeMutation } from 'src/queries/volumes'; +import { useAttachVolumeMutation } from 'src/queries/volumes/volumes'; import { handleFieldErrors, handleGeneralErrors, diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx index 65ac86e7d38..dc0ad3e18b2 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx @@ -15,7 +15,7 @@ import { useEventsPollingActions } from 'src/queries/events/events'; import { useCreateVolumeMutation, useVolumeTypesQuery, -} from 'src/queries/volumes'; +} from 'src/queries/volumes/volumes'; import { sendCreateVolumeEvent } from 'src/utilities/analytics'; import { getErrorStringOrDefault } from 'src/utilities/errorUtils'; import { diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx index 097a27d724b..ad1ee389651 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { Box } from 'src/components/Box'; import { DisplayPrice } from 'src/components/DisplayPrice'; import { MAX_VOLUME_SIZE } from 'src/constants'; -import { useVolumeTypesQuery } from 'src/queries/volumes'; +import { useVolumeTypesQuery } from 'src/queries/volumes/volumes'; import { getDCSpecificPriceByType } from 'src/utilities/pricing/dynamicPricing'; interface Props { currentSize: number; diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx index 03e52ec3296..bad1abae3ab 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx @@ -9,7 +9,7 @@ import { InputAdornment } from 'src/components/InputAdornment'; import { TextField } from 'src/components/TextField'; import { Typography } from 'src/components/Typography'; import { MAX_VOLUME_SIZE } from 'src/constants'; -import { useVolumeTypesQuery } from 'src/queries/volumes'; +import { useVolumeTypesQuery } from 'src/queries/volumes/volumes'; import { UNKNOWN_PRICE } from 'src/utilities/pricing/constants'; import { getDCSpecificPriceByType } from 'src/utilities/pricing/dynamicPricing'; diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/VolumeSelect.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/VolumeSelect.tsx index bbfbfcbcf4c..8a5506e0cc1 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/VolumeSelect.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/VolumeSelect.tsx @@ -2,7 +2,7 @@ import Autocomplete from '@mui/material/Autocomplete'; import * as React from 'react'; import { TextField } from 'src/components/TextField'; -import { useInfiniteVolumesQuery } from 'src/queries/volumes'; +import { useInfiniteVolumesQuery } from 'src/queries/volumes/volumes'; interface Props { disabled?: boolean; diff --git a/packages/manager/src/features/Volumes/VolumesLanding.tsx b/packages/manager/src/features/Volumes/VolumesLanding.tsx index 438a5196b59..d0c4cd8e3ee 100644 --- a/packages/manager/src/features/Volumes/VolumesLanding.tsx +++ b/packages/manager/src/features/Volumes/VolumesLanding.tsx @@ -14,7 +14,7 @@ import { TableRow } from 'src/components/TableRow'; import { TableSortCell } from 'src/components/TableSortCell'; import { useOrder } from 'src/hooks/useOrder'; import { usePagination } from 'src/hooks/usePagination'; -import { useVolumesQuery } from 'src/queries/volumes'; +import { useVolumesQuery } from 'src/queries/volumes/volumes'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import { AttachVolumeDrawer } from './AttachVolumeDrawer'; diff --git a/packages/manager/src/hooks/useEventHandlers.ts b/packages/manager/src/hooks/useEventHandlers.ts index 659bec203e9..268422f9aaa 100644 --- a/packages/manager/src/hooks/useEventHandlers.ts +++ b/packages/manager/src/hooks/useEventHandlers.ts @@ -5,17 +5,17 @@ import { databaseEventsHandler } from 'src/queries/databases'; import { domainEventsHandler } from 'src/queries/domains'; import { firewallEventsHandler } from 'src/queries/firewalls'; import { imageEventsHandler } from 'src/queries/images'; -import { linodeEventsHandler } from 'src/queries/linodes/events'; import { diskEventHandler } from 'src/queries/linodes/events'; +import { linodeEventsHandler } from 'src/queries/linodes/events'; import { nodebalanacerEventHandler } from 'src/queries/nodebalancers'; import { sshKeyEventHandler } from 'src/queries/profile'; +import { stackScriptEventHandler } from 'src/queries/stackscripts'; import { supportTicketEventHandler } from 'src/queries/support'; import { tokenEventHandler } from 'src/queries/tokens'; -import { volumeEventsHandler } from 'src/queries/volumes'; +import { volumeEventsHandler } from 'src/queries/volumes/events'; import type { Event } from '@linode/api-v4'; import type { QueryClient } from '@tanstack/react-query'; -import { stackScriptEventHandler } from 'src/queries/stackscripts'; export interface EventHandlerData { event: Event; diff --git a/packages/manager/src/queries/linodes/events.ts b/packages/manager/src/queries/linodes/events.ts index e958b2972eb..0e9aaafcca0 100644 --- a/packages/manager/src/queries/linodes/events.ts +++ b/packages/manager/src/queries/linodes/events.ts @@ -1,11 +1,10 @@ import { EventHandlerData } from 'src/hooks/useEventHandlers'; import { queryKey as firewallsQueryKey } from 'src/queries/firewalls'; -import { queryKey as volumesQueryKey } from 'src/queries/volumes'; - import { accountQueries } from '../account/queries'; import { queryKey } from './linodes'; import type { Event } from '@linode/api-v4'; +import { volumeQueries } from '../volumes/volumes'; /** * Event handler for Linode events @@ -98,7 +97,7 @@ export const linodeEventsHandler = ({ queryClient.invalidateQueries([firewallsQueryKey]); // A Linode may have been attached to a Volume, but deleted. We need to refetch volumes data so that // the Volumes table does not show a Volume attached to a non-existant Linode. - queryClient.invalidateQueries([volumesQueryKey]); + queryClient.invalidateQueries(volumeQueries.lists.queryKey); return; case 'linode_config_create': case 'linode_config_delete': diff --git a/packages/manager/src/queries/volumes.ts b/packages/manager/src/queries/volumes.ts deleted file mode 100644 index a6726794aa3..00000000000 --- a/packages/manager/src/queries/volumes.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { - AttachVolumePayload, - CloneVolumePayload, - ResizeVolumePayload, - UpdateVolumeRequest, - Volume, - VolumeRequestPayload, - attachVolume, - cloneVolume, - createVolume, - deleteVolume, - detachVolume, - getLinodeVolumes, - getVolumeTypes, - getVolumes, - resizeVolume, - updateVolume, -} from '@linode/api-v4'; -import { APIError, ResourcePage } from '@linode/api-v4/lib/types'; -import { Filter, Params, PriceType } from '@linode/api-v4/src/types'; -import { - useInfiniteQuery, - useMutation, - useQuery, - useQueryClient, -} from '@tanstack/react-query'; - -import { EventHandlerData } from 'src/hooks/useEventHandlers'; -import { getAll } from 'src/utilities/getAll'; - -import { accountQueries } from './account/queries'; -import { queryPresets, updateInPaginatedStore } from './base'; -import { profileQueries } from './profile'; - -export const queryKey = 'volumes'; - -export const useVolumesQuery = (params: Params, filters: Filter) => - useQuery, APIError[]>( - [queryKey, 'paginated', params, filters], - () => getVolumes(params, filters), - { keepPreviousData: true } - ); - -export const useInfiniteVolumesQuery = (filter: Filter) => - useInfiniteQuery, APIError[]>( - [queryKey, 'infinite', filter], - ({ pageParam }) => getVolumes({ page: pageParam, page_size: 25 }, filter), - { - getNextPageParam: ({ page, pages }) => { - if (page === pages) { - return undefined; - } - return page + 1; - }, - } - ); - -export const useAllVolumesQuery = ( - params: Params = {}, - filters: Filter = {}, - enabled = true -) => - useQuery( - [queryKey, 'all', params, filters], - () => getAllVolumes(params, filters), - { - enabled, - } - ); - -export const useLinodeVolumesQuery = ( - linodeId: number, - params: Params = {}, - filters: Filter = {}, - enabled = true -) => - useQuery, APIError[]>( - [queryKey, 'linode', linodeId, params, filters], - () => getLinodeVolumes(linodeId, params, filters), - { enabled, keepPreviousData: true } - ); - -interface ResizeVolumePayloadWithId extends ResizeVolumePayload { - volumeId: number; -} - -export const useResizeVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation( - ({ volumeId, ...data }) => resizeVolume(volumeId, data), - { - onSuccess(volume) { - updateInPaginatedStore( - [queryKey, 'paginated'], - volume.id, - volume, - queryClient - ); - }, - } - ); -}; - -interface CloneVolumePayloadWithId extends CloneVolumePayload { - volumeId: number; -} - -export const useCloneVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation( - ({ volumeId, ...data }) => cloneVolume(volumeId, data), - { - onSuccess() { - queryClient.invalidateQueries([queryKey]); - }, - } - ); -}; - -export const useDeleteVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation<{}, APIError[], { id: number }>( - ({ id }) => deleteVolume(id), - { - onSuccess() { - queryClient.invalidateQueries([queryKey]); - }, - } - ); -}; - -export const useCreateVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation(createVolume, { - onSuccess() { - queryClient.invalidateQueries([queryKey]); - // If a restricted user creates an entity, we must make sure grants are up to date. - queryClient.invalidateQueries(profileQueries.grants.queryKey); - }, - }); -}; - -interface UpdateVolumePayloadWithId extends UpdateVolumeRequest { - volumeId: number; -} - -export const useUpdateVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation( - ({ volumeId, ...data }) => updateVolume(volumeId, data), - { - onSuccess(volume) { - updateInPaginatedStore( - [queryKey, 'paginated'], - volume.id, - volume, - queryClient - ); - if (volume.linode_id) { - queryClient.invalidateQueries([queryKey, 'linode', volume.linode_id]); - } - }, - } - ); -}; - -interface AttachVolumePayloadWithId extends AttachVolumePayload { - volumeId: number; -} - -export const useAttachVolumeMutation = () => { - const queryClient = useQueryClient(); - return useMutation( - ({ volumeId, ...data }) => attachVolume(volumeId, data), - { - onSuccess(volume) { - updateInPaginatedStore( - [queryKey, 'paginated'], - volume.id, - volume, - queryClient - ); - if (volume.linode_id) { - queryClient.invalidateQueries([queryKey, 'linode', volume.linode_id]); - } - }, - } - ); -}; - -export const useDetachVolumeMutation = () => - useMutation<{}, APIError[], { id: number }>(({ id }) => detachVolume(id)); - -export const volumeEventsHandler = ({ - event, - queryClient, -}: EventHandlerData) => { - if (['failed', 'finished', 'notification'].includes(event.status)) { - queryClient.invalidateQueries([queryKey]); - } - - if ( - event.action === 'volume_migrate' && - (event.status === 'finished' || event.status === 'failed') - ) { - // if a migration finishes, we want to re-request notifications so that the `volume_migration_imminent` - // notification goes away. - queryClient.invalidateQueries(accountQueries.notifications.queryKey); - } - - if (event.action === 'volume_clone') { - // The API gives us no way to know when a cloned volume transitions from - // creating to active, so we will just refresh after 10 seconds - setTimeout(() => { - queryClient.invalidateQueries([queryKey]); - }, 10000); - } -}; - -const getAllVolumes = (passedParams: Params = {}, passedFilter: Filter = {}) => - getAll((params, filter) => - getVolumes({ ...params, ...passedParams }, { ...filter, ...passedFilter }) - )().then((data) => data.data); - -export const getVolumesForLinode = (volumes: Volume[], linodeId: number) => - volumes.filter(({ linode_id }) => linode_id && linode_id === linodeId); - -const getAllVolumeTypes = () => - getAll((params) => getVolumeTypes(params))().then( - (data) => data.data - ); - -export const useVolumeTypesQuery = () => - useQuery([`${queryKey}-types`], getAllVolumeTypes, { - ...queryPresets.oneTimeFetch, - }); diff --git a/packages/manager/src/queries/volumes/events.ts b/packages/manager/src/queries/volumes/events.ts new file mode 100644 index 00000000000..84f2c7c6fba --- /dev/null +++ b/packages/manager/src/queries/volumes/events.ts @@ -0,0 +1,41 @@ +import { accountQueries } from '../account/queries'; +import { volumeQueries } from './volumes'; + +import type { EventHandlerData } from 'src/hooks/useEventHandlers'; + +/** + * An event handler that performs invalidations based on incoming volume events. + * + * We use this to give users a realtime-like experience. + */ +export const volumeEventsHandler = ({ + event, + queryClient, +}: EventHandlerData) => { + if (['failed', 'finished', 'notification'].includes(event.status)) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + } + + if ( + event.action === 'volume_migrate' && + (event.status === 'finished' || event.status === 'failed') + ) { + // if a migration finishes, we want to re-request notifications so that the `volume_migration_imminent` + // notification goes away. + queryClient.invalidateQueries({ + queryKey: accountQueries.notifications.queryKey, + }); + } + + if (event.action === 'volume_clone') { + // The API gives us no way to know when a cloned volume transitions from + // creating to active, so we will just refresh after 10 seconds + setTimeout(() => { + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + }, 10000); + } +}; diff --git a/packages/manager/src/queries/volumes/requests.ts b/packages/manager/src/queries/volumes/requests.ts new file mode 100644 index 00000000000..a6c789f5a12 --- /dev/null +++ b/packages/manager/src/queries/volumes/requests.ts @@ -0,0 +1,24 @@ +import { + Filter, + Params, + Volume, + getVolumeTypes, + getVolumes, +} from '@linode/api-v4'; + +import { getAll } from 'src/utilities/getAll'; + +import type { PriceType } from '@linode/api-v4'; + +export const getAllVolumeTypes = () => + getAll((params) => getVolumeTypes(params))().then( + (data) => data.data + ); + +export const getAllVolumes = ( + passedParams: Params = {}, + passedFilter: Filter = {} +) => + getAll((params, filter) => + getVolumes({ ...params, ...passedParams }, { ...filter, ...passedFilter }) + )().then((data) => data.data); diff --git a/packages/manager/src/queries/volumes/volumes.ts b/packages/manager/src/queries/volumes/volumes.ts new file mode 100644 index 00000000000..d2b549100dc --- /dev/null +++ b/packages/manager/src/queries/volumes/volumes.ts @@ -0,0 +1,253 @@ +import { + AttachVolumePayload, + CloneVolumePayload, + ResizeVolumePayload, + UpdateVolumeRequest, + Volume, + VolumeRequestPayload, + attachVolume, + cloneVolume, + createVolume, + deleteVolume, + detachVolume, + getLinodeVolumes, + getVolumes, + migrateVolumes, + resizeVolume, + updateVolume, +} from '@linode/api-v4'; +import { APIError, ResourcePage } from '@linode/api-v4/lib/types'; +import { Filter, Params, PriceType } from '@linode/api-v4/src/types'; +import { createQueryKeys } from '@lukemorales/query-key-factory'; +import { + useInfiniteQuery, + useMutation, + useQuery, + useQueryClient, +} from '@tanstack/react-query'; + +import { accountQueries } from '../account/queries'; +import { queryPresets } from '../base'; +import { profileQueries } from '../profile'; +import { getAllVolumeTypes, getAllVolumes } from './requests'; + +export const volumeQueries = createQueryKeys('volumes', { + linode: (linodeId: number) => ({ + contextQueries: { + volumes: (params: Params = {}, filter: Filter = {}) => ({ + queryFn: () => getLinodeVolumes(linodeId, params, filter), + queryKey: [params, filter], + }), + }, + queryKey: [linodeId], + }), + lists: { + contextQueries: { + all: (params: Params = {}, filter: Filter = {}) => ({ + queryFn: () => getAllVolumes(params, filter), + queryKey: [params, filter], + }), + infinite: (filter: Filter = {}) => ({ + queryFn: ({ pageParam }) => + getVolumes({ page: pageParam, page_size: 25 }, filter), + queryKey: [filter], + }), + paginated: (params: Params = {}, filter: Filter = {}) => ({ + queryFn: () => getVolumes(params, filter), + queryKey: [params, filter], + }), + }, + queryKey: null, + }, + types: { + queryFn: getAllVolumeTypes, + queryKey: null, + }, +}); + +export const useVolumesQuery = (params: Params, filter: Filter) => + useQuery, APIError[]>({ + ...volumeQueries.lists._ctx.paginated(params, filter), + keepPreviousData: true, + }); + +export const useVolumeTypesQuery = () => + useQuery({ + ...volumeQueries.types, + ...queryPresets.oneTimeFetch, + }); + +export const useInfiniteVolumesQuery = (filter: Filter) => + useInfiniteQuery, APIError[]>({ + ...volumeQueries.lists._ctx.infinite(filter), + getNextPageParam: ({ page, pages }) => { + if (page === pages) { + return undefined; + } + return page + 1; + }, + }); + +export const useAllVolumesQuery = ( + params: Params = {}, + filter: Filter = {}, + enabled = true +) => + useQuery({ + ...volumeQueries.lists._ctx.all(params, filter), + enabled, + }); + +export const useLinodeVolumesQuery = ( + linodeId: number, + params: Params = {}, + filter: Filter = {}, + enabled = true +) => + useQuery, APIError[]>({ + ...volumeQueries.linode(linodeId)._ctx.volumes(params, filter), + enabled, + keepPreviousData: true, + }); + +interface ResizeVolumePayloadWithId extends ResizeVolumePayload { + volumeId: number; +} + +export const useResizeVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ volumeId, ...data }) => resizeVolume(volumeId, data), + onSuccess(volume) { + // Invalidate all lists + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + // If the volume is assigned to a Linode, invalidate that Linode's list + if (volume.linode_id) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.linode(volume.linode_id)._ctx.volumes._def, + }); + } + }, + }); +}; + +interface CloneVolumePayloadWithId extends CloneVolumePayload { + volumeId: number; +} + +export const useCloneVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ volumeId, ...data }) => cloneVolume(volumeId, data), + onSuccess() { + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + }, + }); +}; + +export const useDeleteVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation<{}, APIError[], { id: number }>({ + mutationFn: ({ id }) => deleteVolume(id), + onSuccess() { + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + }, + }); +}; + +export const useCreateVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: createVolume, + onSuccess(volume) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + if (volume.linode_id) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.linode(volume.linode_id)._ctx.volumes._def, + }); + } + // If a restricted user creates an entity, we must make sure grants are up to date. + queryClient.invalidateQueries({ + queryKey: profileQueries.grants.queryKey, + }); + }, + }); +}; + +export const useVolumesMigrateMutation = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, APIError[], number[]>({ + mutationFn: migrateVolumes, + onSuccess: () => { + // If a customer "force" migrates they will then see a + // `volume_migration_imminent` notification instead of + // the `volume_migration_scheduled` notification. + setTimeout(() => { + // Refetch notifications after 1.5 seconds. The API needs some time to process. + queryClient.invalidateQueries({ + queryKey: accountQueries.notifications.queryKey, + }); + }, 1500); + }, + }); +}; + +interface UpdateVolumePayloadWithId extends UpdateVolumeRequest { + volumeId: number; +} + +export const useUpdateVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ volumeId, ...data }) => updateVolume(volumeId, data), + onSuccess(volume) { + // Invalidate all lists + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + // If the volume is assigned to a Linode, invalidate that Linodes's list + if (volume.linode_id) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.linode(volume.linode_id)._ctx.volumes._def, + }); + } + }, + }); +}; + +interface AttachVolumePayloadWithId extends AttachVolumePayload { + volumeId: number; +} + +export const useAttachVolumeMutation = () => { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: ({ volumeId, ...data }) => attachVolume(volumeId, data), + onSuccess(volume) { + // Invalidate all lists + queryClient.invalidateQueries({ + queryKey: volumeQueries.lists.queryKey, + }); + // If the volume is assigned to a Linode, invalidate that Linode's list + if (volume.linode_id) { + queryClient.invalidateQueries({ + queryKey: volumeQueries.linode(volume.linode_id)._ctx.volumes._def, + }); + } + }, + }); +}; + +export const useDetachVolumeMutation = () => + useMutation<{}, APIError[], { id: number }>({ + mutationFn: ({ id }) => detachVolume(id), + }); diff --git a/packages/manager/src/queries/volumesMigrations.ts b/packages/manager/src/queries/volumesMigrations.ts deleted file mode 100644 index a830304c6d5..00000000000 --- a/packages/manager/src/queries/volumesMigrations.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { APIError } from '@linode/api-v4/lib/types'; -import { - getVolumesMigrationQueue, - migrateVolumes, -} from '@linode/api-v4/lib/volumes/migrations'; -import { VolumesMigrationQueue } from '@linode/api-v4/lib/volumes/types'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; - -import { accountQueries } from './account/queries'; -import { queryPresets } from './base'; - -const queryKey = 'volumes-migrations'; - -export const useVolumesMigrationQueueQuery = ( - region: string, - enabled: boolean -) => - useQuery( - [`${queryKey}-queue`, region], - () => getVolumesMigrationQueue(region), - { ...queryPresets.shortLived, enabled } - ); - -export const useVolumesMigrateMutation = () => { - const queryClient = useQueryClient(); - - return useMutation<{}, APIError[], number[]>({ - mutationFn: migrateVolumes, - onSuccess: () => { - // If a customer "force" migrates they will then see a - // `volume_migration_imminent` notification instead of - // the `volume_migration_scheduled` notification. - setTimeout(() => { - // Refetch notifications after 1.5 seconds. The API needs some time to process. - queryClient.invalidateQueries(accountQueries.notifications.queryKey); - }, 1500); - }, - }); -};