From 37c710baf10431993d3d347a084b1cb9c7f067a0 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 14 Feb 2024 21:03:27 -0600 Subject: [PATCH] prevent import from '.' --- .eslintrc.json | 1 + libs/api/client.ts | 64 +++++++++++++++++++++++++ libs/api/index.ts | 57 +--------------------- libs/api/roles.ts | 2 +- libs/table/cells/BooleanCell.tsx | 2 +- libs/table/cells/EnabledCell.tsx | 2 +- libs/table/cells/FirewallFilterCell.tsx | 3 +- libs/table/cells/TypeValueListCell.tsx | 3 +- libs/util/math.spec.ts | 2 +- libs/util/math.ts | 2 +- 10 files changed, 75 insertions(+), 63 deletions(-) create mode 100644 libs/api/client.ts diff --git a/.eslintrc.json b/.eslintrc.json index d3e49794f7..a833779c95 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -40,6 +40,7 @@ "eqeqeq": ["error", "always", { "null": "ignore" }], "jsx-a11y/label-has-associated-control": [2, { "controlComponents": ["button"] }], "no-param-reassign": "error", + "no-restricted-imports": ["error", { "paths": ["."] }], "no-return-assign": "error", "no-unused-vars": "off", "prefer-arrow-callback": "off", diff --git a/libs/api/client.ts b/libs/api/client.ts new file mode 100644 index 0000000000..de9cf9c263 --- /dev/null +++ b/libs/api/client.ts @@ -0,0 +1,64 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * Copyright Oxide Computer Company + */ +import { QueryClient } from '@tanstack/react-query' + +import { Api } from './__generated__/Api' +import { + getUseApiMutation, + getUseApiQueries, + getUseApiQuery, + getUseApiQueryClient, + getUseApiQueryErrorsAllowed, + getUsePrefetchedApiQuery, + wrapQueryClient, +} from './hooks' + +export const api = new Api({ + // unit tests run in Node, whose fetch implementation requires a full URL + host: process.env.NODE_ENV === 'test' ? 'http://testhost' : '', +}) + +// add the API client to window for use from the browser JS console. requests +// will use the session cookie, same as normal API calls +if (typeof window !== 'undefined') { + // @ts-expect-error + window.oxide = api.methods +} + +export type ApiMethods = typeof api.methods + +export const useApiQuery = getUseApiQuery(api.methods) +export const useApiQueries = getUseApiQueries(api.methods) +/** + * Same as `useApiQuery`, except we use `invariant(data)` to ensure the data is + * already there in the cache at request time, which means it has been + * prefetched in a loader. Whenever this hook is used, there should be an e2e + * test loading the page to exercise the invariant in CI. + */ +export const usePrefetchedApiQuery = getUsePrefetchedApiQuery(api.methods) +export const useApiQueryErrorsAllowed = getUseApiQueryErrorsAllowed(api.methods) +export const useApiMutation = getUseApiMutation(api.methods) + +// Needs to be defined here instead of in app so we can use it to define +// `apiQueryClient`, which provides API-typed versions of QueryClient methods +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + staleTime: 10000, + refetchOnWindowFocus: false, + }, + }, +}) + +// to be used in loaders, which are outside the component tree and therefore +// don't have access to context +export const apiQueryClient = wrapQueryClient(api.methods, queryClient) + +// to be used to retrieve the typed query client in components +export const useApiQueryClient = getUseApiQueryClient(api.methods) diff --git a/libs/api/index.ts b/libs/api/index.ts index 53572a1287..9199d70b77 100644 --- a/libs/api/index.ts +++ b/libs/api/index.ts @@ -5,66 +5,11 @@ * * Copyright Oxide Computer Company */ -import { QueryClient } from '@tanstack/react-query' // for convenience so we can do `import type { ApiTypes } from '@oxide/api'` import type * as ApiTypes from './__generated__/Api' -import { Api } from './__generated__/Api' -import { - getUseApiMutation, - getUseApiQueries, - getUseApiQuery, - getUseApiQueryClient, - getUseApiQueryErrorsAllowed, - getUsePrefetchedApiQuery, - wrapQueryClient, -} from './hooks' - -export const api = new Api({ - // unit tests run in Node, whose fetch implementation requires a full URL - host: process.env.NODE_ENV === 'test' ? 'http://testhost' : '', -}) - -// add the API client to window for use from the browser JS console. requests -// will use the session cookie, same as normal API calls -if (typeof window !== 'undefined') { - // @ts-expect-error - window.oxide = api.methods -} - -export type ApiMethods = typeof api.methods - -export const useApiQuery = getUseApiQuery(api.methods) -export const useApiQueries = getUseApiQueries(api.methods) -/** - * Same as `useApiQuery`, except we use `invariant(data)` to ensure the data is - * already there in the cache at request time, which means it has been - * prefetched in a loader. Whenever this hook is used, there should be an e2e - * test loading the page to exercise the invariant in CI. - */ -export const usePrefetchedApiQuery = getUsePrefetchedApiQuery(api.methods) -export const useApiQueryErrorsAllowed = getUseApiQueryErrorsAllowed(api.methods) -export const useApiMutation = getUseApiMutation(api.methods) - -// Needs to be defined here instead of in app so we can use it to define -// `apiQueryClient`, which provides API-typed versions of QueryClient methods -export const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: false, - staleTime: 10000, - refetchOnWindowFocus: false, - }, - }, -}) - -// to be used in loaders, which are outside the component tree and therefore -// don't have access to context -export const apiQueryClient = wrapQueryClient(api.methods, queryClient) - -// to be used to retrieve the typed query client in components -export const useApiQueryClient = getUseApiQueryClient(api.methods) +export * from './client' export * from './roles' export * from './util' export * from './__generated__/Api' diff --git a/libs/api/roles.ts b/libs/api/roles.ts index c287fe7cc6..6359347e00 100644 --- a/libs/api/roles.ts +++ b/libs/api/roles.ts @@ -15,8 +15,8 @@ import { useMemo } from 'react' import { lowestBy, sortBy } from '@oxide/util' -import { usePrefetchedApiQuery } from '.' import type { FleetRole, IdentityType, ProjectRole, SiloRole } from './__generated__/Api' +import { usePrefetchedApiQuery } from './client' /** * Union of all the specific roles, which are all the same, which makes making diff --git a/libs/table/cells/BooleanCell.tsx b/libs/table/cells/BooleanCell.tsx index 30b66738a2..74b4cda2df 100644 --- a/libs/table/cells/BooleanCell.tsx +++ b/libs/table/cells/BooleanCell.tsx @@ -11,7 +11,7 @@ // "true" because it insists it's a boolean import { Disabled12Icon, Success12Icon } from '@oxide/ui' -import type { Cell } from '.' +import type { Cell } from './Cell' export const BooleanCell = ({ value }: Cell) => value ? ( diff --git a/libs/table/cells/EnabledCell.tsx b/libs/table/cells/EnabledCell.tsx index 7ca51941c5..4eb28bbdf8 100644 --- a/libs/table/cells/EnabledCell.tsx +++ b/libs/table/cells/EnabledCell.tsx @@ -8,7 +8,7 @@ import type { VpcFirewallRuleStatus } from '@oxide/api' import { Badge, Success12Icon } from '@oxide/ui' -import type { Cell } from '.' +import type { Cell } from './Cell' export const EnabledCell = ({ value }: Cell) => value === 'enabled' ? ( diff --git a/libs/table/cells/FirewallFilterCell.tsx b/libs/table/cells/FirewallFilterCell.tsx index 21b813b6f2..c37f82cf79 100644 --- a/libs/table/cells/FirewallFilterCell.tsx +++ b/libs/table/cells/FirewallFilterCell.tsx @@ -8,7 +8,8 @@ import type { VpcFirewallRuleFilter } from '@oxide/api' import { Badge } from '@oxide/ui' -import { TypeValueCell, type Cell } from '.' +import { type Cell } from './Cell' +import { TypeValueCell } from './TypeValueCell' export const FirewallFilterCell = ({ value: { hosts, ports, protocols }, diff --git a/libs/table/cells/TypeValueListCell.tsx b/libs/table/cells/TypeValueListCell.tsx index 7141366554..8c550cad71 100644 --- a/libs/table/cells/TypeValueListCell.tsx +++ b/libs/table/cells/TypeValueListCell.tsx @@ -5,7 +5,8 @@ * * Copyright Oxide Computer Company */ -import { TypeValueCell, type Cell, type TypeValue } from '.' +import { type Cell } from './Cell' +import { TypeValueCell, type TypeValue } from './TypeValueCell' export const TypeValueListCell = ({ value }: Cell) => (
diff --git a/libs/util/math.spec.ts b/libs/util/math.spec.ts index 5d5f743d4f..4a6226a7c6 100644 --- a/libs/util/math.spec.ts +++ b/libs/util/math.spec.ts @@ -7,8 +7,8 @@ */ import { afterAll, beforeAll, describe, expect, it } from 'vitest' -import { GiB } from '.' import { round, splitDecimal } from './math' +import { GiB } from './units' it('rounds properly', () => { expect(round(0.456, 2)).toEqual(0.46) diff --git a/libs/util/math.ts b/libs/util/math.ts index 0af7c57b17..098da77ee6 100644 --- a/libs/util/math.ts +++ b/libs/util/math.ts @@ -6,7 +6,7 @@ * Copyright Oxide Computer Company */ -import { splitOnceBy } from '.' +import { splitOnceBy } from './array' /** * Get the two parts of a number (before decimal and after-and-including