diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 565e79c35c3..00000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - root: true, - ignorePatterns: ["**/node_modules/", "**/build/"], - parser: "@typescript-eslint/parser", -}; diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 633804d3a14..0b0cd6e2a24 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -46,6 +46,7 @@ Two reviews from members of the Cloud Manager team are required before merge. Af Follow these best practices to write a good changeset: +- Summarize your changes succinctly in 150 characters or less. A changeset shouldn't describe every line of code edited in the PR. - Use a consistent tense in all changeset entries. We have chosen to use **imperative (present)** tense. (This follows established [git commit message best practices](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).) - Avoid starting a changeset with the verb "Add", "Remove", "Change" or "Fix" when listed under that respective `Added`, `Removed`, `Changed` or `Fixed` section. It is unnecessary repetition. - For `Fixed` changesets, describe the bug that needed to be fixed, rather than the fix itself. (e.g. say "Missing button labels in action buttons" rather than "Make label prop required for action buttons"). diff --git a/packages/api-v4/CHANGELOG.md b/packages/api-v4/CHANGELOG.md index 95ea0235a2a..4beb99843f3 100644 --- a/packages/api-v4/CHANGELOG.md +++ b/packages/api-v4/CHANGELOG.md @@ -1,3 +1,12 @@ +## [2025-05-20] - v0.140.0 + +### Upcoming Features: + +- Add Host & VM Maintenance types and queries ([#11990](https://github.com/linode/manager/pull/11990)) +- Add `SubnetAssignedNodeBalancerData` interface, `nodebalancers` property to `Subnet` interface, and `nodebalancer_id` property to `VCPIP` interface ([#12099](https://github.com/linode/manager/pull/12099)) +- CloudPulse: Add payload `DeleteAlertFeature` and request `deleteAlertDefinition` for handling user alert deletion ([#12134](https://github.com/linode/manager/pull/12134)) +- Add `/v4beta` endpoints and types for Node Pool requests ([#12188](https://github.com/linode/manager/pull/12188)) + ## [2025-05-06] - v0.139.0 ### Upcoming Features: diff --git a/packages/api-v4/package.json b/packages/api-v4/package.json index d1dbf13ddd7..0a96986b3ae 100644 --- a/packages/api-v4/package.json +++ b/packages/api-v4/package.json @@ -1,6 +1,6 @@ { "name": "@linode/api-v4", - "version": "0.139.0", + "version": "0.140.0", "homepage": "https://github.com/linode/manager/tree/develop/packages/api-v4", "bugs": { "url": "https://github.com/linode/manager/issues" diff --git a/packages/api-v4/src/account/account.ts b/packages/api-v4/src/account/account.ts index b612da3d082..d423c840c3b 100644 --- a/packages/api-v4/src/account/account.ts +++ b/packages/api-v4/src/account/account.ts @@ -2,27 +2,29 @@ import { updateAccountSchema, UpdateAccountSettingsSchema, } from '@linode/validation/lib/account.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, setHeaders, setMethod, - setURL, setParams, + setURL, setXFilter, } from '../request'; -import { + +import type { Token } from '../profile'; +import type { Filter, Params, RequestOptions, ResourcePage } from '../types'; +import type { Account, AccountAvailability, AccountSettings, + Agreements, CancelAccount, CancelAccountPayload, - Agreements, - RegionalNetworkUtilization, ChildAccountPayload, + RegionalNetworkUtilization, } from './types'; -import type { Filter, ResourcePage, Params, RequestOptions } from '../types'; -import type { Token } from '../profile'; /** * getAccountInfo @@ -44,7 +46,7 @@ export const getAccountInfo = () => { export const getNetworkUtilization = () => Request( setURL(`${API_ROOT}/account/transfer`), - setMethod('GET') + setMethod('GET'), ); /** @@ -57,7 +59,7 @@ export const updateAccountInfo = (data: Partial) => Request( setURL(`${API_ROOT}/account`), setMethod('PUT'), - setData(data, updateAccountSchema) + setData(data, updateAccountSchema), ); /** @@ -69,7 +71,7 @@ export const updateAccountInfo = (data: Partial) => export const getAccountSettings = () => Request( setURL(`${API_ROOT}/account/settings`), - setMethod('GET') + setMethod('GET'), ); /** @@ -82,7 +84,7 @@ export const updateAccountSettings = (data: Partial) => Request( setURL(`${API_ROOT}/account/settings`), setMethod('PUT'), - setData(data, UpdateAccountSettingsSchema) + setData(data, UpdateAccountSettingsSchema), ); /** @@ -94,7 +96,7 @@ export const cancelAccount = (data: CancelAccountPayload) => { return Request( setURL(`${API_ROOT}/account/cancel`), setMethod('POST'), - setData(data) + setData(data), ); }; @@ -107,7 +109,7 @@ export const cancelAccount = (data: CancelAccountPayload) => { export const getAccountAgreements = () => Request( setURL(`${BETA_API_ROOT}/account/agreements`), - setMethod('GET') + setMethod('GET'), ); /** @@ -122,7 +124,7 @@ export const getAccountAvailabilities = (params?: Params, filter?: Filter) => setURL(`${BETA_API_ROOT}/account/availability`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -135,9 +137,9 @@ export const getAccountAvailabilities = (params?: Params, filter?: Filter) => export const getAccountAvailability = (regionId: string) => Request( setURL( - `${BETA_API_ROOT}/account/availability/${encodeURIComponent(regionId)}` + `${BETA_API_ROOT}/account/availability/${encodeURIComponent(regionId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -149,7 +151,7 @@ export const signAgreement = (data: Partial) => { return Request<{}>( setURL(`${BETA_API_ROOT}/account/agreements`), setMethod('POST'), - setData(data) + setData(data), ); }; @@ -165,7 +167,7 @@ export const getChildAccounts = ({ filter, params, headers }: RequestOptions) => setMethod('GET'), setHeaders(headers), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -178,7 +180,7 @@ export const getChildAccount = ({ euuid, headers }: ChildAccountPayload) => Request( setURL(`${API_ROOT}/account/child-accounts/${encodeURIComponent(euuid)}`), setMethod('GET'), - setHeaders(headers) + setHeaders(headers), ); /** @@ -198,9 +200,9 @@ export const createChildAccountPersonalAccessToken = ({ }: ChildAccountPayload) => Request( setURL( - `${API_ROOT}/account/child-accounts/${encodeURIComponent(euuid)}/token` + `${API_ROOT}/account/child-accounts/${encodeURIComponent(euuid)}/token`, ), setMethod('POST'), setHeaders(headers), - setData(euuid) + setData(euuid), ); diff --git a/packages/api-v4/src/account/betas.ts b/packages/api-v4/src/account/betas.ts index 5b184ac5beb..6cd1ec93985 100644 --- a/packages/api-v4/src/account/betas.ts +++ b/packages/api-v4/src/account/betas.ts @@ -1,13 +1,14 @@ import { API_ROOT } from '../constants'; import Request, { + setData, setMethod, setParams, setURL, setXFilter, - setData, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { AccountBeta, EnrollInBetaPayload } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { AccountBeta, EnrollInBetaPayload } from './types'; /** * getBetas @@ -19,7 +20,7 @@ export const getAccountBetas = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/betas`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -31,7 +32,7 @@ export const getAccountBetas = (params?: Params, filter?: Filter) => export const getAccountBeta = (betaId: string) => Request( setURL(`${API_ROOT}/account/betas/${encodeURIComponent(betaId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -45,5 +46,5 @@ export const enrollInBeta = (data: EnrollInBetaPayload) => Request<{}>( setURL(`${API_ROOT}/account/betas`), setMethod('POST'), - setData(data) + setData(data), ); diff --git a/packages/api-v4/src/account/events.ts b/packages/api-v4/src/account/events.ts index f2e1fdc5b04..1cf4934a3f3 100644 --- a/packages/api-v4/src/account/events.ts +++ b/packages/api-v4/src/account/events.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { Event, Notification } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { Event, Notification } from './types'; /** * getEvents @@ -14,7 +15,7 @@ export const getEvents = (params: Params = {}, filter: Filter = {}) => setURL(`${API_ROOT}/account/events`), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -26,7 +27,7 @@ export const getEvents = (params: Params = {}, filter: Filter = {}) => export const getEvent = (eventId: number) => Request( setURL(`${API_ROOT}/account/events/${encodeURIComponent(eventId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -39,7 +40,7 @@ export const getEvent = (eventId: number) => export const markEventSeen = (eventId: number) => Request<{}>( setURL(`${API_ROOT}/account/events/${encodeURIComponent(eventId)}/seen`), - setMethod('POST') + setMethod('POST'), ); /** @@ -53,7 +54,7 @@ export const markEventSeen = (eventId: number) => export const markEventRead = (eventId: number) => Request<{}>( setURL(`${API_ROOT}/account/events/${encodeURIComponent(eventId)}/read`), - setMethod('POST') + setMethod('POST'), ); /** @@ -67,5 +68,5 @@ export const getNotifications = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/notifications`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); diff --git a/packages/api-v4/src/account/index.ts b/packages/api-v4/src/account/index.ts index 9674eae1fc2..3b79af0abfd 100644 --- a/packages/api-v4/src/account/index.ts +++ b/packages/api-v4/src/account/index.ts @@ -6,16 +6,16 @@ export * from './events'; export * from './invoices'; -export * from './payments'; +export * from './logins'; -export * from './users'; +export * from './maintenance'; export * from './oauth'; +export * from './payments'; + export * from './promos'; export * from './types'; -export * from './maintenance'; - -export * from './logins'; +export * from './users'; diff --git a/packages/api-v4/src/account/invoices.ts b/packages/api-v4/src/account/invoices.ts index 97fed621db2..bc951a65571 100644 --- a/packages/api-v4/src/account/invoices.ts +++ b/packages/api-v4/src/account/invoices.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { Invoice, InvoiceItem } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { Invoice, InvoiceItem } from './types'; /** * getInvoices @@ -14,7 +15,7 @@ export const getInvoices = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/invoices`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -28,7 +29,7 @@ export const getInvoices = (params?: Params, filter?: Filter) => export const getInvoice = (invoiceId: number) => Request( setURL(`${API_ROOT}/account/invoices/${encodeURIComponent(invoiceId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -43,13 +44,13 @@ export const getInvoice = (invoiceId: number) => export const getInvoiceItems = ( invoiceId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( - `${API_ROOT}/account/invoices/${encodeURIComponent(invoiceId)}/items` + `${API_ROOT}/account/invoices/${encodeURIComponent(invoiceId)}/items`, ), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); diff --git a/packages/api-v4/src/account/logins.ts b/packages/api-v4/src/account/logins.ts index 478140182ed..d05c942c662 100644 --- a/packages/api-v4/src/account/logins.ts +++ b/packages/api-v4/src/account/logins.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { AccountLogin } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { AccountLogin } from './types'; /** * getAccountLogins @@ -14,7 +15,7 @@ export const getAccountLogins = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/logins`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -28,5 +29,5 @@ export const getAccountLogins = (params?: Params, filter?: Filter) => export const getAccountLogin = (loginId: number) => Request( setURL(`${API_ROOT}/account/logins/${encodeURIComponent(loginId)}`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/account/maintenance.ts b/packages/api-v4/src/account/maintenance.ts index acf22f44c8d..335022e5ca4 100644 --- a/packages/api-v4/src/account/maintenance.ts +++ b/packages/api-v4/src/account/maintenance.ts @@ -1,7 +1,8 @@ -import { API_ROOT } from '../constants'; +import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { AccountMaintenance } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { AccountMaintenance, MaintenancePolicy } from './types'; /** * getAccountMaintenance @@ -14,5 +15,17 @@ export const getAccountMaintenance = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/maintenance`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), + ); + +/** + * getMaintenancePolicies + * + * Returns a list of maintenance policies that are available for Linodes in this account. + * + */ +export const getMaintenancePolicies = () => + Request( + setURL(`${BETA_API_ROOT}/maintenance/policies`), + setMethod('GET'), ); diff --git a/packages/api-v4/src/account/oauth.ts b/packages/api-v4/src/account/oauth.ts index 7fe61509ddc..4090da1aa43 100644 --- a/packages/api-v4/src/account/oauth.ts +++ b/packages/api-v4/src/account/oauth.ts @@ -2,6 +2,7 @@ import { createOAuthClientSchema, updateOAuthClientSchema, } from '@linode/validation/lib/account.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,8 +11,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { OAuthClient, OAuthClientRequest } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { OAuthClient, OAuthClientRequest } from './types'; /** * getOAuthClients @@ -24,7 +26,7 @@ export const getOAuthClients = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/oauth-clients`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -38,7 +40,7 @@ export const getOAuthClients = (params?: Params, filter?: Filter) => export const getOAuthClient = (clientId: number) => Request( setURL(`${API_ROOT}/account/oauth-clients/${encodeURIComponent(clientId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -59,7 +61,7 @@ export const createOAuthClient = (data: OAuthClientRequest) => Request( setURL(`${API_ROOT}/account/oauth-clients`), setMethod('POST'), - setData(data, createOAuthClientSchema) + setData(data, createOAuthClientSchema), ); /** @@ -76,10 +78,10 @@ export const resetOAuthClientSecret = (clientId: number | string) => Request( setURL( `${API_ROOT}/account/oauth-clients/${encodeURIComponent( - clientId - )}/reset-secret` + clientId, + )}/reset-secret`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -91,12 +93,12 @@ export const resetOAuthClientSecret = (clientId: number | string) => */ export const updateOAuthClient = ( clientId: string, - data: Partial + data: Partial, ) => Request( setURL(`${API_ROOT}/account/oauth-clients/${encodeURIComponent(clientId)}`), setMethod('PUT'), - setData(data, updateOAuthClientSchema) + setData(data, updateOAuthClientSchema), ); /** @@ -114,5 +116,5 @@ export const updateOAuthClient = ( export const deleteOAuthClient = (clientId: number | string) => Request<{}>( setURL(`${API_ROOT}/account/oauth-clients/${encodeURIComponent(clientId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/account/payments.ts b/packages/api-v4/src/account/payments.ts index c1a9aad90d4..ac8fbd1ae7d 100644 --- a/packages/api-v4/src/account/payments.ts +++ b/packages/api-v4/src/account/payments.ts @@ -1,8 +1,9 @@ import { CreditCardSchema, - PaymentSchema, PaymentMethodSchema, + PaymentSchema, } from '@linode/validation/lib/account.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -11,15 +12,16 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { + +import type { Filter, Params, ResourcePage } from '../types'; +import type { ClientToken, + MakePaymentData, Payment, PaymentMethod, + PaymentMethodPayload, PaymentResponse, SaveCreditCardData, - MakePaymentData, - PaymentMethodPayload, } from './types'; /** @@ -34,7 +36,7 @@ export const getPayments = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/account/payments`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -77,7 +79,7 @@ export const makePayment = (data: MakePaymentData) => { return Request( setURL(`${API_ROOT}/account/payments`), setMethod('POST'), - setData(data, PaymentSchema) + setData(data, PaymentSchema), ); }; @@ -93,7 +95,7 @@ export const saveCreditCard = (data: SaveCreditCardData) => { return Request<{}>( setURL(`${API_ROOT}/account/credit-card`), setMethod('POST'), - setData(data, CreditCardSchema) + setData(data, CreditCardSchema), ); }; @@ -108,7 +110,7 @@ export const getPaymentMethods = (params?: Params) => { return Request>( setURL(`${API_ROOT}/account/payment-methods`), setMethod('GET'), - setParams(params) + setParams(params), ); }; @@ -124,7 +126,7 @@ export const getPaymentMethods = (params?: Params) => { export const getPaymentMethod = (id: number) => { return Request( setURL(`${API_ROOT}/account/payment-method/${encodeURIComponent(id)}`), - setMethod('GET') + setMethod('GET'), ); }; @@ -138,7 +140,7 @@ export const getPaymentMethod = (id: number) => { export const getClientToken = () => { return Request( setURL(`${API_ROOT}/account/client-token`), - setMethod('GET') + setMethod('GET'), ); }; @@ -159,10 +161,10 @@ export const getClientToken = () => { * */ export const addPaymentMethod = (data: PaymentMethodPayload) => { - return Request<{}>( + return Request>( setURL(`${API_ROOT}/account/payment-methods`), setMethod('POST'), - setData(data, PaymentMethodSchema) + setData(data, PaymentMethodSchema), ); }; @@ -177,10 +179,10 @@ export const makeDefaultPaymentMethod = (id: number) => { return Request<{}>( setURL( `${API_ROOT}/account/payment-methods/${encodeURIComponent( - id - )}/make-default` + id, + )}/make-default`, ), - setMethod('POST') + setMethod('POST'), ); }; @@ -194,6 +196,6 @@ export const makeDefaultPaymentMethod = (id: number) => { export const deletePaymentMethod = (id: number) => { return Request<{}>( setURL(`${API_ROOT}/account/payment-methods/${encodeURIComponent(id)}`), - setMethod('DELETE') + setMethod('DELETE'), ); }; diff --git a/packages/api-v4/src/account/promos.ts b/packages/api-v4/src/account/promos.ts index 865c2c9656f..e76a86f3800 100644 --- a/packages/api-v4/src/account/promos.ts +++ b/packages/api-v4/src/account/promos.ts @@ -1,7 +1,9 @@ import { PromoCodeSchema } from '@linode/validation/lib/account.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { ActivePromotion } from './types'; + +import type { ActivePromotion } from './types'; /** * addPromotion @@ -17,5 +19,5 @@ export const addPromotion = (code: string) => Request( setURL(`${API_ROOT}/account/promo-codes`), setMethod('POST'), - setData({ promo_code: code }, PromoCodeSchema) + setData({ promo_code: code }, PromoCodeSchema), ); diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts index 1611c429d4a..e112e3ac1ea 100644 --- a/packages/api-v4/src/account/types.ts +++ b/packages/api-v4/src/account/types.ts @@ -1,7 +1,7 @@ -import type { APIWarning, RequestOptions } from '../types'; import type { Capabilities, Region } from '../regions'; +import type { APIWarning, RequestOptions } from '../types'; -export type UserType = 'child' | 'parent' | 'proxy' | 'default'; +export type UserType = 'child' | 'default' | 'parent' | 'proxy'; export interface User { email: string; @@ -9,7 +9,7 @@ export interface User { * Information for the most recent login attempt for this User. * `null` if no login attempts have been made since creation of this User. */ - last_login: { + last_login: null | { /** * @example 2022-02-09T16:19:26 */ @@ -18,46 +18,46 @@ export interface User { * @example successful */ status: AccountLoginStatus; - } | null; + }; /** * The date of when a password was set on a user. * `null` if this user has not created a password yet * @example 2022-02-09T16:19:26 * @example null */ - password_created: string | null; + password_created: null | string; restricted: boolean; ssh_keys: string[]; tfa_enabled: boolean; - username: string; user_type: UserType; - verified_phone_number: string | null; + username: string; + verified_phone_number: null | string; } export interface Account { + active_promotions: ActivePromotion[]; active_since: string; - address_2: string; - email: string; - first_name: string; - tax_id: string; - credit_card: CreditCardData; - state: string; - zip: string; address_1: string; - country: string; - last_name: string; + address_2: string; balance: number; balance_uninvoiced: number; billing_source: BillingSource; + capabilities: AccountCapability[]; city: string; - phone: string; company: string; - active_promotions: ActivePromotion[]; - capabilities: AccountCapability[]; + country: string; + credit_card: CreditCardData; + email: string; euuid: string; + first_name: string; + last_name: string; + phone: string; + state: string; + tax_id: string; + zip: string; } -export type BillingSource = 'linode' | 'akamai'; +export type BillingSource = 'akamai' | 'linode'; export const accountCapabilities = [ 'Akamai Cloud Load Balancer', @@ -106,23 +106,24 @@ export type LinodeInterfaceAccountSetting = (typeof linodeInterfaceAccountSettings)[number]; export interface AccountSettings { + backups_enabled: boolean; + interfaces_for_new_linodes: LinodeInterfaceAccountSetting; + longview_subscription: null | string; + maintenance_policy_id: MaintenancePolicyId; managed: boolean; - longview_subscription: string | null; network_helper: boolean; - backups_enabled: boolean; object_storage: 'active' | 'disabled' | 'suspended'; - interfaces_for_new_linodes: LinodeInterfaceAccountSetting; } export interface ActivePromotion { - description: string; - summary: string; - expire_dt: string | null; - credit_remaining: string; - this_month_credit_remaining: string; credit_monthly_cap: string; + credit_remaining: string; + description: string; + expire_dt: null | string; image_url: string; service_type: PromotionServiceType; + summary: string; + this_month_credit_remaining: string; } export type PromotionServiceType = @@ -143,45 +144,45 @@ export type PromotionServiceType = export type ThirdPartyPayment = 'google_pay' | 'paypal'; export type CardType = - | 'Visa' - | 'MasterCard' | 'American Express' | 'Discover' - | 'JCB'; + | 'JCB' + | 'MasterCard' + | 'Visa'; export type PaymentType = 'credit_card' | ThirdPartyPayment; export interface TaxSummary { - tax: number; name: string; + tax: number; } export interface Invoice { - id: number; date: string; + id: number; label: string; - total: number; - tax: number; subtotal: number; + tax: number; tax_summary: TaxSummary[]; + total: number; } export interface InvoiceItem { amount: number; from: null | string; - to: null | string; label: string; quantity: null | number; - type: 'hourly' | 'prepay' | 'misc'; - unit_price: null | string; + region: null | string; tax: number; + to: null | string; total: number; - region: string | null; + type: 'hourly' | 'misc' | 'prepay'; + unit_price: null | string; } export interface Payment { - id: number; date: string; + id: number; usd: number; } @@ -189,30 +190,30 @@ export interface PaymentResponse extends Payment { warnings?: APIWarning[]; } -export type GrantLevel = null | 'read_only' | 'read_write'; +export type GrantLevel = 'read_only' | 'read_write' | null; export interface Grant { id: number; - permissions: GrantLevel; label: string; + permissions: GrantLevel; } export type GlobalGrantTypes = | 'account_access' + | 'add_buckets' | 'add_databases' | 'add_domains' | 'add_firewalls' | 'add_images' + | 'add_kubernetes' | 'add_linodes' + | 'add_lkes' | 'add_longview' - | 'add_databases' - | 'add_kubernetes' | 'add_nodebalancers' | 'add_stackscripts' | 'add_volumes' | 'add_vpcs' | 'cancel_account' | 'child_account_access' - | 'add_buckets' | 'longview_subscription'; export interface GlobalGrants { @@ -220,23 +221,24 @@ export interface GlobalGrants { } export type GrantType = - | 'linode' + | 'database' | 'domain' - | 'nodebalancer' + | 'firewall' | 'image' + | 'linode' + | 'lkecluster' | 'longview' + | 'nodebalancer' | 'stackscript' | 'volume' - | 'database' - | 'firewall' | 'vpc'; export type Grants = GlobalGrants & Record; export interface NetworkUtilization { billable: number; - used: number; quota: number; + used: number; } export interface RegionalNetworkUtilization extends NetworkUtilization { region_transfers: RegionalTransferObject[]; @@ -266,45 +268,47 @@ export interface ChildAccountPayload extends RequestOptions { export type AgreementType = 'eu_model' | 'privacy_policy'; export interface Agreements { + billing_agreement: boolean; eu_model: boolean; privacy_policy: boolean; - billing_agreement: boolean; } export type NotificationType = | 'billing_email_bounce' - | 'migration_scheduled' - | 'migration_pending' - | 'reboot_scheduled' - | 'outage' | 'maintenance' + | 'maintenance_in_progress' + | 'maintenance_pending' | 'maintenance_scheduled' - | 'payment_due' - | 'ticket_important' - | 'ticket_abuse' + | 'migration_pending' + | 'migration_scheduled' | 'notice' + | 'outage' + | 'payment_due' | 'promotion' + | 'reboot_scheduled' + | 'tax_id_verifying' + | 'ticket_abuse' + | 'ticket_important' | 'user_email_bounce' - | 'volume_migration_scheduled' | 'volume_migration_imminent' - | 'tax_id_verifying'; + | 'volume_migration_scheduled'; -export type NotificationSeverity = 'minor' | 'major' | 'critical'; +export type NotificationSeverity = 'critical' | 'major' | 'minor'; export interface Notification { - entity: null | Entity; + body: null | string; + entity: Entity | null; label: string; message: string; - type: NotificationType; severity: NotificationSeverity; - when: null | string; + type: NotificationType; until: null | string; - body: null | string; + when: null | string; } export interface Entity { id: number; - label: string | null; + label: null | string; type: string; url: string; } @@ -395,6 +399,7 @@ export const EventActionKeys = [ 'linode_migrate', 'linode_mutate_create', 'linode_mutate', + 'linode_poweroff_on', 'linode_reboot', 'linode_rebuild', 'linode_resize_create', @@ -499,30 +504,38 @@ export const EventActionKeys = [ export type EventAction = (typeof EventActionKeys)[number]; export type EventStatus = - | 'scheduled' - | 'started' - | 'finished' | 'failed' - | 'notification'; + | 'finished' + | 'notification' + | 'scheduled' + | 'started'; + +export type EventSource = 'platform' | 'user'; export interface Event { - id: number; action: EventAction; + complete_time?: null | string; // @TODO VM & Host Maintenance: verify new fields created: string; - entity: Entity | null; + description?: null | string; // @TODO VM & Host Maintenance: verify new fields /* NOTE: events before the duration key was added will have a duration of 0 */ - duration: number | null; - percent_complete: number | null; - rate: string | null; + duration: null | number; + entity: Entity | null; + id: number; + maintenance_policy_set?: MaintenancePolicyType | null; // @TODO VM & Host Maintenance: verify new fields + message: null | string; + not_before?: null | string; // @TODO VM & Host Maintenance: verify new fields + percent_complete: null | number; + rate: null | string; read: boolean; + secondary_entity: Entity | null; seen: boolean; + source?: EventSource | null; // @TODO VM & Host Maintenance: verify new fields + start_time?: null | string; // @TODO VM & Host Maintenance: verify new fields status: EventStatus; time_remaining: null | string; - username: string | null; - secondary_entity: Entity | null; - message: string | null; + username: null | string; } /** * Represents an event which has an entity. For use with type guards. @@ -535,59 +548,88 @@ export interface EntityEvent extends Event { export interface OAuthClient { id: string; label: string; - redirect_uri: string; - thumbnail_url: string | null; public: boolean; - status: 'disabled' | 'active' | 'suspended'; + redirect_uri: string; secret: string; + status: 'active' | 'disabled' | 'suspended'; + thumbnail_url: null | string; } export interface OAuthClientRequest { label: string; - redirect_uri: string; public?: boolean; + redirect_uri: string; } export interface SaveCreditCardData { card_number: string; - expiry_year: number; - expiry_month: number; cvv: string; + expiry_month: number; + expiry_year: number; } export interface AccountMaintenance { - reason: string; - status: 'pending' | 'started' | 'completed'; - type: 'reboot' | 'cold_migration' | 'live_migration' | 'volume_migration'; - when: string; + complete_time: string; + description: string; entity: { id: number; label: string; type: string; url: string; }; + maintenance_policy_set: MaintenancePolicyType; + not_before: string; + reason: string; + source: 'platform' | 'user'; + start_time: string; + status: + | 'canceled' + | 'completed' + | 'in-progress' + | 'pending' + | 'scheduled' + | 'started'; + type: 'cold_migration' | 'live_migration' | 'reboot' | 'volume_migration'; + when: string; } +export const maintenancePolicies = [ + { id: 1, type: 'migrate' }, + { id: 2, type: 'power on/off' }, +] as const; + +export type MaintenancePolicyId = (typeof maintenancePolicies)[number]['id']; + +export type MaintenancePolicyType = + (typeof maintenancePolicies)[number]['type']; + +export type MaintenancePolicy = (typeof maintenancePolicies)[number] & { + description: string; + is_default: boolean; + name: string; + notification_period_sec: number; +}; + export interface PayPalData { - paypal_id: string; email: string; + paypal_id: string; } export interface CreditCardData { - expiry: string | null; - last_four: string | null; card_type?: CardType; + expiry: null | string; + last_four: null | string; } interface PaymentMethodMetaData { + created: string; id: number; is_default: boolean; - created: string; } interface PaymentMethodData extends PaymentMethodMetaData { - type: T; data: U; + type: T; } export type PaymentMethod = @@ -599,40 +641,40 @@ export interface ClientToken { } export interface PaymentMethodPayload { - type: 'credit_card' | 'payment_method_nonce'; data: SaveCreditCardData | { nonce: string }; is_default: boolean; + type: 'credit_card' | 'payment_method_nonce'; } export interface MakePaymentData { - usd: string; cvv?: string; nonce?: string; payment_method_id?: number; + usd: string; } -export type AccountLoginStatus = 'successful' | 'failed'; +export type AccountLoginStatus = 'failed' | 'successful'; export interface AccountLogin { datetime: string; id: number; ip: string; restricted: boolean; - username: string; status: AccountLoginStatus; + username: string; } export interface AccountBeta { - label: string; - started: string; - id: string; - ended: string | null; - description: string | null; + description: null | string; + ended: null | string; /** * The datetime the account enrolled into the beta * @example 2024-10-23T14:22:29 */ enrolled: string; + id: string; + label: string; + started: string; } export interface EnrollInBetaPayload { diff --git a/packages/api-v4/src/account/users.ts b/packages/api-v4/src/account/users.ts index 0856fd3c7cd..c6c9e83077a 100644 --- a/packages/api-v4/src/account/users.ts +++ b/packages/api-v4/src/account/users.ts @@ -2,6 +2,7 @@ import { CreateUserSchema, UpdateUserSchema, } from '@linode/validation/lib/account.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,8 +11,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { Grants, User } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { Grants, User } from './types'; /** * getUsers @@ -24,7 +26,7 @@ export const getUsers = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/account/users`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -39,7 +41,7 @@ export const getUsers = (params?: Params, filters?: Filter) => export const getUser = (username: string) => Request( setURL(`${API_ROOT}/account/users/${encodeURIComponent(username)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -54,7 +56,7 @@ export const createUser = (data: Partial) => Request( setURL(`${API_ROOT}/account/users`), setMethod('POST'), - setData(data, CreateUserSchema) + setData(data, CreateUserSchema), ); /** @@ -71,7 +73,7 @@ export const updateUser = (username: string, data: Partial) => Request( setURL(`${API_ROOT}/account/users/${encodeURIComponent(username)}`), setMethod('PUT'), - setData(data, UpdateUserSchema) + setData(data, UpdateUserSchema), ); /** @@ -86,7 +88,7 @@ export const updateUser = (username: string, data: Partial) => export const deleteUser = (username: string) => Request<{}>( setURL(`${API_ROOT}/account/users/${encodeURIComponent(username)}`), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -103,7 +105,7 @@ export const deleteUser = (username: string) => export const getGrants = (username: string) => Request( setURL(`${API_ROOT}/account/users/${encodeURIComponent(username)}/grants`), - setMethod('GET') + setMethod('GET'), ); /** @@ -122,5 +124,5 @@ export const updateGrants = (username: string, data: Partial) => Request( setURL(`${API_ROOT}/account/users/${encodeURIComponent(username)}/grants`), setMethod('PUT'), - setData(data) + setData(data), ); diff --git a/packages/api-v4/src/betas/betas.ts b/packages/api-v4/src/betas/betas.ts index 27421f0b90c..873d62c3f31 100644 --- a/packages/api-v4/src/betas/betas.ts +++ b/packages/api-v4/src/betas/betas.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { Beta } from './types'; + +import type { Filter, Params, ResourcePage } from '../types'; +import type { Beta } from './types'; /** * getBetas @@ -14,7 +15,7 @@ export const getBetas = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/betas`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -28,5 +29,5 @@ export const getBetas = (params?: Params, filter?: Filter) => export const getBeta = (betaId: string) => Request( setURL(`${API_ROOT}/betas/${encodeURIComponent(betaId)}`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/betas/index.ts b/packages/api-v4/src/betas/index.ts index 9dc8cc15670..7b96423dcd1 100644 --- a/packages/api-v4/src/betas/index.ts +++ b/packages/api-v4/src/betas/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './betas'; + +export * from './types'; diff --git a/packages/api-v4/src/betas/types.ts b/packages/api-v4/src/betas/types.ts index b0202aa6e2d..1364e59dd09 100644 --- a/packages/api-v4/src/betas/types.ts +++ b/packages/api-v4/src/betas/types.ts @@ -1,8 +1,8 @@ export interface Beta { - label: string; - started: string; - id: string; + description?: string; ended?: string; + id: string; + label: string; more_info?: string; - description?: string; + started: string; } diff --git a/packages/api-v4/src/cloudpulse/alerts.ts b/packages/api-v4/src/cloudpulse/alerts.ts index 1eb2d6232fb..bdb3378efec 100644 --- a/packages/api-v4/src/cloudpulse/alerts.ts +++ b/packages/api-v4/src/cloudpulse/alerts.ts @@ -2,35 +2,37 @@ import { createAlertDefinitionSchema, editAlertDefinitionSchema, } from '@linode/validation'; + +import { BETA_API_ROOT as API_ROOT } from '../constants'; import Request, { - setURL, - setMethod, setData, + setMethod, setParams, + setURL, setXFilter, } from '../request'; -import { + +import type { Filter, Params, ResourcePage } from '../types'; +import type { Alert, AlertServiceType, CreateAlertDefinitionPayload, EditAlertDefinitionPayload, NotificationChannel, } from './types'; -import { BETA_API_ROOT as API_ROOT } from '../constants'; -import { Params, Filter, ResourcePage } from '../types'; export const createAlertDefinition = ( data: CreateAlertDefinitionPayload, - serviceType: AlertServiceType + serviceType: AlertServiceType, ) => Request( setURL( `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType! - )}/alert-definitions` + serviceType!, + )}/alert-definitions`, ), setMethod('POST'), - setData(data, createAlertDefinitionSchema) + setData(data, createAlertDefinitionSchema), ); export const getAlertDefinitions = (params?: Params, filters?: Filter) => @@ -38,20 +40,20 @@ export const getAlertDefinitions = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/monitor/alert-definitions`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); export const getAlertDefinitionByServiceTypeAndId = ( serviceType: string, - alertId: string + alertId: string, ) => Request( setURL( `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/alert-definitions/${encodeURIComponent(alertId)}` + serviceType, + )}/alert-definitions/${encodeURIComponent(alertId)}`, ), - setMethod('GET') + setMethod('GET'), ); export const editAlertDefinition = ( @@ -73,46 +75,54 @@ export const getNotificationChannels = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/monitor/alert-channels`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); export const getAlertDefinitionByServiceType = (serviceType: string) => Request>( setURL( `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/alert-definitions` + serviceType, + )}/alert-definitions`, ), - setMethod('GET') + setMethod('GET'), ); export const addEntityToAlert = ( serviceType: string, entityId: string, - data: { 'alert-definition-id': number } + data: { 'alert-definition-id': number }, ) => Request<{}>( setURL( `${API_ROOT}/monitor/service/${encodeURIComponent( - serviceType - )}/entity/${encodeURIComponent(entityId)}/alert-definition` + serviceType, + )}/entity/${encodeURIComponent(entityId)}/alert-definition`, ), setMethod('POST'), - setData(data) + setData(data), ); export const deleteEntityFromAlert = ( serviceType: string, entityId: string, - alertId: number + alertId: number, ) => Request<{}>( setURL( `${API_ROOT}/monitor/service/${encodeURIComponent( - serviceType + serviceType, )}/entity/${encodeURIComponent( - entityId - )}/alert-definition/${encodeURIComponent(alertId)}` + entityId, + )}/alert-definition/${encodeURIComponent(alertId)}`, + ), + setMethod('DELETE'), + ); + +export const deleteAlertDefinition = (serviceType: string, alertId: number) => + Request( + setURL( + `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/alert-definitions/${encodeURIComponent(alertId)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/cloudpulse/dashboards.ts b/packages/api-v4/src/cloudpulse/dashboards.ts index c8802747e52..9a84a74aabd 100644 --- a/packages/api-v4/src/cloudpulse/dashboards.ts +++ b/packages/api-v4/src/cloudpulse/dashboards.ts @@ -1,21 +1,23 @@ -import { ResourcePage } from 'src/types'; -import Request, { setMethod, setURL } from '../request'; -import { Dashboard } from './types'; import { BETA_API_ROOT as API_ROOT } from 'src/constants'; +import Request, { setMethod, setURL } from '../request'; + +import type { Dashboard } from './types'; +import type { ResourcePage } from 'src/types'; + // Returns the list of all the dashboards available export const getDashboards = (serviceType: string) => Request>( setURL( `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/dashboards` + serviceType, + )}/dashboards`, ), - setMethod('GET') + setMethod('GET'), ); export const getDashboardById = (dashboardId: number) => Request( setURL(`${API_ROOT}/monitor/dashboards/${encodeURIComponent(dashboardId)}`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/cloudpulse/index.ts b/packages/api-v4/src/cloudpulse/index.ts index 72a80c197e5..2c383d94abc 100644 --- a/packages/api-v4/src/cloudpulse/index.ts +++ b/packages/api-v4/src/cloudpulse/index.ts @@ -1,7 +1,7 @@ -export * from './types'; +export * from './alerts'; export * from './dashboards'; export * from './services'; -export * from './alerts'; +export * from './types'; diff --git a/packages/api-v4/src/cloudpulse/services.ts b/packages/api-v4/src/cloudpulse/services.ts index bab5c965a99..3ee4c309661 100644 --- a/packages/api-v4/src/cloudpulse/services.ts +++ b/packages/api-v4/src/cloudpulse/services.ts @@ -1,4 +1,5 @@ import { BETA_API_ROOT as API_ROOT } from 'src/constants'; + import Request, { setData, setMethod, @@ -6,43 +7,44 @@ import Request, { setURL, setXFilter, } from '../request'; -import { + +import type { JWEToken, JWETokenPayLoad, MetricDefinition, ServiceTypesList, } from './types'; -import { Filter, Params, ResourcePage } from 'src/types'; +import type { Filter, Params, ResourcePage } from 'src/types'; export const getMetricDefinitionsByServiceType = ( serviceType: string, params?: Params, - filters?: Filter + filters?: Filter, ) => { return Request>( setURL( `${API_ROOT}/monitor/services/${encodeURIComponent( - serviceType - )}/metric-definitions` + serviceType, + )}/metric-definitions`, ), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); }; export const getJWEToken = (data: JWETokenPayLoad, serviceType: string) => Request( setURL( - `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token` + `${API_ROOT}/monitor/services/${encodeURIComponent(serviceType)}/token`, ), setMethod('POST'), - setData(data) + setData(data), ); // Returns the list of service types available export const getCloudPulseServiceTypes = () => Request( setURL(`${API_ROOT}/monitor/services`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/cloudpulse/types.ts b/packages/api-v4/src/cloudpulse/types.ts index 5fe095d8566..7636bcdb8d3 100644 --- a/packages/api-v4/src/cloudpulse/types.ts +++ b/packages/api-v4/src/cloudpulse/types.ts @@ -1,47 +1,47 @@ export type AlertSeverityType = 0 | 1 | 2 | 3; -export type MetricAggregationType = 'avg' | 'sum' | 'min' | 'max' | 'count'; -export type MetricOperatorType = 'eq' | 'gt' | 'lt' | 'gte' | 'lte'; -export type AlertServiceType = 'linode' | 'dbaas'; +export type MetricAggregationType = 'avg' | 'count' | 'max' | 'min' | 'sum'; +export type MetricOperatorType = 'eq' | 'gt' | 'gte' | 'lt' | 'lte'; +export type AlertServiceType = 'dbaas' | 'linode'; export type AlertClass = 'dedicated' | 'shared'; export type DimensionFilterOperatorType = + | 'endswith' | 'eq' | 'neq' - | 'startswith' - | 'endswith'; + | 'startswith'; export type AlertDefinitionType = 'system' | 'user'; -export type AlertStatusType = 'enabled' | 'disabled' | 'in progress' | 'failed'; +export type AlertStatusType = 'disabled' | 'enabled' | 'failed' | 'in progress'; export type CriteriaConditionType = 'ALL'; export type MetricUnitType = - | 'number' - | 'byte' - | 'second' - | 'percent' | 'bit_per_second' - | 'millisecond' + | 'byte' + | 'GB' | 'KB' | 'MB' - | 'GB'; -export type NotificationStatus = 'Enabled' | 'Disabled'; -export type ChannelType = 'email' | 'slack' | 'pagerduty' | 'webhook'; -export type AlertNotificationType = 'default' | 'custom'; + | 'millisecond' + | 'number' + | 'percent' + | 'second'; +export type NotificationStatus = 'Disabled' | 'Enabled'; +export type ChannelType = 'email' | 'pagerduty' | 'slack' | 'webhook'; +export type AlertNotificationType = 'custom' | 'default'; type AlertNotificationEmail = 'email'; type AlertNotificationSlack = 'slack'; type AlertNotificationPagerDuty = 'pagerduty'; type AlertNotificationWebHook = 'webhook'; export interface Dashboard { + created: string; id: number; label: string; - widgets: Widgets[]; - created: string; - updated: string; - time_duration: TimeDuration; service_type: string; + time_duration: TimeDuration; + updated: string; + widgets: Widgets[]; } export interface TimeGranularity { + label?: string; unit: string; value: number; - label?: string; } export interface TimeDuration { @@ -51,8 +51,8 @@ export interface TimeDuration { export interface DateTimeWithPreset { end: string; - start: string; preset?: string; + start: string; } export interface Widgets { @@ -82,13 +82,13 @@ export interface Filters { } export type FilterValue = + | DateTimeWithPreset | number + | number[] | string | string[] - | number[] - | WidgetFilterValue - | DateTimeWithPreset - | undefined; + | undefined + | WidgetFilterValue; type WidgetFilterValue = { [key: string]: AclpWidget }; @@ -99,25 +99,25 @@ export interface AclpConfig { export interface AclpWidget { aggregateFunction: string; - timeGranularity: TimeGranularity; label: string; size: number; + timeGranularity: TimeGranularity; } export interface MetricDefinition { + available_aggregate_functions: string[]; + dimensions: Dimension[]; + is_alertable: boolean; label: string; metric: string; metric_type: string; - unit: string; scrape_interval: string; - available_aggregate_functions: string[]; - dimensions: Dimension[]; - is_alertable: boolean; + unit: string; } export interface Dimension { - label: string; dimension_label: string; + label: string; values: string[]; } @@ -164,8 +164,8 @@ export interface CloudPulseMetricsList { } export interface ServiceTypes { - service_type: string; label: string; + service_type: string; } export interface ServiceTypesList { @@ -173,31 +173,31 @@ export interface ServiceTypesList { } export interface CreateAlertDefinitionPayload { - label: string; - tags?: string[]; + channel_ids: number[]; description?: string; entity_ids?: string[]; - severity: AlertSeverityType; + label: string; rule_criteria: { rules: MetricCriteria[]; }; + severity: AlertSeverityType; + tags?: string[]; trigger_conditions: TriggerCondition; - channel_ids: number[]; } export interface MetricCriteria { - metric: string; aggregate_function: MetricAggregationType; + dimension_filters?: DimensionFilter[]; + metric: string; operator: MetricOperatorType; threshold: number; - dimension_filters?: DimensionFilter[]; } export interface AlertDefinitionMetricCriteria extends Omit { - unit: string; - label: string; dimension_filters?: AlertDefinitionDimensionFilter[]; + label: string; + unit: string; } export interface DimensionFilter { dimension_label: string; @@ -209,56 +209,56 @@ export interface AlertDefinitionDimensionFilter extends DimensionFilter { label: string; } export interface TriggerCondition { - polling_interval_seconds: number; + criteria_condition: CriteriaConditionType; evaluation_period_seconds: number; + polling_interval_seconds: number; trigger_occurrences: number; - criteria_condition: CriteriaConditionType; } export interface Alert { - id: number; - label: string; - tags: string[]; - description: string; - class?: AlertClass; - has_more_resources: boolean; - status: AlertStatusType; - type: AlertDefinitionType; - severity: AlertSeverityType; - service_type: AlertServiceType; - entity_ids: string[]; - rule_criteria: { - rules: AlertDefinitionMetricCriteria[]; - }; - trigger_conditions: TriggerCondition; alert_channels: { id: number; label: string; - url: string; type: 'alert-channel'; + url: string; }[]; - created_by: string; - updated_by: string; + class?: AlertClass; created: string; + created_by: string; + description: string; + entity_ids: string[]; + has_more_resources: boolean; + id: number; + label: string; + rule_criteria: { + rules: AlertDefinitionMetricCriteria[]; + }; + service_type: AlertServiceType; + severity: AlertSeverityType; + status: AlertStatusType; + tags: string[]; + trigger_conditions: TriggerCondition; + type: AlertDefinitionType; updated: string; + updated_by: string; } interface NotificationChannelAlerts { id: number; label: string; - url: string; type: 'alerts-definitions'; + url: string; } interface NotificationChannelBase { + alerts: NotificationChannelAlerts[]; + channel_type: ChannelType; + created_at: string; + created_by: string; id: number; label: string; - channel_type: ChannelType; - type: AlertNotificationType; status: NotificationStatus; - alerts: NotificationChannelAlerts[]; - created_by: string; - updated_by: string; - created_at: string; + type: AlertNotificationType; updated_at: string; + updated_by: string; } interface NotificationChannelEmail extends NotificationChannelBase { @@ -266,8 +266,8 @@ interface NotificationChannelEmail extends NotificationChannelBase { content: { email: { email_addresses: string[]; - subject: string; message: string; + subject: string; }; }; } @@ -276,9 +276,9 @@ interface NotificationChannelSlack extends NotificationChannelBase { channel_type: AlertNotificationSlack; content: { slack: { - slack_webhook_url: string; - slack_channel: string; message: string; + slack_channel: string; + slack_webhook_url: string; }; }; } @@ -287,9 +287,9 @@ interface NotificationChannelPagerDuty extends NotificationChannelBase { channel_type: AlertNotificationPagerDuty; content: { pagerduty: { - service_api_key: string; attributes: string[]; description: string; + service_api_key: string; }; }; } @@ -297,43 +297,48 @@ interface NotificationChannelWebHook extends NotificationChannelBase { channel_type: AlertNotificationWebHook; content: { webhook: { - webhook_url: string; http_headers: { header_key: string; header_value: string; }[]; + webhook_url: string; }; }; } export type NotificationChannel = | NotificationChannelEmail + | NotificationChannelPagerDuty | NotificationChannelSlack - | NotificationChannelWebHook - | NotificationChannelPagerDuty; + | NotificationChannelWebHook; export interface EditAlertDefinitionPayload { - label?: string; - tags?: string[]; + channel_ids?: number[]; description?: string; entity_ids?: string[]; - severity?: AlertSeverityType; + label?: string; rule_criteria?: { rules: MetricCriteria[]; }; - trigger_conditions?: TriggerCondition; - channel_ids?: number[]; + severity?: AlertSeverityType; status?: AlertStatusType; + tags?: string[]; + trigger_conditions?: TriggerCondition; } export interface EditAlertPayloadWithService extends EditAlertDefinitionPayload { - serviceType: string; alertId: number; + serviceType: string; } -export type AlertStatusUpdateType = 'Enable' | 'Disable'; +export type AlertStatusUpdateType = 'Disable' | 'Enable'; export interface EntityAlertUpdatePayload { - entityId: string; alert: Alert; + entityId: string; +} + +export interface DeleteAlertPayload { + alertId: number; + serviceType: string; } diff --git a/packages/api-v4/src/databases/databases.ts b/packages/api-v4/src/databases/databases.ts index 08edf17bf50..02f4a5b23ca 100644 --- a/packages/api-v4/src/databases/databases.ts +++ b/packages/api-v4/src/databases/databases.ts @@ -2,6 +2,7 @@ import { createDatabaseSchema, updateDatabaseSchema, } from '@linode/validation/lib/databases.schema'; + import { BETA_API_ROOT as API_ROOT } from '../constants'; import Request, { setData, @@ -10,20 +11,21 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateDatabasePayload, Database, - DatabaseInstance, DatabaseBackup, DatabaseCredentials, - DatabaseType, DatabaseEngine, + DatabaseEngineConfig, + DatabaseFork, + DatabaseInstance, + DatabaseType, Engine, SSLFields, UpdateDatabasePayload, - DatabaseFork, - DatabaseEngineConfig, } from './types'; /** @@ -37,7 +39,7 @@ export const getDatabases = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/databases/instances`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -51,7 +53,7 @@ export const getDatabaseTypes = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/databases/types`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -63,7 +65,7 @@ export const getDatabaseTypes = (params?: Params, filter?: Filter) => export const getDatabaseType = (typeSlug: string) => Request( setURL(`${API_ROOT}/databases/types/${encodeURIComponent(typeSlug)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -77,7 +79,7 @@ export const getDatabaseEngines = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/databases/engines`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -89,7 +91,7 @@ export const getDatabaseEngines = (params?: Params, filter?: Filter) => export const getDatabaseEngine = (engineSlug: string) => Request( setURL(`${API_ROOT}/databases/engines/${encodeURIComponent(engineSlug)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -100,12 +102,12 @@ export const getDatabaseEngine = (engineSlug: string) => */ export const createDatabase = ( engine: Engine = 'mysql', - data: CreateDatabasePayload + data: CreateDatabasePayload, ) => Request( setURL(`${API_ROOT}/databases/${encodeURIComponent(engine)}/instances`), setMethod('POST'), - setData(data, createDatabaseSchema) + setData(data, createDatabaseSchema), ); /** @@ -117,13 +119,13 @@ export const createDatabase = ( export const getEngineDatabases = ( engine: Engine, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL(`${API_ROOT}/databases/${encodeURIComponent(engine)}/instances`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -136,10 +138,10 @@ export const getEngineDatabase = (engine: Engine, databaseID: number) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}` + engine, + )}/instances/${encodeURIComponent(databaseID)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -152,16 +154,16 @@ export const getEngineDatabase = (engine: Engine, databaseID: number) => export const updateDatabase = ( engine: Engine, databaseID: number, - data: UpdateDatabasePayload + data: UpdateDatabasePayload, ) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}` + engine, + )}/instances/${encodeURIComponent(databaseID)}`, ), setMethod('PUT'), - setData(data, updateDatabaseSchema) + setData(data, updateDatabaseSchema), ); /** @@ -173,10 +175,10 @@ export const patchDatabase = (engine: Engine, databaseID: number) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/patch` + engine, + )}/instances/${encodeURIComponent(databaseID)}/patch`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -188,10 +190,10 @@ export const deleteDatabase = (engine: Engine, databaseID: number) => Request<{}>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}` + engine, + )}/instances/${encodeURIComponent(databaseID)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -204,17 +206,17 @@ export const getDatabaseBackups = ( engine: Engine, databaseID: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/backups` + engine, + )}/instances/${encodeURIComponent(databaseID)}/backups`, ), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -226,17 +228,17 @@ export const getDatabaseBackups = ( export const getDatabaseBackup = ( engine: Engine, databaseID: number, - backupID: number + backupID: number, ) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine + engine, )}/instances/${encodeURIComponent( - databaseID - )}/backups/${encodeURIComponent(backupID)}` + databaseID, + )}/backups/${encodeURIComponent(backupID)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -247,17 +249,17 @@ export const getDatabaseBackup = ( export const legacyRestoreWithBackup = ( engine: Engine, databaseID: number, - backupID: number + backupID: number, ) => Request<{}>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine + engine, )}/instances/${encodeURIComponent( - databaseID - )}/backups/${encodeURIComponent(backupID)}/restore` + databaseID, + )}/backups/${encodeURIComponent(backupID)}/restore`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -269,7 +271,7 @@ export const restoreWithBackup = (engine: Engine, fork: DatabaseFork) => Request( setURL(`${API_ROOT}/databases/${encodeURIComponent(engine)}/instances`), setMethod('POST'), - setData({ fork }) + setData({ fork }), ); /** @@ -282,10 +284,10 @@ export const getDatabaseCredentials = (engine: Engine, databaseID: number) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/credentials` + engine, + )}/instances/${encodeURIComponent(databaseID)}/credentials`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -297,10 +299,10 @@ export const resetDatabaseCredentials = (engine: Engine, databaseID: number) => Request<{}>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/credentials/reset` + engine, + )}/instances/${encodeURIComponent(databaseID)}/credentials/reset`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -312,10 +314,10 @@ export const getSSLFields = (engine: Engine, databaseID: number) => Request( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/ssl` + engine, + )}/instances/${encodeURIComponent(databaseID)}/ssl`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -327,10 +329,10 @@ export const suspendDatabase = (engine: Engine, databaseID: number) => Request<{}>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/suspend` + engine, + )}/instances/${encodeURIComponent(databaseID)}/suspend`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -342,10 +344,10 @@ export const resumeDatabase = (engine: Engine, databaseID: number) => Request<{}>( setURL( `${API_ROOT}/databases/${encodeURIComponent( - engine - )}/instances/${encodeURIComponent(databaseID)}/resume` + engine, + )}/instances/${encodeURIComponent(databaseID)}/resume`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -357,5 +359,5 @@ export const resumeDatabase = (engine: Engine, databaseID: number) => export const getDatabaseEngineConfig = (engine: Engine) => Request( setURL(`${API_ROOT}/databases/${encodeURIComponent(engine)}/config`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/databases/types.ts b/packages/api-v4/src/databases/types.ts index c983595b964..05d0e4076a4 100644 --- a/packages/api-v4/src/databases/types.ts +++ b/packages/api-v4/src/databases/types.ts @@ -1,17 +1,17 @@ -import { BaseType } from '../linodes/types'; +import type { BaseType } from '../linodes/types'; -export type DatabaseTypeClass = 'standard' | 'dedicated' | 'nanode' | 'premium'; +export type DatabaseTypeClass = 'dedicated' | 'nanode' | 'premium' | 'standard'; export type Platform = 'rdbms-default' | 'rdbms-legacy'; export interface DatabasePriceObject { - monthly: number; hourly: number; + monthly: number; } export interface DatabaseClusterSizeObject { - quantity: number; price: DatabasePriceObject; + quantity: number; } export type Engines = Record; @@ -23,18 +23,18 @@ export interface DatabaseType extends BaseType { export type Engine = 'mysql' | 'postgresql'; export interface DatabaseEngine { - id: string; + deprecated?: boolean; engine: Engine; + id: string; version: string; - deprecated?: boolean; } export type DatabaseStatus = | 'active' | 'degraded' | 'failed' - | 'migrating' | 'migrated' + | 'migrating' | 'provisioning' | 'resizing' | 'restoring' @@ -42,7 +42,7 @@ export type DatabaseStatus = | 'suspended' | 'suspending'; /** @deprecated TODO (UIE-8214) remove after migration */ -export type DatabaseBackupType = 'snapshot' | 'auto'; +export type DatabaseBackupType = 'auto' | 'snapshot'; /** @deprecated TODO (UIE-8214) remove after migration */ export interface DatabaseBackup { created: string; @@ -94,7 +94,7 @@ export interface SSLFields { ca_certificate: string; } -type MemberType = 'primary' | 'failover'; +type MemberType = 'failover' | 'primary'; // DatabaseInstance is the interface for the shape of data returned by the /databases/instances endpoint. export interface DatabaseInstance { @@ -105,6 +105,7 @@ export interface DatabaseInstance { /** @Deprecated used by rdbms-legacy only, rdbms-default always encrypts */ encrypted: boolean; engine: Engine; + engine_config: DatabaseInstanceAdvancedConfig; hosts: DatabaseHosts; id: number; instance_uri?: string; @@ -122,7 +123,6 @@ export interface DatabaseInstance { updated: string; updates: UpdatesSchedule; version: string; - engine_config: DatabaseInstanceAdvancedConfig; } export type ClusterSize = 1 | 2 | 3; @@ -130,7 +130,7 @@ export type ClusterSize = 1 | 2 | 3; type ReadonlyCount = 0 | 2; /** @deprecated TODO (UIE-8214) remove POST GA */ -export type MySQLReplicationType = 'none' | 'semi_synch' | 'asynch'; +export type MySQLReplicationType = 'asynch' | 'none' | 'semi_synch'; export interface CreateDatabasePayload { allow_list?: string[]; @@ -148,7 +148,7 @@ export interface CreateDatabasePayload { } /** @deprecated TODO (UIE-8214) remove POST GA */ -type DriverTypes = 'jdbc' | 'odbc' | 'php' | 'python' | 'ruby' | 'node.js'; +type DriverTypes = 'jdbc' | 'node.js' | 'odbc' | 'php' | 'python' | 'ruby'; /** @deprecated TODO (UIE-8214) remove POST GA */ interface ConnectionStrings { @@ -156,7 +156,7 @@ interface ConnectionStrings { value: string; } -export type UpdatesFrequency = 'weekly' | 'monthly'; +export type UpdatesFrequency = 'monthly' | 'weekly'; export interface UpdatesSchedule { day_of_week: number; @@ -164,7 +164,7 @@ export interface UpdatesSchedule { frequency: UpdatesFrequency; hour_of_day: number; pending?: PendingUpdates[]; - week_of_month: number | null; + week_of_month: null | number; } /** @@ -176,14 +176,14 @@ export interface PendingUpdates { * describing the point in time by which a mandatory update must be applied. * Not all updates have deadlines. */ - deadline: string | null; + deadline: null | string; description: string; /** * Optional ISO-8601 UTC timestamp * describing the maintenance window in which the update is planned to be applied. * Users may trigger these updates outside a scheduled maintenance window by calling the patch API. */ - planned_for: string | null; + planned_for: null | string; } // Database is the base interface for the shape of data returned by /databases/{engine}/instances @@ -192,7 +192,7 @@ interface BaseDatabase extends DatabaseInstance { /** @Deprecated used by rdbms-legacy only, rdbms-default always uses TLS */ ssl_connection: boolean; total_disk_size_gb: number; - used_disk_size_gb: number | null; + used_disk_size_gb: null | number; } /** @deprecated TODO (UIE-8214) remove POST GA */ @@ -202,22 +202,22 @@ export interface MySQLDatabase extends BaseDatabase { } /** @deprecated TODO (UIE-8214) remove POST GA */ -export type PostgresReplicationType = 'none' | 'synch' | 'asynch'; +export type PostgresReplicationType = 'asynch' | 'none' | 'synch'; /** @deprecated TODO (UIE-8214) remove POST GA */ export type ReplicationCommitTypes = - | 'on' | 'local' - | 'remote_write' + | 'off' + | 'on' | 'remote_apply' - | 'off'; + | 'remote_write'; /** @deprecated TODO (UIE-8214) remove POST GA */ export interface PostgresDatabase extends BaseDatabase { - /** @Deprecated used by rdbms-legacy only */ - replication_type?: PostgresReplicationType; /** @Deprecated used by rdbms-legacy only */ replication_commit_type?: ReplicationCommitTypes; + /** @Deprecated used by rdbms-legacy only */ + replication_type?: PostgresReplicationType; } /** @deprecated TODO (UIE-8214) remove POST GA */ @@ -229,11 +229,11 @@ export type Database = BaseDatabase & Partial; export interface UpdateDatabasePayload { + allow_list?: string[]; cluster_size?: number; + engine_config?: DatabaseInstanceAdvancedConfig; label?: string; - allow_list?: string[]; - updates?: UpdatesSchedule; type?: string; + updates?: UpdatesSchedule; version?: string; - engine_config?: DatabaseInstanceAdvancedConfig; } diff --git a/packages/api-v4/src/domains/domains.ts b/packages/api-v4/src/domains/domains.ts index 9d1ced65d37..28445351442 100644 --- a/packages/api-v4/src/domains/domains.ts +++ b/packages/api-v4/src/domains/domains.ts @@ -3,6 +3,7 @@ import { importZoneSchema, updateDomainSchema, } from '@linode/validation/lib/domains.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -11,8 +12,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CloneDomainPayload, CreateDomainPayload, Domain, @@ -30,7 +32,7 @@ export const getDomains = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/domains`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -41,7 +43,7 @@ export const getDomains = (params?: Params, filter?: Filter) => export const getDomain = (domainId: number) => Request( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -53,7 +55,7 @@ export const createDomain = (data: CreateDomainPayload) => Request( setData(data, createDomainSchema), setURL(`${API_ROOT}/domains`), - setMethod('POST') + setMethod('POST'), ); /** @@ -66,7 +68,7 @@ export const updateDomain = (domainId: number, data: UpdateDomainPayload) => Request( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}`), setMethod('PUT'), - setData(data, updateDomainSchema) + setData(data, updateDomainSchema), ); /** @@ -78,7 +80,7 @@ export const updateDomain = (domainId: number, data: UpdateDomainPayload) => export const deleteDomain = (domainId: number) => Request<{}>( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -91,7 +93,7 @@ export const cloneDomain = (domainId: number, data: CloneDomainPayload) => Request( setData(data), setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}/clone`), - setMethod('POST') + setMethod('POST'), ); /** @@ -104,7 +106,7 @@ export const importZone = (data: ImportZonePayload) => Request( setData(data, importZoneSchema), setURL(`${API_ROOT}/domains/import`), - setMethod('POST') + setMethod('POST'), ); /** @@ -115,5 +117,5 @@ export const importZone = (data: ImportZonePayload) => export const getDNSZoneFile = (domainId: number) => Request( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}/zone-file`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/domains/records.ts b/packages/api-v4/src/domains/records.ts index 318f16f4918..18c98d82b74 100644 --- a/packages/api-v4/src/domains/records.ts +++ b/packages/api-v4/src/domains/records.ts @@ -2,10 +2,12 @@ import { createRecordSchema, updateRecordSchema, } from '@linode/validation/lib/records.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setParams, setURL } from '../request'; -import { Params, ResourcePage as Page } from '../types'; -import { DomainRecord } from './types'; + +import type { ResourcePage as Page, Params } from '../types'; +import type { DomainRecord } from './types'; /** * Returns a paginated list of Records configured on a Domain in Linode's DNS Manager. @@ -17,7 +19,7 @@ export const getDomainRecords = (domainId: number, params?: Params) => Request>( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}/records`), setParams(params), - setMethod('GET') + setMethod('GET'), ); /** @@ -30,10 +32,10 @@ export const getDomainRecord = (domainId: number, recordId: number) => Request( setURL( `${API_ROOT}/domains/${encodeURIComponent( - domainId - )}/records/${encodeURIComponent(recordId)}` + domainId, + )}/records/${encodeURIComponent(recordId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -44,12 +46,12 @@ export const getDomainRecord = (domainId: number, recordId: number) => */ export const createDomainRecord = ( domainId: number, - data: Partial + data: Partial, ) => Request( setURL(`${API_ROOT}/domains/${encodeURIComponent(domainId)}/records`), setMethod('POST'), - setData(data, createRecordSchema) + setData(data, createRecordSchema), ); /** @@ -62,16 +64,16 @@ export const createDomainRecord = ( export const updateDomainRecord = ( domainId: number, recordId: number, - data: Partial + data: Partial, ) => Request( setURL( `${API_ROOT}/domains/${encodeURIComponent( - domainId - )}/records/${encodeURIComponent(recordId)}` + domainId, + )}/records/${encodeURIComponent(recordId)}`, ), setMethod('PUT'), - setData(data, updateRecordSchema) + setData(data, updateRecordSchema), ); /** @@ -84,8 +86,8 @@ export const deleteDomainRecord = (domainId: number, recordId: number) => Request<{}>( setURL( `${API_ROOT}/domains/${encodeURIComponent( - domainId - )}/records/${encodeURIComponent(recordId)}` + domainId, + )}/records/${encodeURIComponent(recordId)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/domains/types.ts b/packages/api-v4/src/domains/types.ts index 90a0b158d39..20afa4a1563 100644 --- a/packages/api-v4/src/domains/types.ts +++ b/packages/api-v4/src/domains/types.ts @@ -1,17 +1,17 @@ export interface Domain { - id: number; - domain: string; - soa_email: string; + axfr_ips: string[]; description: string; + domain: string; + expire_sec: number; + group: string; + id: number; + master_ips: string[]; refresh_sec: number; retry_sec: number; - expire_sec: number; - ttl_sec: number; + soa_email: string; status: DomainStatus; tags: string[]; - master_ips: string[]; - axfr_ips: string[]; - group: string; + ttl_sec: number; type: DomainType; updated: string; } @@ -45,6 +45,7 @@ export type RecordType = | 'TXT'; export interface DomainRecord { + created: string; id: number; name: string; port: number; @@ -55,29 +56,28 @@ export interface DomainRecord { target: string; ttl_sec: number; type: RecordType; - weight: number; - created: string; updated: string; + weight: number; } export interface CreateDomainPayload { domain: string; - type: DomainType; master_ips?: string[]; soa_email?: string; tags?: string[]; + type: DomainType; } export interface UpdateDomainPayload { - domain?: string; - soa_email?: string; + axfr_ips?: string[]; description?: string; + domain?: string; + expire_sec?: number; + group?: string; + master_ips?: string[]; refresh_sec?: number; retry_sec?: number; - expire_sec?: number; - ttl_sec?: number; + soa_email?: string; status?: DomainStatus; tags?: string[]; - master_ips?: string[]; - axfr_ips?: string[]; - group?: string; + ttl_sec?: number; } diff --git a/packages/api-v4/src/entities/entities.ts b/packages/api-v4/src/entities/entities.ts index 56ea45db5a6..8c2471fe30c 100644 --- a/packages/api-v4/src/entities/entities.ts +++ b/packages/api-v4/src/entities/entities.ts @@ -1,7 +1,8 @@ -import { ResourcePage } from 'src/types'; import { BETA_API_ROOT } from '../constants'; import Request, { setMethod, setURL } from '../request'; -import { AccountEntity } from './types'; + +import type { AccountEntity } from './types'; +import type { ResourcePage } from 'src/types'; /** * getAccountEntities @@ -12,6 +13,6 @@ import { AccountEntity } from './types'; export const getAccountEntities = () => { return Request>( setURL(`${BETA_API_ROOT}/entities`), - setMethod('GET') + setMethod('GET'), ); }; diff --git a/packages/api-v4/src/entities/types.ts b/packages/api-v4/src/entities/types.ts index bad27588967..f3d4b256edc 100644 --- a/packages/api-v4/src/entities/types.ts +++ b/packages/api-v4/src/entities/types.ts @@ -11,7 +11,7 @@ export type EntityType = | 'vpc'; export interface AccountEntity { + id: number; label: string; type: EntityType; - id: number; } diff --git a/packages/api-v4/src/entity-transfers/index.ts b/packages/api-v4/src/entity-transfers/index.ts index 54ee48d2db0..2097859b8d8 100644 --- a/packages/api-v4/src/entity-transfers/index.ts +++ b/packages/api-v4/src/entity-transfers/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './transfers'; + +export * from './types'; diff --git a/packages/api-v4/src/entity-transfers/transfers.ts b/packages/api-v4/src/entity-transfers/transfers.ts index ec32e88040e..c7ce4e0be9e 100644 --- a/packages/api-v4/src/entity-transfers/transfers.ts +++ b/packages/api-v4/src/entity-transfers/transfers.ts @@ -1,4 +1,5 @@ import { CreateTransferSchema } from '@linode/validation/lib/transfers.schema'; + import { BETA_API_ROOT } from '../constants'; import Request, { setData, @@ -7,8 +8,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { CreateTransferPayload, EntityTransfer } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateTransferPayload, EntityTransfer } from './types'; /** * @deprecated @@ -21,7 +23,7 @@ export const getEntityTransfers = (params?: Params, filter?: Filter) => setMethod('GET'), setParams(params), setXFilter(filter), - setURL(`${BETA_API_ROOT}/account/entity-transfers`) + setURL(`${BETA_API_ROOT}/account/entity-transfers`), ); /** @@ -36,8 +38,8 @@ export const getEntityTransfer = (token: string) => Request( setMethod('GET'), setURL( - `${BETA_API_ROOT}/account/entity-transfers/${encodeURIComponent(token)}` - ) + `${BETA_API_ROOT}/account/entity-transfers/${encodeURIComponent(token)}`, + ), ); /** @@ -51,7 +53,7 @@ export const createEntityTransfer = (data: CreateTransferPayload) => Request( setMethod('POST'), setData(data, CreateTransferSchema), - setURL(`${BETA_API_ROOT}/account/entity-transfers`) + setURL(`${BETA_API_ROOT}/account/entity-transfers`), ); /** @@ -65,9 +67,9 @@ export const acceptEntityTransfer = (token: string) => setMethod('POST'), setURL( `${BETA_API_ROOT}/account/entity-transfers/${encodeURIComponent( - token - )}/accept` - ) + token, + )}/accept`, + ), ); /** @@ -82,6 +84,6 @@ export const cancelTransfer = (token: string) => Request<{}>( setMethod('DELETE'), setURL( - `${BETA_API_ROOT}/account/entity-transfers/${encodeURIComponent(token)}` - ) + `${BETA_API_ROOT}/account/entity-transfers/${encodeURIComponent(token)}`, + ), ); diff --git a/packages/api-v4/src/entity-transfers/types.ts b/packages/api-v4/src/entity-transfers/types.ts index f9034fbf2c6..cdea773cc9f 100644 --- a/packages/api-v4/src/entity-transfers/types.ts +++ b/packages/api-v4/src/entity-transfers/types.ts @@ -1,9 +1,9 @@ export type EntityTransferStatus = - | 'pending' | 'accepted' | 'canceled' | 'completed' | 'failed' + | 'pending' | 'stale'; // @todo merge this with the types made for M3-4900 @@ -12,13 +12,13 @@ export interface TransferEntities { } export interface EntityTransfer { - token: string; - status: EntityTransferStatus; created: string; - updated: string; - is_sender: boolean; - expiry: string; entities: TransferEntities; + expiry: string; + is_sender: boolean; + status: EntityTransferStatus; + token: string; + updated: string; } export interface CreateTransferPayload { entities: TransferEntities; diff --git a/packages/api-v4/src/firewalls/firewalls.ts b/packages/api-v4/src/firewalls/firewalls.ts index 7b5671110ff..cd744bc2c8c 100644 --- a/packages/api-v4/src/firewalls/firewalls.ts +++ b/packages/api-v4/src/firewalls/firewalls.ts @@ -1,3 +1,10 @@ +import { + CreateFirewallSchema, + FirewallDeviceSchema, + UpdateFirewallSchema, + UpdateFirewallSettingsSchema, +} from '@linode/validation/lib/firewalls.schema'; + import { BETA_API_ROOT } from '../constants'; import Request, { setData, @@ -6,14 +13,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { - CreateFirewallSchema, - FirewallDeviceSchema, - UpdateFirewallSchema, - UpdateFirewallSettingsSchema, -} from '@linode/validation/lib/firewalls.schema'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateFirewallPayload, Firewall, FirewallDevice, @@ -37,7 +39,7 @@ export const getFirewalls = (params?: Params, filter?: Filter) => setMethod('GET'), setParams(params), setXFilter(filter), - setURL(`${BETA_API_ROOT}/networking/firewalls`) + setURL(`${BETA_API_ROOT}/networking/firewalls`), ); /** @@ -51,8 +53,8 @@ export const getFirewall = (firewallID: number) => Request( setMethod('GET'), setURL( - `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}` - ) + `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}`, + ), ); /** @@ -70,7 +72,7 @@ export const createFirewall = (data: CreateFirewallPayload) => Request( setMethod('POST'), setData(data, CreateFirewallSchema), - setURL(`${BETA_API_ROOT}/networking/firewalls`) + setURL(`${BETA_API_ROOT}/networking/firewalls`), ); /** @@ -82,14 +84,14 @@ export const createFirewall = (data: CreateFirewallPayload) => */ export const updateFirewall = ( firewallID: number, - data: UpdateFirewallPayload + data: UpdateFirewallPayload, ) => Request( setMethod('PUT'), setData(data, UpdateFirewallSchema), setURL( - `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}` - ) + `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}`, + ), ); /** @@ -122,8 +124,8 @@ export const deleteFirewall = (firewallID: number) => Request<{}>( setMethod('DELETE'), setURL( - `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}` - ) + `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent(firewallID)}`, + ), ); // #region Firewall Rules @@ -136,7 +138,7 @@ export const deleteFirewall = (firewallID: number) => export const getFirewallRules = ( firewallID: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setMethod('GET'), @@ -144,9 +146,9 @@ export const getFirewallRules = ( setXFilter(filter), setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/rules` - ) + firewallID, + )}/rules`, + ), ); /** @@ -157,16 +159,16 @@ export const getFirewallRules = ( */ export const updateFirewallRules = ( firewallID: number, - data: UpdateFirewallRules + data: UpdateFirewallRules, ) => Request( setMethod('PUT'), setData(data), // Validation is too complicated for these; leave it to the API. setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/rules` - ) + firewallID, + )}/rules`, + ), ); // #region Devices @@ -180,7 +182,7 @@ export const updateFirewallRules = ( export const getFirewallDevices = ( firewallID: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setMethod('GET'), @@ -188,9 +190,9 @@ export const getFirewallDevices = ( setXFilter(filter), setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/devices` - ) + firewallID, + )}/devices`, + ), ); /** @@ -204,9 +206,9 @@ export const getFirewallDevice = (firewallID: number, deviceID: number) => setMethod('GET'), setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/devices/${encodeURIComponent(deviceID)}` - ) + firewallID, + )}/devices/${encodeURIComponent(deviceID)}`, + ), ); /** @@ -223,16 +225,16 @@ export const getFirewallDevice = (firewallID: number, deviceID: number) => */ export const addFirewallDevice = ( firewallID: number, - data: FirewallDevicePayload + data: FirewallDevicePayload, ) => Request( setMethod('POST'), setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/devices` + firewallID, + )}/devices`, ), - setData(data, FirewallDeviceSchema) + setData(data, FirewallDeviceSchema), ); /** @@ -248,9 +250,9 @@ export const deleteFirewallDevice = (firewallID: number, deviceID: number) => setMethod('DELETE'), setURL( `${BETA_API_ROOT}/networking/firewalls/${encodeURIComponent( - firewallID - )}/devices/${encodeURIComponent(deviceID)}` - ) + firewallID, + )}/devices/${encodeURIComponent(deviceID)}`, + ), ); /** @@ -261,7 +263,7 @@ export const deleteFirewallDevice = (firewallID: number, deviceID: number) => export const getFirewallSettings = () => Request( setMethod('GET'), - setURL(`${BETA_API_ROOT}/networking/firewalls/settings`) + setURL(`${BETA_API_ROOT}/networking/firewalls/settings`), ); /** @@ -273,7 +275,7 @@ export const updateFirewallSettings = (data: UpdateFirewallSettings) => Request( setMethod('PUT'), setURL(`${BETA_API_ROOT}/networking/firewalls/settings`), - setData(data, UpdateFirewallSettingsSchema) + setData(data, UpdateFirewallSettingsSchema), ); // #region Templates @@ -286,7 +288,7 @@ export const updateFirewallSettings = (data: UpdateFirewallSettings) => export const getTemplates = () => Request>( setMethod('GET'), - setURL(`${BETA_API_ROOT}/networking/firewalls/templates`) + setURL(`${BETA_API_ROOT}/networking/firewalls/templates`), ); /** @@ -299,7 +301,7 @@ export const getTemplate = (templateSlug: FirewallTemplateSlug) => setMethod('GET'), setURL( `${BETA_API_ROOT}/networking/firewalls/templates/${encodeURIComponent( - templateSlug - )}` - ) + templateSlug, + )}`, + ), ); diff --git a/packages/api-v4/src/firewalls/index.ts b/packages/api-v4/src/firewalls/index.ts index d4a944388c2..285da544f72 100644 --- a/packages/api-v4/src/firewalls/index.ts +++ b/packages/api-v4/src/firewalls/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './firewalls'; + +export * from './types'; diff --git a/packages/api-v4/src/firewalls/types.ts b/packages/api-v4/src/firewalls/types.ts index ec3ce8dea40..5aaf4bb8557 100644 --- a/packages/api-v4/src/firewalls/types.ts +++ b/packages/api-v4/src/firewalls/types.ts @@ -1,27 +1,27 @@ -export type FirewallStatus = 'enabled' | 'disabled' | 'deleted'; +export type FirewallStatus = 'deleted' | 'disabled' | 'enabled'; -export type FirewallRuleProtocol = 'ALL' | 'TCP' | 'UDP' | 'ICMP' | 'IPENCAP'; +export type FirewallRuleProtocol = 'ALL' | 'ICMP' | 'IPENCAP' | 'TCP' | 'UDP'; -export type FirewallDeviceEntityType = 'linode' | 'nodebalancer' | 'interface'; +export type FirewallDeviceEntityType = 'interface' | 'linode' | 'nodebalancer'; export type FirewallPolicyType = 'ACCEPT' | 'DROP'; export interface Firewall { + created: string; + entities: FirewallDeviceEntity[]; id: number; - status: FirewallStatus; label: string; - tags: string[]; rules: FirewallRules; - created: string; + status: FirewallStatus; + tags: string[]; updated: string; - entities: FirewallDeviceEntity[]; } export interface FirewallRules { fingerprint: string; inbound?: FirewallRuleType[] | null; - outbound?: FirewallRuleType[] | null; inbound_policy: FirewallPolicyType; + outbound?: FirewallRuleType[] | null; outbound_policy: FirewallPolicyType; version: number; } @@ -34,53 +34,53 @@ export type UpdateFirewallRules = Omit< export type FirewallTemplateRules = UpdateFirewallRules; export interface FirewallRuleType { - label?: string | null; - description?: string | null; - protocol: FirewallRuleProtocol; - ports?: string; action: FirewallPolicyType; addresses?: null | { ipv4?: null | string[]; ipv6?: null | string[]; }; + description?: null | string; + label?: null | string; + ports?: string; + protocol: FirewallRuleProtocol; } export interface FirewallDeviceEntity { id: number; + label: null | string; type: FirewallDeviceEntityType; - label: string | null; url: string; } export interface FirewallDevice { - id: number; created: string; - updated: string; entity: FirewallDeviceEntity; + id: number; + updated: string; } -export type FirewallTemplateSlug = 'akamai-non-prod' | 'vpc' | 'public'; +export type FirewallTemplateSlug = 'akamai-non-prod' | 'public' | 'vpc'; export interface FirewallTemplate { - slug: FirewallTemplateSlug; rules: FirewallTemplateRules; + slug: FirewallTemplateSlug; } export interface CreateFirewallPayload { - label: string; - tags?: string[]; - rules: UpdateFirewallRules; - devices?: { + devices?: null | { + interfaces?: number[]; linodes?: number[]; nodebalancers?: number[]; - interfaces?: number[]; - } | null; + }; + label: string; + rules: UpdateFirewallRules; + tags?: string[]; } export interface UpdateFirewallPayload { label?: string; - tags?: string[]; status?: Omit; + tags?: string[]; } export interface FirewallDevicePayload { @@ -89,10 +89,10 @@ export interface FirewallDevicePayload { } export interface DefaultFirewallIDs { - public_interface: number | null; - vpc_interface: number | null; - linode: number | null; - nodebalancer: number | null; + linode: null | number; + nodebalancer: null | number; + public_interface: null | number; + vpc_interface: null | number; } export interface FirewallSettings { diff --git a/packages/api-v4/src/iam/index.ts b/packages/api-v4/src/iam/index.ts index 0b2cffa9534..8442040a86a 100644 --- a/packages/api-v4/src/iam/index.ts +++ b/packages/api-v4/src/iam/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './iam'; + +export * from './types'; diff --git a/packages/api-v4/src/images/images.ts b/packages/api-v4/src/images/images.ts index 110f19158ed..b56866929a4 100644 --- a/packages/api-v4/src/images/images.ts +++ b/packages/api-v4/src/images/images.ts @@ -4,6 +4,7 @@ import { updateImageSchema, uploadImageSchema, } from '@linode/validation/lib/images.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -12,7 +13,8 @@ import Request, { setURL, setXFilter, } from '../request'; -import type { Filter, Params, ResourcePage as Page } from '../types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; import type { CreateImagePayload, Image, @@ -30,7 +32,7 @@ import type { export const getImage = (imageId: string) => Request( setURL(`${API_ROOT}/images/${encodeURIComponent(imageId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -42,7 +44,7 @@ export const getImages = (params: Params = {}, filters: Filter = {}) => setURL(`${API_ROOT}/images`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -52,7 +54,7 @@ export const createImage = (data: CreateImagePayload) => { return Request( setURL(`${API_ROOT}/images`), setMethod('POST'), - setData(data, createImageSchema) + setData(data, createImageSchema), ); }; @@ -66,7 +68,7 @@ export const updateImage = (imageId: string, data: UpdateImagePayload) => { return Request( setURL(`${API_ROOT}/images/${encodeURIComponent(imageId)}`), setMethod('PUT'), - setData(data, updateImageSchema) + setData(data, updateImageSchema), ); }; @@ -78,7 +80,7 @@ export const updateImage = (imageId: string, data: UpdateImagePayload) => { export const deleteImage = (imageId: string) => { return Request<{}>( setURL(`${API_ROOT}/images/${encodeURIComponent(imageId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); }; @@ -95,7 +97,7 @@ export const uploadImage = (data: ImageUploadPayload) => { return Request( setURL(`${API_ROOT}/images/upload`), setMethod('POST'), - setData(data, uploadImageSchema) + setData(data, uploadImageSchema), ); }; @@ -106,11 +108,11 @@ export const uploadImage = (data: ImageUploadPayload) => { */ export const updateImageRegions = ( imageId: string, - data: UpdateImageRegionsPayload + data: UpdateImageRegionsPayload, ) => { return Request( setURL(`${API_ROOT}/images/${encodeURIComponent(imageId)}/regions`), setMethod('POST'), - setData(data, updateImageRegionsSchema) + setData(data, updateImageRegionsSchema), ); }; diff --git a/packages/api-v4/src/images/index.ts b/packages/api-v4/src/images/index.ts index 582af21dfe6..7425f0c62e4 100644 --- a/packages/api-v4/src/images/index.ts +++ b/packages/api-v4/src/images/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './images'; + +export * from './types'; diff --git a/packages/api-v4/src/images/types.ts b/packages/api-v4/src/images/types.ts index 4a707b361d8..8eb4c68fbe9 100644 --- a/packages/api-v4/src/images/types.ts +++ b/packages/api-v4/src/images/types.ts @@ -2,12 +2,12 @@ export type ImageStatus = 'available' | 'creating' | 'pending_upload'; export type ImageCapabilities = 'cloud-init' | 'distributed-sites'; -type ImageType = 'manual' | 'automatic'; +type ImageType = 'automatic' | 'manual'; export type ImageRegionStatus = + | 'available' | 'creating' | 'pending' - | 'available' | 'pending deletion' | 'pending replication' | 'replicating' @@ -20,94 +20,94 @@ export interface ImageRegion { export interface Image { /** - * An optional timestamp of this image's planned end-of-life. + * A list of the capabilities of this image. */ - eol: string | null; + capabilities: ImageCapabilities[]; /** - * The unique ID of the this image. + * The timestamp of when this image was created. */ - id: string; + created: string; /** - * A short description of this image. + * The name of the user who created this image or 'linode' for public images. */ - label: string; + created_by: null | string; /** - * A detailed description of this image. + * Whether this is a public image that is deprecated. */ - description: string | null; + deprecated: boolean; /** - * The timestamp of when this image was created. + * A detailed description of this image. */ - created: string; + description: null | string; /** - * The timestamp of when this image was last updated. + * An optional timestamp of this image's planned end-of-life. */ - updated: string; + eol: null | string; /** - * Indicates the method of this image's creation. + * A timestamp of when this image will expire if it was automatically captured. */ - type: ImageType; + expiry: null | string; /** - * Whether this image is marked for public distribution. + * The unique ID of the this image. */ - is_public: boolean; + id: string; /** - * The minimum size in MB needed to deploy this image. + * Whether this image is marked for public distribution. */ - size: number; + is_public: boolean; /** - * The total storage consumed by this image across its regions. + * A short description of this image. */ - total_size: number; + label: string; /** - * The name of the user who created this image or 'linode' for public images. + * A list of the regions in which this image is available. */ - created_by: null | string; + regions: ImageRegion[]; /** - * The distribution author. + * The minimum size in MB needed to deploy this image. */ - vendor: string | null; + size: number; /** - * Whether this is a public image that is deprecated. + * The current status of this image. */ - deprecated: boolean; + status: ImageStatus; /** - * A timestamp of when this image will expire if it was automatically captured. + * A list of tags added to this image. */ - expiry: null | string; + tags: string[]; /** - * The current status of this image. + * The total storage consumed by this image across its regions. */ - status: ImageStatus; + total_size: number; /** - * A list of the capabilities of this image. + * Indicates the method of this image's creation. */ - capabilities: ImageCapabilities[]; + type: ImageType; /** - * A list of the regions in which this image is available. + * The timestamp of when this image was last updated. */ - regions: ImageRegion[]; + updated: string; /** - * A list of tags added to this image. + * The distribution author. */ - tags: string[]; + vendor: null | string; } export interface UploadImageResponse { @@ -117,20 +117,20 @@ export interface UploadImageResponse { export interface BaseImagePayload { /** - * A short title of this Image. - * - * Defaults to the label of the Disk it is being created from if not provided. + * Whether this Image supports cloud-init. + * @default false */ - label?: string; + cloud_init?: boolean; /** * A detailed description of this Image. */ description?: string; /** - * Whether this Image supports cloud-init. - * @default false + * A short title of this Image. + * + * Defaults to the label of the Disk it is being created from if not provided. */ - cloud_init?: boolean; + label?: string; /** * An array of Tags applied to this Image. Tags are for organizational purposes only. */ diff --git a/packages/api-v4/src/index.ts b/packages/api-v4/src/index.ts index a1a181f55cf..0971eb34474 100644 --- a/packages/api-v4/src/index.ts +++ b/packages/api-v4/src/index.ts @@ -1,15 +1,21 @@ export * from './account'; +export * from './betas'; + export * from './cloudpulse'; export * from './databases'; export * from './domains'; +export * from './entities'; + export * from './entity-transfers'; export * from './firewalls'; +export * from './iam'; + export * from './images'; export * from './kubernetes'; @@ -20,10 +26,10 @@ export * from './longview'; export * from './managed'; -export * from './networking'; - export * from './network-transfer'; +export * from './networking'; + export * from './nodebalancers'; export * from './object-storage'; @@ -36,6 +42,13 @@ export * from './quotas'; export * from './regions'; +export { + baseRequest, + convertYupToLinodeErrors, + isEmpty, + setToken, +} from './request'; + export * from './service-transfers'; export * from './stackscripts'; @@ -51,16 +64,3 @@ export * from './vlans'; export * from './volumes'; export * from './vpcs'; - -export * from './betas'; - -export * from './iam'; - -export * from './entities'; - -export { - baseRequest, - setToken, - isEmpty, - convertYupToLinodeErrors, -} from './request'; diff --git a/packages/api-v4/src/kubernetes/kubernetes.ts b/packages/api-v4/src/kubernetes/kubernetes.ts index faba1e5ba66..8b61b41caa3 100644 --- a/packages/api-v4/src/kubernetes/kubernetes.ts +++ b/packages/api-v4/src/kubernetes/kubernetes.ts @@ -1,4 +1,5 @@ import { createKubeClusterSchema } from '@linode/validation/lib/kubernetes.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, @@ -7,16 +8,17 @@ import Request, { setURL, setXFilter, } from '../request'; -import type { Filter, Params, ResourcePage as Page, PriceType } from '../types'; + +import type { Filter, ResourcePage as Page, Params, PriceType } from '../types'; import type { CreateKubeClusterPayload, KubeConfigResponse, KubernetesCluster, - KubernetesEndpointResponse, - KubernetesDashboardResponse, - KubernetesVersion, KubernetesControlPlaneACLPayload, + KubernetesDashboardResponse, + KubernetesEndpointResponse, KubernetesTieredVersion, + KubernetesVersion, } from './types'; /** @@ -29,7 +31,7 @@ export const getKubernetesClusters = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/lke/clusters`) + setURL(`${API_ROOT}/lke/clusters`), ); /** @@ -42,7 +44,7 @@ export const getKubernetesClustersBeta = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${BETA_API_ROOT}/lke/clusters`) + setURL(`${BETA_API_ROOT}/lke/clusters`), ); /** @@ -53,7 +55,7 @@ export const getKubernetesClustersBeta = (params?: Params, filters?: Filter) => export const getKubernetesCluster = (clusterID: number) => Request( setMethod('GET'), - setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`) + setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`), ); /** @@ -64,7 +66,7 @@ export const getKubernetesCluster = (clusterID: number) => export const getKubernetesClusterBeta = (clusterID: number) => Request( setMethod('GET'), - setURL(`${BETA_API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`) + setURL(`${BETA_API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`), ); /** @@ -76,7 +78,7 @@ export const createKubernetesCluster = (data: CreateKubeClusterPayload) => { return Request( setMethod('POST'), setURL(`${API_ROOT}/lke/clusters`), - setData(data, createKubeClusterSchema) + setData(data, createKubeClusterSchema), ); }; @@ -94,7 +96,7 @@ export const createKubernetesClusterBeta = (data: CreateKubeClusterPayload) => { return Request( setMethod('POST'), setURL(`${BETA_API_ROOT}/lke/clusters`), - setData(data, createKubeClusterSchema) + setData(data, createKubeClusterSchema), ); }; @@ -105,12 +107,12 @@ export const createKubernetesClusterBeta = (data: CreateKubeClusterPayload) => { */ export const updateKubernetesCluster = ( clusterID: number, - data: Partial + data: Partial, ) => Request( setMethod('PUT'), setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`), - setData(data) + setData(data), ); /** @@ -121,7 +123,7 @@ export const updateKubernetesCluster = ( export const deleteKubernetesCluster = (clusterID: number) => Request<{}>( setMethod('DELETE'), - setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`) + setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}`), ); /** @@ -136,8 +138,8 @@ export const getKubeConfig = (clusterId: number) => Request( setMethod('GET'), setURL( - `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterId)}/kubeconfig` - ) + `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterId)}/kubeconfig`, + ), ); /** @@ -151,8 +153,8 @@ export const resetKubeConfig = (clusterId: number) => Request<{}>( setMethod('DELETE'), setURL( - `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterId)}/kubeconfig` - ) + `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterId)}/kubeconfig`, + ), ); /** getKubernetesVersions @@ -166,7 +168,7 @@ export const getKubernetesVersions = (params?: Params, filters?: Filter) => setMethod('GET'), setXFilter(filters), setParams(params), - setURL(`${API_ROOT}/lke/versions`) + setURL(`${API_ROOT}/lke/versions`), ); /** getKubernetesTieredVersionsBeta @@ -178,13 +180,13 @@ export const getKubernetesVersions = (params?: Params, filters?: Filter) => export const getKubernetesTieredVersionsBeta = ( tier: string, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setMethod('GET'), setXFilter(filters), setParams(params), - setURL(`${BETA_API_ROOT}/lke/tiers/${encodeURIComponent(tier)}/versions`) + setURL(`${BETA_API_ROOT}/lke/tiers/${encodeURIComponent(tier)}/versions`), ); /** getKubernetesVersion @@ -196,7 +198,7 @@ export const getKubernetesTieredVersionsBeta = ( export const getKubernetesVersion = (versionID: string) => Request( setMethod('GET'), - setURL(`${API_ROOT}/lke/versions/${encodeURIComponent(versionID)}`) + setURL(`${API_ROOT}/lke/versions/${encodeURIComponent(versionID)}`), ); /** getKubernetesTieredVersionBeta @@ -207,15 +209,15 @@ export const getKubernetesVersion = (versionID: string) => export const getKubernetesTieredVersionBeta = ( tier: string, - versionID: string + versionID: string, ) => Request( setMethod('GET'), setURL( `${BETA_API_ROOT}/lke/tiers/${encodeURIComponent( - tier - )}/versions/${encodeURIComponent(versionID)}` - ) + tier, + )}/versions/${encodeURIComponent(versionID)}`, + ), ); /** getKubernetesClusterEndpoint @@ -227,15 +229,15 @@ export const getKubernetesTieredVersionBeta = ( export const getKubernetesClusterEndpoints = ( clusterID: number, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setMethod('GET'), setXFilter(filters), setParams(params), setURL( - `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/api-endpoints` - ) + `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/api-endpoints`, + ), ); /** getKubernetesClusterDashboard @@ -247,8 +249,8 @@ export const getKubernetesClusterDashboard = (clusterID: number) => Request( setMethod('GET'), setURL( - `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/dashboard` - ) + `${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/dashboard`, + ), ); /** recycleClusterNodes @@ -260,7 +262,7 @@ export const getKubernetesClusterDashboard = (clusterID: number) => export const recycleClusterNodes = (clusterID: number) => Request<{}>( setMethod('POST'), - setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/recycle`) + setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/recycle`), ); /** @@ -272,7 +274,7 @@ export const getKubernetesTypes = (params?: Params) => Request>( setURL(`${API_ROOT}/lke/types`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -284,7 +286,7 @@ export const getKubernetesTypesBeta = (params?: Params) => Request>( setURL(`${BETA_API_ROOT}/lke/types`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -297,9 +299,9 @@ export const getKubernetesClusterControlPlaneACL = (clusterId: number) => setMethod('GET'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterId - )}/control_plane_acl` - ) + clusterId, + )}/control_plane_acl`, + ), ); /** @@ -309,14 +311,14 @@ export const getKubernetesClusterControlPlaneACL = (clusterId: number) => */ export const updateKubernetesClusterControlPlaneACL = ( clusterID: number, - data: Partial + data: Partial, ) => Request( setMethod('PUT'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/control_plane_acl` + clusterID, + )}/control_plane_acl`, ), - setData(data) + setData(data), ); diff --git a/packages/api-v4/src/kubernetes/nodePools.ts b/packages/api-v4/src/kubernetes/nodePools.ts index 0038b63e1b2..f7cfadcc256 100644 --- a/packages/api-v4/src/kubernetes/nodePools.ts +++ b/packages/api-v4/src/kubernetes/nodePools.ts @@ -1,5 +1,9 @@ -import { nodePoolSchema } from '@linode/validation/lib/kubernetes.schema'; -import { API_ROOT } from '../constants'; +import { + nodePoolBetaSchema, + nodePoolSchema, +} from '@linode/validation/lib/kubernetes.schema'; + +import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, setMethod, @@ -7,11 +11,15 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { - KubeNodePoolResponse, + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateNodePoolData, + CreateNodePoolDataBeta, + KubeNodePoolResponse, + KubeNodePoolResponseBeta, UpdateNodePoolData, + UpdateNodePoolDataBeta, } from './types'; /** @@ -22,13 +30,13 @@ import { export const getNodePools = ( clusterID: number, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/pools`) + setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/pools`), ); /** @@ -41,9 +49,24 @@ export const getNodePool = (clusterID: number, nodePoolID: number) => setMethod('GET'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/pools/${encodeURIComponent(nodePoolID)}` - ) + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}`, + ), + ); + +/** + * getNodePoolBeta + * + * Returns a single node pool with additional beta fields + */ +export const getNodePoolBeta = (clusterID: number, nodePoolID: number) => + Request( + setMethod('GET'), + setURL( + `${BETA_API_ROOT}/lke/clusters/${encodeURIComponent( + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}`, + ), ); /** @@ -55,7 +78,24 @@ export const createNodePool = (clusterID: number, data: CreateNodePoolData) => Request( setMethod('POST'), setURL(`${API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/pools`), - setData(data, nodePoolSchema) + setData(data, nodePoolSchema), + ); + +/** + * createNodePool + * + * Adds a node pool to the specified cluster with beta fields. + */ +export const createNodePoolBeta = ( + clusterID: number, + data: CreateNodePoolDataBeta, +) => + Request( + setMethod('POST'), + setURL( + `${BETA_API_ROOT}/lke/clusters/${encodeURIComponent(clusterID)}/pools`, + ), + setData(data, nodePoolBetaSchema), ); /** @@ -66,16 +106,36 @@ export const createNodePool = (clusterID: number, data: CreateNodePoolData) => export const updateNodePool = ( clusterID: number, nodePoolID: number, - data: Partial + data: Partial, ) => Request( setMethod('PUT'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/pools/${encodeURIComponent(nodePoolID)}` + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}`, + ), + setData(data, nodePoolSchema), + ); + +/** + * updateNodePoolBeta + * + * Change the type, count, upgrade_strategy, or k8_version of a node pool + */ +export const updateNodePoolBeta = ( + clusterID: number, + nodePoolID: number, + data: Partial, +) => + Request( + setMethod('PUT'), + setURL( + `${BETA_API_ROOT}/lke/clusters/${encodeURIComponent( + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}`, ), - setData(data, nodePoolSchema) + setData(data, nodePoolBetaSchema), ); /** @@ -88,9 +148,9 @@ export const deleteNodePool = (clusterID: number, nodePoolID: number) => setMethod('DELETE'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/pools/${encodeURIComponent(nodePoolID)}` - ) + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}`, + ), ); /** @@ -103,9 +163,9 @@ export const recycleAllNodes = (clusterID: number, nodePoolID: number) => setMethod('POST'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/pools/${encodeURIComponent(nodePoolID)}/recycle` - ) + clusterID, + )}/pools/${encodeURIComponent(nodePoolID)}/recycle`, + ), ); /** @@ -118,7 +178,7 @@ export const recycleNode = (clusterID: number, nodeID: string) => setMethod('POST'), setURL( `${API_ROOT}/lke/clusters/${encodeURIComponent( - clusterID - )}/nodes/${encodeURIComponent(nodeID)}/recycle` - ) + clusterID, + )}/nodes/${encodeURIComponent(nodeID)}/recycle`, + ), ); diff --git a/packages/api-v4/src/kubernetes/types.ts b/packages/api-v4/src/kubernetes/types.ts index bb370db3688..dc6acc1f041 100644 --- a/packages/api-v4/src/kubernetes/types.ts +++ b/packages/api-v4/src/kubernetes/types.ts @@ -1,16 +1,18 @@ import type { EncryptionStatus } from '../linodes'; -export type KubernetesTier = 'standard' | 'enterprise'; +export type KubernetesTier = 'enterprise' | 'standard'; export type KubernetesTaintEffect = + | 'NoExecute' | 'NoSchedule' - | 'PreferNoSchedule' - | 'NoExecute'; + | 'PreferNoSchedule'; export type Label = { [key: string]: string; }; +export type NodePoolUpdateStrategy = 'on_recycle' | 'rolling_update'; + export interface Taint { effect: KubernetesTaintEffect; key: string; @@ -18,57 +20,75 @@ export interface Taint { } export interface KubernetesCluster { + apl_enabled?: boolean; // this is not the ideal solution, but a necessary compromise to prevent a lot of duplicated code. + control_plane: ControlPlaneOptions; created: string; - updated: string; + id: number; + k8s_version: string; + label: string; region: string; status: string; // @todo enum this - label: string; - k8s_version: string; - id: number; tags: string[]; - control_plane: ControlPlaneOptions; - apl_enabled?: boolean; // this is not the ideal solution, but a necessary compromise to prevent a lot of duplicated code. /** Marked as 'optional' in this existing interface to prevent duplicated code for beta functionality, in line with the apl_enabled approach. * @todo LKE-E - Make this field required once LKE-E is in GA. tier defaults to 'standard' in the API. */ tier?: KubernetesTier; + updated: string; } export interface KubeNodePoolResponse { + autoscaler: AutoscaleSettings; count: number; + disk_encryption?: EncryptionStatus; // @TODO LDE: remove optionality once LDE is fully rolled out id: number; labels: Label; nodes: PoolNodeResponse[]; tags: string[]; taints: Taint[]; type: string; - autoscaler: AutoscaleSettings; - disk_encryption?: EncryptionStatus; // @TODO LDE: remove optionality once LDE is fully rolled out +} + +export interface KubeNodePoolResponseBeta extends KubeNodePoolResponse { + firewall_id: number; + k8s_version: string; + update_strategy: NodePoolUpdateStrategy; } export interface PoolNodeResponse { id: string; - instance_id: number | null; + instance_id: null | number; status: string; } export interface CreateNodePoolData { - type: string; count: number; + type: string; +} + +export interface CreateNodePoolDataBeta extends CreateNodePoolData { + firewall_id?: number; + k8s_version?: string; + update_strategy?: NodePoolUpdateStrategy; } export interface UpdateNodePoolData { autoscaler: AutoscaleSettings; count: number; - tags: string[]; labels: Label; + tags: string[]; taints: Taint[]; } +export interface UpdateNodePoolDataBeta extends UpdateNodePoolData { + firewall_id?: number; + k8s_version?: string; + update_strategy?: NodePoolUpdateStrategy; +} + export interface AutoscaleSettings { enabled: boolean; - min: number; max: number; + min: number; } export interface KubeConfigResponse { @@ -97,25 +117,25 @@ export interface KubernetesControlPlaneACLPayload { } export interface ControlPlaneACLOptions { - enabled?: boolean; - 'revision-id'?: string; addresses?: null | { ipv4?: null | string[]; ipv6?: null | string[]; }; + enabled?: boolean; + 'revision-id'?: string; } export interface ControlPlaneOptions { - high_availability?: boolean; acl?: ControlPlaneACLOptions; + high_availability?: boolean; } export interface CreateKubeClusterPayload { + apl_enabled?: boolean; // this is not the ideal solution, but a necessary compromise to prevent a lot of duplicated code. + control_plane?: ControlPlaneOptions; + k8s_version?: string; // Will be caught by Yup if undefined label?: string; // Label will be assigned by the API if not provided - region?: string; // Will be caught by Yup if undefined node_pools: CreateNodePoolData[]; - k8s_version?: string; // Will be caught by Yup if undefined - control_plane?: ControlPlaneOptions; - apl_enabled?: boolean; // this is not the ideal solution, but a necessary compromise to prevent a lot of duplicated code. + region?: string; // Will be caught by Yup if undefined tier?: KubernetesTier; // For LKE-E: Will be assigned 'standard' by the API if not provided } diff --git a/packages/api-v4/src/linodes/actions.ts b/packages/api-v4/src/linodes/actions.ts index dc814e2079d..b06b7395acc 100644 --- a/packages/api-v4/src/linodes/actions.ts +++ b/packages/api-v4/src/linodes/actions.ts @@ -1,7 +1,9 @@ import { RebuildLinodeSchema } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { + +import type { Devices, Linode, LinodeCloneData, @@ -29,7 +31,7 @@ export const linodeBoot = (linodeId: number | string, config_id?: number) => Request<{}>( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/boot`), setMethod('POST'), - setData({ config_id }) + setData({ config_id }), ); /** @@ -45,10 +47,10 @@ export const linodeBoot = (linodeId: number | string, config_id?: number) => export const linodeReboot = (linodeId: number | string, config_id?: number) => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/reboot` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/reboot`, ), setMethod('POST'), - setData({ config_id }) + setData({ config_id }), ); /** @@ -63,9 +65,9 @@ export const linodeReboot = (linodeId: number | string, config_id?: number) => export const linodeShutdown = (linodeId: number | string) => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/shutdown` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/shutdown`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -88,10 +90,10 @@ export const linodeShutdown = (linodeId: number | string) => export const resizeLinode = (linodeId: number, data: ResizeLinodePayload) => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/resize` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/resize`, ), setMethod('POST'), - setData(data) + setData(data), ); /** @@ -112,10 +114,10 @@ export const resizeLinode = (linodeId: number, data: ResizeLinodePayload) => export const rebuildLinode = (linodeId: number, data: RebuildRequest) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rebuild` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rebuild`, ), setMethod('POST'), - setData(data, RebuildLinodeSchema) + setData(data, RebuildLinodeSchema), ); /** @@ -134,16 +136,16 @@ export const rebuildLinode = (linodeId: number, data: RebuildRequest) => */ export const rescueLinode = ( linodeId: number, - devices: Devices + devices: Devices, ): Promise<{}> => { const _devices = { ...devices } as any; delete _devices['sdh']; return Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rescue` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rescue`, ), setMethod('POST'), - setData({ devices: _devices as RescueRequestObject }) + setData({ devices: _devices as RescueRequestObject }), ); }; @@ -164,9 +166,9 @@ export const rescueLinode = ( export const rescueMetalLinode = (linodeId: number): Promise<{}> => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rescue` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/rescue`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -183,10 +185,10 @@ export const rescueMetalLinode = (linodeId: number): Promise<{}> => export const cloneLinode = (sourceLinodeId: number, data: LinodeCloneData) => { return Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(sourceLinodeId)}/clone` + `${API_ROOT}/linode/instances/${encodeURIComponent(sourceLinodeId)}/clone`, ), setMethod('POST'), - setData(data) + setData(data), ); }; @@ -204,9 +206,9 @@ export const cloneLinode = (sourceLinodeId: number, data: LinodeCloneData) => { export const startMutation = (linodeID: number) => { return Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeID)}/mutate` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeID)}/mutate`, ), - setMethod('POST') + setMethod('POST'), ); }; @@ -220,12 +222,12 @@ export const startMutation = (linodeID: number) => { */ export const scheduleOrQueueMigration = ( linodeID: number, - payload?: { region: string } + payload?: { region: string }, ) => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeID)}/migrate` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeID)}/migrate`, ), setData(payload || {}), - setMethod('POST') + setMethod('POST'), ); diff --git a/packages/api-v4/src/linodes/backups.ts b/packages/api-v4/src/linodes/backups.ts index a882d8a3e65..9c200380216 100644 --- a/packages/api-v4/src/linodes/backups.ts +++ b/packages/api-v4/src/linodes/backups.ts @@ -1,7 +1,9 @@ import { CreateSnapshotSchema } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { LinodeBackup, LinodeBackupsResponse } from './types'; + +import type { LinodeBackup, LinodeBackupsResponse } from './types'; type Backup = LinodeBackup; @@ -15,7 +17,7 @@ type Backup = LinodeBackup; export const getLinodeBackups = (id: number) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(id)}/backups`), - setMethod('GET') + setMethod('GET'), ); /** @@ -29,10 +31,10 @@ export const enableBackups = (linodeId: number) => Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/backups/enable` + linodeId, + )}/backups/enable`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -46,10 +48,10 @@ export const cancelBackups = (linodeId: number) => Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/backups/cancel` + linodeId, + )}/backups/cancel`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -64,10 +66,10 @@ export const cancelBackups = (linodeId: number) => export const takeSnapshot = (linodeId: number, label: string) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/backups` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/backups`, ), setMethod('POST'), - setData({ label }, CreateSnapshotSchema) + setData({ label }, CreateSnapshotSchema), ); /** @@ -85,14 +87,14 @@ export const restoreBackup = ( linodeId: number, backupId: number, targetLinodeId: number, - overwrite: boolean + overwrite: boolean, ) => Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/backups/${encodeURIComponent(backupId)}/restore` + linodeId, + )}/backups/${encodeURIComponent(backupId)}/restore`, ), setMethod('POST'), - setData({ linode_id: targetLinodeId, overwrite }) + setData({ linode_id: targetLinodeId, overwrite }), ); diff --git a/packages/api-v4/src/linodes/configs.ts b/packages/api-v4/src/linodes/configs.ts index 0c3927fa58a..e76510cff7a 100644 --- a/packages/api-v4/src/linodes/configs.ts +++ b/packages/api-v4/src/linodes/configs.ts @@ -1,10 +1,11 @@ import { + ConfigProfileInterfaceSchema, CreateLinodeConfigSchema, UpdateConfigInterfaceOrderSchema, UpdateConfigInterfaceSchema, UpdateLinodeConfigSchema, - ConfigProfileInterfaceSchema, } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -13,8 +14,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, ResourcePage as Page, Params } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Config, ConfigInterfaceOrderPayload, Interface, @@ -34,13 +36,13 @@ import { export const getLinodeConfigs = ( linodeId: number, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setURL(`${API_ROOT}/linode/instances/${linodeId}/configs`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -54,7 +56,7 @@ export const getLinodeConfigs = ( export const getLinodeConfig = (linodeId: number, configId: number) => Request( setURL(`${API_ROOT}/linode/instances/${linodeId}/configs/${configId}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -66,14 +68,14 @@ export const getLinodeConfig = (linodeId: number, configId: number) => */ export const createLinodeConfig = ( linodeId: number, - data: LinodeConfigCreationData + data: LinodeConfigCreationData, ) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/configs` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/configs`, ), setMethod('POST'), - setData(data, CreateLinodeConfigSchema) + setData(data, CreateLinodeConfigSchema), ); /** @@ -89,9 +91,9 @@ export const deleteLinodeConfig = (linodeId: number, configId: number) => setMethod('DELETE'), setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/configs/${encodeURIComponent(configId)}` - ) + linodeId, + )}/configs/${encodeURIComponent(configId)}`, + ), ); /** @@ -106,16 +108,16 @@ export const deleteLinodeConfig = (linodeId: number, configId: number) => export const updateLinodeConfig = ( linodeId: number, configId: number, - data: Partial + data: Partial, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/configs/${encodeURIComponent(configId)}` + linodeId, + )}/configs/${encodeURIComponent(configId)}`, ), setMethod('PUT'), - setData(data, UpdateLinodeConfigSchema) + setData(data, UpdateLinodeConfigSchema), ); /** @@ -130,10 +132,10 @@ export const getConfigInterfaces = (linodeId: number, configId: number) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/configs/${encodeURIComponent(configId)}/interfaces` + linodeId, + )}/configs/${encodeURIComponent(configId)}/interfaces`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -148,17 +150,17 @@ export const getConfigInterfaces = (linodeId: number, configId: number) => export const getConfigInterface = ( linodeId: number, configId: number, - interfaceId: number + interfaceId: number, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId + linodeId, )}/configs/${encodeURIComponent( - configId - )}/interfaces/${encodeURIComponent(interfaceId)}` + configId, + )}/interfaces/${encodeURIComponent(interfaceId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -173,16 +175,16 @@ export const getConfigInterface = ( export const appendConfigInterface = ( linodeId: number, configId: number, - data: InterfacePayload + data: InterfacePayload, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/configs/${encodeURIComponent(configId)}/interfaces` + linodeId, + )}/configs/${encodeURIComponent(configId)}/interfaces`, ), setMethod('POST'), - setData(data, ConfigProfileInterfaceSchema) + setData(data, ConfigProfileInterfaceSchema), ); /** @@ -198,18 +200,18 @@ export const updateConfigInterface = ( linodeId: number, configId: number, interfaceId: number, - data: UpdateConfigInterfacePayload + data: UpdateConfigInterfacePayload, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId + linodeId, )}/configs/${encodeURIComponent( - configId - )}/interfaces/${encodeURIComponent(interfaceId)}` + configId, + )}/interfaces/${encodeURIComponent(interfaceId)}`, ), setMethod('PUT'), - setData(data, UpdateConfigInterfaceSchema) + setData(data, UpdateConfigInterfaceSchema), ); /** @@ -223,16 +225,16 @@ export const updateConfigInterface = ( export const updateLinodeConfigOrder = ( linodeId: number, configId: number, - data: ConfigInterfaceOrderPayload + data: ConfigInterfaceOrderPayload, ) => Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/configs/${encodeURIComponent(configId)}/interfaces/order` + linodeId, + )}/configs/${encodeURIComponent(configId)}/interfaces/order`, ), setMethod('POST'), - setData(data, UpdateConfigInterfaceOrderSchema) + setData(data, UpdateConfigInterfaceOrderSchema), ); /** @@ -247,15 +249,15 @@ export const updateLinodeConfigOrder = ( export const deleteLinodeConfigInterface = ( linodeId: number, configId: number, - interfaceId: number + interfaceId: number, ) => Request<{}>( setMethod('DELETE'), setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId + linodeId, )}/configs/${encodeURIComponent( - configId - )}/interfaces/${encodeURIComponent(interfaceId)}` - ) + configId, + )}/interfaces/${encodeURIComponent(interfaceId)}`, + ), ); diff --git a/packages/api-v4/src/linodes/disks.ts b/packages/api-v4/src/linodes/disks.ts index 0a07bee36ab..f9ea0245506 100644 --- a/packages/api-v4/src/linodes/disks.ts +++ b/packages/api-v4/src/linodes/disks.ts @@ -3,6 +3,7 @@ import { ResizeLinodeDiskSchema, UpdateLinodePasswordSchema, } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -11,8 +12,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Disk, LinodeDiskCreationData } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Disk, LinodeDiskCreationData } from './types'; /** * getLinodeDisks @@ -24,15 +26,15 @@ import { Disk, LinodeDiskCreationData } from './types'; export const getLinodeDisks = ( linodeId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/disks` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/disks`, ), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -44,14 +46,14 @@ export const getLinodeDisks = ( */ export const createLinodeDisk = ( linodeId: number, - data: LinodeDiskCreationData + data: LinodeDiskCreationData, ) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/disks` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/disks`, ), setMethod('POST'), - setData(data, CreateLinodeDiskSchema) + setData(data, CreateLinodeDiskSchema), ); /** @@ -66,10 +68,10 @@ export const getLinodeDisk = (linodeId: number, diskId: number) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}` + linodeId, + )}/disks/${encodeURIComponent(diskId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -83,16 +85,16 @@ export const getLinodeDisk = (linodeId: number, diskId: number) => export const updateLinodeDisk = ( linodeId: number, diskId: number, - data: Pick + data: Pick, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}` + linodeId, + )}/disks/${encodeURIComponent(diskId)}`, ), setMethod('PUT'), - setData(data) + setData(data), ); /** @@ -112,16 +114,16 @@ export const updateLinodeDisk = ( export const resizeLinodeDisk = ( linodeId: number, diskId: number, - size: number + size: number, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}/resize` + linodeId, + )}/disks/${encodeURIComponent(diskId)}/resize`, ), setMethod('POST'), - setData({ size }, ResizeLinodeDiskSchema) + setData({ size }, ResizeLinodeDiskSchema), ); /** @@ -135,10 +137,10 @@ export const cloneLinodeDisk = (linodeId: number, diskId: number) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}/clone` + linodeId, + )}/disks/${encodeURIComponent(diskId)}/clone`, ), - setMethod('POST') + setMethod('POST'), ); /** @@ -153,10 +155,10 @@ export const deleteLinodeDisk = (linodeId: number, diskId: number) => Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}` + linodeId, + )}/disks/${encodeURIComponent(diskId)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -171,14 +173,14 @@ export const deleteLinodeDisk = (linodeId: number, diskId: number) => export const changeLinodeDiskPassword = ( linodeId: number, diskId: number, - password: string + password: string, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/disks/${encodeURIComponent(diskId)}/password` + linodeId, + )}/disks/${encodeURIComponent(diskId)}/password`, ), setMethod('POST'), - setData({ password }, UpdateLinodePasswordSchema) + setData({ password }, UpdateLinodePasswordSchema), ); diff --git a/packages/api-v4/src/linodes/index.ts b/packages/api-v4/src/linodes/index.ts index 38625c60acd..d06387e5f01 100644 --- a/packages/api-v4/src/linodes/index.ts +++ b/packages/api-v4/src/linodes/index.ts @@ -10,8 +10,8 @@ export * from './info'; export * from './ips'; -export * from './linodes'; - export * from './linode-interfaces'; +export * from './linodes'; + export * from './types'; diff --git a/packages/api-v4/src/linodes/info.ts b/packages/api-v4/src/linodes/info.ts index c5de3f6081d..19f953fa49c 100644 --- a/packages/api-v4/src/linodes/info.ts +++ b/packages/api-v4/src/linodes/info.ts @@ -1,8 +1,12 @@ import { API_ROOT } from '../constants'; -import { RegionalNetworkUtilization, NetworkTransfer } from '../account/types'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Kernel, LinodeType as Type, Stats } from './types'; + +import type { + NetworkTransfer, + RegionalNetworkUtilization, +} from '../account/types'; +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Kernel, Stats, LinodeType as Type } from './types'; /** * getLinodeStats @@ -14,9 +18,9 @@ import { Kernel, LinodeType as Type, Stats } from './types'; export const getLinodeStats = (linodeId: number) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/stats` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/stats`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -33,15 +37,15 @@ export const getLinodeStats = (linodeId: number) => export const getLinodeStatsByDate = ( linodeId: number, year: string, - month: string + month: string, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/stats/${encodeURIComponent(year)}/${encodeURIComponent(month)}` + linodeId, + )}/stats/${encodeURIComponent(year)}/${encodeURIComponent(month)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -54,9 +58,9 @@ export const getLinodeStatsByDate = ( export const getLinodeTransfer = (linodeId: number) => Request( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/transfer` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/transfer`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -71,15 +75,15 @@ export const getLinodeTransfer = (linodeId: number) => export const getLinodeTransferByDate = ( linodeId: number, year: string, - month: string + month: string, ) => Request( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - linodeId - )}/transfer/${encodeURIComponent(year)}/${encodeURIComponent(month)}` + linodeId, + )}/transfer/${encodeURIComponent(year)}/${encodeURIComponent(month)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -94,7 +98,7 @@ export const getLinodeKernels = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/linode/kernels`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -109,7 +113,7 @@ export const getLinodeKernels = (params?: Params, filter?: Filter) => export const getLinodeKernel = (kernelId: string) => Request( setURL(`${API_ROOT}/linode/kernels/${encodeURIComponent(kernelId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -122,7 +126,7 @@ export const getLinodeTypes = (params?: Params) => Request>( setURL(`${API_ROOT}/linode/types`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -136,7 +140,7 @@ export const getLinodeTypes = (params?: Params) => export const getType = (typeId: string) => Request( setURL(`${API_ROOT}/linode/types/${encodeURIComponent(typeId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -149,5 +153,5 @@ export const getType = (typeId: string) => export const getDeprecatedLinodeTypes = () => Request>( setURL(`${API_ROOT}/linode/types-legacy`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/linodes/ips.ts b/packages/api-v4/src/linodes/ips.ts index cb248604798..bb273333f7d 100644 --- a/packages/api-v4/src/linodes/ips.ts +++ b/packages/api-v4/src/linodes/ips.ts @@ -1,8 +1,10 @@ import { IPAllocationSchema } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; -import { IPAddress } from '../networking/types'; import Request, { setData, setMethod, setURL } from '../request'; -import { IPAllocationRequest, LinodeIPsResponse } from './types'; + +import type { IPAddress } from '../networking/types'; +import type { IPAllocationRequest, LinodeIPsResponse } from './types'; /** * getLinodeIPs @@ -14,7 +16,7 @@ import { IPAllocationRequest, LinodeIPsResponse } from './types'; export const getLinodeIPs = (id: number) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(id)}/ips`), - setMethod('GET') + setMethod('GET'), ); /** @@ -29,12 +31,12 @@ export const getLinodeIPs = (id: number) => */ export const allocateIPAddress = ( linodeID: number, - data: IPAllocationRequest + data: IPAllocationRequest, ) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeID)}/ips`), setMethod('POST'), - setData(data, IPAllocationSchema) + setData(data, IPAllocationSchema), ); /** @@ -47,16 +49,16 @@ export const allocateIPAddress = ( * @param payload.address {string} - the IP Address for which you'd like the delete request to be invoked */ export const removeIPAddress = (payload: { - linodeID: number; address: string; + linodeID: number; }) => { return Request<{}>( setURL( `${API_ROOT}/linode/instances/${encodeURIComponent( - payload.linodeID - )}/ips/${encodeURIComponent(payload.address)}` + payload.linodeID, + )}/ips/${encodeURIComponent(payload.address)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); }; @@ -70,8 +72,8 @@ export const removeIPAddress = (payload: { export const removeIPv6Range = (payload: { range: string }) => { return Request<{}>( setURL( - `${API_ROOT}/networking/ipv6/ranges/${encodeURIComponent(payload.range)}` + `${API_ROOT}/networking/ipv6/ranges/${encodeURIComponent(payload.range)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); }; diff --git a/packages/api-v4/src/linodes/linodes.ts b/packages/api-v4/src/linodes/linodes.ts index c69795ffad7..2423bd8d6d1 100644 --- a/packages/api-v4/src/linodes/linodes.ts +++ b/packages/api-v4/src/linodes/linodes.ts @@ -2,8 +2,8 @@ import { CreateLinodeSchema, UpdateLinodeSchema, } from '@linode/validation/lib/linodes.schema'; + import { API_ROOT } from '../constants'; -import { Firewall } from '../firewalls/types'; import Request, { setData, setMethod, @@ -11,9 +11,16 @@ import Request, { setURL, setXFilter, } from '../request'; -import { DeepPartial, Filter, Params, ResourcePage as Page } from '../types'; -import { Volume } from '../volumes/types'; -import { CreateLinodeRequest, Linode, LinodeLishData } from './types'; + +import type { Firewall } from '../firewalls/types'; +import type { + DeepPartial, + Filter, + ResourcePage as Page, + Params, +} from '../types'; +import type { Volume } from '../volumes/types'; +import type { CreateLinodeRequest, Linode, LinodeLishData } from './types'; /** * getLinode @@ -25,7 +32,7 @@ import { CreateLinodeRequest, Linode, LinodeLishData } from './types'; export const getLinode = (linodeId: number) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -38,7 +45,7 @@ export const getLinode = (linodeId: number) => export const getLinodeLish = (linodeId: number) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/lish`), - setMethod('POST') + setMethod('POST'), ); /** @@ -52,15 +59,15 @@ export const getLinodeLish = (linodeId: number) => export const getLinodeVolumes = ( linodeId: number, params: Params = {}, - filter: Filter = {} + filter: Filter = {}, ) => Request>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/volumes` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/volumes`, ), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -75,7 +82,7 @@ export const getLinodes = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/linode/instances`), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -92,7 +99,7 @@ export const createLinode = (data: CreateLinodeRequest) => Request( setURL(`${API_ROOT}/linode/instances`), setMethod('POST'), - setData(data, CreateLinodeSchema) + setData(data, CreateLinodeSchema), ); /** @@ -108,7 +115,7 @@ export const updateLinode = (linodeId: number, values: DeepPartial) => Request( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}`), setMethod('PUT'), - setData(values, UpdateLinodeSchema) + setData(values, UpdateLinodeSchema), ); /** @@ -121,7 +128,7 @@ export const updateLinode = (linodeId: number, values: DeepPartial) => export const deleteLinode = (linodeId: number) => Request<{}>( setURL(`${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -137,10 +144,10 @@ export const deleteLinode = (linodeId: number) => export const changeLinodePassword = (linodeId: number, root_pass: string) => Request<{}>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/password` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/password`, ), setData({ root_pass }), - setMethod('POST') + setMethod('POST'), ); /** @@ -152,13 +159,13 @@ export const changeLinodePassword = (linodeId: number, root_pass: string) => export const getLinodeFirewalls = ( linodeId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( - `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/firewalls` + `${API_ROOT}/linode/instances/${encodeURIComponent(linodeId)}/firewalls`, ), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); diff --git a/packages/api-v4/src/linodes/types.ts b/packages/api-v4/src/linodes/types.ts index eb9242117c0..d9fd16bb377 100644 --- a/packages/api-v4/src/linodes/types.ts +++ b/packages/api-v4/src/linodes/types.ts @@ -8,6 +8,7 @@ import type { UpdateLinodeInterfaceSettingsSchema, UpgradeToLinodeInterfaceSchema, } from '@linode/validation'; +import type { MaintenancePolicyId } from 'src/account'; import type { VPCIP } from 'src/vpcs'; import type { InferType } from 'yup'; @@ -18,38 +19,39 @@ export type EncryptionStatus = 'disabled' | 'enabled'; export type InterfaceGenerationType = 'legacy_config' | 'linode'; export interface LinodeSpecs { + accelerated_devices: number; disk: number; + gpus: number; memory: number; - vcpus: number; transfer: number; - gpus: number; - accelerated_devices: number; + vcpus: number; } export interface Linode { - id: number; alerts: LinodeAlerts; backups: LinodeBackups; capabilities: LinodeCapabilities[]; created: string; disk_encryption?: EncryptionStatus; // @TODO LDE: Remove optionality once LDE is fully rolled out - region: string; - image: string | null; group: string; + hypervisor: Hypervisor; + id: number; + image: null | string; interface_generation?: InterfaceGenerationType; // @TODO Linode Interfaces - Remove optionality once fully rolled out ipv4: string[]; - ipv6: string | null; + ipv6: null | string; label: string; - lke_cluster_id: number | null; + lke_cluster_id: null | number; + maintenance_policy_id?: MaintenancePolicyId; placement_group?: LinodePlacementGroupPayload; // If not in a placement group, this will be excluded from the response. - type: string | null; + region: string; + site_type: RegionSite; + specs: LinodeSpecs; status: LinodeStatus; + tags: string[]; + type: null | string; updated: string; - hypervisor: Hypervisor; - specs: LinodeSpecs; watchdog_enabled: boolean; - tags: string[]; - site_type: RegionSite; } export interface LinodeAlerts { @@ -62,14 +64,14 @@ export interface LinodeAlerts { export interface LinodeBackups { enabled: boolean; + last_successful: null | string; schedule: LinodeBackupSchedule; - last_successful: string | null; } export type LinodeCapabilities = | 'Block Storage Encryption' - | 'SMTP Enabled' - | 'Block Storage Performance B1'; + | 'Block Storage Performance B1' + | 'SMTP Enabled'; export type Window = | 'Scheduling' @@ -86,18 +88,18 @@ export type Window = | 'W22'; export type Day = + | 'Friday' + | 'Monday' + | 'Saturday' | 'Scheduling' | 'Sunday' - | 'Monday' - | 'Tuesday' - | 'Wednesday' | 'Thursday' - | 'Friday' - | 'Saturday'; + | 'Tuesday' + | 'Wednesday'; export interface LinodeBackupSchedule { - window: Window | null; day: Day | null; + window: null | Window; } export interface LinodeBackupsResponse { @@ -108,37 +110,37 @@ export interface LinodeBackupsResponse { }; } -export type Filesystem = 'raw' | 'swap' | 'ext4' | 'ext3' | 'initrd'; +export type Filesystem = 'ext3' | 'ext4' | 'initrd' | 'raw' | 'swap'; export interface LinodeBackupDisk { - size: number; - label: string; filesystem: Filesystem; + label: string; + size: number; } export interface LinodeBackup { + available: boolean; + configs: string[]; + created: string; + disks: LinodeBackupDisk[]; + finished: string; id: number; - label: string | null; + label: null | string; + region: string; status: LinodeBackupStatus; type: LinodeBackupType; - region: string; - created: string; updated: string; - finished: string; - configs: string[]; - disks: LinodeBackupDisk[]; - available: boolean; } export type LinodeBackupType = 'auto' | 'snapshot'; export type LinodeBackupStatus = + | 'failed' + | 'needsPostProcessing' + | 'paused' | 'pending' | 'running' - | 'paused' - | 'needsPostProcessing' | 'successful' - | 'failed' | 'userAborted'; export interface LinodeIPsResponse { @@ -147,31 +149,31 @@ export interface LinodeIPsResponse { } export interface LinodeIPsResponseIPV4 { - public: IPAddress[]; private: IPAddress[]; - shared: IPAddress[]; + public: IPAddress[]; reserved: IPAddress[]; + shared: IPAddress[]; vpc: VPCIP[]; } export interface LinodeIPsResponseIPV6 { + global: IPRange[]; link_local: IPAddress; slaac: IPAddress; - global: IPRange[]; } export type LinodeStatus = - | 'offline' | 'booting' - | 'running' - | 'shutting_down' - | 'rebooting' - | 'rebuilding' - | 'provisioning' + | 'cloning' | 'deleting' | 'migrating' - | 'cloning' + | 'offline' + | 'provisioning' + | 'rebooting' + | 'rebuilding' | 'restoring' + | 'running' + | 'shutting_down' | 'stopped'; // --------------------------------------------------------------------- @@ -181,54 +183,54 @@ export type InterfacePurpose = 'public' | 'vlan' | 'vpc'; // IPv4 export interface ConfigInterfaceIPv4 { - vpc?: string | null; - nat_1_1?: string | null; + nat_1_1?: null | string; + vpc?: null | string; } export interface IPv6SLAAC { - range: string; address: string; + range: string; } export interface ConfigInterfaceIPv6 { - slaac: IPv6SLAAC[]; + is_public: boolean; ranges: { range?: string; }[]; - is_public: boolean; + slaac: IPv6SLAAC[]; } // The legacy interface type - for Configuration Profile Interfaces export interface Interface { - id: number; - label: string | null; - purpose: InterfacePurpose; - ipam_address: string | null; - primary?: boolean; active: boolean; - subnet_id?: number | null; - vpc_id?: number | null; + id: number; + ip_ranges?: string[]; + ipam_address: null | string; ipv4?: ConfigInterfaceIPv4; ipv6?: ConfigInterfaceIPv6; - ip_ranges?: string[]; + label: null | string; + primary?: boolean; + purpose: InterfacePurpose; + subnet_id?: null | number; + vpc_id?: null | number; } export interface InterfacePayload { - /** - * Required to specify a VLAN - */ - label?: string | null; - purpose: InterfacePurpose; + ip_ranges?: null | string[]; /** * Used for VLAN, but is optional */ - ipam_address?: string | null; - primary?: boolean; - subnet_id?: number | null; - vpc_id?: number | null; + ipam_address?: null | string; ipv4?: ConfigInterfaceIPv4; ipv6?: ConfigInterfaceIPv6; - ip_ranges?: string[] | null; + /** + * Required to specify a VLAN + */ + label?: null | string; + primary?: boolean; + purpose: InterfacePurpose; + subnet_id?: null | number; + vpc_id?: null | number; } export interface ConfigInterfaceOrderPayload { @@ -237,25 +239,25 @@ export interface ConfigInterfaceOrderPayload { export type UpdateConfigInterfacePayload = Pick< Interface, - 'primary' | 'ipv4' | 'ipv6' | 'ip_ranges' + 'ip_ranges' | 'ipv4' | 'ipv6' | 'primary' >; export interface Config { + comments: string; + created: string; + devices: Devices; + helpers: any; id: number; + initrd: null | string; + // If a Linode is using new Linode Interfaces, the interfaces in the Config object will be returned as null. + interfaces: Interface[] | null; kernel: string; - comments: string; + label: string; memory_limit: number; root_device: string; - run_level: 'default' | 'single' | 'binbash'; - virt_mode: 'paravirt' | 'fullvirt'; - helpers: any; - label: string; - devices: Devices; - created: string; + run_level: 'binbash' | 'default' | 'single'; updated: string; - initrd: string | null; - // If a Linode is using new Linode Interfaces, the interfaces in the Config object will be returned as null. - interfaces: Interface[] | null; + virt_mode: 'fullvirt' | 'paravirt'; } // ---------------------------------------------------------- @@ -278,18 +280,18 @@ export type ModifyLinodeInterfacePayload = InferType< // GET object export interface LinodeInterface { + created: string; + default_route: DefaultRoute; id: number; mac_address: string; - default_route: DefaultRoute; - version: number; - created: string; + public: null | PublicInterfaceData; updated: string; - vpc: VPCInterfaceData | null; - public: PublicInterfaceData | null; - vlan: { - vlan_label: string; + version: number; + vlan: null | { ipam_address: string; - } | null; + vlan_label: string; + }; + vpc: null | VPCInterfaceData; } export interface LinodeInterfaces { @@ -297,25 +299,25 @@ export interface LinodeInterfaces { } export interface LinodeInterfaceIPv6 { - slaac: IPv6SLAAC[]; + is_public: boolean; ranges: { range: string; }[]; - is_public: boolean; + slaac: IPv6SLAAC[]; } export interface VPCInterfaceData { - vpc_id: number; - subnet_id: number; ipv4?: { addresses: { address: string; - primary: boolean; nat_1_1_address?: string; + primary: boolean; }[]; ranges: { range: string }[]; }; ipv6?: LinodeInterfaceIPv6; + subnet_id: number; + vpc_id: number; } export interface PublicInterfaceData { @@ -330,43 +332,43 @@ export interface PublicInterfaceData { }[]; }; ipv6: { - slaac: { - address: string; - prefix: string; + ranges: { + range: string; + route_target: null | string; }[]; shared: { range: string; - route_target: string | null; + route_target: null | string; }[]; - ranges: { - range: string; - route_target: string | null; + slaac: { + address: string; + prefix: string; }[]; }; } // Other Linode Interface types -export type LinodeInterfaceStatus = 'active' | 'inactive' | 'deleted'; +export type LinodeInterfaceStatus = 'active' | 'deleted' | 'inactive'; export interface LinodeInterfaceHistory { + created: string; + event_id: number; + interface_data: string; // will come in as JSON string object that we'll need to parse interface_history_id: number; interface_id: number; linode_id: number; - event_id: number; - version: number; - interface_data: string; // will come in as JSON string object that we'll need to parse status: LinodeInterfaceStatus; - created: string; + version: number; } export interface LinodeInterfaceSettings { - network_helper: boolean; default_route: { - ipv4_interface_id?: number | null; ipv4_eligible_interface_ids: number[]; - ipv6_interface_id?: number | null; + ipv4_interface_id?: null | number; ipv6_eligible_interface_ids: number[]; + ipv6_interface_id?: null | number; }; + network_helper: boolean; } export type LinodeInterfaceSettingsPayload = InferType< @@ -393,30 +395,30 @@ export interface VolumeDevice { } export interface Devices { - sda: null | DiskDevice | VolumeDevice; - sdb: null | DiskDevice | VolumeDevice; - sdc: null | DiskDevice | VolumeDevice; - sdd: null | DiskDevice | VolumeDevice; - sde: null | DiskDevice | VolumeDevice; - sdf: null | DiskDevice | VolumeDevice; - sdg: null | DiskDevice | VolumeDevice; - sdh: null | DiskDevice | VolumeDevice; + sda: DiskDevice | null | VolumeDevice; + sdb: DiskDevice | null | VolumeDevice; + sdc: DiskDevice | null | VolumeDevice; + sdd: DiskDevice | null | VolumeDevice; + sde: DiskDevice | null | VolumeDevice; + sdf: DiskDevice | null | VolumeDevice; + sdg: DiskDevice | null | VolumeDevice; + sdh: DiskDevice | null | VolumeDevice; } -export type KernelArchitecture = 'x86_64' | 'i386'; +export type KernelArchitecture = 'i386' | 'x86_64'; export interface Kernel { - id: string; - label: string; - version: string; - kvm: boolean; architecture: KernelArchitecture; - pvops: boolean; - deprecated: boolean; /** * @example 2009-10-26T04:00:00 */ built: string; + deprecated: boolean; + id: string; + kvm: boolean; + label: string; + pvops: boolean; + version: string; } export interface NetStats { @@ -437,46 +439,46 @@ export interface StatsData { } export interface Stats { - title: string; data: StatsData; + title: string; } export interface Disk { + created: string; + disk_encryption?: EncryptionStatus; // @TODO LDE: remove optionality once LDE is fully rolled out + filesystem: Filesystem; id: number; label: string; - status: DiskStatus; size: number; - filesystem: Filesystem; - created: string; + status: DiskStatus; updated: string; - disk_encryption?: EncryptionStatus; // @TODO LDE: remove optionality once LDE is fully rolled out } -export type DiskStatus = 'ready' | 'not ready' | 'deleting'; +export type DiskStatus = 'deleting' | 'not ready' | 'ready'; export interface LinodeConfigCreationData { - label: string; - devices: Devices; - initrd: string | number | null; - kernel?: string; comments?: string; - memory_limit?: number; - run_level?: 'default' | 'single' | 'binbash'; - virt_mode?: 'fullvirt' | 'paravirt'; + devices: Devices; helpers: { - updatedb_disabled: boolean; + devtmpfs_automount: boolean; distro: boolean; modules_dep: boolean; network?: boolean; - devtmpfs_automount: boolean; + updatedb_disabled: boolean; }; - root_device: string; + initrd: null | number | string; interfaces?: InterfacePayload[]; + kernel?: string; + label: string; + memory_limit?: number; + root_device: string; + run_level?: 'binbash' | 'default' | 'single'; + virt_mode?: 'fullvirt' | 'paravirt'; } export interface PriceObject { - monthly: number | null; - hourly: number | null; + hourly: null | number; + monthly: null | number; } export interface RegionPriceObject extends PriceObject { @@ -484,71 +486,68 @@ export interface RegionPriceObject extends PriceObject { } export interface BaseType { + disk: number; id: string; label: string; - disk: number; memory: number; vcpus: number; } export interface LinodeType extends BaseType { - transfer: number; - class: LinodeTypeClass; - successor: string | null; - network_out: number; - gpus: number; accelerated_devices: number; - price: PriceObject; - region_prices: RegionPriceObject[]; addons: { backups: { price: PriceObject; region_prices: RegionPriceObject[] }; }; + class: LinodeTypeClass; + gpus: number; + network_out: number; + price: PriceObject; + region_prices: RegionPriceObject[]; + successor: null | string; + transfer: number; } export type LinodeTypeClass = | 'accelerated' - | 'nanode' - | 'standard' | 'dedicated' - | 'highmem' | 'gpu' + | 'highmem' | 'metal' + | 'nanode' + | 'premium' | 'prodedicated' - | 'premium'; + | 'standard'; export interface IPAllocationRequest { - type: 'ipv4'; public: boolean; + type: 'ipv4'; } export interface UserData { - user_data: string | null; + user_data: null | string; } export interface CreateLinodePlacementGroupPayload { - id: number; /** * This parameter is silent in Cloud Manager, but still needs to be represented in the API types. * * @default false */ compliant_only?: boolean; + id: number; } export interface CreateLinodeRequest { /** - * The Linode Type of the Linode you are creating. - */ - type: string; - /** - * The Region where the Linode will be located. + * A list of public SSH keys that will be automatically appended to the root user’s + * `~/.ssh/authorized_keys`file when deploying from an Image. */ - region: string; + authorized_keys?: null | string[]; /** - * A StackScript ID that will cause the referenced StackScript to be run during deployment of this Linode. - * - * This field cannot be used when deploying from a Backup or a Private Image. + * A list of usernames. If the usernames have associated SSH keys, + * the keys will be appended to the root users `~/.ssh/authorized_keys` + * file automatically when deploying from an Image. */ - stackscript_id?: number | null; + authorized_users?: null | string[]; /** * A Backup ID from another Linode’s available backups. * @@ -558,26 +557,7 @@ export interface CreateLinodeRequest { * * This field and the image field are mutually exclusive. */ - backup_id?: number | null; - /** - * When deploying from an Image, this field is optional, otherwise it is ignored. - * This is used to set the swap disk size for the newly-created Linode. - * @default 512 - */ - swap_size?: number | null; - /** - * An Image ID to deploy the Linode Disk from. - */ - image?: string | null; - /** - * This sets the root user’s password on a newly-created Linode Disk when deploying from an Image. - */ - root_pass?: string; - /** - * A list of public SSH keys that will be automatically appended to the root user’s - * `~/.ssh/authorized_keys`file when deploying from an Image. - */ - authorized_keys?: string[] | null; + backup_id?: null | number; /** * If this field is set to true, the created Linode will automatically be enrolled in the Linode Backup service. * This will incur an additional charge. The cost for the Backup service is dependent on the Type of Linode deployed. @@ -587,10 +567,6 @@ export interface CreateLinodeRequest { * @default false */ backups_enabled?: boolean | null; - /** - * This field is required only if the StackScript being deployed requires input data from the User for successful completion - */ - stackscript_data?: any; /** * If it is deployed from an Image or a Backup and you wish it to remain offline after deployment, set this to false. * @@ -599,31 +575,18 @@ export interface CreateLinodeRequest { */ booted?: boolean | null; /** - * The Linode’s label is for display purposes only. - * If no label is provided for a Linode, a default will be assigned. - */ - label?: string | null; - /** - * An array of tags applied to this object. - * - * Tags are for organizational purposes only. - */ - tags?: string[] | null; - /** - * If true, the created Linode will have private networking enabled and assigned a private IPv4 address. - * @default false + * A property with a string literal type indicating whether the Linode is encrypted or unencrypted. + * @default 'enabled' (if the region supports LDE) */ - private_ip?: boolean | null; + disk_encryption?: EncryptionStatus | null; /** - * A list of usernames. If the usernames have associated SSH keys, - * the keys will be appended to the root users `~/.ssh/authorized_keys` - * file automatically when deploying from an Image. + * The `id` of the Firewall to attach this Linode to upon creation. */ - authorized_users?: string[] | null; + firewall_id?: null | number; /** - * An array of Network Interfaces to add to this Linode’s Configuration Profile. + * An Image ID to deploy the Linode Disk from. */ - interfaces?: InterfacePayload[] | CreateLinodeInterfacePayload[]; + image?: null | string; /** * When present, used by the API to determine what type of interface objects (legacy * config interfaces or new Linode Interfaces) are in the above interfaces field. @@ -637,38 +600,82 @@ export interface CreateLinodeRequest { */ interface_generation?: InterfaceGenerationType | null; /** - * Default value mirrors network_helper in AccountSettings object. Should only be - * present when using Linode Interfaces. + * An array of Network Interfaces to add to this Linode’s Configuration Profile. */ - network_helper?: boolean; + interfaces?: CreateLinodeInterfacePayload[] | InterfacePayload[]; /** * An array of IPv4 addresses for this Linode * Must be empty if Linode is configured to use new Linode Interfaces. */ ipv4?: string[]; + /** + * The Linode’s label is for display purposes only. + * If no label is provided for a Linode, a default will be assigned. + */ + label?: null | string; + /** + * Allows customers to specify which strategy this Linode should follow during + * maintenance events. + */ + maintenance_policy_id?: null | number; /** * An object containing user-defined data relevant to the creation of Linodes. */ - metadata?: UserData | null; + metadata?: null | UserData; /** - * The `id` of the Firewall to attach this Linode to upon creation. + * Default value mirrors network_helper in AccountSettings object. Should only be + * present when using Linode Interfaces. */ - firewall_id?: number | null; + network_helper?: boolean; /** * An object that assigns this the Linode to a placement group upon creation. */ placement_group?: CreateLinodePlacementGroupPayload | null; /** - * A property with a string literal type indicating whether the Linode is encrypted or unencrypted. - * @default 'enabled' (if the region supports LDE) + * If true, the created Linode will have private networking enabled and assigned a private IPv4 address. + * @default false */ - disk_encryption?: EncryptionStatus | null; + private_ip?: boolean | null; + /** + * The Region where the Linode will be located. + */ + region: string; + /** + * This sets the root user’s password on a newly-created Linode Disk when deploying from an Image. + */ + root_pass?: string; + /** + * This field is required only if the StackScript being deployed requires input data from the User for successful completion + */ + stackscript_data?: any; + /** + * A StackScript ID that will cause the referenced StackScript to be run during deployment of this Linode. + * + * This field cannot be used when deploying from a Backup or a Private Image. + */ + stackscript_id?: null | number; + /** + * When deploying from an Image, this field is optional, otherwise it is ignored. + * This is used to set the swap disk size for the newly-created Linode. + * @default 512 + */ + swap_size?: null | number; + /** + * An array of tags applied to this object. + * + * Tags are for organizational purposes only. + */ + tags?: null | string[]; + /** + * The Linode Type of the Linode you are creating. + */ + type: string; } export interface MigrateLinodeRequest { placement_group?: { - id: number; compliant_only?: boolean; + id: number; }; region: string; } @@ -679,39 +686,39 @@ export type RescueRequestObject = Pick< >; export interface LinodeCloneData { - linode_id?: number; - region?: string | null; - type?: string | null; - label?: string | null; backups_enabled?: boolean | null; - tags?: string[] | null; configs?: number[]; disks?: number[]; + label?: null | string; + linode_id?: number; + region?: null | string; + tags?: null | string[]; + type?: null | string; } export type RebuildRequest = InferType; export interface LinodeDiskCreationData { - label: string; - size: number; - filesystem?: 'raw' | 'swap' | 'ext3' | 'ext4' | 'initrd'; - read_only?: boolean; - image?: string; authorized_keys?: string[]; authorized_users?: string[]; + filesystem?: 'ext3' | 'ext4' | 'initrd' | 'raw' | 'swap'; + image?: string; + label: string; + read_only?: boolean; root_pass?: string; - stackscript_id?: number; + size: number; stackscript_data?: any; + stackscript_id?: number; } -export type MigrationTypes = 'warm' | 'cold'; +export type MigrationTypes = 'cold' | 'warm'; export interface ResizeLinodePayload { - type: string; /** @default true */ allow_auto_disk_resize?: boolean; /** @default 'cold' */ migration_type?: MigrationTypes; + type: string; } export interface DeleteInterfaceIds { @@ -721,8 +728,8 @@ export interface DeleteInterfaceIds { } export interface LinodeLishData { - weblish_url: string; glish_url: string; monitor_url: string; + weblish_url: string; ws_protocols: string[]; } diff --git a/packages/api-v4/src/longview/longview.ts b/packages/api-v4/src/longview/longview.ts index f0c224ee742..bdec5c51c6a 100644 --- a/packages/api-v4/src/longview/longview.ts +++ b/packages/api-v4/src/longview/longview.ts @@ -1,4 +1,5 @@ import { longviewClientCreate } from '@linode/validation/lib/longview.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -7,8 +8,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { + +import type { Filter, Params, ResourcePage } from '../types'; +import type { ActiveLongviewPlan, LongviewClient, LongviewSubscription, @@ -22,9 +24,9 @@ export const createLongviewClient = (label?: string) => { { label, }, - longviewClientCreate + longviewClientCreate, ), - setMethod('POST') + setMethod('POST'), ); }; @@ -33,13 +35,13 @@ export const getLongviewClients = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/longview/clients`), setParams(params), setXFilter(filter), - setMethod('GET') + setMethod('GET'), ); export const deleteLongviewClient = (id: number) => Request<{}>( setURL(`${API_ROOT}/longview/clients/${encodeURIComponent(id)}`), - setMethod('DELETE') + setMethod('DELETE'), ); export const updateLongviewClient = (id: number, label: string) => { @@ -49,22 +51,22 @@ export const updateLongviewClient = (id: number, label: string) => { { label, }, - longviewClientCreate + longviewClientCreate, ), - setMethod('PUT') + setMethod('PUT'), ); }; export const getLongviewSubscriptions = () => Request>( setURL(`${API_ROOT}/longview/subscriptions`), - setMethod('GET') + setMethod('GET'), ); export const getActiveLongviewPlan = () => Request( setURL(`${API_ROOT}/longview/plan`), - setMethod('GET') + setMethod('GET'), ); /** @@ -78,5 +80,5 @@ export const updateActiveLongviewPlan = (plan: LongviewSubscriptionPayload) => Request( setURL(`${API_ROOT}/longview/plan`), setData(plan), - setMethod('PUT') + setMethod('PUT'), ); diff --git a/packages/api-v4/src/longview/types.ts b/packages/api-v4/src/longview/types.ts index 6c6f5e2dadb..f296e99c60d 100644 --- a/packages/api-v4/src/longview/types.ts +++ b/packages/api-v4/src/longview/types.ts @@ -1,17 +1,17 @@ export interface LongviewClient { - id: number; + api_key: string; + apps: Apps; created: string; + id: number; + install_code: string; label: string; updated: string; - api_key: string; - install_code: string; - apps: Apps; } export interface LongviewSubscription { + clients_included: number; id: string; label: string; - clients_included: number; price: { hourly: number; monthly: number; @@ -28,6 +28,6 @@ export type ActiveLongviewPlan = LongviewSubscription | {}; export interface Apps { apache: boolean; - nginx: boolean; mysql: boolean; + nginx: boolean; } diff --git a/packages/api-v4/src/managed/types.ts b/packages/api-v4/src/managed/types.ts index ec06e923b2a..30db0d47994 100644 --- a/packages/api-v4/src/managed/types.ts +++ b/packages/api-v4/src/managed/types.ts @@ -1,54 +1,54 @@ export interface ManagedServiceMonitor { + address: string; + body: string; + consultation_group: string; // deprecated but still returned by API + created: string; + credentials: number[]; // @todo id: number; label: string; - created: string; - updated: string; - status: MonitorStatus; + notes: string; + region: null | string; service_type: ServiceType; + status: MonitorStatus; timeout: number; - region: string | null; - credentials: number[]; // @todo - address: string; - body: string; - notes: string; - consultation_group: string; // deprecated but still returned by API + updated: string; } -export type MonitorStatus = 'pending' | 'disabled' | 'ok' | 'problem'; +export type MonitorStatus = 'disabled' | 'ok' | 'pending' | 'problem'; -export type ServiceType = 'url' | 'tcp'; +export type ServiceType = 'tcp' | 'url'; export interface ManagedLinodeSetting { + group: string; id: number; label: string; - group: string; ssh: ManagedSSHSetting; } export interface ManagedSSHSetting { access: boolean; - user: string; ip: string; port: number; + user: string; } export interface ManagedCredential { id: number; - last_decrypted: string | null; label: string; + last_decrypted: null | string; } export interface ManagedContact { + email: string; + group: null | string; id: number; name: string; - email: string; phone: ManagedContactPhone; - group: string | null; updated: string; } export interface ManagedContactPhone { - primary?: string | null; - secondary?: string | null; + primary?: null | string; + secondary?: null | string; } export interface ManagedSSHPubKey { @@ -56,14 +56,14 @@ export interface ManagedSSHPubKey { } export interface ManagedServicePayload { - label: string; - service_type: ServiceType; address: string; - timeout: number; - notes?: string; body?: string; consultation_group?: string; credentials?: number[]; + label: string; + notes?: string; + service_type: ServiceType; + timeout: number; } export interface CredentialPayload { @@ -83,17 +83,17 @@ export interface UpdatePasswordPayload { } export interface ContactPayload { - name: string; email: string; + group?: null | string; + name: string; phone?: ManagedContactPhone; - group?: string | null; } export interface ManagedIssue { - id: number; - services: number[]; created: string; entity: IssueEntity; + id: number; + services: number[]; } // This is much like a support ticket but it's a special case so here's a special type: @@ -110,8 +110,8 @@ export interface DataSeries { } export interface ManagedStatsData { - disk: DataSeries[]; cpu: DataSeries[]; + disk: DataSeries[]; net_in: DataSeries[]; net_out: DataSeries[]; swap: DataSeries[]; diff --git a/packages/api-v4/src/network-transfer/prices.ts b/packages/api-v4/src/network-transfer/prices.ts index ccb0233bb75..b1249fb6a4b 100644 --- a/packages/api-v4/src/network-transfer/prices.ts +++ b/packages/api-v4/src/network-transfer/prices.ts @@ -1,10 +1,11 @@ import { API_ROOT } from 'src/constants'; -import Request, { setMethod, setURL, setParams } from 'src/request'; -import { Params, PriceType, ResourcePage } from 'src/types'; +import Request, { setMethod, setParams, setURL } from 'src/request'; + +import type { Params, PriceType, ResourcePage } from 'src/types'; export const getNetworkTransferPrices = (params?: Params) => Request>( setURL(`${API_ROOT}/network-transfer/prices`), setMethod('GET'), - setParams(params) + setParams(params), ); diff --git a/packages/api-v4/src/networking/index.ts b/packages/api-v4/src/networking/index.ts index 51f295f29d8..4e5f21f6b7a 100644 --- a/packages/api-v4/src/networking/index.ts +++ b/packages/api-v4/src/networking/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './networking'; + +export * from './types'; diff --git a/packages/api-v4/src/networking/networking.ts b/packages/api-v4/src/networking/networking.ts index e61c8db4e60..cdf3bfb60a5 100644 --- a/packages/api-v4/src/networking/networking.ts +++ b/packages/api-v4/src/networking/networking.ts @@ -4,6 +4,7 @@ import { shareAddressesSchema, updateIPSchema, } from '@linode/validation/lib/networking.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, @@ -12,8 +13,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateIPv6RangePayload, IPAddress, IPAssignmentPayload, @@ -32,7 +34,7 @@ export const getIPs = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/networking/ips`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -43,7 +45,7 @@ export const getIPs = (params?: Params, filters?: Filter) => export const getIP = (address: string) => Request( setURL(`${API_ROOT}/networking/ips/${encodeURIComponent(address)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -56,11 +58,11 @@ export const getIP = (address: string) => * IPv4 addresses, this will be set to a default value provided by Linode if not * explicitly set. */ -export const updateIP = (address: string, rdns: string | null = null) => +export const updateIP = (address: string, rdns: null | string = null) => Request( setURL(`${API_ROOT}/networking/ips/${encodeURIComponent(address)}`), setData({ rdns }, updateIPSchema), - setMethod('PUT') + setMethod('PUT'), ); /** @@ -80,7 +82,7 @@ export const allocateIp = (payload: any) => Request( setURL(`${API_ROOT}/networking/ips/`), setData(payload, allocateIPSchema), - setMethod('POST') + setMethod('POST'), ); /** @@ -99,7 +101,7 @@ export const assignAddresses = (payload: IPAssignmentPayload) => Request<{}>( setURL(`${API_ROOT}/networking/ips/assign`), setMethod('POST'), - setData(payload, assignAddressesSchema) + setData(payload, assignAddressesSchema), ); /** @@ -121,7 +123,7 @@ export const shareAddressesv4 = (payload: IPSharingPayload) => Request<{}>( setURL(`${API_ROOT}/networking/ipv4/share`), setMethod('POST'), - setData(payload, shareAddressesSchema) + setData(payload, shareAddressesSchema), ); /** @@ -142,7 +144,7 @@ export const shareAddresses = (payload: IPSharingPayload) => Request<{}>( setURL(`${BETA_API_ROOT}/networking/ips/share`), setMethod('POST'), - setData(payload, shareAddressesSchema) + setData(payload, shareAddressesSchema), ); /** @@ -153,7 +155,7 @@ export const getIPv6Pools = (params?: Params) => Request>( setURL(`${API_ROOT}/networking/ipv6/pools`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -165,7 +167,7 @@ export const getIPv6Ranges = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/networking/ipv6/ranges`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -177,7 +179,7 @@ export const getIPv6RangeInfo = (range: string, params?: Params) => Request( setURL(`${API_ROOT}/networking/ipv6/ranges/${encodeURIComponent(range)}`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -189,6 +191,6 @@ export const createIPv6Range = (payload: CreateIPv6RangePayload) => { return Request<{}>( setURL(`${API_ROOT}/networking/ipv6/ranges`), setMethod('POST'), - setData(payload) + setData(payload), ); }; diff --git a/packages/api-v4/src/networking/types.ts b/packages/api-v4/src/networking/types.ts index 9508ff35f88..88805c44ffd 100644 --- a/packages/api-v4/src/networking/types.ts +++ b/packages/api-v4/src/networking/types.ts @@ -1,29 +1,29 @@ export interface IPAddress { address: string; - gateway: string | null; - subnet_mask: string; + gateway: null | string; + interface_id: null | number; + linode_id: number; prefix: number; - type: string; public: boolean; - rdns: string | null; - linode_id: number; - interface_id: number | null; + rdns: null | string; region: string; - vpc_nat_1_1?: { + subnet_mask: string; + type: string; + vpc_nat_1_1?: null | { address: string; subnet_id: number; vpc_id: number; - } | null; + }; } export interface IPRangeBaseData { + prefix: number; range: string; region: string; - prefix: number; } export interface IPRange extends IPRangeBaseData { - route_target: string | null; + route_target: null | string; } export interface IPRangeInformation extends IPRangeBaseData { is_bgp: boolean; @@ -40,14 +40,14 @@ export interface IPAssignment { linode_id: number; } export interface IPAssignmentPayload { - region: string; assignments: IPAssignment[]; + region: string; } export type IPv6Prefix = 56 | 64; export interface CreateIPv6RangePayload { linode_id?: number; - route_target?: string; prefix_length: IPv6Prefix; + route_target?: string; } diff --git a/packages/api-v4/src/nodebalancers/index.ts b/packages/api-v4/src/nodebalancers/index.ts index def61d4b815..72f5b297bd1 100644 --- a/packages/api-v4/src/nodebalancers/index.ts +++ b/packages/api-v4/src/nodebalancers/index.ts @@ -1,7 +1,7 @@ -export * from './types'; - -export * from './nodebalancers'; +export * from './nodebalancer-config-nodes'; export * from './nodebalancer-configs'; -export * from './nodebalancer-config-nodes'; +export * from './nodebalancers'; + +export * from './types'; diff --git a/packages/api-v4/src/nodebalancers/nodebalancer-config-nodes.ts b/packages/api-v4/src/nodebalancers/nodebalancer-config-nodes.ts index ccff24807b7..faa06a2b472 100644 --- a/packages/api-v4/src/nodebalancers/nodebalancer-config-nodes.ts +++ b/packages/api-v4/src/nodebalancers/nodebalancer-config-nodes.ts @@ -1,13 +1,15 @@ import { nodeBalancerConfigNodeSchema } from '@linode/validation/lib/nodebalancers.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { ResourcePage as Page } from '../types'; -import { +import { mergeAddressAndPort } from './utils'; + +import type { ResourcePage as Page } from '../types'; +import type { CreateNodeBalancerConfigNode, NodeBalancerConfigNode, UpdateNodeBalancerConfigNode, } from './types'; -import { mergeAddressAndPort } from './utils'; /** * getNodeBalancerConfigNodes @@ -20,15 +22,15 @@ import { mergeAddressAndPort } from './utils'; */ export const getNodeBalancerConfigNodes = ( nodeBalancerId: number, - configId: number + configId: number, ) => Request>( setMethod('GET'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/nodes` - ) + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/nodes`, + ), ); /** @@ -42,15 +44,15 @@ export const getNodeBalancerConfigNodes = ( */ export const getNodeBalancerConfigNodesBeta = ( nodeBalancerId: number, - configId: number + configId: number, ) => Request>( setMethod('GET'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/nodes` - ) + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/nodes`, + ), ); /** @@ -65,17 +67,17 @@ export const getNodeBalancerConfigNodesBeta = ( export const getNodeBalancerConfigNode = ( nodeBalancerId: number, configId: number, - nodeId: number + nodeId: number, ) => Request>( setMethod('GET'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId + nodeBalancerId, )}/configs/${encodeURIComponent(configId)}/nodes/${encodeURIComponent( - nodeId - )}` - ) + nodeId, + )}`, + ), ); /** * getNodeBalancerConfigNodeBeta @@ -91,17 +93,17 @@ export const getNodeBalancerConfigNode = ( export const getNodeBalancerConfigNodeBeta = ( nodeBalancerId: number, configId: number, - nodeId: number + nodeId: number, ) => Request>( setMethod('GET'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId + nodeBalancerId, )}/configs/${encodeURIComponent(configId)}/nodes/${encodeURIComponent( - nodeId - )}` - ) + nodeId, + )}`, + ), ); /** * createNodeBalancerConfigNode @@ -130,16 +132,16 @@ export const getNodeBalancerConfigNodeBeta = ( export const createNodeBalancerConfigNode = ( nodeBalancerId: number, configId: number, - data: CreateNodeBalancerConfigNode + data: CreateNodeBalancerConfigNode, ) => Request( setMethod('POST'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/nodes` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/nodes`, ), - setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort) + setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort), ); /** @@ -157,16 +159,16 @@ export const createNodeBalancerConfigNode = ( export const createNodeBalancerConfigNodeBeta = ( nodeBalancerId: number, configId: number, - data: CreateNodeBalancerConfigNode + data: CreateNodeBalancerConfigNode, ) => Request( setMethod('POST'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/nodes` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/nodes`, ), - setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort) + setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort), ); /** @@ -196,18 +198,18 @@ export const updateNodeBalancerConfigNode = ( nodeBalancerId: number, configId: number, nodeId: number, - data: UpdateNodeBalancerConfigNode + data: UpdateNodeBalancerConfigNode, ) => Request( setMethod('PUT'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId + nodeBalancerId, )}/configs/${encodeURIComponent(configId)}/nodes/${encodeURIComponent( - nodeId - )}` + nodeId, + )}`, ), - setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort) + setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort), ); /** @@ -225,18 +227,18 @@ export const updateNodeBalancerConfigNodeBeta = ( nodeBalancerId: number, configId: number, nodeId: number, - data: UpdateNodeBalancerConfigNode + data: UpdateNodeBalancerConfigNode, ) => Request( setMethod('PUT'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId + nodeBalancerId, )}/configs/${encodeURIComponent(configId)}/nodes/${encodeURIComponent( - nodeId - )}` + nodeId, + )}`, ), - setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort) + setData(data, nodeBalancerConfigNodeSchema, mergeAddressAndPort), ); /** * deleteNodeBalancerConfigNode @@ -250,15 +252,15 @@ export const updateNodeBalancerConfigNodeBeta = ( export const deleteNodeBalancerConfigNode = ( nodeBalancerId: number, configId: number, - nodeId: number + nodeId: number, ) => Request<{}>( setMethod('DELETE'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId + nodeBalancerId, )}/configs/${encodeURIComponent(configId)}/nodes/${encodeURIComponent( - nodeId - )}` - ) + nodeId, + )}`, + ), ); diff --git a/packages/api-v4/src/nodebalancers/nodebalancer-configs.ts b/packages/api-v4/src/nodebalancers/nodebalancer-configs.ts index 2a2806e0712..89ca28ffa73 100644 --- a/packages/api-v4/src/nodebalancers/nodebalancer-configs.ts +++ b/packages/api-v4/src/nodebalancers/nodebalancer-configs.ts @@ -2,19 +2,21 @@ import { createNodeBalancerConfigSchema, UpdateNodeBalancerConfigSchema, } from '@linode/validation/lib/nodebalancers.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, setMethod, setParams, setURL } from '../request'; -import { ResourcePage as Page, Params } from '../types'; import { + combineConfigNodeAddressAndPort, + combineConfigNodeAddressAndPortBeta, +} from './utils'; + +import type { ResourcePage as Page, Params } from '../types'; +import type { CreateNodeBalancerConfig, NodeBalancerConfig, RebuildNodeBalancerConfig, UpdateNodeBalancerConfig, } from './types'; -import { - combineConfigNodeAddressAndPort, - combineConfigNodeAddressAndPortBeta, -} from './utils'; /** * getNodeBalancerConfigs @@ -25,14 +27,14 @@ import { */ export const getNodeBalancerConfigs = ( nodeBalancerId: number, - params?: Params + params?: Params, ) => Request>( setURL( - `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/configs` + `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/configs`, ), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -44,15 +46,15 @@ export const getNodeBalancerConfigs = ( */ export const getNodeBalancerConfig = ( nodeBalancerId: number, - configId: number + configId: number, ) => Request>( setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -65,18 +67,18 @@ export const getNodeBalancerConfig = ( */ export const createNodeBalancerConfig = ( nodeBalancerId: number, - data: CreateNodeBalancerConfig + data: CreateNodeBalancerConfig, ) => Request( setMethod('POST'), setURL( - `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/configs` + `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/configs`, ), setData( data, createNodeBalancerConfigSchema, - combineConfigNodeAddressAndPort - ) + combineConfigNodeAddressAndPort, + ), ); /** @@ -91,20 +93,20 @@ export const createNodeBalancerConfig = ( */ export const createNodeBalancerConfigBeta = ( nodeBalancerId: number, - data: CreateNodeBalancerConfig + data: CreateNodeBalancerConfig, ) => Request( setMethod('POST'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs` + nodeBalancerId, + )}/configs`, ), setData( data, createNodeBalancerConfigSchema, - combineConfigNodeAddressAndPortBeta - ) + combineConfigNodeAddressAndPortBeta, + ), ); /** @@ -118,20 +120,20 @@ export const createNodeBalancerConfigBeta = ( export const rebuildNodeBalancerConfig = ( nodeBalancerId: number, configId: number, - data: RebuildNodeBalancerConfig + data: RebuildNodeBalancerConfig, ) => Request( setMethod('POST'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/rebuild` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/rebuild`, ), setData( data, createNodeBalancerConfigSchema, - combineConfigNodeAddressAndPort - ) + combineConfigNodeAddressAndPort, + ), ); /** @@ -145,20 +147,20 @@ export const rebuildNodeBalancerConfig = ( export const rebuildNodeBalancerConfigBeta = ( nodeBalancerId: number, configId: number, - data: RebuildNodeBalancerConfig + data: RebuildNodeBalancerConfig, ) => Request( setMethod('POST'), setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}/rebuild` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}/rebuild`, ), setData( data, createNodeBalancerConfigSchema, - combineConfigNodeAddressAndPortBeta - ) + combineConfigNodeAddressAndPortBeta, + ), ); /** @@ -172,16 +174,16 @@ export const rebuildNodeBalancerConfigBeta = ( export const updateNodeBalancerConfig = ( nodeBalancerId: number, configId: number, - data: UpdateNodeBalancerConfig + data: UpdateNodeBalancerConfig, ) => Request( setMethod('PUT'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}` + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}`, ), - setData(data, UpdateNodeBalancerConfigSchema) + setData(data, UpdateNodeBalancerConfigSchema), ); /** @@ -194,13 +196,13 @@ export const updateNodeBalancerConfig = ( */ export const deleteNodeBalancerConfig = ( nodeBalancerId: number, - configId: number + configId: number, ) => Request<{}>( setMethod('DELETE'), setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/configs/${encodeURIComponent(configId)}` - ) + nodeBalancerId, + )}/configs/${encodeURIComponent(configId)}`, + ), ); diff --git a/packages/api-v4/src/nodebalancers/nodebalancers.ts b/packages/api-v4/src/nodebalancers/nodebalancers.ts index 8560eafe0eb..da9f3cb5c6b 100644 --- a/packages/api-v4/src/nodebalancers/nodebalancers.ts +++ b/packages/api-v4/src/nodebalancers/nodebalancers.ts @@ -2,6 +2,7 @@ import { NodeBalancerSchema, UpdateNodeBalancerSchema, } from '@linode/validation/lib/nodebalancers.schema'; + import { API_ROOT, BETA_API_ROOT } from '../constants'; import Request, { setData, @@ -10,18 +11,19 @@ import Request, { setURL, setXFilter, } from '../request'; -import type { Filter, Params, ResourcePage as Page, PriceType } from '../types'; +import { + combineNodeBalancerConfigNodeAddressAndPort, + combineNodeBalancerConfigNodeAddressAndPortBeta, +} from './utils'; + +import type { Firewall } from '../firewalls/types'; +import type { Filter, ResourcePage as Page, Params, PriceType } from '../types'; import type { CreateNodeBalancerPayload, NodeBalancer, NodeBalancerStats, NodebalancerVpcConfig, } from './types'; -import { - combineNodeBalancerConfigNodeAddressAndPort, - combineNodeBalancerConfigNodeAddressAndPortBeta, -} from './utils'; -import type { Firewall } from '../firewalls/types'; /** * getNodeBalancers @@ -33,7 +35,7 @@ export const getNodeBalancers = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/nodebalancers`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -46,7 +48,7 @@ export const getNodeBalancers = (params?: Params, filters?: Filter) => export const getNodeBalancer = (nodeBalancerId: number) => Request( setURL(`${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -59,9 +61,9 @@ export const getNodeBalancer = (nodeBalancerId: number) => export const getNodeBalancerBeta = (nodeBalancerId: number) => Request( setURL( - `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}` + `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -75,12 +77,12 @@ export const getNodeBalancerBeta = (nodeBalancerId: number) => */ export const updateNodeBalancer = ( nodeBalancerId: number, - data: Partial + data: Partial, ) => Request( setURL(`${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}`), setMethod('PUT'), - setData(data, UpdateNodeBalancerSchema) + setData(data, UpdateNodeBalancerSchema), ); /** @@ -95,8 +97,8 @@ export const createNodeBalancer = (data: CreateNodeBalancerPayload) => setData( data, NodeBalancerSchema, - combineNodeBalancerConfigNodeAddressAndPort - ) + combineNodeBalancerConfigNodeAddressAndPort, + ), ); /** @@ -111,8 +113,8 @@ export const createNodeBalancerBeta = (data: CreateNodeBalancerPayload) => setData( data, NodeBalancerSchema, - combineNodeBalancerConfigNodeAddressAndPortBeta - ) + combineNodeBalancerConfigNodeAddressAndPortBeta, + ), ); /** @@ -125,7 +127,7 @@ export const createNodeBalancerBeta = (data: CreateNodeBalancerPayload) => export const deleteNodeBalancer = (nodeBalancerId: number) => Request<{}>( setMethod('DELETE'), - setURL(`${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}`) + setURL(`${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}`), ); /** @@ -138,9 +140,9 @@ export const deleteNodeBalancer = (nodeBalancerId: number) => export const getNodeBalancerStats = (nodeBalancerId: number) => { return Request( setURL( - `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/stats` + `${API_ROOT}/nodebalancers/${encodeURIComponent(nodeBalancerId)}/stats`, ), - setMethod('GET') + setMethod('GET'), ); }; @@ -153,17 +155,17 @@ export const getNodeBalancerStats = (nodeBalancerId: number) => { export const getNodeBalancerFirewalls = ( nodeBalancerId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( `${API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/firewalls` + nodeBalancerId, + )}/firewalls`, ), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -176,7 +178,7 @@ export const getNodeBalancerTypes = (params?: Params) => Request>( setURL(`${API_ROOT}/nodebalancers/types`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -189,17 +191,17 @@ export const getNodeBalancerTypes = (params?: Params) => export const getNodeBalancerVPCConfigsBeta = ( nodeBalancerId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/vpcs` + nodeBalancerId, + )}/vpcs`, ), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** * getNodeBalancerVPCConfigBeta @@ -210,13 +212,13 @@ export const getNodeBalancerVPCConfigsBeta = ( */ export const getNodeBalancerVPCConfigBeta = ( nodeBalancerId: number, - nbVpcConfigId: number + nbVpcConfigId: number, ) => Request( setURL( `${BETA_API_ROOT}/nodebalancers/${encodeURIComponent( - nodeBalancerId - )}/vpcs/${encodeURIComponent(nbVpcConfigId)}` + nodeBalancerId, + )}/vpcs/${encodeURIComponent(nbVpcConfigId)}`, ), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/nodebalancers/types.ts b/packages/api-v4/src/nodebalancers/types.ts index 0ce208c81fa..22069a32f5f 100644 --- a/packages/api-v4/src/nodebalancers/types.ts +++ b/packages/api-v4/src/nodebalancers/types.ts @@ -1,11 +1,11 @@ -type TCPAlgorithm = 'roundrobin' | 'leastconn' | 'source'; -type UDPAlgorithm = 'roundrobin' | 'leastconn' | 'ring_hash'; +type TCPAlgorithm = 'leastconn' | 'roundrobin' | 'source'; +type UDPAlgorithm = 'leastconn' | 'ring_hash' | 'roundrobin'; export type Algorithm = TCPAlgorithm | UDPAlgorithm; export type Protocol = 'http' | 'https' | 'tcp' | 'udp'; -type TCPStickiness = 'none' | 'table' | 'http_cookie'; +type TCPStickiness = 'http_cookie' | 'none' | 'table'; type UDPStickiness = 'none' | 'session' | 'source_ip'; export type Stickiness = TCPStickiness | UDPStickiness; @@ -13,16 +13,13 @@ export type Stickiness = TCPStickiness | UDPStickiness; type NodeBalancerType = 'common' | 'premium'; export interface LKEClusterInfo { - label: string; id: number; - url: string; + label: string; type: 'lkecluster'; + url: string; } export interface NodeBalancer { - id: number; - label: string; - hostname: string; /** * Maximum number of new TCP connections that a client (identified by a specific source IP) * is allowed to initiate every second. @@ -35,19 +32,22 @@ export interface NodeBalancer { * @todo Remove optionality once UDP support is live */ client_udp_sess_throttle?: number; - region: string; - type?: NodeBalancerType; + created: string; + hostname: string; + id: number; + ipv4: string; + ipv6: null | string; + label: string; /** * If the NB is associated with a cluster (active or deleted), return its info * If the NB is not associated with a cluster, return null */ lke_cluster?: LKEClusterInfo | null; - ipv4: string; - ipv6: null | string; - created: string; - updated: string; - transfer: BalancerTransfer; + region: string; tags: string[]; + transfer: BalancerTransfer; + type?: NodeBalancerType; + updated: string; } export interface NodeBalancerWithConfigIDs extends NodeBalancer { @@ -59,8 +59,8 @@ export interface NodeBalancerWithConfigs extends NodeBalancer { } export interface NodesStatus { - up: number; down: number; + up: number; } export interface BalancerTransfer { @@ -74,25 +74,36 @@ export interface BalancerTransfer { */ export type NodeBalancerConfigNodeMode = | 'accept' - | 'reject' | 'backup' | 'drain' - | 'none'; + | 'none' + | 'reject'; export interface NodeBalancerConfig { + algorithm: Algorithm; + check: 'connection' | 'http' | 'http_body' | 'none'; + check_attempts: number; + check_body: string; + check_interval: number; + check_passive: boolean; + check_path: string; + check_timeout: number; + /** + * Is `none` when protocol is UDP + */ + cipher_suite: 'legacy' | 'none' | 'recommended'; id: number; nodebalancer_id: number; - port: number; - check_passive: boolean; - ssl_cert: string; + nodes: NodeBalancerConfigNode[]; nodes_status: NodesStatus; + port: number; protocol: Protocol; + proxy_protocol: NodeBalancerProxyProtocol; + ssl_cert: string; ssl_commonname: string; - check_interval: number; - check_attempts: number; - check_timeout: number; - check_body: string; - check_path: string; + ssl_fingerprint: string; + ssl_key: string; + stickiness: Stickiness; /** * @todo Remove optionality once UDP support is live */ @@ -103,17 +114,6 @@ export interface NodeBalancerConfig { * @default 16 */ udp_session_timeout?: number; - proxy_protocol: NodeBalancerProxyProtocol; - check: 'none' | 'connection' | 'http' | 'http_body'; - ssl_key: string; - stickiness: Stickiness; - algorithm: Algorithm; - ssl_fingerprint: string; - /** - * Is `none` when protocol is UDP - */ - cipher_suite: 'recommended' | 'legacy' | 'none'; - nodes: NodeBalancerConfigNode[]; } export type NodeBalancerProxyProtocol = 'none' | 'v1' | 'v2'; @@ -124,26 +124,44 @@ export interface NodeBalancerConfigPort { } export interface NodeBalancerStats { - title: string; data: { connections: [number, number][]; traffic: { - out: [number, number][]; in: [number, number][]; + out: [number, number][]; }; }; + title: string; } export interface NodebalancerVpcConfig { id: number; + ipv4_range: null | string; + ipv6_range: null | string; nodebalancer_id: number; - vpc_id: number; subnet_id: number; - ipv4_range: string | null; - ipv6_range: string | null; + vpc_id: number; } export interface CreateNodeBalancerConfig { + /** + * The algorithm for this configuration. + * + * TCP and HTTP support `roundrobin`, `leastconn`, and `source` + * UDP supports `roundrobin`, `leastconn`, and `ring_hash` + * + * @default roundrobin + */ + algorithm?: Algorithm; + check?: 'connection' | 'http' | 'http_body' | 'none'; + check_attempts?: number; + check_body?: string; + check_interval?: number; + check_passive?: boolean; + check_path?: string; + check_timeout?: number; + cipher_suite?: 'legacy' | 'none' | 'recommended'; + nodes?: CreateNodeBalancerConfigNode[]; port?: number; /** * If `udp` is chosen: @@ -156,15 +174,8 @@ export interface CreateNodeBalancerConfig { * @default "none" */ proxy_protocol?: NodeBalancerProxyProtocol; - /** - * The algorithm for this configuration. - * - * TCP and HTTP support `roundrobin`, `leastconn`, and `source` - * UDP supports `roundrobin`, `leastconn`, and `ring_hash` - * - * @default roundrobin - */ - algorithm?: Algorithm; + ssl_cert?: string; + ssl_key?: string; /** * Session stickiness for this configuration. * @@ -175,22 +186,11 @@ export interface CreateNodeBalancerConfig { * @default `none` for TCP and HTTP */ stickiness?: Stickiness; - check?: 'none' | 'connection' | 'http' | 'http_body'; - check_interval?: number; - check_timeout?: number; - check_attempts?: number; - check_path?: string; - check_body?: string; - check_passive?: boolean; /** * Must be between 1 and 65535 * @default 80 */ udp_check_port?: number; - cipher_suite?: 'recommended' | 'legacy' | 'none'; - ssl_cert?: string; - ssl_key?: string; - nodes?: CreateNodeBalancerConfigNode[]; } export type UpdateNodeBalancerConfig = CreateNodeBalancerConfig; @@ -204,11 +204,12 @@ export interface CreateNodeBalancerConfigNode { * Should not be specified when creating a node used on a UDP configuration */ mode?: NodeBalancerConfigNodeMode; - weight?: number; subnet_id?: number; + weight?: number; } -export type UpdateNodeBalancerConfigNode = Partial; +export type UpdateNodeBalancerConfigNode = + Partial; export interface NodeBalancerConfigNode { address: string; @@ -217,9 +218,9 @@ export interface NodeBalancerConfigNode { label: string; mode: NodeBalancerConfigNodeMode; nodebalancer_id: number; - status: 'unknown' | 'UP' | 'DOWN'; + status: 'DOWN' | 'unknown' | 'UP'; + vpc_config_id?: null | number; weight: number; - vpc_config_id?: number | null; } export interface NodeBalancerConfigNodeWithPort extends NodeBalancerConfigNode { @@ -227,8 +228,6 @@ export interface NodeBalancerConfigNodeWithPort extends NodeBalancerConfigNode { } export interface CreateNodeBalancerPayload { - region?: string; - label?: string; /** * The connections per second throttle for TCP and HTTP connections * @@ -245,10 +244,12 @@ export interface CreateNodeBalancerPayload { client_udp_sess_throttle?: number; configs: CreateNodeBalancerConfig[]; firewall_id?: number; + label?: string; + region?: string; tags?: string[]; vpcs?: { - subnet_id: number; ipv4_range: string; ipv6_range?: string; + subnet_id: number; }[]; } diff --git a/packages/api-v4/src/nodebalancers/utils.ts b/packages/api-v4/src/nodebalancers/utils.ts index 17d4fdab160..e85e7db546f 100644 --- a/packages/api-v4/src/nodebalancers/utils.ts +++ b/packages/api-v4/src/nodebalancers/utils.ts @@ -1,4 +1,4 @@ -import { NodeBalancerConfigNodeWithPort } from './types'; +import type { NodeBalancerConfigNodeWithPort } from './types'; export const combineConfigNodeAddressAndPort = (data: any) => ({ ...data, diff --git a/packages/api-v4/src/object-storage/buckets.ts b/packages/api-v4/src/object-storage/buckets.ts index c3be674f718..f4b3e09b681 100644 --- a/packages/api-v4/src/object-storage/buckets.ts +++ b/packages/api-v4/src/object-storage/buckets.ts @@ -3,6 +3,7 @@ import { UpdateBucketAccessSchema, UploadCertificateSchema, } from '@linode/validation/lib/buckets.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -11,23 +12,24 @@ import Request, { setURL, setXFilter, } from '../request'; + import type { Filter, - Params, ResourcePage as Page, + Params, RequestOptions, } from '../types'; import type { - ObjectStorageBucket, - ObjectStorageEndpoint, - UpdateObjectStorageBucketAccessPayload, - ObjectStorageBucketAccess, CreateObjectStorageBucketPayload, CreateObjectStorageBucketSSLPayload, - ObjectStorageBucketSSL, DeleteObjectStorageBucketPayload, GetObjectStorageObjectListPayload, + ObjectStorageBucket, + ObjectStorageBucketAccess, + ObjectStorageBucketSSL, + ObjectStorageEndpoint, ObjectStorageObjectList, + UpdateObjectStorageBucketAccessPayload, } from './types'; /** @@ -40,9 +42,9 @@ export const getBucket = (clusterId: string, bucketName: string) => setMethod('GET'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}`, + ), ); /** @@ -55,7 +57,7 @@ export const getBuckets = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/object-storage/buckets`) + setURL(`${API_ROOT}/object-storage/buckets`), ); /** @@ -66,15 +68,15 @@ export const getBuckets = (params?: Params, filters?: Filter) => export const getBucketsInCluster = ( clusterId: string, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setMethod('GET'), setParams(params), setXFilter(filters), setURL( - `${API_ROOT}/object-storage/buckets/${encodeURIComponent(clusterId)}` - ) + `${API_ROOT}/object-storage/buckets/${encodeURIComponent(clusterId)}`, + ), ); /** @@ -85,13 +87,15 @@ export const getBucketsInCluster = ( export const getBucketsInRegion = ( regionId: string, params?: Params, - filters?: Filter + filters?: Filter, ) => Request>( setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/object-storage/buckets/${encodeURIComponent(regionId)}`) + setURL( + `${API_ROOT}/object-storage/buckets/${encodeURIComponent(regionId)}`, + ), ); /** @@ -106,7 +110,7 @@ export const createBucket = (data: CreateObjectStorageBucketPayload) => Request( setURL(`${API_ROOT}/object-storage/buckets`), setMethod('POST'), - setData(data, CreateBucketSchema) + setData(data, CreateBucketSchema), ); /** @@ -123,10 +127,10 @@ export const deleteBucket = ({ Request( setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - cluster - )}/${encodeURIComponent(label)}` + cluster, + )}/${encodeURIComponent(label)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -146,16 +150,16 @@ export const deleteBucketWithRegion = ({ region, label, }: { - region: string; label: string; + region: string; }) => Request( setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - region - )}/${encodeURIComponent(label)}` + region, + )}/${encodeURIComponent(label)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -171,9 +175,9 @@ export const getObjectList = ({ setParams(params), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/object-list` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}/object-list`, + ), ); /** @@ -182,16 +186,16 @@ export const getObjectList = ({ export const uploadSSLCert = ( clusterId: string, bucketName: string, - data: CreateObjectStorageBucketSSLPayload + data: CreateObjectStorageBucketSSLPayload, ) => Request( setMethod('POST'), setData(data, UploadCertificateSchema), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/ssl` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}/ssl`, + ), ); /** @@ -205,9 +209,9 @@ export const getSSLCert = (clusterId: string, bucketName: string) => setMethod('GET'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/ssl` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}/ssl`, + ), ); /** @@ -222,9 +226,9 @@ export const deleteSSLCert = (clusterId: string, bucketName: string) => setMethod('DELETE'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/ssl` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}/ssl`, + ), ); /** @@ -237,9 +241,9 @@ export const getBucketAccess = (clusterId: string, bucketName: string) => setMethod('GET'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/access` - ) + clusterId, + )}/${encodeURIComponent(bucketName)}/access`, + ), ); /** @@ -250,16 +254,16 @@ export const getBucketAccess = (clusterId: string, bucketName: string) => export const updateBucketAccess = ( clusterId: string, bucketName: string, - params: UpdateObjectStorageBucketAccessPayload + params: UpdateObjectStorageBucketAccessPayload, ) => Request<{}>( setMethod('PUT'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/access` + clusterId, + )}/${encodeURIComponent(bucketName)}/access`, ), - setData(params, UpdateBucketAccessSchema) + setData(params, UpdateBucketAccessSchema), ); /** @@ -272,5 +276,5 @@ export const getObjectStorageEndpoints = ({ filter, params }: RequestOptions) => setMethod('GET'), setURL(`${API_ROOT}/object-storage/endpoints`), setParams(params), - setXFilter(filter) + setXFilter(filter), ); diff --git a/packages/api-v4/src/object-storage/clusters.ts b/packages/api-v4/src/object-storage/clusters.ts index 58ff3893fca..091764107ae 100644 --- a/packages/api-v4/src/object-storage/clusters.ts +++ b/packages/api-v4/src/object-storage/clusters.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { ObjectStorageCluster } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { ObjectStorageCluster } from './types'; /** * @deprecated This method returns legacy clusterId values representing regions @@ -13,5 +14,5 @@ export const getClusters = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/object-storage/clusters`) + setURL(`${API_ROOT}/object-storage/clusters`), ); diff --git a/packages/api-v4/src/object-storage/index.ts b/packages/api-v4/src/object-storage/index.ts index e2985222d3f..36e29f03304 100644 --- a/packages/api-v4/src/object-storage/index.ts +++ b/packages/api-v4/src/object-storage/index.ts @@ -8,6 +8,6 @@ export * from './objects'; export * from './objectStorageKeys'; -export * from './types'; - export * from './prices'; + +export * from './types'; diff --git a/packages/api-v4/src/object-storage/objectStorageKeys.ts b/packages/api-v4/src/object-storage/objectStorageKeys.ts index 365697c6e26..d0c778f6528 100644 --- a/packages/api-v4/src/object-storage/objectStorageKeys.ts +++ b/packages/api-v4/src/object-storage/objectStorageKeys.ts @@ -2,6 +2,7 @@ import { createObjectStorageKeysSchema, updateObjectStorageKeysSchema, } from '@linode/validation/lib/objectStorageKeys.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,10 +11,11 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { - ObjectStorageKey, + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateObjectStorageKeyPayload, + ObjectStorageKey, UpdateObjectStorageKeyPayload, } from './types'; @@ -27,7 +29,7 @@ export const getObjectStorageKeys = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/object-storage/keys`) + setURL(`${API_ROOT}/object-storage/keys`), ); /** @@ -39,7 +41,7 @@ export const createObjectStorageKeys = (data: CreateObjectStorageKeyPayload) => Request( setMethod('POST'), setURL(`${API_ROOT}/object-storage/keys`), - setData(data, createObjectStorageKeysSchema) + setData(data, createObjectStorageKeysSchema), ); /** @@ -49,12 +51,12 @@ export const createObjectStorageKeys = (data: CreateObjectStorageKeyPayload) => */ export const updateObjectStorageKey = ( id: number, - data: UpdateObjectStorageKeyPayload + data: UpdateObjectStorageKeyPayload, ) => Request( setMethod('PUT'), setURL(`${API_ROOT}/object-storage/keys/${encodeURIComponent(id)}`), - setData(data, updateObjectStorageKeysSchema) + setData(data, updateObjectStorageKeysSchema), ); /** @@ -65,5 +67,5 @@ export const updateObjectStorageKey = ( export const revokeObjectStorageKey = (id: number) => Request( setMethod('DELETE'), - setURL(`${API_ROOT}/object-storage/keys/${encodeURIComponent(id)}`) + setURL(`${API_ROOT}/object-storage/keys/${encodeURIComponent(id)}`), ); diff --git a/packages/api-v4/src/object-storage/objects.ts b/packages/api-v4/src/object-storage/objects.ts index 7cb8f718dcc..33a105d9623 100644 --- a/packages/api-v4/src/object-storage/objects.ts +++ b/packages/api-v4/src/object-storage/objects.ts @@ -1,11 +1,12 @@ import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { + +import type { ACLType, + CreateObjectStorageObjectURLPayload, + GetObjectStorageACLPayload, ObjectStorageObjectACL, ObjectStorageObjectURL, - GetObjectStorageACLPayload, - CreateObjectStorageObjectURLPayload, } from './types'; /** @@ -17,17 +18,17 @@ export const getObjectURL = ( clusterId: string, bucketName: string, name: string, - method: 'GET' | 'PUT' | 'POST' | 'DELETE', - options?: CreateObjectStorageObjectURLPayload + method: 'DELETE' | 'GET' | 'POST' | 'PUT', + options?: CreateObjectStorageObjectURLPayload, ) => Request( setMethod('POST'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/object-url` + clusterId, + )}/${encodeURIComponent(bucketName)}/object-url`, ), - setData({ name, method, ...options }) + setData({ name, method, ...options }), ); /** @@ -45,11 +46,11 @@ export const getObjectACL = ({ setMethod('GET'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId + clusterId, )}/${encodeURIComponent(bucket)}/object-acl?name=${encodeURIComponent( - params.name - )}` - ) + params.name, + )}`, + ), ); /** @@ -62,14 +63,14 @@ export const updateObjectACL = ( clusterId: string, bucketName: string, name: string, - acl: Omit + acl: Omit, ) => Request<{}>( setMethod('PUT'), setURL( `${API_ROOT}/object-storage/buckets/${encodeURIComponent( - clusterId - )}/${encodeURIComponent(bucketName)}/object-acl` + clusterId, + )}/${encodeURIComponent(bucketName)}/object-acl`, ), - setData({ acl, name }) + setData({ acl, name }), ); diff --git a/packages/api-v4/src/object-storage/prices.ts b/packages/api-v4/src/object-storage/prices.ts index 2907a6a110c..52effabdfa4 100644 --- a/packages/api-v4/src/object-storage/prices.ts +++ b/packages/api-v4/src/object-storage/prices.ts @@ -1,7 +1,8 @@ -import { Params, PriceType, ResourcePage } from 'src/types'; import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL } from '../request'; +import type { Params, PriceType, ResourcePage } from 'src/types'; + /** * getObjectStorageTypes * @@ -12,5 +13,5 @@ export const getObjectStorageTypes = (params?: Params) => Request>( setURL(`${API_ROOT}/object-storage/types`), setMethod('GET'), - setParams(params) + setParams(params), ); diff --git a/packages/api-v4/src/object-storage/types.ts b/packages/api-v4/src/object-storage/types.ts index a749fbc0866..7aeb59b614e 100644 --- a/packages/api-v4/src/object-storage/types.ts +++ b/packages/api-v4/src/object-storage/types.ts @@ -1,6 +1,10 @@ export type ObjectStorageEndpointTypes = 'E0' | 'E1' | 'E2' | 'E3'; export interface ObjectStorageKeyRegions { + /** + * The type specifying which generation of endpoint this is. + */ + endpoint_type?: ObjectStorageEndpointTypes; /** * Region ID (e.g. 'us-east') */ @@ -9,10 +13,6 @@ export interface ObjectStorageKeyRegions { * The hostname prefix for the region (e.g. 'us-east-1.linodeobjects.com') */ s3_endpoint: string; - /** - * The type specifying which generation of endpoint this is. - */ - endpoint_type?: ObjectStorageEndpointTypes; } export interface ObjectStorageKey { @@ -23,7 +23,7 @@ export interface ObjectStorageKey { /** * Settings that restrict access to specific buckets, each with defined permission levels. */ - bucket_access: ObjectStorageKeyBucketAccess[] | null; + bucket_access: null | ObjectStorageKeyBucketAccess[]; /** * This Object Storage key's unique ID. */ @@ -47,20 +47,20 @@ export interface ObjectStorageKey { } export type ObjectStorageKeyBucketAccessPermissions = + | 'none' | 'read_only' - | 'read_write' - | 'none'; + | 'read_write'; export interface ObjectStorageKeyBucketAccess { bucket_name: string; - permissions: ObjectStorageKeyBucketAccessPermissions; cluster: string; + permissions: ObjectStorageKeyBucketAccessPermissions; region?: string; // @TODO OBJ Multicluster: Remove optional indicator when API changes get released to prod } export interface CreateObjectStorageKeyPayload { + bucket_access: null | ObjectStorageKeyBucketAccess[]; label: string; - bucket_access: ObjectStorageKeyBucketAccess[] | null; regions?: string[]; } @@ -70,15 +70,15 @@ export interface UpdateObjectStorageKeyPayload { } export interface CreateObjectStorageBucketPayload { - acl?: 'private' | 'public-read' | 'authenticated-read' | 'public-read-write'; + acl?: 'authenticated-read' | 'private' | 'public-read' | 'public-read-write'; cluster?: string; cors_enabled?: boolean; - label: string; - region?: string; /** * To explicitly create a bucket on a specific endpoint type. */ endpoint_type?: ObjectStorageEndpointTypes; + label: string; + region?: string; /** * Used to create a bucket on a specific already-assigned S3 endpoint. */ @@ -99,23 +99,23 @@ export interface DeleteObjectStorageBucketPayload { } export interface ObjectStorageBucket { - region?: string; - label: string; - created: string; cluster: string; + created: string; + endpoint_type?: ObjectStorageEndpointTypes; hostname: string; + label: string; objects: number; - size: number; // Size of bucket in bytes + region?: string; s3_endpoint?: string; - endpoint_type?: ObjectStorageEndpointTypes; + size: number; // Size of bucket in bytes } export interface ObjectStorageObject { - size: number | null; // Size of object in bytes - owner: string | null; - etag: string | null; - last_modified: string | null; // Date + etag: null | string; + last_modified: null | string; // Date name: string; + owner: null | string; + size: null | number; // Size of object in bytes } export interface ObjectStorageObjectURL { @@ -124,65 +124,65 @@ export interface ObjectStorageObjectURL { } export interface ObjectStorageEndpoint { - region: string; endpoint_type: ObjectStorageEndpointTypes; - s3_endpoint: string | null; + region: string; + s3_endpoint: null | string; } export type ACLType = + | 'authenticated-read' + | 'custom' | 'private' | 'public-read' - | 'authenticated-read' - | 'public-read-write' - | 'custom'; + | 'public-read-write'; // Gen2 endpoints ('E2', 'E3') are not supported and will return null. export interface ObjectStorageObjectACL { acl: ACLType | null; - acl_xml: string | null; + acl_xml: null | string; } export interface CreateObjectStorageObjectURLPayload { - expires_in?: number; + content_disposition?: 'attachment'; // "Content-Type" is normally an HTTP header, but here it is used in the body // of a request to /object-url, to inform the API which kind of file it is // we're trying to upload. content_type?: string; - content_disposition?: 'attachment'; + expires_in?: number; } // Enum containing IDs for each Cluster export type ObjectStorageClusterID = - | 'us-east-1' - | 'eu-central-1' | 'ap-south-1' + | 'eu-central-1' + | 'us-east-1' | 'us-southeast-1'; export interface ObjectStorageCluster { - region: string; - status: string; // @todo: should be enum - id: ObjectStorageClusterID; domain: string; + id: ObjectStorageClusterID; + region: string; static_site_domain: string; + status: string; // @todo: should be enum } export interface GetObjectStorageObjectListPayload { - clusterId: string; bucket: string; + clusterId: string; params?: ObjectStorageObjectListParams; } interface ObjectStorageObjectListParams { delimiter?: string; marker?: string; - prefix?: string; page_size?: number; + prefix?: string; } export interface ObjectStorageObjectList { data: ObjectStorageObject[]; - next_marker: string | null; is_truncated: boolean; + next_marker: null | string; } export interface CreateObjectStorageBucketSSLPayload { @@ -201,8 +201,8 @@ export interface UpdateObjectStorageBucketAccessPayload { } export interface GetObjectStorageACLPayload { - clusterId: string; bucket: string; + clusterId: string; params: { name: string; }; @@ -213,5 +213,5 @@ export interface ObjectStorageBucketAccess { acl: ACLType; acl_xml: string; cors_enabled: boolean | null; - cors_xml: string | null; + cors_xml: null | string; } diff --git a/packages/api-v4/src/placement-groups/index.ts b/packages/api-v4/src/placement-groups/index.ts index b56a82cb8dd..84fe9a1caf9 100644 --- a/packages/api-v4/src/placement-groups/index.ts +++ b/packages/api-v4/src/placement-groups/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './placement-groups'; + +export * from './types'; diff --git a/packages/api-v4/src/placement-groups/placement-groups.ts b/packages/api-v4/src/placement-groups/placement-groups.ts index ca58aa147b7..e766836368a 100644 --- a/packages/api-v4/src/placement-groups/placement-groups.ts +++ b/packages/api-v4/src/placement-groups/placement-groups.ts @@ -2,8 +2,8 @@ import { createPlacementGroupSchema, updatePlacementGroupSchema, } from '@linode/validation'; -import { API_ROOT } from '../constants'; +import { API_ROOT } from '../constants'; import Request, { setData, setMethod, @@ -11,7 +11,8 @@ import Request, { setURL, setXFilter, } from '../request'; -import type { Filter, Params, ResourcePage as Page } from '../types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; import type { AssignLinodesToPlacementGroupPayload, CreatePlacementGroupPayload, @@ -30,7 +31,7 @@ export const getPlacementGroups = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/placement/groups`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -43,9 +44,9 @@ export const getPlacementGroups = (params?: Params, filter?: Filter) => export const getPlacementGroup = (placementGroupId: number) => Request( setURL( - `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}` + `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -59,7 +60,7 @@ export const createPlacementGroup = (data: CreatePlacementGroupPayload) => Request( setURL(`${API_ROOT}/placement/groups`), setMethod('POST'), - setData(data, createPlacementGroupSchema) + setData(data, createPlacementGroupSchema), ); /** @@ -72,14 +73,14 @@ export const createPlacementGroup = (data: CreatePlacementGroupPayload) => */ export const updatePlacementGroup = ( placementGroupId: number, - data: UpdatePlacementGroupPayload + data: UpdatePlacementGroupPayload, ) => Request( setURL( - `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}` + `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}`, ), setMethod('PUT'), - setData(data, updatePlacementGroupSchema) + setData(data, updatePlacementGroupSchema), ); /** @@ -92,9 +93,9 @@ export const updatePlacementGroup = ( export const deletePlacementGroup = (placementGroupId: number) => Request<{}>( setURL( - `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}` + `${API_ROOT}/placement/groups/${encodeURIComponent(placementGroupId)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -109,16 +110,16 @@ export const deletePlacementGroup = (placementGroupId: number) => */ export const assignLinodesToPlacementGroup = ( placementGroupId: number, - payload: AssignLinodesToPlacementGroupPayload + payload: AssignLinodesToPlacementGroupPayload, ) => Request( setURL( `${API_ROOT}/placement/groups/${encodeURIComponent( - placementGroupId - )}/assign` + placementGroupId, + )}/assign`, ), setMethod('POST'), - setData(payload) + setData(payload), ); /** @@ -133,14 +134,14 @@ export const assignLinodesToPlacementGroup = ( */ export const unassignLinodesFromPlacementGroup = ( placementGroupId: number, - payload: UnassignLinodesFromPlacementGroupPayload + payload: UnassignLinodesFromPlacementGroupPayload, ) => Request( setURL( `${API_ROOT}/placement/groups/${encodeURIComponent( - placementGroupId - )}/unassign` + placementGroupId, + )}/unassign`, ), setMethod('POST'), - setData(payload) + setData(payload), ); diff --git a/packages/api-v4/src/placement-groups/types.ts b/packages/api-v4/src/placement-groups/types.ts index 197a28fe44d..df57b26edfd 100644 --- a/packages/api-v4/src/placement-groups/types.ts +++ b/packages/api-v4/src/placement-groups/types.ts @@ -15,27 +15,27 @@ export type PlacementGroupPolicy = keyof typeof PLACEMENT_GROUP_POLICIES; export interface PlacementGroup { id: number; - label: string; - region: Region['id']; - placement_group_type: PlacementGroupType; is_compliant: boolean; + label: string; members: { - linode_id: number; is_compliant: boolean; + linode_id: number; }[]; - placement_group_policy: PlacementGroupPolicy; - migrations: { + migrations: null | { inbound?: Array<{ linode_id: number }>; outbound?: Array<{ linode_id: number }>; - } | null; + }; + placement_group_policy: PlacementGroupPolicy; + placement_group_type: PlacementGroupType; + region: Region['id']; } export interface LinodePlacementGroupPayload extends Pick< PlacementGroup, - 'id' | 'label' | 'placement_group_type' | 'placement_group_policy' + 'id' | 'label' | 'placement_group_policy' | 'placement_group_type' > { - migrating_to: number | null; + migrating_to: null | number; } export interface CreatePlacementGroupPayload @@ -49,13 +49,13 @@ export type UpdatePlacementGroupPayload = Pick; * Since the API expects an array of ONE linode id, we'll use a tuple here. */ export type AssignLinodesToPlacementGroupPayload = { - linodes: [number]; /** * This parameter is silent in Cloud Manager, but still needs to be represented in the API types. * * @default false */ compliant_only?: boolean; + linodes: [number]; }; export type UnassignLinodesFromPlacementGroupPayload = { diff --git a/packages/api-v4/src/profile/accessTokens.ts b/packages/api-v4/src/profile/accessTokens.ts index a4a2fc61ea1..90df6e9028c 100644 --- a/packages/api-v4/src/profile/accessTokens.ts +++ b/packages/api-v4/src/profile/accessTokens.ts @@ -1,4 +1,5 @@ import { createPersonalAccessTokenSchema } from '@linode/validation/lib/profile.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -7,8 +8,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Token, TokenRequest } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Token, TokenRequest } from './types'; /** * getPersonalAccessTokens @@ -21,7 +23,7 @@ export const getPersonalAccessTokens = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/profile/tokens`) + setURL(`${API_ROOT}/profile/tokens`), ); /** @@ -35,7 +37,7 @@ export const getPersonalAccessTokens = (params?: Params, filters?: Filter) => export const getPersonalAccessToken = (id: number) => Request( setMethod('GET'), - setURL(`${API_ROOT}/profile/tokens/${encodeURIComponent(id)}`) + setURL(`${API_ROOT}/profile/tokens/${encodeURIComponent(id)}`), ); /** @@ -59,7 +61,7 @@ export const createPersonalAccessToken = (data: TokenRequest) => Request( setMethod('POST'), setURL(`${API_ROOT}/profile/tokens`), - setData(data, createPersonalAccessTokenSchema) + setData(data, createPersonalAccessTokenSchema), ); /** @@ -75,12 +77,12 @@ export const createPersonalAccessToken = (data: TokenRequest) => */ export const updatePersonalAccessToken = ( tokenId: number, - data: Partial + data: Partial, ) => Request( setURL(`${API_ROOT}/profile/tokens/${encodeURIComponent(tokenId)}`), setMethod('PUT'), - setData(data, createPersonalAccessTokenSchema) + setData(data, createPersonalAccessTokenSchema), ); /** @@ -94,5 +96,5 @@ export const updatePersonalAccessToken = ( export const deletePersonalAccessToken = (tokenId: number) => Request<{}>( setURL(`${API_ROOT}/profile/tokens/${encodeURIComponent(tokenId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/profile/appTokens.ts b/packages/api-v4/src/profile/appTokens.ts index b6846e68763..e205bb0fd55 100644 --- a/packages/api-v4/src/profile/appTokens.ts +++ b/packages/api-v4/src/profile/appTokens.ts @@ -1,7 +1,8 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Token } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Token } from './types'; /** * getAppTokens @@ -14,7 +15,7 @@ export const getAppTokens = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/profile/apps`) + setURL(`${API_ROOT}/profile/apps`), ); /** @@ -27,7 +28,7 @@ export const getAppTokens = (params?: Params, filters?: Filter) => export const getAppToken = (tokenId: number) => Request( setMethod('GET'), - setURL(`${API_ROOT}/profile/apps/${encodeURIComponent(tokenId)}`) + setURL(`${API_ROOT}/profile/apps/${encodeURIComponent(tokenId)}`), ); /** @@ -41,5 +42,5 @@ export const getAppToken = (tokenId: number) => export const deleteAppToken = (tokenId: number) => Request<{}>( setURL(`${API_ROOT}/profile/apps/${encodeURIComponent(tokenId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/profile/index.ts b/packages/api-v4/src/profile/index.ts index ccb37b62068..93d6708927e 100644 --- a/packages/api-v4/src/profile/index.ts +++ b/packages/api-v4/src/profile/index.ts @@ -1,11 +1,11 @@ -export * from './types'; - -export * from './twofactor'; +export * from './accessTokens'; -export * from './sshkeys'; +export * from './appTokens'; export * from './profile'; -export * from './appTokens'; +export * from './sshkeys'; -export * from './accessTokens'; +export * from './twofactor'; + +export * from './types'; diff --git a/packages/api-v4/src/profile/profile.ts b/packages/api-v4/src/profile/profile.ts index 1779d465d66..fc04865bdfa 100644 --- a/packages/api-v4/src/profile/profile.ts +++ b/packages/api-v4/src/profile/profile.ts @@ -1,31 +1,33 @@ import { + SecurityQuestionsSchema, SendCodeToPhoneNumberSchema, VerifyPhoneNumberCodeSchema, - SecurityQuestionsSchema, } from '@linode/validation/lib/profile.schema'; import { updateProfileSchema } from '@linode/validation/lib/profile.schema'; + import { API_ROOT } from '../constants'; -import { Grants } from '../account'; import Request, { setData, + setHeaders, setMethod, setParams, - setHeaders, setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage } from '../types'; -import { + +import type { Grants } from '../account'; +import type { Filter, Params, ResourcePage } from '../types'; +import type { RequestOptions } from '../types'; +import type { Profile, ProfileLogin, - TrustedDevice, - UserPreferences, SecurityQuestionsData, SecurityQuestionsPayload, SendPhoneVerificationCodePayload, + TrustedDevice, + UserPreferences, VerifyVerificationCodePayload, } from './types'; -import type { RequestOptions } from '../types'; /** * getProfile @@ -37,7 +39,7 @@ export const getProfile = ({ headers }: RequestOptions = {}) => { return Request( setURL(`${API_ROOT}/profile`), setMethod('GET'), - setHeaders(headers) + setHeaders(headers), ); }; @@ -53,7 +55,7 @@ export const updateProfile = (data: any) => Request( setURL(`${API_ROOT}/profile`), setMethod('PUT'), - setData(data, updateProfileSchema) + setData(data, updateProfileSchema), ); /** @@ -93,7 +95,7 @@ export const getTrustedDevices = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/profile/devices`), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -104,7 +106,7 @@ export const getTrustedDevices = (params?: Params, filter?: Filter) => export const deleteTrustedDevice = (id: number) => Request<{}>( setURL(`${API_ROOT}/profile/devices/${encodeURIComponent(id)}`), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -115,7 +117,7 @@ export const deleteTrustedDevice = (id: number) => */ export const getUserPreferences = () => { return Request>( - setURL(`${API_ROOT}/profile/preferences`) + setURL(`${API_ROOT}/profile/preferences`), ); }; @@ -129,7 +131,7 @@ export const updateUserPreferences = (payload: UserPreferences) => { return Request( setURL(`${API_ROOT}/profile/preferences`), setData(payload), - setMethod('PUT') + setMethod('PUT'), ); }; @@ -138,7 +140,7 @@ export const getLogins = (params?: Params, filter?: Filter) => { setURL(`${API_ROOT}/profile/logins`), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); }; @@ -150,7 +152,7 @@ export const getLogins = (params?: Params, filter?: Filter) => { export const getSecurityQuestions = () => { return Request( setURL(`${API_ROOT}/profile/security-questions`), - setMethod('GET') + setMethod('GET'), ); }; @@ -163,7 +165,7 @@ export const updateSecurityQuestions = (payload: SecurityQuestionsPayload) => { return Request( setURL(`${API_ROOT}/profile/security-questions`), setMethod('POST'), - setData(payload, SecurityQuestionsSchema) + setData(payload, SecurityQuestionsSchema), ); }; @@ -175,7 +177,7 @@ export const updateSecurityQuestions = (payload: SecurityQuestionsPayload) => { export const smsOptOut = () => { return Request<{}>( setURL(`${API_ROOT}/profile/phone-number`), - setMethod('DELETE') + setMethod('DELETE'), ); }; @@ -185,12 +187,12 @@ export const smsOptOut = () => { * Sends a one-time password via SMS to be used to verify a phone number. */ export const sendCodeToPhoneNumber = ( - data: SendPhoneVerificationCodePayload + data: SendPhoneVerificationCodePayload, ) => { return Request<{}>( setURL(`${API_ROOT}/profile/phone-number`), setMethod('POST'), - setData(data, SendCodeToPhoneNumberSchema) + setData(data, SendCodeToPhoneNumberSchema), ); }; @@ -203,6 +205,6 @@ export const verifyPhoneNumberCode = (data: VerifyVerificationCodePayload) => { return Request<{}>( setURL(`${API_ROOT}/profile/phone-number/verify`), setMethod('POST'), - setData(data, VerifyPhoneNumberCodeSchema) + setData(data, VerifyPhoneNumberCodeSchema), ); }; diff --git a/packages/api-v4/src/profile/sshkeys.ts b/packages/api-v4/src/profile/sshkeys.ts index 974dce14237..f502f8ce41b 100644 --- a/packages/api-v4/src/profile/sshkeys.ts +++ b/packages/api-v4/src/profile/sshkeys.ts @@ -2,6 +2,7 @@ import { createSSHKeySchema, updateSSHKeySchema, } from '@linode/validation/lib/profile.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,8 +11,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { SSHKey } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { SSHKey } from './types'; /** * getSSHKeys @@ -24,7 +26,7 @@ export const getSSHKeys = (params?: Params, filters?: Filter) => setMethod('GET'), setParams(params), setXFilter(filters), - setURL(`${API_ROOT}/profile/sshkeys`) + setURL(`${API_ROOT}/profile/sshkeys`), ); /** @@ -36,7 +38,7 @@ export const getSSHKeys = (params?: Params, filters?: Filter) => export const getSSHKey = (keyId: number) => Request( setMethod('GET'), - setURL(`${API_ROOT}/profile/sshkeys/${encodeURIComponent(keyId)}`) + setURL(`${API_ROOT}/profile/sshkeys/${encodeURIComponent(keyId)}`), ); /** @@ -49,7 +51,7 @@ export const createSSHKey = (data: { label: string; ssh_key: string }) => Request( setMethod('POST'), setURL(`${API_ROOT}/profile/sshkeys`), - setData(data, createSSHKeySchema) + setData(data, createSSHKeySchema), ); /** @@ -64,7 +66,7 @@ export const updateSSHKey = (keyId: number, data: { label: string }) => Request( setMethod('PUT'), setURL(`${API_ROOT}/profile/sshkeys/${encodeURIComponent(keyId)}`), - setData(data, updateSSHKeySchema) + setData(data, updateSSHKeySchema), ); /** @@ -78,5 +80,5 @@ export const updateSSHKey = (keyId: number, data: { label: string }) => export const deleteSSHKey = (keyId: number) => Request<{}>( setMethod('DELETE'), - setURL(`${API_ROOT}/profile/sshkeys/${encodeURIComponent(keyId)}`) + setURL(`${API_ROOT}/profile/sshkeys/${encodeURIComponent(keyId)}`), ); diff --git a/packages/api-v4/src/profile/twofactor.ts b/packages/api-v4/src/profile/twofactor.ts index d0bc720bd7c..b72e8336bea 100644 --- a/packages/api-v4/src/profile/twofactor.ts +++ b/packages/api-v4/src/profile/twofactor.ts @@ -1,7 +1,9 @@ import { enableTwoFactorSchema } from '@linode/validation/lib/twofactor.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { Secret } from './types'; + +import type { Secret } from './types'; /** * getTFAToken @@ -46,5 +48,5 @@ export const confirmTwoFactor = (tfa_code: string) => Request<{ scratch: string }>( setMethod('POST'), setURL(`${API_ROOT}/profile/tfa-enable-confirm`), - setData({ tfa_code }, enableTwoFactorSchema) + setData({ tfa_code }, enableTwoFactorSchema), ); diff --git a/packages/api-v4/src/profile/types.ts b/packages/api-v4/src/profile/types.ts index aed94d75fda..054e5bce838 100644 --- a/packages/api-v4/src/profile/types.ts +++ b/packages/api-v4/src/profile/types.ts @@ -2,55 +2,55 @@ import type { UserType } from '../account'; export interface Referrals { code: string; - url: string; - total: number; completed: number; - pending: number; credit: number; + pending: number; + total: number; + url: string; } -export type TPAProvider = 'password' | 'github' | 'google'; +export type TPAProvider = 'github' | 'google' | 'password'; export interface Profile { - uid: number; - username: string; + authentication_type: TPAProvider; + authorized_keys: string[]; email: string; - timezone: string; email_notifications: boolean; - referrals: Referrals; ip_whitelist_enabled: boolean; - lish_auth_method: 'password_keys' | 'keys_only' | 'disabled'; - authentication_type: TPAProvider; - authorized_keys: string[]; - two_factor_auth: boolean; + lish_auth_method: 'disabled' | 'keys_only' | 'password_keys'; + referrals: Referrals; restricted: boolean; - verified_phone_number: string | null; + timezone: string; + two_factor_auth: boolean; + uid: number; user_type: UserType; + username: string; + verified_phone_number: null | string; } export interface TokenRequest { - scopes?: string; expiry?: string; label: string; + scopes?: string; } export interface Token { + created: string; + expiry: null | string; id: number; - scopes: string; label: string; - created: string; + scopes: string; + thumbnail_url?: null | string; token?: string; - expiry: string | null; website?: string; - thumbnail_url?: null | string; } export interface TrustedDevice { created: string; + expiry: string; + id: number; last_authenticated: string; last_remote_addr: string; - id: number; user_agent: string; - expiry: string; } export interface SSHKey { @@ -61,18 +61,18 @@ export interface SSHKey { } export interface Secret { - secret: string; expiry: Date; + secret: string; } export type UserPreferences = Record; export interface ProfileLogin { - id: number; datetime: string; + id: number; ip: string; - username: string; restricted: boolean; + username: string; } export type SecurityQuestions = Record; @@ -84,7 +84,7 @@ export interface VerifyVerificationCodePayload { export interface SecurityQuestion { id: number; question: string; - response: string | null; + response: null | string; } export interface SecurityQuestionsData { @@ -99,6 +99,6 @@ export interface SecurityQuestionsPayload { } export interface SendPhoneVerificationCodePayload { - phone_number: string; iso_code: string; + phone_number: string; } diff --git a/packages/api-v4/src/quotas/index.ts b/packages/api-v4/src/quotas/index.ts index 2b1b25700ed..6ef13792c3c 100644 --- a/packages/api-v4/src/quotas/index.ts +++ b/packages/api-v4/src/quotas/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './quotas'; + +export * from './types'; diff --git a/packages/api-v4/src/quotas/quotas.ts b/packages/api-v4/src/quotas/quotas.ts index 6e790425bb5..2f7a7303f2b 100644 --- a/packages/api-v4/src/quotas/quotas.ts +++ b/packages/api-v4/src/quotas/quotas.ts @@ -1,7 +1,8 @@ -import { Filter, Params, ResourcePage as Page } from 'src/types'; import { BETA_API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Quota, QuotaType, QuotaUsage } from './types'; + +import type { Quota, QuotaType, QuotaUsage } from './types'; +import type { Filter, ResourcePage as Page, Params } from 'src/types'; /** * getQuota @@ -14,7 +15,7 @@ import { Quota, QuotaType, QuotaUsage } from './types'; export const getQuota = (type: QuotaType, id: number) => Request( setURL(`${BETA_API_ROOT}/${type}/quotas/${id}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -29,13 +30,13 @@ export const getQuota = (type: QuotaType, id: number) => export const getQuotas = ( type: QuotaType, params: Params = {}, - filter: Filter = {} + filter: Filter = {}, ) => Request>( setURL(`${BETA_API_ROOT}/${type}/quotas`), setMethod('GET'), setXFilter(filter), - setParams(params) + setParams(params), ); /** @@ -49,5 +50,5 @@ export const getQuotas = ( export const getQuotaUsage = (type: QuotaType, id: number) => Request( setURL(`${BETA_API_ROOT}/${type}/quotas/${id}/usage`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/regions/regions.ts b/packages/api-v4/src/regions/regions.ts index 736e0623d34..4048afd5837 100644 --- a/packages/api-v4/src/regions/regions.ts +++ b/packages/api-v4/src/regions/regions.ts @@ -1,7 +1,9 @@ import { API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Region, RegionAvailability } from './types'; +import { Region } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { RegionAvailability } from './types'; /** * getRegions @@ -19,7 +21,7 @@ export const getRegions = (params?: Params) => Request>( setURL(`${API_ROOT}/regions`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -33,7 +35,7 @@ export const getRegions = (params?: Params) => export const getRegion = (regionId: string) => Request( setURL(`${API_ROOT}/regions/${encodeURIComponent(regionId)}`), - setMethod('GET') + setMethod('GET'), ); export { Region }; @@ -48,7 +50,7 @@ export const getRegionAvailabilities = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/regions/availability`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -61,5 +63,5 @@ export const getRegionAvailabilities = (params?: Params, filter?: Filter) => export const getRegionAvailability = (regionId: string) => Request( setURL(`${API_ROOT}/regions/${encodeURIComponent(regionId)}/availability`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/regions/types.ts b/packages/api-v4/src/regions/types.ts index dba281ec3f4..8c40c392d84 100644 --- a/packages/api-v4/src/regions/types.ts +++ b/packages/api-v4/src/regions/types.ts @@ -1,4 +1,4 @@ -import { COUNTRY_CODE_TO_CONTINENT_CODE } from './constants'; +import type { COUNTRY_CODE_TO_CONTINENT_CODE } from './constants'; export type Capabilities = | 'Backups' @@ -9,22 +9,23 @@ export type Capabilities = | 'Cloud Firewall' | 'Disk Encryption' | 'Distributed Plans' - | 'LA Disk Encryption' // @TODO LDE: Remove once LDE is fully rolled out in every DC - | 'Linode Interfaces' | 'GPU Linodes' | 'Kubernetes' | 'Kubernetes Enterprise' + | 'LA Disk Encryption' // @TODO LDE: Remove once LDE is fully rolled out in every DC + | 'Linode Interfaces' | 'Linodes' + | 'Maintenance Policy' | 'Managed Databases' | 'Metadata' - | 'NodeBalancers' | 'NETINT Quadra T1U' + | 'NodeBalancers' | 'Object Storage' | 'Placement Group' | 'Premium Plans' + | 'StackScripts' | 'Vlans' - | 'VPCs' - | 'StackScripts'; + | 'VPCs'; export interface DNSResolvers { ipv4: string; // Comma-separated IP addresses @@ -36,17 +37,17 @@ export type RegionStatus = 'ok' | 'outage'; export type RegionSite = 'core' | 'distributed'; export interface Region { + capabilities: Capabilities[]; + country: Country; id: string; label: string; - country: Country; - capabilities: Capabilities[]; placement_group_limits: { - maximum_pgs_per_customer: number | null; // This value can be unlimited for some customers, for which the API returns the `null` value. maximum_linodes_per_pg: number; + maximum_pgs_per_customer: null | number; // This value can be unlimited for some customers, for which the API returns the `null` value. }; - status: RegionStatus; resolvers: DNSResolvers; site_type: RegionSite; + status: RegionStatus; } export interface RegionAvailability { diff --git a/packages/api-v4/src/request.test.ts b/packages/api-v4/src/request.test.ts index f719403dead..4d352944908 100644 --- a/packages/api-v4/src/request.test.ts +++ b/packages/api-v4/src/request.test.ts @@ -1,6 +1,7 @@ -import { beforeEach, describe, vi, expect, it } from 'vitest'; import adapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { object, string } from 'yup'; + import request, { baseRequest, isEmpty, @@ -49,7 +50,7 @@ describe('Linode JS SDK', () => { await request(setHeaders({ 'Content-Type': contentType })); expect(mock.history.get[0].headers).toHaveProperty( 'Content-Type', - contentType + contentType, ); }); }); @@ -60,7 +61,7 @@ describe('Linode JS SDK', () => { await request(setXFilter(filter)); expect(mock.history.get[0].headers).toHaveProperty( 'X-Filter', - JSON.stringify(filter) + JSON.stringify(filter), ); }); @@ -71,7 +72,7 @@ describe('Linode JS SDK', () => { await request(setXFilter(filter)); expect(mock.history.get[0].headers).toHaveProperty( 'X-Filter', - JSON.stringify(filter) + JSON.stringify(filter), ); }); }); @@ -104,7 +105,7 @@ describe('Linode JS SDK', () => { setHeaders({ 'Content-Type': headers }), setXFilter(filter), setParams(params), - setData(data) + setData(data), ); const response = mock.history.post[0]; expect(response).toBeDefined(); @@ -114,7 +115,7 @@ describe('Linode JS SDK', () => { expect(response).toHaveProperty('params', params); expect(response.headers).toHaveProperty( 'X-Filter', - JSON.stringify(filter) + JSON.stringify(filter), ); }); }); diff --git a/packages/api-v4/src/request.ts b/packages/api-v4/src/request.ts index c63a5198048..a55774335c8 100644 --- a/packages/api-v4/src/request.ts +++ b/packages/api-v4/src/request.ts @@ -1,11 +1,8 @@ -import Axios, { - AxiosError, - AxiosHeaders, - AxiosRequestConfig, - AxiosResponse, -} from 'axios'; -import { ValidationError, AnySchema } from 'yup'; -import { APIError, Filter, Params } from './types'; +import Axios, { AxiosHeaders } from 'axios'; + +import type { APIError, Filter, Params } from './types'; +import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; +import type { AnySchema, ValidationError } from 'yup'; interface RequestConfig extends AxiosRequestConfig { validationErrors?: APIError[]; @@ -13,7 +10,7 @@ interface RequestConfig extends AxiosRequestConfig { type RequestConfigFn = (config: RequestConfig) => RequestConfig; -type ConfigField = 'headers' | 'data' | 'params' | 'method' | 'url'; +type ConfigField = 'data' | 'headers' | 'method' | 'params' | 'url'; export const baseRequest = Axios.create({ baseURL: 'https://api.linode.com/v4', @@ -67,7 +64,7 @@ export const isEmpty = (v: any) => export const setURL = (url: string) => set('url', url); /** METHOD */ -export const setMethod = (method: 'GET' | 'POST' | 'PUT' | 'DELETE') => +export const setMethod = (method: 'DELETE' | 'GET' | 'POST' | 'PUT') => set('method', method); /** Param */ @@ -85,7 +82,6 @@ export const setHeaders = * Validate and set data in the request configuration object. */ export const setData = ( - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types data: any, /** * If a schema is provided, execute its validate method. If the validation fails, the @@ -230,8 +226,8 @@ const createError = (message: string, response: AxiosResponse) => { }; export interface CancellableRequest { - request: () => Promise; cancel: () => void; + request: () => Promise; } export const CancellableRequest = ( diff --git a/packages/api-v4/src/service-transfers/service-transfers.ts b/packages/api-v4/src/service-transfers/service-transfers.ts index 2a83edcc725..67db00b656b 100644 --- a/packages/api-v4/src/service-transfers/service-transfers.ts +++ b/packages/api-v4/src/service-transfers/service-transfers.ts @@ -1,4 +1,5 @@ import { CreateTransferSchema } from '@linode/validation'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -7,11 +8,12 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { + +import type { CreateTransferPayload, EntityTransfer, } from '../entity-transfers/types'; +import type { Filter, ResourcePage as Page, Params } from '../types'; /** * getServiceTransfers @@ -23,7 +25,7 @@ export const getServiceTransfers = (params?: Params, filter?: Filter) => setMethod('GET'), setParams(params), setXFilter(filter), - setURL(`${API_ROOT}/account/service-transfers`) + setURL(`${API_ROOT}/account/service-transfers`), ); /** @@ -36,7 +38,9 @@ export const getServiceTransfers = (params?: Params, filter?: Filter) => export const getServiceTransfer = (token: string) => Request( setMethod('GET'), - setURL(`${API_ROOT}/account/service-transfers/${encodeURIComponent(token)}`) + setURL( + `${API_ROOT}/account/service-transfers/${encodeURIComponent(token)}`, + ), ); /** @@ -49,7 +53,7 @@ export const createServiceTransfer = (data: CreateTransferPayload) => Request( setMethod('POST'), setData(data, CreateTransferSchema), - setURL(`${API_ROOT}/account/service-transfers`) + setURL(`${API_ROOT}/account/service-transfers`), ); /** @@ -62,9 +66,9 @@ export const acceptServiceTransfer = (token: string) => setMethod('POST'), setURL( `${API_ROOT}/account/service-transfers/${encodeURIComponent( - token - )}/accept` - ) + token, + )}/accept`, + ), ); /** @@ -77,5 +81,7 @@ export const acceptServiceTransfer = (token: string) => export const cancelServiceTransfer = (token: string) => Request<{}>( setMethod('DELETE'), - setURL(`${API_ROOT}/account/service-transfers/${encodeURIComponent(token)}`) + setURL( + `${API_ROOT}/account/service-transfers/${encodeURIComponent(token)}`, + ), ); diff --git a/packages/api-v4/src/stackscripts/index.ts b/packages/api-v4/src/stackscripts/index.ts index 4172f84525d..917cdfe0629 100644 --- a/packages/api-v4/src/stackscripts/index.ts +++ b/packages/api-v4/src/stackscripts/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './stackscripts'; + +export * from './types'; diff --git a/packages/api-v4/src/stackscripts/stackscripts.ts b/packages/api-v4/src/stackscripts/stackscripts.ts index f28796103c2..55dc7ba5d88 100644 --- a/packages/api-v4/src/stackscripts/stackscripts.ts +++ b/packages/api-v4/src/stackscripts/stackscripts.ts @@ -2,6 +2,7 @@ import { stackScriptSchema, updateStackScriptSchema, } from '@linode/validation/lib/stackscripts.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,8 +11,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { StackScript, StackScriptPayload } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { StackScript, StackScriptPayload } from './types'; /** * Returns a paginated list of StackScripts. @@ -22,7 +24,7 @@ export const getStackScripts = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/linode/stackscripts`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -33,9 +35,9 @@ export const getStackScripts = (params?: Params, filter?: Filter) => export const getStackScript = (stackscriptId: number) => Request( setURL( - `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}` + `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -56,7 +58,7 @@ export const createStackScript = (payload: StackScriptPayload) => Request( setURL(`${API_ROOT}/linode/stackscripts`), setMethod('POST'), - setData(payload, stackScriptSchema) + setData(payload, stackScriptSchema), ); /** @@ -76,14 +78,14 @@ export const createStackScript = (payload: StackScriptPayload) => */ export const updateStackScript = ( stackscriptId: number, - payload: Partial + payload: Partial, ) => Request( setURL( - `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}` + `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}`, ), setMethod('PUT'), - setData(payload, updateStackScriptSchema) + setData(payload, updateStackScriptSchema), ); /** @@ -94,7 +96,7 @@ export const updateStackScript = ( export const deleteStackScript = (stackscriptId: number) => Request<{}>( setURL( - `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}` + `${API_ROOT}/linode/stackscripts/${encodeURIComponent(stackscriptId)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/stackscripts/types.ts b/packages/api-v4/src/stackscripts/types.ts index 3fc8a663dfa..41837017e71 100644 --- a/packages/api-v4/src/stackscripts/types.ts +++ b/packages/api-v4/src/stackscripts/types.ts @@ -1,38 +1,38 @@ export interface StackScriptPayload { - script: string; - label: string; - images: string[]; description?: string; + images: string[]; is_public?: boolean; + label: string; rev_note?: string; + script: string; } export interface StackScript { + created: string; deployments_active: number; - id: number; - user_gravatar_id: string; - label: string; + deployments_total: number; description: string; + id: number; images: string[]; - deployments_total: number; - username: string; is_public: boolean; + label: string; + logo_url: string; mine: boolean; - created: string; - updated: string; + ordinal: number; rev_note: string; script: string; + updated: string; user_defined_fields: UserDefinedField[]; - ordinal: number; - logo_url: string; + user_gravatar_id: string; + username: string; } export interface UserDefinedField { + default?: string; + example?: string; + header?: string; label: string; + manyof?: string; name: string; - example?: string; oneof?: string; - manyof?: string; - default?: string; - header?: string; } diff --git a/packages/api-v4/src/support/index.ts b/packages/api-v4/src/support/index.ts index c8dd88d7459..ba09b6e5761 100644 --- a/packages/api-v4/src/support/index.ts +++ b/packages/api-v4/src/support/index.ts @@ -1,3 +1,3 @@ -export * from './types'; - export * from './support'; + +export * from './types'; diff --git a/packages/api-v4/src/support/support.ts b/packages/api-v4/src/support/support.ts index 8f5bc09fb02..16bdb2cce90 100644 --- a/packages/api-v4/src/support/support.ts +++ b/packages/api-v4/src/support/support.ts @@ -2,6 +2,7 @@ import { createReplySchema, createSupportTicketSchema, } from '@linode/validation/lib/support.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -10,8 +11,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { ReplyRequest, SupportReply, SupportTicket, @@ -33,7 +35,7 @@ export const getTickets = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/support/tickets`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -49,7 +51,7 @@ export const getTickets = (params?: Params, filter?: Filter) => export const getTicket = (ticketID: number) => Request( setURL(`${API_ROOT}/support/tickets/${encodeURIComponent(ticketID)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -67,15 +69,15 @@ export const getTicket = (ticketID: number) => export const getTicketReplies = ( ticketId: number, params?: Params, - filter?: Filter + filter?: Filter, ) => Request>( setURL( - `${API_ROOT}/support/tickets/${encodeURIComponent(ticketId)}/replies` + `${API_ROOT}/support/tickets/${encodeURIComponent(ticketId)}/replies`, ), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -92,7 +94,7 @@ export const createSupportTicket = (data: TicketRequest) => Request( setURL(`${API_ROOT}/support/tickets`), setMethod('POST'), - setData(data, createSupportTicketSchema) + setData(data, createSupportTicketSchema), ); /** @@ -108,7 +110,7 @@ export const createSupportTicket = (data: TicketRequest) => export const closeSupportTicket = (ticketId: number) => Request<{}>( setURL(`${API_ROOT}/support/tickets/${encodeURIComponent(ticketId)}/close`), - setMethod('POST') + setMethod('POST'), ); /** @@ -126,11 +128,11 @@ export const createReply = (data: ReplyRequest) => Request( setURL( `${API_ROOT}/support/tickets/${encodeURIComponent( - data.ticket_id - )}/replies` + data.ticket_id, + )}/replies`, ), setMethod('POST'), - setData(data, createReplySchema) + setData(data, createReplySchema), ); /** @@ -145,8 +147,8 @@ export const createReply = (data: ReplyRequest) => export const uploadAttachment = (ticketId: number, formData: FormData) => Request<{}>( setURL( - `${API_ROOT}/support/tickets/${encodeURIComponent(ticketId)}/attachments` + `${API_ROOT}/support/tickets/${encodeURIComponent(ticketId)}/attachments`, ), setMethod('POST'), - setData(formData) + setData(formData), ); diff --git a/packages/api-v4/src/support/types.ts b/packages/api-v4/src/support/types.ts index a62c1d96040..11fac542090 100644 --- a/packages/api-v4/src/support/types.ts +++ b/packages/api-v4/src/support/types.ts @@ -1,48 +1,48 @@ -import { Entity } from '../account/types'; +import type { Entity } from '../account/types'; export interface SupportTicket { - opened: string; - id: number; - closed: string | null; + attachments: string[]; closable: boolean; + closed: null | string; description: string; entity: Entity | null; gravatar_id: string; - attachments: string[]; + id: number; + opened: string; opened_by: string; + severity: null | TicketSeverity; status: 'closed' | 'new' | 'open'; summary: string; updated: string; - updated_by: string | null; - severity: TicketSeverity | null; + updated_by: null | string; } export interface SupportReply { created: string; created_by: string; - gravatar_id: string; description: string; - id: number; - from_linode: boolean; friendly_name: string; + from_linode: boolean; + gravatar_id: string; + id: number; } export interface ReplyRequest { - ticket_id: number; description: string; + ticket_id: number; } export interface TicketRequest { - summary: string; - description: string; bucket?: string; + description: string; domain_id?: number; linode_id?: number; longviewclient_id?: number; nodebalancer_id?: number; region?: string; - volume_id?: number; severity?: TicketSeverity; + summary: string; + volume_id?: number; } export type TicketSeverity = 1 | 2 | 3; diff --git a/packages/api-v4/src/tags/tags.ts b/packages/api-v4/src/tags/tags.ts index 436a1325fd3..8c5164f72be 100644 --- a/packages/api-v4/src/tags/tags.ts +++ b/packages/api-v4/src/tags/tags.ts @@ -6,15 +6,16 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { Tag, TagRequest } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { Tag, TagRequest } from './types'; export const getTags = (params?: Params, filter?: Filter) => Request>( setURL(`${API_ROOT}/tags`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); export const createTag = (data: TagRequest) => @@ -23,5 +24,5 @@ export const createTag = (data: TagRequest) => export const deleteTag = (label: string) => Request( setURL(`${API_ROOT}/tags/${encodeURIComponent(label)}`), - setMethod('DELETE') + setMethod('DELETE'), ); diff --git a/packages/api-v4/src/types.ts b/packages/api-v4/src/types.ts index 0231d49a097..c46c82d9f85 100644 --- a/packages/api-v4/src/types.ts +++ b/packages/api-v4/src/types.ts @@ -6,8 +6,8 @@ export interface APIError { } export interface APIWarning { - title: string; detail: string; + title: string; } export interface ConfigOverride { @@ -34,32 +34,32 @@ export interface Params { } export interface RequestOptions { - params?: Params; filter?: Filter; headers?: RequestHeaders; + params?: Params; } export interface FilterConditionTypes { '+and'?: Filter[]; - '+or'?: Filter[] | string[]; - '+order_by'?: string; - '+order'?: 'asc' | 'desc'; - '+eq'?: string | number; + '+contains'?: string; + '+eq'?: number | string; '+gt'?: number; '+gte'?: number; '+lt'?: number; '+lte'?: number; - '+contains'?: string; '+neq'?: string; + '+or'?: Filter[] | string[]; + '+order'?: 'asc' | 'desc'; + '+order_by'?: string; } export type Filter = LinodeFilter | LinodeFilter[]; type LinodeFilter = + | { [key: string]: boolean | Filter | null | number | string | undefined } | { [key in keyof FilterConditionTypes]: FilterConditionTypes[key]; - } - | { [key: string]: string | number | boolean | Filter | null | undefined }; + }; // const filter: Filter = { // '+or': [{ vcpus: 1 }, { class: 'standard' }], @@ -98,16 +98,16 @@ type LinodeFilter = // ], // }; -type RequestHeaderValue = string | string[] | number | boolean | null; +type RequestHeaderValue = boolean | null | number | string | string[]; type RequestContentType = - | RequestHeaderValue | 'application/json' | 'application/octet-stream' | 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/html' - | 'text/plain'; + | 'text/plain' + | RequestHeaderValue; export interface RequestHeaders { [key: string]: RequestHeaderValue | undefined; @@ -115,8 +115,8 @@ export interface RequestHeaders { Authorization?: string; 'Content-Encoding'?: string; 'Content-Length'?: number; - 'User-Agent'?: string; 'Content-Type'?: RequestContentType; + 'User-Agent'?: string; } export interface PriceType { diff --git a/packages/api-v4/src/vlans/types.ts b/packages/api-v4/src/vlans/types.ts index 4437432f85c..0e4b09a9547 100644 --- a/packages/api-v4/src/vlans/types.ts +++ b/packages/api-v4/src/vlans/types.ts @@ -1,8 +1,8 @@ export interface VLAN { - label: string; - id: number; - region: string; - linodes: { id: number; ipv4_address: string; mac_address: string }[]; cidr_block: string; created: string; + id: number; + label: string; + linodes: { id: number; ipv4_address: string; mac_address: string }[]; + region: string; } diff --git a/packages/api-v4/src/vlans/vlans.ts b/packages/api-v4/src/vlans/vlans.ts index 601b08c6a9e..bfe6f747404 100644 --- a/packages/api-v4/src/vlans/vlans.ts +++ b/packages/api-v4/src/vlans/vlans.ts @@ -1,7 +1,8 @@ import { BETA_API_ROOT as API_ROOT } from '../constants'; import Request, { setMethod, setParams, setURL, setXFilter } from '../request'; -import { Filter, Params, ResourcePage as Page } from '../types'; -import { VLAN } from './types'; + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { VLAN } from './types'; /** * getVlans @@ -14,7 +15,7 @@ export const getVlans = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/networking/vlans`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -26,5 +27,5 @@ export const getVlans = (params?: Params, filters?: Filter) => export const getVlan = (vlanID: number) => Request>( setURL(`${API_ROOT}/networking/vlans/${encodeURIComponent(vlanID)}`), - setMethod('GET') + setMethod('GET'), ); diff --git a/packages/api-v4/src/volumes/index.ts b/packages/api-v4/src/volumes/index.ts index 1df87f1f305..209cf794c13 100644 --- a/packages/api-v4/src/volumes/index.ts +++ b/packages/api-v4/src/volumes/index.ts @@ -1,5 +1,5 @@ +export * from './migrations'; + export * from './types'; export * from './volumes'; - -export * from './migrations'; diff --git a/packages/api-v4/src/volumes/migrations.ts b/packages/api-v4/src/volumes/migrations.ts index 15aabd60c71..9e3eb30d23e 100644 --- a/packages/api-v4/src/volumes/migrations.ts +++ b/packages/api-v4/src/volumes/migrations.ts @@ -1,6 +1,7 @@ import { BETA_API_ROOT } from '../constants'; import Request, { setData, setMethod, setURL } from '../request'; -import { VolumesMigrationQueue } from './types'; + +import type { VolumesMigrationQueue } from './types'; /** * getVolumesMigrationQueue @@ -11,9 +12,9 @@ import { VolumesMigrationQueue } from './types'; export const getVolumesMigrationQueue = (region: string) => Request( setURL( - `${BETA_API_ROOT}/regions/${encodeURIComponent(region)}/migration-queue` + `${BETA_API_ROOT}/regions/${encodeURIComponent(region)}/migration-queue`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -27,6 +28,6 @@ export const migrateVolumes = (volumes: number[]) => { return Request<{}>( setURL(`${BETA_API_ROOT}/volumes/migrate`), setMethod('POST'), - setData({ volumes }) + setData({ volumes }), ); }; diff --git a/packages/api-v4/src/volumes/types.ts b/packages/api-v4/src/volumes/types.ts index cc1d1c6c4ea..e0d9433d61c 100644 --- a/packages/api-v4/src/volumes/types.ts +++ b/packages/api-v4/src/volumes/types.ts @@ -1,19 +1,19 @@ -export type VolumeEncryption = 'enabled' | 'disabled'; +export type VolumeEncryption = 'disabled' | 'enabled'; export interface Volume { + created: string; + encryption?: VolumeEncryption; // @TODO BSE: Remove optionality once BSE is fully rolled out + filesystem_path: string; + hardware_type: VolumeHardwareType; id: number; label: string; - status: VolumeStatus; - size: number; - region: string; linode_id: null | number; linode_label: null | string; - created: string; - updated: string; - filesystem_path: string; + region: string; + size: number; + status: VolumeStatus; tags: string[]; - hardware_type: VolumeHardwareType; - encryption?: VolumeEncryption; // @TODO BSE: Remove optionality once BSE is fully rolled out + updated: string; } type VolumeHardwareType = 'hdd' | 'nvme'; @@ -27,18 +27,18 @@ export type VolumeStatus = | 'resizing'; export interface VolumeRequestPayload { + config_id?: number; + encryption?: VolumeEncryption; label: string; - size?: number; - region?: string; linode_id?: number; - config_id?: number; + region?: string; + size?: number; tags?: string[]; - encryption?: VolumeEncryption; } export interface AttachVolumePayload { - linode_id: number; config_id?: number; + linode_id: number; } export interface CloneVolumePayload { label: string; @@ -49,8 +49,8 @@ export interface ResizeVolumePayload { } export interface VolumesMigrationQueue { - volumes: number; linodes: number; + volumes: number; } export interface MigrateVolumesPayload { diff --git a/packages/api-v4/src/volumes/volumes.ts b/packages/api-v4/src/volumes/volumes.ts index d489fd1bb57..68b4f768bdb 100644 --- a/packages/api-v4/src/volumes/volumes.ts +++ b/packages/api-v4/src/volumes/volumes.ts @@ -4,6 +4,7 @@ import { ResizeVolumeSchema, UpdateVolumeSchema, } from '@linode/validation/lib/volumes.schema'; + import { API_ROOT } from '../constants'; import Request, { setData, @@ -12,8 +13,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, Params, ResourcePage as Page, PriceType } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params, PriceType } from '../types'; +import type { AttachVolumePayload, CloneVolumePayload, ResizeVolumePayload, @@ -31,7 +33,7 @@ import { export const getVolume = (volumeId: number) => Request( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -45,7 +47,7 @@ export const getVolumes = (params?: Params, filters?: Filter) => setURL(`${API_ROOT}/volumes`), setMethod('GET'), setParams(params), - setXFilter(filters) + setXFilter(filters), ); /** @@ -58,7 +60,7 @@ export const getVolumeTypes = (params?: Params) => Request>( setURL(`${API_ROOT}/volumes/types`), setMethod('GET'), - setParams(params) + setParams(params), ); /** @@ -78,7 +80,7 @@ export const attachVolume = (volumeId: number, payload: AttachVolumePayload) => Request( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}/attach`), setMethod('POST'), - setData(payload) + setData(payload), ); /** @@ -92,7 +94,7 @@ export const attachVolume = (volumeId: number, payload: AttachVolumePayload) => export const detachVolume = (volumeId: number) => Request<{}>( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}/detach`), - setMethod('POST') + setMethod('POST'), ); /** @@ -107,7 +109,7 @@ export const detachVolume = (volumeId: number) => export const deleteVolume = (volumeId: number) => Request<{}>( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}`), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -125,7 +127,7 @@ export const cloneVolume = (volumeId: number, data: CloneVolumePayload) => Request( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}/clone`), setMethod('POST'), - setData(data, CloneVolumeSchema) + setData(data, CloneVolumeSchema), ); /** @@ -146,7 +148,7 @@ export const resizeVolume = (volumeId: number, data: ResizeVolumePayload) => * Unless we require the old size, we wont be able to validate. We know 10 is the * absolute min so it's safe to set here. */ - setData(data, ResizeVolumeSchema(10)) + setData(data, ResizeVolumeSchema(10)), ); export interface UpdateVolumeRequest { @@ -167,7 +169,7 @@ export const updateVolume = (volumeId: number, data: UpdateVolumeRequest) => Request( setURL(`${API_ROOT}/volumes/${encodeURIComponent(volumeId)}`), setMethod('PUT'), - setData(data, UpdateVolumeSchema) + setData(data, UpdateVolumeSchema), ); /** @@ -184,5 +186,5 @@ export const createVolume = (data: VolumeRequestPayload) => Request( setURL(`${API_ROOT}/volumes`), setMethod('POST'), - setData(data, CreateVolumeSchema) + setData(data, CreateVolumeSchema), ); diff --git a/packages/api-v4/src/vpcs/index.ts b/packages/api-v4/src/vpcs/index.ts index 6506438fdc6..07099a4fd58 100644 --- a/packages/api-v4/src/vpcs/index.ts +++ b/packages/api-v4/src/vpcs/index.ts @@ -1,3 +1,3 @@ -export * from './vpcs'; - export * from './types'; + +export * from './vpcs'; diff --git a/packages/api-v4/src/vpcs/types.ts b/packages/api-v4/src/vpcs/types.ts index 2626c8de526..0fd7519e1ba 100644 --- a/packages/api-v4/src/vpcs/types.ts +++ b/packages/api-v4/src/vpcs/types.ts @@ -7,27 +7,27 @@ interface CreateVPCIPv6 extends VPCIPv6 { } export interface VPC { + created: string; + description: string; id: number; + ipv6?: VPCIPv6[]; label: string; - description: string; region: string; subnets: Subnet[]; - created: string; updated: string; - ipv6?: VPCIPv6[]; } export interface CreateVPCPayload { - label: string; description?: string; - region: string; ipv6?: CreateVPCIPv6[]; + label: string; + region: string; subnets?: CreateSubnetPayload[]; } export interface UpdateVPCPayload { - label?: string; description?: string; + label?: string; } interface VPCIPv6Subnet { @@ -35,15 +35,16 @@ interface VPCIPv6Subnet { } export interface CreateSubnetPayload { - label: string; ipv4?: string; ipv6?: VPCIPv6Subnet[]; + label: string; } export interface Subnet extends CreateSubnetPayload { + created: string; id: number; linodes: SubnetAssignedLinodeData[]; - created: string; + nodebalancers: SubnetAssignedNodeBalancerData[]; updated: string; } @@ -52,9 +53,9 @@ export interface ModifySubnetPayload { } export interface SubnetLinodeInterfaceData { - id: number; active: boolean; - config_id: number | null; + config_id: null | number; + id: number; } export interface SubnetAssignedLinodeData { @@ -62,21 +63,27 @@ export interface SubnetAssignedLinodeData { interfaces: SubnetLinodeInterfaceData[]; } +export interface SubnetAssignedNodeBalancerData { + id: number; + ipv4_range: string; +} + export interface VPCIP { active: boolean; - address: string | null; - address_range: string | null; - ipv6_range: string | null; - ipv6_is_public: boolean | null; + address: null | string; + address_range: null | string; + config_id: null | number; + gateway: null | string; + interface_id: number; ipv6_addresses: { slaac_address: string; }[]; - config_id: number | null; - gateway: string | null; - interface_id: number; - linode_id: number; + ipv6_is_public: boolean | null; + ipv6_range: null | string; + linode_id: null | number; nat_1_1: string; - prefix: number | null; + nodebalancer_id: null | number; + prefix: null | number; region: string; subnet_id: number; subnet_mask: string; diff --git a/packages/api-v4/src/vpcs/vpcs.ts b/packages/api-v4/src/vpcs/vpcs.ts index 88daa6015bf..69b09ebfa29 100644 --- a/packages/api-v4/src/vpcs/vpcs.ts +++ b/packages/api-v4/src/vpcs/vpcs.ts @@ -4,6 +4,7 @@ import { modifySubnetSchema, updateVPCSchema, } from '@linode/validation/lib/vpcs.schema'; + import { BETA_API_ROOT as API_ROOT } from '../constants'; import Request, { setData, @@ -12,8 +13,9 @@ import Request, { setURL, setXFilter, } from '../request'; -import { Filter, ResourcePage as Page, Params } from '../types'; -import { + +import type { Filter, ResourcePage as Page, Params } from '../types'; +import type { CreateSubnetPayload, CreateVPCPayload, ModifySubnetPayload, @@ -35,7 +37,7 @@ export const getVPCs = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/vpcs`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -47,7 +49,7 @@ export const getVPCs = (params?: Params, filter?: Filter) => export const getVPC = (vpcID: number) => Request( setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}`), - setMethod('GET') + setMethod('GET'), ); /** @@ -60,7 +62,7 @@ export const createVPC = (data: CreateVPCPayload) => Request( setURL(`${API_ROOT}/vpcs`), setMethod('POST'), - setData(data, createVPCSchema) + setData(data, createVPCSchema), ); /** @@ -73,7 +75,7 @@ export const updateVPC = (vpcID: number, data: UpdateVPCPayload) => Request( setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}`), setMethod('PUT'), - setData(data, updateVPCSchema) + setData(data, updateVPCSchema), ); /** @@ -85,7 +87,7 @@ export const updateVPC = (vpcID: number, data: UpdateVPCPayload) => export const deleteVPC = (vpcID: number) => Request<{}>( setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}`), - setMethod('DELETE') + setMethod('DELETE'), ); // Subnet methods @@ -100,7 +102,7 @@ export const getSubnets = (vpcID: number, params?: Params, filter?: Filter) => setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}/subnets`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -113,10 +115,10 @@ export const getSubnet = (vpcID: number, subnetID: number) => Request( setURL( `${API_ROOT}/vpcs/${encodeURIComponent( - vpcID - )}/subnets/${encodeURIComponent(subnetID)}` + vpcID, + )}/subnets/${encodeURIComponent(subnetID)}`, ), - setMethod('GET') + setMethod('GET'), ); /** @@ -129,7 +131,7 @@ export const createSubnet = (vpcID: number, data: CreateSubnetPayload) => Request( setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}/subnets`), setMethod('POST'), - setData(data, createSubnetSchemaIPv4) + setData(data, createSubnetSchemaIPv4), ); /** @@ -141,16 +143,16 @@ export const createSubnet = (vpcID: number, data: CreateSubnetPayload) => export const modifySubnet = ( vpcID: number, subnetID: number, - data: ModifySubnetPayload + data: ModifySubnetPayload, ) => Request( setURL( `${API_ROOT}/vpcs/${encodeURIComponent( - vpcID - )}/subnets/${encodeURIComponent(subnetID)}` + vpcID, + )}/subnets/${encodeURIComponent(subnetID)}`, ), setMethod('PUT'), - setData(data, modifySubnetSchema) + setData(data, modifySubnetSchema), ); /** @@ -163,10 +165,10 @@ export const deleteSubnet = (vpcID: number, subnetID: number) => Request<{}>( setURL( `${API_ROOT}/vpcs/${encodeURIComponent( - vpcID - )}/subnets/${encodeURIComponent(subnetID)}` + vpcID, + )}/subnets/${encodeURIComponent(subnetID)}`, ), - setMethod('DELETE') + setMethod('DELETE'), ); /** @@ -179,7 +181,7 @@ export const getVPCsIPs = (params?: Params, filter?: Filter) => setURL(`${API_ROOT}/vpcs/ips`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); /** @@ -192,5 +194,5 @@ export const getVPCIPs = (vpcID: number, params?: Params, filter?: Filter) => setURL(`${API_ROOT}/vpcs/${encodeURIComponent(vpcID)}/ips`), setMethod('GET'), setParams(params), - setXFilter(filter) + setXFilter(filter), ); diff --git a/packages/manager/CHANGELOG.md b/packages/manager/CHANGELOG.md index f13e5c0e1e0..ec7171b48bf 100644 --- a/packages/manager/CHANGELOG.md +++ b/packages/manager/CHANGELOG.md @@ -4,6 +4,76 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2025-05-20] - v1.142.0 + +### Changed: + +- Update styles to match CDS for Entity Header & Action Panel ([#11857](https://github.com/linode/manager/pull/11857)) +- Move Linode create flow PG warning to helper text ([#12145](https://github.com/linode/manager/pull/12145)) +- Quotas UI updates for GA ([#12197](https://github.com/linode/manager/pull/12197)) + +### Fixed: + +- PayPal button styles when using dark mode ([#12136](https://github.com/linode/manager/pull/12136)) +- Add text to toast notification to inform user of IPv6 rDNS update delays in Cloud Manager UI ([#12147](https://github.com/linode/manager/pull/12147)) +- Incorrect icon in Firewall warning banner to use outlined icon ([#12159](https://github.com/linode/manager/pull/12159)) +- Redirect /object-storage to /object-storage/buckets ([#12165](https://github.com/linode/manager/pull/12165)) +- Issue preventing Internal Akamai Employees from creating Linodes using VLAN interfaces ([#12166](https://github.com/linode/manager/pull/12166)) +- StackScripts Landing description truncation ([#12194](https://github.com/linode/manager/pull/12194)) +- Console warnings related to first-child pseudo class in LandingHeader component ([#12200](https://github.com/linode/manager/pull/12200)) +- CloudPulse-Metrics: Refine tooltip behavior for zoom button interactions at `Zoomer.tsx` ([#12206](https://github.com/linode/manager/pull/12206)) + +### Removed: + +- DeletionDialog Component ([#12153](https://github.com/linode/manager/pull/12153)) + +### Tech Stories: + +- Update @paypal/react-paypal-js to ^8.8.3 ([#12102](https://github.com/linode/manager/pull/12102)) +- Deprecate useDialogData ([#12153](https://github.com/linode/manager/pull/12153)) +- Delete root level `.eslintrc.js` ([#12195](https://github.com/linode/manager/pull/12195)) +- Migrate Hidden Component to `@linode/ui` ([#12128](https://github.com/linode/manager/pull/12128)) +- Lint whole monorepo for perfectionist rules ([#12140](https://github.com/linode/manager/pull/12140)) + +### Tests: + +- Add Cypress integration tests for restricted user details page ([#12086](https://github.com/linode/manager/pull/12086)) +- Fix DBaaS Cypress test region mocks so tests pass in DevCloud ([#12127](https://github.com/linode/manager/pull/12127)) +- Fix for object enrollment tests in devcloud ([#12135](https://github.com/linode/manager/pull/12135)) +- Fix for LKE landing page Cypress test ([#12142](https://github.com/linode/manager/pull/12142)) +- Fix for Image Search test ([#12149](https://github.com/linode/manager/pull/12149)) +- Add test spec for Adobe Launch analytics integration ([#12158](https://github.com/linode/manager/pull/12158)) +- Improve stability of Object Storage bucket clean up during Cypress tests ([#12164](https://github.com/linode/manager/pull/12164)) +- Fix for Object Storage create integration test ([#12169](https://github.com/linode/manager/pull/12169)) +- Fix Linode Rebuild test failures stemming from Alpine 3.18 Image deprecation ([#12172](https://github.com/linode/manager/pull/12172)) +- Use chooseCluster() in object-storage e2e test ([#12185](https://github.com/linode/manager/pull/12185)) +- Fix for misc test failures ([#12198](https://github.com/linode/manager/pull/12198)) + +### Upcoming Features: + +- LKE for Restricted users ([#11956](https://github.com/linode/manager/pull/11956)) +- Types and queries for Host & VM Maintenance ([#11990](https://github.com/linode/manager/pull/11990)) +- Restrict Migration Region options to MTC availability regions only ([#12105](https://github.com/linode/manager/pull/12105)) +- Disable CloudPulse create alert button when list api is still loading ([#12133](https://github.com/linode/manager/pull/12133)) +- Add Delete functionality for the user alert in alerting page with ConfirmationDialog box, deleteHandler ([#12134](https://github.com/linode/manager/pull/12134)) +- Add support for VPC IPv6 feature flag ([#12151](https://github.com/linode/manager/pull/12151)) +- Improve Network Interface table for small screen sizes by hiding columns ([#12157](https://github.com/linode/manager/pull/12157)) +- Hide Delete IP button in Linode IP table for Linode Interfaces even if IP isn't associated with an interface ([#12157](https://github.com/linode/manager/pull/12157)) +- Hide `Learn more` link in `PublicIPAddressesTooltip` for Linode Interfaces ([#12157](https://github.com/linode/manager/pull/12157)) +- Support Linode Interfaces in the Linode Create Summary ([#12160](https://github.com/linode/manager/pull/12160)) +- IAM RBAC: update texts, update the sorting logic in the AssignedRolesTable ([#12167](https://github.com/linode/manager/pull/12167)) +- CloudPulse-Metrics: Upgrade filter configs at `filterConfig.ts` to have view based control of filters ([#12174](https://github.com/linode/manager/pull/12174)) +- Add `InputValueField` component, Add logic to switch between text field and autocomplete in `DimensionFilterField` component for CloudPulse Alert ([#12175](https://github.com/linode/manager/pull/12175)) +- Add reusable `AclpPreferenceToggle` to support both Alerts and Metrics preferences and Alerts notification banner with a legacy-beta toggle option ([#12180](https://github.com/linode/manager/pull/12180)) +- IAM RBAC: Fix styling issue for the Assigned Roles Table ([#12183](https://github.com/linode/manager/pull/12183)) +- IAM RBAC: Fix styling issues in the Assigned Permissions Panel and Assigned Entities Table, update 'Hide details' logic and text update ([#12184](https://github.com/linode/manager/pull/12184)) +- Fix incorrect endpoint use when adding a new LKE-E cluster node pool by using `/v4beta` endpoint ([#12188](https://github.com/linode/manager/pull/12188)) +- CloudPulse: Remove `tags filter` from linode filter config and rename resources to `Linode Label(s)` in CloudPulse dashboards ([#12192](https://github.com/linode/manager/pull/12192)) +- Add beta ACLP contextual metrics to the Metrics tab on the Linode details page ([#12193](https://github.com/linode/manager/pull/12193)) +- Disable action menu and MTC plans on Linode resize ([#12111](https://github.com/linode/manager/pull/12111)) +- Remove `g8-premium-64-ht` MTC plan check per updated design doc ([#12168](https://github.com/linode/manager/pull/12168)) +- IAM RBAC: Add drawer for assigning selected roles to a user ([#12182](https://github.com/linode/manager/pull/12182)) + ## [2025-05-09] - v1.141.1 ### Fixed: diff --git a/packages/manager/cypress.config.ts b/packages/manager/cypress.config.ts index d3c582dff3b..aab31745a48 100644 --- a/packages/manager/cypress.config.ts +++ b/packages/manager/cypress.config.ts @@ -1,30 +1,34 @@ -/* eslint-disable no-console */ import { defineConfig } from 'cypress'; +import cypressOnFix from 'cypress-on-fix'; + import { setupPlugins } from './cypress/support/plugins'; +import { configureApi } from './cypress/support/plugins/configure-api'; import { configureBrowser } from './cypress/support/plugins/configure-browser'; import { configureFileWatching } from './cypress/support/plugins/configure-file-watching'; +import { configureMultiReporters } from './cypress/support/plugins/configure-multi-reporters'; +import { discardPassedTestRecordings } from './cypress/support/plugins/discard-passed-test-recordings'; +import { featureFlagOverrides } from './cypress/support/plugins/feature-flag-override'; +import { fetchAccount } from './cypress/support/plugins/fetch-account'; +import { fetchLinodeClusters } from './cypress/support/plugins/fetch-linode-clusters'; +import { fetchLinodeRegions } from './cypress/support/plugins/fetch-linode-regions'; +import { generateTestWeights } from './cypress/support/plugins/generate-weights'; +import { enableHtmlReport } from './cypress/support/plugins/html-report'; import { - enableJunitE2eReport, enableJunitComponentReport, + enableJunitE2eReport, } from './cypress/support/plugins/junit-report'; -import { discardPassedTestRecordings } from './cypress/support/plugins/discard-passed-test-recordings'; import { loadEnvironmentConfig } from './cypress/support/plugins/load-env-config'; import { nodeVersionCheck } from './cypress/support/plugins/node-version-check'; -import { regionOverrideCheck } from './cypress/support/plugins/region-override-check'; -import { vitePreprocess } from './cypress/support/plugins/vite-preprocessor'; -import { configureApi } from './cypress/support/plugins/configure-api'; -import { fetchAccount } from './cypress/support/plugins/fetch-account'; -import { fetchLinodeRegions } from './cypress/support/plugins/fetch-linode-regions'; +import { + clusterOverrideCheck, + regionOverrideCheck, +} from './cypress/support/plugins/override-check'; +import { postRunCleanup } from './cypress/support/plugins/post-run-cleanup'; +import { resetUserPreferences } from './cypress/support/plugins/reset-user-preferences'; import { splitCypressRun } from './cypress/support/plugins/split-run'; -import { generateTestWeights } from './cypress/support/plugins/generate-weights'; import { logTestTagInfo } from './cypress/support/plugins/test-tagging-info'; +import { vitePreprocess } from './cypress/support/plugins/vite-preprocessor'; import cypressViteConfig from './cypress/vite.config'; -import { featureFlagOverrides } from './cypress/support/plugins/feature-flag-override'; -import { postRunCleanup } from './cypress/support/plugins/post-run-cleanup'; -import { resetUserPreferences } from './cypress/support/plugins/reset-user-preferences'; -import { enableHtmlReport } from './cypress/support/plugins/html-report'; -import { configureMultiReporters } from './cypress/support/plugins/configure-multi-reporters'; -import cypressOnFix from 'cypress-on-fix'; /** * Exports a Cypress configuration object. * @@ -97,8 +101,10 @@ export default defineConfig({ discardPassedTestRecordings, fetchAccount, fetchLinodeRegions, + fetchLinodeClusters, resetUserPreferences, regionOverrideCheck, + clusterOverrideCheck, featureFlagOverrides, logTestTagInfo, splitCypressRun, diff --git a/packages/manager/cypress/component/components/select.spec.tsx b/packages/manager/cypress/component/components/select.spec.tsx index 71d0c2c5c97..4afaa83e88e 100644 --- a/packages/manager/cypress/component/components/select.spec.tsx +++ b/packages/manager/cypress/component/components/select.spec.tsx @@ -158,11 +158,11 @@ componentTests('Select', (mount) => { mount( ); @@ -221,12 +221,12 @@ componentTests('Select', (mount) => { mount( { setColor(e.target.value); onChange(e.target.value); }} - color={color} - id="color-picker" style={inputStyles} type="color" value={color} diff --git a/packages/manager/src/components/ConfirmationDialog/ConfirmationDialog.tsx b/packages/manager/src/components/ConfirmationDialog/ConfirmationDialog.tsx index 7fd5211fe9b..dd7856e6529 100644 --- a/packages/manager/src/components/ConfirmationDialog/ConfirmationDialog.tsx +++ b/packages/manager/src/components/ConfirmationDialog/ConfirmationDialog.tsx @@ -2,13 +2,17 @@ import { Dialog, Stack } from '@linode/ui'; import { styled } from '@mui/material/styles'; import * as React from 'react'; +import type { APIError } from '@linode/api-v4'; import type { DialogProps } from '@linode/ui'; - export interface ConfirmationDialogProps extends DialogProps { /** * The actions to be displayed in the dialog. */ actions?: ((props: DialogProps) => JSX.Element) | JSX.Element; + /** + * The error to be displayed in case fetching the entity failed. + */ + entityError?: APIError[] | null | string; } /** @@ -24,10 +28,15 @@ export const ConfirmationDialog = React.forwardRef< HTMLDivElement, ConfirmationDialogProps >((props, ref) => { - const { actions, children, ...dialogProps } = props; + const { actions, children, entityError, ...dialogProps } = props; return ( - + {children} {actions && typeof actions === 'function' diff --git a/packages/manager/src/components/CopyTooltip/CopyTooltip.test.tsx b/packages/manager/src/components/CopyTooltip/CopyTooltip.test.tsx index 0ab2a7f1c3a..078c8bd7b1c 100644 --- a/packages/manager/src/components/CopyTooltip/CopyTooltip.test.tsx +++ b/packages/manager/src/components/CopyTooltip/CopyTooltip.test.tsx @@ -54,19 +54,15 @@ describe('CopyTooltip', () => { }); it('should mask and toggle visibility of tooltip text with the masked property', async () => { - const { - getByLabelText, - getByTestId, - getByText, - queryByText, - } = renderWithTheme( - - ); + const { getByLabelText, getByTestId, getByText, queryByText } = + renderWithTheme( + + ); const copyIconButton = getByLabelText(`Copy ${mockText} to clipboard`); const visibilityToggle = getByTestId('VisibilityTooltip'); diff --git a/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx b/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx index 3d794afbad7..b527095664e 100644 --- a/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx +++ b/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx @@ -10,11 +10,11 @@ import type { TextFieldProps } from '@linode/ui'; import type { CopyTooltipProps } from 'src/components/CopyTooltip/CopyTooltip'; export interface CopyableTextFieldProps extends TextFieldProps { + className?: string; /** * Optional props that are passed to the underlying CopyTooltip component */ CopyTooltipProps?: Partial; - className?: string; hideIcons?: boolean; showDownloadIcon?: boolean; } @@ -35,6 +35,9 @@ export const CopyableTextField = (props: CopyableTextFieldProps) => { @@ -45,9 +48,6 @@ export const CopyableTextField = (props: CopyableTextFieldProps) => { ), }} - className={`${className} copy removeDisabledStyles`} - data-qa-copy-tooltip - disabled /> ); }; diff --git a/packages/manager/src/components/DatePicker/DateTimePicker.stories.tsx b/packages/manager/src/components/DatePicker/DateTimePicker.stories.tsx index 7df04ed26cd..0cbfdc6b400 100644 --- a/packages/manager/src/components/DatePicker/DateTimePicker.stories.tsx +++ b/packages/manager/src/components/DatePicker/DateTimePicker.stories.tsx @@ -26,10 +26,8 @@ export const ControlledExample: Story = { }, render: (args) => { const ControlledDateTimePicker = () => { - const [ - selectedDateTime, - setSelectedDateTime, - ] = React.useState(args.value || null); + const [selectedDateTime, setSelectedDateTime] = + React.useState(args.value || null); const handleChange = (newDateTime: DateTime | null) => { setSelectedDateTime(newDateTime); diff --git a/packages/manager/src/components/DatePicker/DateTimePicker.tsx b/packages/manager/src/components/DatePicker/DateTimePicker.tsx index d46e281df1a..4adab2e34d2 100644 --- a/packages/manager/src/components/DatePicker/DateTimePicker.tsx +++ b/packages/manager/src/components/DatePicker/DateTimePicker.tsx @@ -153,6 +153,7 @@ export const DateTimePicker = ({ setAnchorEl(event.currentTarget)} + placeholder={placeholder} value={ selectedDateTime ? `${selectedDateTime.toFormat(format)}${generateTimeZone( @@ -176,11 +181,6 @@ export const DateTimePicker = ({ )}` : '' } - errorText={errorText} - label={label} - noMarginTop - onClick={(event) => setAnchorEl(event.currentTarget)} - placeholder={placeholder} /> ({ @@ -265,9 +268,6 @@ export const DateTimePicker = ({ sx={{ marginTop: 0, }} - data-qa-time="time-picker" - label={timeSelectProps?.label || 'Select Time'} - onChange={handleTimeChange} value={selectedDateTime || null} /> @@ -288,6 +288,7 @@ export const DateTimePicker = ({ @@ -306,8 +306,9 @@ export const DateTimePicker = ({ }; const generateTimeZone = (selectedTimezone: null | string): string => { - const offset = timezones.find((zone) => zone.name === selectedTimezone) - ?.offset; + const offset = timezones.find( + (zone) => zone.name === selectedTimezone + )?.offset; if (!offset) { return ''; } diff --git a/packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx b/packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx index d1c1ef06c1e..f1912c77917 100644 --- a/packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx +++ b/packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx @@ -114,7 +114,8 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { placeholder: presetsPlaceholder = 'Select a preset', } = {}, startDateProps: { - errorMessage: startDateErrorMessage = 'Start date/time cannot be after the end date/time.', + errorMessage: + startDateErrorMessage = 'Start date/time cannot be after the end date/time.', label: startLabel = 'Start Date and Time', placeholder: startDatePlaceholder, showTimeZone: showStartTimeZone = false, @@ -131,11 +132,11 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { endDateTimeValue ?? DateTime.now().set({ second: 0 }) ); const [presetValue, setPresetValue] = useState< + | undefined | { label: string; value: string; } - | undefined >( presetsOptions.find((option) => option.value === presetsDefaultValue) ?? presetsOptions[0] @@ -171,27 +172,27 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { let newEndDateTime: DateTime | null = now; switch (value) { - case '30minutes': - newStartDateTime = now.minus({ minutes: 30 }); - break; case '1hour': newStartDateTime = now.minus({ hours: 1 }); break; + case '7days': + newStartDateTime = now.minus({ days: 7 }); + break; case '12hours': newStartDateTime = now.minus({ hours: 12 }); break; case '24hours': newStartDateTime = now.minus({ hours: 24 }); break; - case '7days': - newStartDateTime = now.minus({ days: 7 }); - break; case '30days': newStartDateTime = now.minus({ days: 30 }); break; - case 'this_month': - newEndDateTime = DateTime.now(); - newStartDateTime = newEndDateTime.startOf('month'); + case '30minutes': + newStartDateTime = now.minus({ minutes: 30 }); + break; + case 'custom_range': + newStartDateTime = startDateTime; + newEndDateTime = endDateTime; break; case 'last_month': const lastMonth = DateTime.now().minus({ months: 1 }); @@ -199,9 +200,9 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { newEndDateTime = lastMonth.endOf('month'); break; - case 'custom_range': - newStartDateTime = startDateTime; - newEndDateTime = endDateTime; + case 'this_month': + newEndDateTime = DateTime.now(); + newStartDateTime = newEndDateTime.startOf('month'); break; default: return; @@ -257,17 +258,17 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { {showPresets ? ( { - if (selection) { - handlePresetSelection(selection.value as DatePresetType); - } - }} data-qa-preset="preset-select" data-testid="preset-select" disableClearable fullWidth label={presetsLabel} noMarginTop + onChange={(_, selection) => { + if (selection) { + handlePresetSelection(selection.value as DatePresetType); + } + }} options={presetsOptions} placeholder={presetsPlaceholder} value={presetValue} @@ -279,11 +280,6 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { gap={2} > setStartTimeZone(value), - value: startTimeZone, - }} disabledTimeZone={disabledTimeZone} errorText={startDateError ?? undefined} format={format} @@ -292,12 +288,14 @@ export const DateTimeRangePicker = (props: DateTimeRangePickerProps) => { placeholder={startDatePlaceholder} showTimeZone={showStartTimeZone} timeSelectProps={{ label: 'Start Time' }} - value={startDateTime} - /> - setStartTimeZone(value), value: startTimeZone, }} + value={startDateTime} + /> + { placeholder={endDatePlaceholder} showTimeZone={showEndTimeZone} timeSelectProps={{ label: 'End Time' }} + timeZoneSelectProps={{ + value: startTimeZone, + }} value={endDateTime} /> { setShowPresets(true); setPresetValue(undefined); setStartDateError(null); }} - data-qa-buttons="true" variant="text" > Presets diff --git a/packages/manager/src/components/DatePicker/TimeZoneSelect.tsx b/packages/manager/src/components/DatePicker/TimeZoneSelect.tsx index f4bd68c97a3..813ba76478c 100644 --- a/packages/manager/src/components/DatePicker/TimeZoneSelect.tsx +++ b/packages/manager/src/components/DatePicker/TimeZoneSelect.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { timezones } from 'src/assets/timezones/timezones'; -type Timezone = typeof timezones[number]; +type Timezone = (typeof timezones)[number]; interface TimeZoneSelectProps { disabled?: boolean; @@ -48,9 +48,6 @@ export const TimeZoneSelect = ({ }: TimeZoneSelectProps) => { return ( option.value === value) ?? undefined - } autoHighlight disabled={disabled} errorText={errorText} @@ -59,6 +56,9 @@ export const TimeZoneSelect = ({ onChange={(e, option) => onChange(option?.value || '')} options={timezoneOptions} placeholder="Choose a Timezone" + value={ + timezoneOptions.find((option) => option.value === value) ?? undefined + } /> ); }; diff --git a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx index 8269edc4a7f..f568d261c30 100644 --- a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx +++ b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx @@ -94,6 +94,13 @@ export const DebouncedSearchTextField = React.memo( return ( } {clearable && Boolean(textFieldValue) && ( { setTextFieldValue(''); onSearch(''); }} + size="small" sx={{ padding: 0, }} - aria-label="Clear" - size="small" > @@ -124,13 +131,6 @@ export const DebouncedSearchTextField = React.memo( ...inputSlotProps, }, }} - className={className} - data-qa-debounced-search - defaultValue={defaultValue} - hideLabel={hideLabel} - label={label} - onChange={debouncedOnChange} - placeholder={placeholder || 'Filter by query'} value={textFieldValue} {...restOfTextFieldProps} /> diff --git a/packages/manager/src/components/DeletionDialog/DeletionDialog.stories.tsx b/packages/manager/src/components/DeletionDialog/DeletionDialog.stories.tsx deleted file mode 100644 index 016ea3debf3..00000000000 --- a/packages/manager/src/components/DeletionDialog/DeletionDialog.stories.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { action } from '@storybook/addon-actions'; -import React from 'react'; - -import { DeletionDialog } from 'src/components/DeletionDialog/DeletionDialog'; - -import type { Meta, StoryObj } from '@storybook/react'; - -const meta: Meta = { - argTypes: { - entity: { - description: 'They type of entity that is going to be deleted', - }, - error: { - description: 'Error that will be shown in the dialog.', - }, - label: { - description: 'The label of the entity you will delete.', - }, - maxWidth: { - control: { - type: 'select', - }, - if: { arg: 'fullWidth' }, - options: ['xs', 'sm', 'md', 'lg', 'xl', false], - }, - onClose: { - action: 'onClose', - description: 'Callback fired when the component requests to be closed.', - }, - onDelete: { - action: 'onDelete', - }, - open: { - description: 'Is the modal open?', - }, - }, - args: { - disableAutoFocus: true, - disableEnforceFocus: true, - disablePortal: true, - disableScrollLock: true, - entity: 'Linode', - error: undefined, - fullWidth: false, - label: 'my-linode-0', - loading: false, - maxWidth: 'md', - onClose: action('onClose'), - onDelete: action('onDelete'), - open: true, - style: { position: 'unset' }, - }, - component: DeletionDialog, - title: 'Components/Dialog/DeletionDialog', -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - render: (args) => {args.children}, -}; - -export const DeletionDialogError: Story = { - args: { - error: 'There was an error deleting this Linode.', - }, - render: (args) => {args.children}, -}; - -export const DeletionDialogLoading: Story = { - args: { - loading: true, - }, - render: (args) => {args.children}, -}; diff --git a/packages/manager/src/components/DeletionDialog/DeletionDialog.test.tsx b/packages/manager/src/components/DeletionDialog/DeletionDialog.test.tsx deleted file mode 100644 index 196ab5452c1..00000000000 --- a/packages/manager/src/components/DeletionDialog/DeletionDialog.test.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { fireEvent } from '@testing-library/react'; -import * as React from 'react'; - -import { renderWithTheme } from 'src/utilities/testHelpers'; - -import { DeletionDialog } from './DeletionDialog'; - -import type { DeletionDialogProps } from './DeletionDialog'; -import type { ManagerPreferences } from '@linode/utilities'; - -const preference: ManagerPreferences['type_to_confirm'] = true; - -const queryMocks = vi.hoisted(() => ({ - usePreferences: vi.fn().mockReturnValue({}), -})); - -vi.mock('@linode/queries', async () => { - const actual = await vi.importActual('@linode/queries'); - return { - ...actual, - usePreferences: queryMocks.usePreferences, - }; -}); - -queryMocks.usePreferences.mockReturnValue({ - data: preference, -}); - -describe('DeletionDialog', () => { - const defaultArgs: DeletionDialogProps = { - entity: 'Linode', - isFetching: false, - label: 'my-linode-0', - loading: false, - onClose: vi.fn(), - onDelete: vi.fn(), - open: false, - }; - - it.each([ - ['not render', false], - ['render', true], - ])( - 'should %s a DeletionDialog with the correct title, close button, and action buttons when open is %s', - (_, isOpen) => { - const { queryByRole, queryByTestId, queryByText } = renderWithTheme( - - ); - const title = queryByText( - `Delete ${defaultArgs.entity} ${defaultArgs.label}?` - ); - const dialog = queryByTestId('drawer'); - const closeButton = queryByRole('button', { name: 'Close' }); - const cancelButton = queryByTestId('cancel'); - const deleteButton = queryByTestId('confirm'); - - if (isOpen) { - expect(title).toBeInTheDocument(); - expect(dialog).toBeInTheDocument(); - expect(closeButton).toBeInTheDocument(); - expect(cancelButton).toBeInTheDocument(); - expect(deleteButton).toBeInTheDocument(); - expect(deleteButton).toHaveTextContent(`Delete ${defaultArgs.entity}`); - } else { - expect(title).not.toBeInTheDocument(); - expect(dialog).not.toBeInTheDocument(); - expect(closeButton).not.toBeInTheDocument(); - expect(cancelButton).not.toBeInTheDocument(); - expect(deleteButton).not.toBeInTheDocument(); - } - } - ); - - it('should call onClose when the DeletionDialog close button or Action cancel button is clicked', () => { - const { getByRole, getByTestId } = renderWithTheme( - - ); - - // For close icon button - const closeButton = getByRole('button', { name: 'Close' }); - expect(closeButton).not.toBeDisabled(); - fireEvent.click(closeButton); - - expect(defaultArgs.onClose).toHaveBeenCalled(); - - // For action cancel button - const cancelButton = getByTestId('cancel'); - expect(cancelButton).not.toBeDisabled(); - fireEvent.click(cancelButton); - - expect(defaultArgs.onClose).toHaveBeenCalled(); - }); - - it('should call onDelete when the DeletionDialog delete button is clicked', () => { - queryMocks.usePreferences.mockReturnValue({ - data: preference, - }); - const { getByTestId } = renderWithTheme( - - ); - - const deleteButton = getByTestId('confirm'); - expect(deleteButton).toBeDisabled(); - - const input = getByTestId('textfield-input'); - fireEvent.change(input, { target: { value: defaultArgs.label } }); - - expect(deleteButton).toBeEnabled(); - - fireEvent.click(deleteButton); - - expect(defaultArgs.onDelete).toHaveBeenCalled(); - }); - - it('should render a DeletionDialog with an error message if provided', () => { - const { getByText } = renderWithTheme( - - ); - - expect(getByText('Error that will be shown in the dialog.')).toBeVisible(); - }); - - it('should disable delete button and show loading icon if loading is true', () => { - const { getByTestId } = renderWithTheme( - - ); - - const deleteButton = getByTestId('confirm'); - expect(deleteButton).toBeInTheDocument(); - expect(deleteButton).toBeDisabled(); - - const loadingSvgIcon = deleteButton.querySelector('[role="progressbar"]'); - - expect(loadingSvgIcon).toBeInTheDocument(); - }); - - it('should display the correct warning text in the DeletionDialog', () => { - const { getByTestId } = renderWithTheme( - - ); - - const dialog = getByTestId('drawer'); - const warningText = `Warning: Deleting this ${defaultArgs.entity} is permanent and can\u2019t be undone.`; - - expect(dialog).toHaveTextContent(warningText); - }); - - it.each([ - ['not render', false], - ['render', true], - ])( - 'should %s input field with label when typeToConfirm is %s', - (_, typeToConfirm) => { - queryMocks.usePreferences.mockReturnValue({ - data: typeToConfirm, - }); - - const { queryByTestId } = renderWithTheme( - - ); - - if (typeToConfirm) { - expect(queryByTestId('inputLabelWrapper')).toBeInTheDocument(); - expect(queryByTestId('textfield-input')).toBeInTheDocument(); - } else { - expect(queryByTestId('inputLabelWrapper')).not.toBeInTheDocument(); - expect(queryByTestId('textfield-input')).not.toBeInTheDocument(); - } - } - ); -}); diff --git a/packages/manager/src/components/DeletionDialog/DeletionDialog.tsx b/packages/manager/src/components/DeletionDialog/DeletionDialog.tsx deleted file mode 100644 index 30717f9ab4c..00000000000 --- a/packages/manager/src/components/DeletionDialog/DeletionDialog.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { ActionsPanel, Notice, Typography } from '@linode/ui'; -import { capitalize } from '@linode/utilities'; -import { useTheme } from '@mui/material/styles'; -import * as React from 'react'; - -import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog'; -import { TypeToConfirm } from 'src/components/TypeToConfirm/TypeToConfirm'; -import { titlecase } from 'src/features/Linodes/presentation'; -import { usePreferences } from '@linode/queries'; - -import type { DialogProps } from '@linode/ui'; - -export interface DeletionDialogProps extends Omit { - entity: string; - error?: string; - label: string; - loading: boolean; - onClose: () => void; - onDelete: () => void; - open: boolean; -} - -/** - * @deprecated - * Use the ConfirmationDialog component instead. - */ -export const DeletionDialog = React.memo((props: DeletionDialogProps) => { - const theme = useTheme(); - const { entity, error, label, loading, onClose, onDelete, open, ...rest } = - props; - - const { data: typeToConfirmPreference } = usePreferences( - (preferences) => preferences?.type_to_confirm ?? true - ); - - const [confirmationText, setConfirmationText] = React.useState(''); - - const renderActions = () => ( - - ); - - React.useEffect(() => { - /** Reset confirmation text when the modal opens */ - if (open) { - setConfirmationText(''); - } - }, [open]); - - return ( - - - - Warning: Deleting this {entity} is permanent and - can’t be undone. - - - - To confirm deletion, type the name of the {entity} ( - {label}) in the field below: - - } - onChange={(input) => { - setConfirmationText(input); - }} - expand - label={`${capitalize(entity)} Name:`} - placeholder={label} - value={confirmationText} - visible={Boolean(typeToConfirmPreference)} - /> - - ); -}); diff --git a/packages/manager/src/components/DescriptionList/DescriptionList.styles.ts b/packages/manager/src/components/DescriptionList/DescriptionList.styles.ts index 83b3939ca91..9a602e3ff2d 100644 --- a/packages/manager/src/components/DescriptionList/DescriptionList.styles.ts +++ b/packages/manager/src/components/DescriptionList/DescriptionList.styles.ts @@ -1,6 +1,6 @@ -import { Typography, omittedProps } from '@linode/ui'; -import { styled } from '@mui/material/styles'; +import { omittedProps, Typography } from '@linode/ui'; import Grid from '@mui/material/Grid2'; +import { styled } from '@mui/material/styles'; import type { DescriptionListProps } from './DescriptionList'; import type { TypographyProps } from '@mui/material'; diff --git a/packages/manager/src/components/DescriptionList/DescriptionList.tsx b/packages/manager/src/components/DescriptionList/DescriptionList.tsx index 1a6e3da5f2d..1f25c1e9a23 100644 --- a/packages/manager/src/components/DescriptionList/DescriptionList.tsx +++ b/packages/manager/src/components/DescriptionList/DescriptionList.tsx @@ -74,8 +74,8 @@ interface DescriptionListGridProps * Only for the "grid" display mode. */ gridProps: { - columnSpacing?: number; columns: number; + columnSpacing?: number; }; } diff --git a/packages/manager/src/components/DocsLink/DocsLink.stories.tsx b/packages/manager/src/components/DocsLink/DocsLink.stories.tsx index e0e422795c6..4fc8d94f977 100644 --- a/packages/manager/src/components/DocsLink/DocsLink.stories.tsx +++ b/packages/manager/src/components/DocsLink/DocsLink.stories.tsx @@ -12,8 +12,7 @@ export const Default: StoryObj = { const meta: Meta = { argTypes: {}, args: { - href: - 'https://techdocs.akamai.com/cloud-computing/docs/faqs-for-compute-instances', + href: 'https://techdocs.akamai.com/cloud-computing/docs/faqs-for-compute-instances', label: 'Custom Doc Link Label', }, component: DocsLink, diff --git a/packages/manager/src/components/DocsLink/DocsLink.tsx b/packages/manager/src/components/DocsLink/DocsLink.tsx index cea62a0f49e..e6a6f417a15 100644 --- a/packages/manager/src/components/DocsLink/DocsLink.tsx +++ b/packages/manager/src/components/DocsLink/DocsLink.tsx @@ -10,6 +10,8 @@ export interface DocsLinkProps { analyticsLabel?: string; /** The URL to link to */ href: string; + /* */ + icon?: JSX.Element; /** * The clickable text of the link * @default Docs @@ -17,8 +19,6 @@ export interface DocsLinkProps { label?: string; /** A callback function when the link is clicked */ onClick?: () => void; - /* */ - icon?: JSX.Element; } /** @@ -31,6 +31,7 @@ export const DocsLink = (props: DocsLinkProps) => { return ( { if (onClick === undefined) { sendHelpButtonClickEvent(href, analyticsLabel); @@ -38,7 +39,6 @@ export const DocsLink = (props: DocsLinkProps) => { onClick(); } }} - className="docsButton" to={href} > {icon ?? } diff --git a/packages/manager/src/components/DocumentTitle/DocumentTitle.tsx b/packages/manager/src/components/DocumentTitle/DocumentTitle.tsx index 546d75b8186..a2165dab440 100644 --- a/packages/manager/src/components/DocumentTitle/DocumentTitle.tsx +++ b/packages/manager/src/components/DocumentTitle/DocumentTitle.tsx @@ -64,34 +64,34 @@ export const DocumentTitleSegment = (props: DocumentTitleSegmentProps) => { ); }; -export const withDocumentTitleProvider = ( - Component: React.ComponentType -) => (props: Props) => { - let titleSegments: string[] = []; - - const updateDocumentTitle = () => { - const newTitle = reverse(titleSegments).join(' | '); - document.title = newTitle; +export const withDocumentTitleProvider = + (Component: React.ComponentType) => + (props: Props) => { + let titleSegments: string[] = []; + + const updateDocumentTitle = () => { + const newTitle = reverse(titleSegments).join(' | '); + document.title = newTitle; + }; + + const appendSegment: DocumentTitleSegmentsContext['appendSegment'] = ( + segment: string + ) => { + titleSegments = [...titleSegments, segment]; + updateDocumentTitle(); + }; + + const removeSegment: DocumentTitleSegmentsContext['removeSegment'] = ( + segment: string + ) => { + const targetIdx = titleSegments.findIndex((el) => el === segment); + titleSegments.splice(targetIdx, 1); + updateDocumentTitle(); + }; + + return ( + + + + ); }; - - const appendSegment: DocumentTitleSegmentsContext['appendSegment'] = ( - segment: string - ) => { - titleSegments = [...titleSegments, segment]; - updateDocumentTitle(); - }; - - const removeSegment: DocumentTitleSegmentsContext['removeSegment'] = ( - segment: string - ) => { - const targetIdx = titleSegments.findIndex((el) => el === segment); - titleSegments.splice(targetIdx, 1); - updateDocumentTitle(); - }; - - return ( - - - - ); -}; diff --git a/packages/manager/src/components/DownloadTooltip.stories.tsx b/packages/manager/src/components/DownloadTooltip.stories.tsx index f4ee9429139..b5f1ffd09ab 100644 --- a/packages/manager/src/components/DownloadTooltip.stories.tsx +++ b/packages/manager/src/components/DownloadTooltip.stories.tsx @@ -1,8 +1,9 @@ -import { Meta, StoryObj } from '@storybook/react'; import React from 'react'; import { DownloadTooltip } from './DownloadTooltip'; +import type { Meta, StoryObj } from '@storybook/react'; + const meta: Meta = { component: DownloadTooltip, title: 'Components/Tooltip/Download Tooltip', diff --git a/packages/manager/src/components/EditableEntityLabel/EditableEntityLabel.tsx b/packages/manager/src/components/EditableEntityLabel/EditableEntityLabel.tsx index 13d33101bce..c669f1f7508 100644 --- a/packages/manager/src/components/EditableEntityLabel/EditableEntityLabel.tsx +++ b/packages/manager/src/components/EditableEntityLabel/EditableEntityLabel.tsx @@ -1,6 +1,6 @@ import { Typography } from '@linode/ui'; -import { styled, useTheme } from '@mui/material/styles'; import Grid from '@mui/material/Grid2'; +import { styled, useTheme } from '@mui/material/styles'; import * as React from 'react'; import { EntityIcon } from 'src/components/EntityIcon/EntityIcon'; @@ -50,21 +50,21 @@ export const EditableEntityLabel = (props: EditableEntityLabelProps) => { {!isEditing && iconVariant && ( diff --git a/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx b/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx index b36143aa9af..051fa0dbe0b 100644 --- a/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx +++ b/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx @@ -1,4 +1,4 @@ -import { Box, Button, TextField, Typography, fadeIn } from '@linode/ui'; +import { Box, Button, fadeIn, TextField, Typography } from '@linode/ui'; import Edit from '@mui/icons-material/Edit'; import { styled } from '@mui/material/styles'; diff --git a/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinks.tsx b/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinks.tsx index 95be51757e4..c236f71cdde 100644 --- a/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinks.tsx +++ b/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinks.tsx @@ -14,11 +14,11 @@ export const ResourceLinks = (props: ResourcesLinks) => { {links.map((linkData) => ( { getLinkOnClick(linkAnalyticsEvent, linkData.text); onClick?.(); }} - external={linkData.external} to={linkData.to} > {linkData.text} diff --git a/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinksSubSection.tsx b/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinksSubSection.tsx index 71fe15f3b76..010f0e16837 100644 --- a/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinksSubSection.tsx +++ b/packages/manager/src/components/EmptyLandingPageResources/ResourcesLinksSubSection.tsx @@ -3,10 +3,10 @@ import { styled } from '@mui/material/styles'; import * as React from 'react'; interface ResourcesLinksSubSectionProps { - MoreLink?: (props: { className?: any }) => JSX.Element; children?: JSX.Element | JSX.Element[]; external?: boolean; icon?: JSX.Element; + MoreLink?: (props: { className?: any }) => JSX.Element; title?: string; } diff --git a/packages/manager/src/components/EmptyLandingPageResources/ResourcesSection.tsx b/packages/manager/src/components/EmptyLandingPageResources/ResourcesSection.tsx index f7d72ddad85..5d5dd94df7a 100644 --- a/packages/manager/src/components/EmptyLandingPageResources/ResourcesSection.tsx +++ b/packages/manager/src/components/EmptyLandingPageResources/ResourcesSection.tsx @@ -17,9 +17,9 @@ import { } from 'src/utilities/emptyStateLandingUtils'; import type { + LinkAnalyticsEvent, ResourcesHeaders, ResourcesLinkSection, - LinkAnalyticsEvent, } from 'src/components/EmptyLandingPageResources/ResourcesLinksTypes'; interface ButtonProps { @@ -30,11 +30,6 @@ interface ButtonProps { } interface ResourcesSectionProps { - /** - * The custom resource to be rendered between docs and youtube links - * @example on linodes empty state landing - */ - CustomResource?: () => JSX.Element; /** * The additional copy to be rendered between primary button and resource links. */ @@ -43,6 +38,11 @@ interface ResourcesSectionProps { * The button's handlers and text */ buttonProps: ButtonProps[]; + /** + * The custom resource to be rendered between docs and youtube links + * @example on linodes empty state landing + */ + CustomResource?: () => JSX.Element; /** * Allow to set a custom max width for the description (better word wrapping) * */ @@ -115,9 +115,16 @@ export const ResourcesSection = (props: ResourcesSectionProps) => { return ( } MoreLink={(props) => ( { )} - icon={} title={gettingStartedGuidesData.title} > {GuideLinks(gettingStartedGuidesData, linkAnalyticsEvent)} {CustomResource && } } MoreLink={(props) => ( {youtubeMoreLinkText} )} - icon={} title={youtubeLinkData?.title || ''} > {youtubeLinkData && @@ -161,12 +167,6 @@ export const ResourcesSection = (props: ResourcesSectionProps) => { } - additionalCopy={additionalCopy} - buttonProps={buttonProps} - dataQAPlaceholder="resources-section" - descriptionMaxWidth={descriptionMaxWidth} - icon={icon} - isEntity showTransferDisplay={showTransferDisplay} subtitle={subtitle} title={title} diff --git a/packages/manager/src/components/Encryption/Encryption.tsx b/packages/manager/src/components/Encryption/Encryption.tsx index a8fa269c681..ef7a41c8d74 100644 --- a/packages/manager/src/components/Encryption/Encryption.tsx +++ b/packages/manager/src/components/Encryption/Encryption.tsx @@ -51,12 +51,12 @@ export const Encryption = (props: EncryptionProps) => { )} @@ -117,8 +117,8 @@ export const EnhancedNumberInput = React.memo( aria-label="Add 1" buttonType="outlined" data-testid={'increment-button'} - disableFocusRipple disabled={disabled || value === max} + disableFocusRipple name="Add 1" onClick={incrementValue} > diff --git a/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx b/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx index 4e64482c745..e630d1172a8 100644 --- a/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx +++ b/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx @@ -1,9 +1,9 @@ import { Box, Button } from '@linode/ui'; +import { Hidden } from '@linode/ui'; import { action } from '@storybook/addon-actions'; import React from 'react'; import { EntityHeader } from 'src/components/EntityHeader/EntityHeader'; -import { Hidden } from 'src/components/Hidden'; import { LinodeActionMenu } from 'src/features/Linodes/LinodesLanding/LinodeActionMenu/LinodeActionMenu'; import { Link } from '../Link'; @@ -58,6 +58,10 @@ export const Default: Story = { window: 'W0', }, }} + linodeId={12434} + linodeLabel="linode-001" + linodeRegion="us-east" + linodeStatus="running" linodeType={{ accelerated_devices: 0, addons: { @@ -96,10 +100,6 @@ export const Default: Story = { transfer: 2000, vcpus: 1, }} - linodeId={12434} - linodeLabel="linode-001" - linodeRegion="us-east" - linodeStatus="running" onOpenDeleteDialog={action('onOpenDeleteDialog')} onOpenMigrateDialog={action('onOpenMigrateDialog')} onOpenPowerDialog={action('onOpenPowerDialog')} diff --git a/packages/manager/src/components/EntityHeader/EntityHeader.test.tsx b/packages/manager/src/components/EntityHeader/EntityHeader.test.tsx index fb71431f560..e523d276d58 100644 --- a/packages/manager/src/components/EntityHeader/EntityHeader.test.tsx +++ b/packages/manager/src/components/EntityHeader/EntityHeader.test.tsx @@ -4,7 +4,7 @@ import { renderWithTheme } from 'src/utilities/testHelpers'; import { EntityHeader } from './EntityHeader'; -import { HeaderProps } from './EntityHeader'; +import type { HeaderProps } from './EntityHeader'; const mockText = 'Hello world'; @@ -15,7 +15,7 @@ const defaultProps: HeaderProps = { describe('EntityHeader', () => { it('should render title with variant when isSummaryView is True', () => { const { getByRole } = renderWithTheme( - + ); const heading = getByRole('heading', { level: 2 }); expect(heading).toBeInTheDocument(); diff --git a/packages/manager/src/components/EntityIcon/EntityIcon.stories.tsx b/packages/manager/src/components/EntityIcon/EntityIcon.stories.tsx index a70ef8e32fc..b66e56752a6 100644 --- a/packages/manager/src/components/EntityIcon/EntityIcon.stories.tsx +++ b/packages/manager/src/components/EntityIcon/EntityIcon.stories.tsx @@ -1,5 +1,5 @@ -import { styled } from '@mui/material/styles'; import Grid from '@mui/material/Grid2'; +import { styled } from '@mui/material/styles'; import React from 'react'; import { EntityIcon } from 'src/components/EntityIcon/EntityIcon'; @@ -43,7 +43,7 @@ export const Default: Story = { display: 'flex', }} > - + {args.variant} diff --git a/packages/manager/src/components/Flag.stories.tsx b/packages/manager/src/components/Flag.stories.tsx index 82676bdfb81..6687e02e3ba 100644 --- a/packages/manager/src/components/Flag.stories.tsx +++ b/packages/manager/src/components/Flag.stories.tsx @@ -1,8 +1,9 @@ -import { Meta, StoryObj } from '@storybook/react'; import React from 'react'; import { Flag } from './Flag'; +import type { Meta, StoryObj } from '@storybook/react'; + const meta: Meta = { component: Flag, title: 'Icons/Flag', diff --git a/packages/manager/src/components/GaugePercent/GaugePercent.test.tsx b/packages/manager/src/components/GaugePercent/GaugePercent.test.tsx index 4f0c63ac444..7ebe801a3ec 100644 --- a/packages/manager/src/components/GaugePercent/GaugePercent.test.tsx +++ b/packages/manager/src/components/GaugePercent/GaugePercent.test.tsx @@ -2,7 +2,9 @@ import React from 'react'; import { renderWithTheme } from 'src/utilities/testHelpers'; -import { GaugePercent, GaugePercentProps } from './GaugePercent'; +import { GaugePercent } from './GaugePercent'; + +import type { GaugePercentProps } from './GaugePercent'; describe('GaugePercent Component', () => { const defaultProps: GaugePercentProps = { diff --git a/packages/manager/src/components/GaugePercent/GaugePercent.tsx b/packages/manager/src/components/GaugePercent/GaugePercent.tsx index 449e4845aa2..5d528d14f5a 100644 --- a/packages/manager/src/components/GaugePercent/GaugePercent.tsx +++ b/packages/manager/src/components/GaugePercent/GaugePercent.tsx @@ -64,8 +64,8 @@ export const GaugePercent = React.memo((props: GaugePercentProps) => { props.max === 0 && props.value === 0 ? 1 // if they're both actually 0, make sure we have a full grey gauge : props.max - props.value < 0 - ? 0 - : props.max - props.value; + ? 0 + : props.max - props.value; const graphDatasets = [ { diff --git a/packages/manager/src/components/GenerateFirewallDialog/GenerateFirewallDialog.test.tsx b/packages/manager/src/components/GenerateFirewallDialog/GenerateFirewallDialog.test.tsx index 93a0464762f..5ae5b4cc69e 100644 --- a/packages/manager/src/components/GenerateFirewallDialog/GenerateFirewallDialog.test.tsx +++ b/packages/manager/src/components/GenerateFirewallDialog/GenerateFirewallDialog.test.tsx @@ -7,7 +7,7 @@ import { firewallTemplateFactory, } from 'src/factories'; import { makeResourcePage } from 'src/mocks/serverHandlers'; -import { HttpResponse, http, server } from 'src/mocks/testServer'; +import { http, HttpResponse, server } from 'src/mocks/testServer'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { GenerateFirewallDialog } from './GenerateFirewallDialog'; diff --git a/packages/manager/src/components/GroupByTagToggle.tsx b/packages/manager/src/components/GroupByTagToggle.tsx index ba1f9ad3fc0..cbdb5190dd8 100644 --- a/packages/manager/src/components/GroupByTagToggle.tsx +++ b/packages/manager/src/components/GroupByTagToggle.tsx @@ -27,17 +27,17 @@ export const GroupByTagToggle = React.memo((props: GroupByTagToggleProps) => { title={`${isGroupedByTag ? 'Ungroup' : 'Group'} by tag`} > diff --git a/packages/manager/src/components/Hidden.ts b/packages/manager/src/components/Hidden.ts deleted file mode 100644 index 4128966ed89..00000000000 --- a/packages/manager/src/components/Hidden.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as Hidden } from '@mui/material/Hidden'; -export type { HiddenProps } from '@mui/material/Hidden'; diff --git a/packages/manager/src/components/IPSelect/IPSelect.tsx b/packages/manager/src/components/IPSelect/IPSelect.tsx index 8c712690d1b..cb74f88f0a6 100644 --- a/packages/manager/src/components/IPSelect/IPSelect.tsx +++ b/packages/manager/src/components/IPSelect/IPSelect.tsx @@ -1,8 +1,7 @@ +import { useLinodeQuery } from '@linode/queries'; import { Autocomplete } from '@linode/ui'; import * as React from 'react'; -import { useLinodeQuery } from '@linode/queries'; - interface Option { label: string; value: string; diff --git a/packages/manager/src/components/IconTextLink/IconTextLink.tsx b/packages/manager/src/components/IconTextLink/IconTextLink.tsx index 2cd7b0f3079..172973a21c6 100644 --- a/packages/manager/src/components/IconTextLink/IconTextLink.tsx +++ b/packages/manager/src/components/IconTextLink/IconTextLink.tsx @@ -39,12 +39,12 @@ const useStyles = makeStyles()((theme: Theme) => ({ })); export interface Props { - SideIcon: React.ComponentClass | typeof SvgIcon; active?: boolean; children?: string; className?: string; disabled?: boolean; onClick?: () => void; + SideIcon: React.ComponentClass | typeof SvgIcon; text: string; title: string; to?: string; @@ -52,16 +52,8 @@ export interface Props { export const IconTextLink = (props: Props) => { const { classes, cx } = useStyles(); - const { - SideIcon, - active, - className, - disabled, - onClick, - text, - title, - to, - } = props; + const { SideIcon, active, className, disabled, onClick, text, title, to } = + props; const LinkButton = ( } + entityError={stackscriptError} error={error?.[0].reason} isFetching={isFetching} onClose={onClose} diff --git a/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptRow.tsx b/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptRow.tsx index 17ceda1a2e1..74842021c02 100644 --- a/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptRow.tsx +++ b/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptRow.tsx @@ -1,8 +1,8 @@ import { Stack, Typography } from '@linode/ui'; +import { Hidden } from '@linode/ui'; import React from 'react'; import { DateTimeDisplay } from 'src/components/DateTimeDisplay'; -import { Hidden } from 'src/components/Hidden'; import { Link } from 'src/components/Link'; import { TableCell } from 'src/components/TableCell'; import { TableRow } from 'src/components/TableRow'; @@ -24,19 +24,25 @@ export const StackScriptRow = (props: Props) => { return ( - + - - - {stackscript.username} / {stackscript.label} - - + + {stackscript.username} / {stackscript.label} + ({ color: theme.textColors.tableHeader, fontSize: '.75rem', overflow: 'hidden', textOverflow: 'ellipsis', + whiteSpace: 'nowrap', })} > {stackscript.description} diff --git a/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptsLanding.tsx b/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptsLanding.tsx index 0ee8229e3f8..2ae5da2061b 100644 --- a/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptsLanding.tsx +++ b/packages/manager/src/features/StackScripts/StackScriptLanding/StackScriptsLanding.tsx @@ -43,13 +43,14 @@ export const StackScriptsLanding = () => { resourceType: 'StackScripts', }), }} - onButtonClick={() => { - navigate({ to: '/stackscripts/create' }); - }} disabledCreateButton={isStackScriptCreationRestricted} docsLink="https://techdocs.akamai.com/cloud-computing/docs/stackscripts" entity="StackScript" + onButtonClick={() => { + navigate({ to: '/stackscripts/create' }); + }} removeCrumbX={1} + spacingBottom={4} title="StackScripts" /> diff --git a/packages/manager/src/features/StackScripts/StackScriptsDetail.tsx b/packages/manager/src/features/StackScripts/StackScriptsDetail.tsx index 2a7c6fa9497..9afeb851298 100644 --- a/packages/manager/src/features/StackScripts/StackScriptsDetail.tsx +++ b/packages/manager/src/features/StackScripts/StackScriptsDetail.tsx @@ -4,6 +4,7 @@ import { } from '@linode/queries'; import { useGrants, useProfile } from '@linode/queries'; import { CircleProgress, ErrorState, Paper } from '@linode/ui'; +import { NotFound } from '@linode/ui'; import { useParams } from '@tanstack/react-router'; import React from 'react'; // eslint-disable-next-line no-restricted-imports @@ -11,7 +12,6 @@ import { useHistory } from 'react-router-dom'; import { DocumentTitleSegment } from 'src/components/DocumentTitle'; import { LandingHeader } from 'src/components/LandingHeader'; -import { NotFound } from 'src/components/NotFound'; import { StackScript } from 'src/components/StackScript/StackScript'; import { getRestrictedResourceText } from '../Account/utils'; diff --git a/packages/manager/src/features/StackScripts/stackScriptUtils.ts b/packages/manager/src/features/StackScripts/stackScriptUtils.ts index 318554b03ab..637de3cf9b3 100644 --- a/packages/manager/src/features/StackScripts/stackScriptUtils.ts +++ b/packages/manager/src/features/StackScripts/stackScriptUtils.ts @@ -8,17 +8,17 @@ export const getStackScriptUrl = ( let type; let subtype; switch (username) { - case 'linode': - // This is a Marketplace App - type = 'One-Click'; - subtype = 'One-Click%20Apps'; - break; case currentUser: // My StackScripts // @todo: handle account stackscripts type = 'StackScripts'; subtype = 'Account'; break; + case 'linode': + // This is a Marketplace App + type = 'One-Click'; + subtype = 'One-Click%20Apps'; + break; default: // Community StackScripts type = 'StackScripts'; diff --git a/packages/manager/src/features/Support/AttachFileForm.tsx b/packages/manager/src/features/Support/AttachFileForm.tsx index 4b909b54c69..fd6028a9f5b 100644 --- a/packages/manager/src/features/Support/AttachFileForm.tsx +++ b/packages/manager/src/features/Support/AttachFileForm.tsx @@ -60,14 +60,14 @@ export const AttachFileForm = (props: Props) => { type="file" /> { return ( diff --git a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.stories.tsx b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.stories.tsx index 368c1244615..2352b260bdf 100644 --- a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.stories.tsx +++ b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.stories.tsx @@ -15,7 +15,6 @@ const meta: Meta = { component: NotificationMenu, decorators: [ (Story: StoryFn) => { - // eslint-disable-next-line react-hooks/rules-of-hooks const contextValue = useNotificationContext(); const NotificationProvider = _notificationContext.Provider; return ( diff --git a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx index 99705772617..3f9a2e9911b 100644 --- a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx +++ b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx @@ -1,5 +1,5 @@ import { useNotificationsQuery } from '@linode/queries'; -import { Box, Chip, Divider, Typography, rotate360 } from '@linode/ui'; +import { Box, Chip, Divider, rotate360, Typography } from '@linode/ui'; import { usePrevious } from '@linode/utilities'; import AutorenewIcon from '@mui/icons-material/Autorenew'; import { IconButton } from '@mui/material'; @@ -24,7 +24,7 @@ import { useMarkEventsAsSeen, } from 'src/queries/events/events'; -import { TopMenuTooltip, topMenuIconButtonSx } from '../TopMenuTooltip'; +import { topMenuIconButtonSx, TopMenuTooltip } from '../TopMenuTooltip'; export const NotificationMenu = () => { const history = useHistory(); @@ -86,12 +86,6 @@ export const NotificationMenu = () => { <> ({ - ...topMenuIconButtonSx(theme), - color: notificationContext.menuOpen - ? theme.tokens.component.GlobalHeader.Icon.Active - : theme.tokens.component.GlobalHeader.Icon.Default, - })} aria-describedby={id} aria-haspopup="true" aria-label="Notifications" @@ -99,6 +93,12 @@ export const NotificationMenu = () => { id={menuButtonId} onClick={handleNotificationMenuToggle} ref={anchorRef} + sx={(theme) => ({ + ...topMenuIconButtonSx(theme), + color: notificationContext.menuOpen + ? theme.tokens.component.GlobalHeader.Icon.Active + : theme.tokens.component.GlobalHeader.Icon.Default, + })} > {numNotifications > 0 && ( @@ -106,13 +106,13 @@ export const NotificationMenu = () => { adjustBorderRadius={ numNotifications > 9 || showInProgressEventIcon } + color="error" + data-testid="events-count-notification" icon={ - Boolean(showInProgressEventIcon) ? ( + showInProgressEventIcon ? ( ) : undefined } - color="error" - data-testid="events-count-notification" label={numNotifications > 9 ? '9+' : numNotifications} size="small" /> @@ -120,10 +120,15 @@ export const NotificationMenu = () => { ({ @@ -138,11 +143,6 @@ export const NotificationMenu = () => { }), }, }} - anchorEl={anchorRef.current} - data-qa-notification-menu - id={id} - onClose={handleClose} - open={notificationContext.menuOpen} > diff --git a/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx b/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx index 275f585f3a5..9054d716b44 100644 --- a/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx +++ b/packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx @@ -47,7 +47,7 @@ export const SearchBar = () => { }); // MUI Autocomplete state - const [value, setValue] = React.useState(null); + const [value, setValue] = React.useState(null); const [searchActive, setSearchActive] = React.useState(false); const [menuOpen, setMenuOpen] = React.useState(false); @@ -185,24 +185,45 @@ export const SearchBar = () => { Main search + autoHighlight + data-qa-main-search + disableClearable filterOptions={(options) => { /* Need to override the default RS filtering; otherwise entities whose label * doesn't match the search term will be automatically filtered, meaning that * searching by tag won't work. */ return options; }} + inputValue={searchText} + keepSearchEnabledOnMobile + label={label} + loading={isLoading} + multiple={false} + noOptionsText="No results" + onBlur={handleBlur} onChange={(_, value) => { if (value) { onSelect(value); } }} + onClose={handleClose} + onFocus={handleFocus} + onKeyDown={handleKeyDown} + onOpen={handleOpen} + open={menuOpen && searchText !== ''} + options={options} + placeholder={label} + popupIcon={null} renderInput={(params) => { return ( { handleSearchChange(e.target.value); }} + placeholder={label} slotProps={{ htmlInput: { ...params.inputProps, @@ -219,6 +240,10 @@ export const SearchBar = () => { endAdornment: ( svg': { '&:hover': { @@ -235,10 +260,6 @@ export const SearchBar = () => { display: 'none', }, }} - aria-label="close menu" - color="inherit" - onClick={toggleSearch} - size="large" > @@ -286,9 +307,6 @@ export const SearchBar = () => { paddingRight: theme.tokens.spacing.S8, }, }} - hideLabel - label={label} - placeholder={label} /> ); }} @@ -300,13 +318,13 @@ export const SearchBar = () => { return ( ({ '&.MuiButtonBase-root.MuiMenuItem-root': { padding: `${theme.spacing(1)} !important`, }, font: theme.font.bold, })} - key={`${key}-${value}`} > {option.icon && ( { sx={{ maxWidth: '100%', }} - autoHighlight - data-qa-main-search - disableClearable - inputValue={searchText} - keepSearchEnabledOnMobile - label={label} - loading={isLoading} - multiple={false} - noOptionsText="No results" - onBlur={handleBlur} - onClose={handleClose} - onFocus={handleFocus} - onKeyDown={handleKeyDown} - onOpen={handleOpen} - open={menuOpen && searchText !== ''} - options={options} - placeholder={label} - popupIcon={null} value={value} /> diff --git a/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx b/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx index 28b52c2f174..b9b1ac07a20 100644 --- a/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx +++ b/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx @@ -2,6 +2,8 @@ import { Box, Chip, SvgIcon } from '@linode/ui'; import * as React from 'react'; import { useHistory } from 'react-router-dom'; +import { searchableEntityIconMap } from 'src/features/Search/utils'; + import { StyledSearchSuggestion, StyledSegment, @@ -12,7 +14,6 @@ import { } from './SearchSuggestion.styles'; import type { SearchableItem } from 'src/features/Search/search.interfaces'; -import { searchableEntityIconMap } from 'src/features/Search/utils'; export interface SearchSuggestionProps { data: SearchableItem; diff --git a/packages/manager/src/features/TopMenu/TopMenu.tsx b/packages/manager/src/features/TopMenu/TopMenu.tsx index 19fcaa0eb9c..c810d1d3db3 100644 --- a/packages/manager/src/features/TopMenu/TopMenu.tsx +++ b/packages/manager/src/features/TopMenu/TopMenu.tsx @@ -53,19 +53,23 @@ export const TopMenu = React.memo((props: TopMenuProps) => { {isNarrowViewport && ( ({ - padding: theme.tokens.spacing.S16, - })} aria-label="open menu" color="inherit" disableRipple onClick={openSideMenu} + sx={(theme) => ({ + padding: theme.tokens.spacing.S16, + })} > )} ({ md: theme.tokens.spacing.S32, xs: theme.tokens.spacing.S12, @@ -76,10 +80,6 @@ export const TopMenu = React.memo((props: TopMenuProps) => { sm: theme.tokens.spacing.S16, }, })} - alignItems="center" - display="flex" - flexGrow={1} - flexShrink={0} > {!isNarrowViewport && ( { ({ gap: { sm: theme.tokens.spacing.S24, @@ -119,18 +122,15 @@ export const TopMenu = React.memo((props: TopMenuProps) => { xs: theme.tokens.spacing.S8, }, })} - alignItems="center" - direction="row" - justifyContent="flex-end" > {!isSmallScreen && } diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx index 67b5b1c47d8..8a1ec8a9831 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx +++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx @@ -3,10 +3,10 @@ import { Button, ChevronDownIcon, ChevronUpIcon, + omittedProps, Stack, Tooltip, Typography, - omittedProps, } from '@linode/ui'; import { truncateEnd } from '@linode/utilities'; import { styled, useMediaQuery } from '@mui/material'; diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenuPopover.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenuPopover.tsx index 5dd9b19b4fb..74ae06e3558 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/UserMenuPopover.tsx +++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenuPopover.tsx @@ -128,12 +128,12 @@ export const UserMenuPopover = (props: UserMenuPopoverProps) => { return ( {link.display} @@ -154,10 +154,16 @@ export const UserMenuPopover = (props: UserMenuPopoverProps) => { return ( ({ @@ -167,12 +173,6 @@ export const UserMenuPopover = (props: UserMenuPopoverProps) => { }), }, }} - anchorEl={anchorEl} - data-testid={id} - id={id} - marginThreshold={0} - onClose={onClose} - open={open} // When the Switch Account drawer is open, hide the user menu popover so it's not covering the drawer. sx={{ zIndex: isDrawerOpen ? 0 : 1 }} > @@ -204,12 +204,12 @@ export const UserMenuPopover = (props: UserMenuPopoverProps) => { {canSwitchBetweenParentOrProxyAccount && ( { sendSwitchAccountEvent('User Menu'); handleAccountSwitch(); }} - buttonType="outlined" - data-testid="switch-account-button" /> )} @@ -236,13 +236,13 @@ export const UserMenuPopover = (props: UserMenuPopoverProps) => { {accountLinks.map((menuLink) => menuLink.hide ? null : ( {menuLink.display} diff --git a/packages/manager/src/features/TopMenu/UserMenu/utils.ts b/packages/manager/src/features/TopMenu/UserMenu/utils.ts index d63d4b3307f..36bd8606ae3 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/utils.ts +++ b/packages/manager/src/features/TopMenu/UserMenu/utils.ts @@ -1,4 +1,4 @@ -import { Profile } from '@linode/api-v4'; +import type { Profile } from '@linode/api-v4'; export interface CompanyNameOrEmailOptions { company: string | undefined; diff --git a/packages/manager/src/features/Users/CreateUserDrawer.tsx b/packages/manager/src/features/Users/CreateUserDrawer.tsx index f1c40048a83..9772b33fcc1 100644 --- a/packages/manager/src/features/Users/CreateUserDrawer.tsx +++ b/packages/manager/src/features/Users/CreateUserDrawer.tsx @@ -9,14 +9,13 @@ import { } from '@linode/ui'; import * as React from 'react'; import { withRouter } from 'react-router-dom'; +import type { RouteComponentProps } from 'react-router-dom'; -import { NotFound } from 'src/components/NotFound'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import { getAPIErrorFor } from 'src/utilities/getAPIErrorFor'; import type { User } from '@linode/api-v4/lib/account'; import type { APIError } from '@linode/api-v4/lib/types'; -import type { RouteComponentProps } from 'react-router-dom'; interface Props { onClose: () => void; @@ -35,6 +34,26 @@ interface State { interface CreateUserDrawerProps extends Props, RouteComponentProps<{}> {} class CreateUserDrawer extends React.Component { + state: State = { + email: '', + errors: [], + restricted: false, + submitting: false, + username: '', + }; + + componentDidUpdate(prevProps: CreateUserDrawerProps) { + if (this.props.open === true && prevProps.open === false) { + this.setState({ + email: '', + errors: [], + restricted: false, + submitting: false, + username: '', + }); + } + } + handleChangeEmail = (e: React.ChangeEvent) => { this.setState({ email: e.target.value, @@ -85,26 +104,6 @@ class CreateUserDrawer extends React.Component { }); }; - state: State = { - email: '', - errors: [], - restricted: false, - submitting: false, - username: '', - }; - - componentDidUpdate(prevProps: CreateUserDrawerProps) { - if (this.props.open === true && prevProps.open === false) { - this.setState({ - email: '', - errors: [], - restricted: false, - submitting: false, - username: '', - }); - } - } - render() { const { onClose, open } = this.props; const { email, errors, restricted, submitting, username } = this.state; @@ -116,12 +115,7 @@ class CreateUserDrawer extends React.Component { const generalError = hasErrorFor('none'); return ( - + {generalError && } void; diff --git a/packages/manager/src/features/Users/UserDetail.tsx b/packages/manager/src/features/Users/UserDetail.tsx index df24bcb970c..0e5e65a3cf3 100644 --- a/packages/manager/src/features/Users/UserDetail.tsx +++ b/packages/manager/src/features/Users/UserDetail.tsx @@ -1,3 +1,4 @@ +import { useAccountUser, useProfile } from '@linode/queries'; import { CircleProgress, ErrorState } from '@linode/ui'; import { useQueryClient } from '@tanstack/react-query'; import { createLazyRoute } from '@tanstack/react-router'; @@ -9,7 +10,6 @@ import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { TabLinkList } from 'src/components/Tabs/TabLinkList'; import { TabPanels } from 'src/components/Tabs/TabPanels'; import { Tabs } from 'src/components/Tabs/Tabs'; -import { useAccountUser, useProfile } from '@linode/queries'; import UserPermissions from './UserPermissions'; import { UserProfile } from './UserProfile/UserProfile'; diff --git a/packages/manager/src/features/Users/UserPermissions.styles.ts b/packages/manager/src/features/Users/UserPermissions.styles.ts index 56c54766ab3..2df58b8f27f 100644 --- a/packages/manager/src/features/Users/UserPermissions.styles.ts +++ b/packages/manager/src/features/Users/UserPermissions.styles.ts @@ -1,6 +1,6 @@ import { CircleProgress, Paper } from '@linode/ui'; -import { styled } from '@mui/material/styles'; import Grid from '@mui/material/Grid2'; +import { styled } from '@mui/material/styles'; export const StyledDivWrapper = styled('div', { label: 'StyledDivWrapper', diff --git a/packages/manager/src/features/Users/UserPermissions.tsx b/packages/manager/src/features/Users/UserPermissions.tsx index 29e8077879e..f96db5d4ec4 100644 --- a/packages/manager/src/features/Users/UserPermissions.tsx +++ b/packages/manager/src/features/Users/UserPermissions.tsx @@ -31,7 +31,7 @@ import { TabPanels } from 'src/components/Tabs/TabPanels'; import { Tabs } from 'src/components/Tabs/Tabs'; import { withFeatureFlags } from 'src/containers/flags.container'; import { withQueryClient } from 'src/containers/withQueryClient.container'; -import { PARENT_USER, grantTypeMap } from 'src/features/Account/constants'; +import { grantTypeMap, PARENT_USER } from 'src/features/Account/constants'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import { getAPIErrorFor } from 'src/utilities/getAPIErrorFor'; @@ -50,8 +50,8 @@ import type { GlobalGrantTypes, Grant, GrantLevel, - GrantType, Grants, + GrantType, User, } from '@linode/api-v4/lib/account'; import type { APIError } from '@linode/api-v4/lib/types'; @@ -91,6 +91,47 @@ interface State { type CombinedProps = Props & WithQueryClientProps & WithFeatureFlagProps; class UserPermissions extends React.Component { + entityPerms: GrantType[] = [ + 'linode', + 'firewall', + 'stackscript', + 'image', + 'volume', + 'lkecluster', + 'nodebalancer', + 'domain', + 'longview', + 'database', + 'vpc', + ]; + + formContainerRef = React.createRef(); + + globalBooleanPerms: GlobalGrantTypes[] = [ + 'add_databases', + 'add_domains', + 'add_firewalls', + 'add_images', + 'add_linodes', + 'add_longview', + 'add_lkes', + 'add_nodebalancers', + 'add_stackscripts', + 'add_volumes', + 'add_vpcs', + 'cancel_account', + 'longview_subscription', + ]; + + state: State = { + isSavingEntity: false, + isSavingGlobal: false, + loading: true, + loadingGrants: false, + setAllPerm: 'null', + userType: null, + }; + billingPermOnClick = (value: null | string) => () => { const lp = lensPath(['grants', 'global', 'account_access']); this.setState(set(lp, value)); @@ -120,6 +161,18 @@ class UserPermissions extends React.Component { } }; + componentDidMount() { + this.getUserGrants(); + this.getUserType(); + } + + componentDidUpdate(prevProps: CombinedProps) { + if (prevProps.currentUsername !== this.props.currentUsername) { + this.getUserGrants(); + this.getUserType(); + } + } + entityIsAll = (entity: GrantType, value: GrantLevel): boolean => { const { grants } = this.state; if (!(grants && grants[entity])) { @@ -130,19 +183,6 @@ class UserPermissions extends React.Component { }, true); }; - entityPerms: GrantType[] = [ - 'linode', - 'firewall', - 'stackscript', - 'image', - 'volume', - 'nodebalancer', - 'domain', - 'longview', - 'database', - 'vpc', - ]; - entitySetAllTo = (entity: GrantType, value: GrantLevel) => () => { const { grants } = this.state; if (!(grants && grants[entity])) { @@ -159,8 +199,6 @@ class UserPermissions extends React.Component { } }; - formContainerRef = React.createRef(); - getTabInformation = (grants: Grants) => this.entityPerms.reduce( (acc: TabInfo, entity: GrantType) => { @@ -237,27 +275,11 @@ class UserPermissions extends React.Component { } }; - globalBooleanPerms: GlobalGrantTypes[] = [ - 'add_databases', - 'add_domains', - 'add_firewalls', - 'add_images', - 'add_linodes', - 'add_longview', - 'add_nodebalancers', - 'add_stackscripts', - 'add_volumes', - 'add_vpcs', - 'cancel_account', - 'longview_subscription', - ]; - - globalPermOnChange = (perm: string) => ( - e: React.ChangeEvent - ) => { - const lp = lensPath(['grants', 'global', perm]); - this.setState(set(lp, e.target.checked)); - }; + globalPermOnChange = + (perm: string) => (e: React.ChangeEvent) => { + const lp = lensPath(['grants', 'global', perm]); + this.setState(set(lp, e.target.checked)); + }; onChangeRestricted = () => { const { currentUsername } = this.props; @@ -298,6 +320,18 @@ class UserPermissions extends React.Component { } }; + render() { + const { loading } = this.state; + const { currentUsername } = this.props; + + return ( +
+ + {loading ? : this.renderBody()} +
+ ); + } + renderActions = ( onConfirm: () => void, onCancel: () => void, @@ -305,6 +339,9 @@ class UserPermissions extends React.Component { ) => { return ( { marginTop: theme.spacing(2), paddingBottom: 0, })} - alignItems="center" - display="flex" - justifyContent="flex-end" /> ); }; @@ -339,12 +373,12 @@ class UserPermissions extends React.Component { return ( ({ marginTop: theme.spacing(2), paddingBottom: 0, })} - container - spacing={2} > @@ -353,12 +387,12 @@ class UserPermissions extends React.Component { ({ marginTop: theme.spacing(2), paddingBottom: 0, })} - container - spacing={2} > { checked={ grants.global.account_access === 'read_write' && !isChildUser } - subheadings={[ - 'Can make payments, update contact and billing info, and will receive copies of all invoices and payment emails.', - ]} data-qa-billing-access="Read-Write" disabled={isChildUser} heading="Read-Write" onClick={this.billingPermOnClick('read_write')} + subheadings={[ + 'Can make payments, update contact and billing info, and will receive copies of all invoices and payment emails.', + ]} /> @@ -410,20 +444,20 @@ class UserPermissions extends React.Component { )} {isProxyUser ? PARENT_USER : 'General'} Permissions @@ -433,19 +467,22 @@ class UserPermissions extends React.Component { } + data-qa="toggle-full-account-access" + label="Full Account Access" + labelPlacement="end" slotProps={{ typography: { sx: (theme) => ({ @@ -454,9 +491,6 @@ class UserPermissions extends React.Component { }), }, }} - data-qa="toggle-full-account-access" - label="Full Account Access" - labelPlacement="end" value={restricted} /> @@ -474,6 +508,7 @@ class UserPermissions extends React.Component { add_firewalls: 'Can add Firewalls to this account', add_images: 'Can create frozen Images under this account ($)', add_linodes: 'Can add Linodes to this account ($)', + add_lkes: 'Can add Kubernetes Clusters to this account ($)', add_longview: 'Can add Longview clients to this account', add_nodebalancers: 'Can add NodeBalancers to this account ($)', add_stackscripts: 'Can create StackScripts under this account', @@ -491,12 +526,12 @@ class UserPermissions extends React.Component { return ( { onChange={this.globalPermOnChange(perm)} /> } + label={permDescriptionMap[perm]} sx={(theme) => ({ padding: `${theme.spacing(1)} 0`, })} - label={permDescriptionMap[perm]} /> ); @@ -534,12 +569,12 @@ class UserPermissions extends React.Component { '$' symbol may incur additional charges. ({ marginTop: theme.spacing(2), paddingBottom: 0, })} - container - spacing={2} > {grants && grants.global && @@ -593,17 +628,17 @@ class UserPermissions extends React.Component { return ( ({ marginTop: theme.spacing(2), })} - data-qa-entity-section > { + option.value === value.value && option.label === value.label } + label="My Select" + onChange={onChange} + options={options} value={{ label: options[0].label, value: options[0].value, }} - clearable - label="My Select" - onChange={onChange} - options={options} - /> + />, ); const select = getByRole('combobox'); expect(select).toHaveValue(options[0].label); const clearButton = container.querySelector( - '.MuiAutocomplete-clearIndicator' + '.MuiAutocomplete-clearIndicator', ); expect(clearButton).toBeInTheDocument(); await userEvent.click(clearButton!); @@ -84,37 +84,37 @@ describe('Select', () => { it('features helper text', () => { const { getByText } = renderWithTheme( - , ); expect(getByText('Helper text')).toBeInTheDocument(); }); it('features error text', () => { const { getByText } = renderWithTheme( - , ); expect(getByText('Error text')).toBeInTheDocument(); }); it('features loading state', () => { const { getByRole } = renderWithTheme( - , ); expect( - getByRole('progressbar', { name: 'Content is loading' }) + getByRole('progressbar', { name: 'Content is loading' }), ).toBeInTheDocument(); }); it('features a required state', () => { const { getByText } = renderWithTheme( - , ); expect(getByText('(required)')).toBeInTheDocument(); }); it('features a searchable state', () => { const { getByRole } = renderWithTheme( - , ); const select = getByRole('combobox'); expect(select).not.toHaveAttribute('readOnly'); diff --git a/packages/ui/src/components/Select/Select.tsx b/packages/ui/src/components/Select/Select.tsx index 3f340788202..c81c9aa472c 100644 --- a/packages/ui/src/components/Select/Select.tsx +++ b/packages/ui/src/components/Select/Select.tsx @@ -97,7 +97,7 @@ export interface SelectProps * The props for the ListItem component. */ listItemProps?: (value: T) => { - dataAttributes?: Record; + dataAttributes?: Record; }; /** * The callback function that is invoked when the value changes. @@ -153,7 +153,7 @@ export const Select = ( const handleChange = ( event: React.SyntheticEvent, - value: SelectOption | null | string, + value: null | SelectOption | string, ) => { if (creatable && typeof value === 'string') { onChange?.(event, { @@ -179,18 +179,32 @@ export const Select = ( return ( {...rest} + disableClearable={!clearable} + forcePopupIcon + freeSolo={creatable} + getOptionDisabled={(option: SelectOption) => option.value === ''} isOptionEqualToValue={(option, value) => { if (!option || !value) { return false; } return option.value === value.value; }} + keepSearchEnabledOnMobile={keepSearchEnabledOnMobile} + label={label} + noOptionsText={noOptionsText} + onChange={handleChange} + onInputChange={(_, value) => setInputValue(value)} + options={_options} renderInput={(params) => ( ( readOnly: !creatable && !searchable, sx: { cursor: creatable || searchable ? 'text' : 'pointer' }, }} - errorText={props.errorText} - helperText={props.helperText} - hideLabel={hideLabel} - inputId={params.id} label={label} placeholder={props.placeholder} required={props.required} @@ -231,6 +241,7 @@ export const Select = ( {...(option.create || option.noOptions ? undefined : listItemProps?.(option as T)?.dataAttributes)} + key={option.create ? `create-${option.value}` : key} sx={ option.noOptions ? { @@ -238,7 +249,6 @@ export const Select = ( } : null } - key={option.create ? `create-${option.value}` : key} > {option.create ? ( <> @@ -250,6 +260,7 @@ export const Select = ( ); }} + selectOnFocus={false} sx={{ ...sx, ...(!creatable && !searchable @@ -262,17 +273,6 @@ export const Select = ( } : null), }} - disableClearable={!clearable} - forcePopupIcon - freeSolo={creatable} - getOptionDisabled={(option: SelectOption) => option.value === ''} - keepSearchEnabledOnMobile={keepSearchEnabledOnMobile} - label={label} - noOptionsText={noOptionsText} - onChange={handleChange} - onInputChange={(_, value) => setInputValue(value)} - options={_options} - selectOnFocus={false} /> ); }; diff --git a/packages/ui/src/components/TextField/TextField.test.tsx b/packages/ui/src/components/TextField/TextField.test.tsx index 57cfe760045..171b8c86e6d 100644 --- a/packages/ui/src/components/TextField/TextField.test.tsx +++ b/packages/ui/src/components/TextField/TextField.test.tsx @@ -14,7 +14,7 @@ describe('TextField', () => { it('Renders a TextField with the given label and initial value', () => { const { getByDisplayValue, getByText } = renderWithTheme( - + , ); expect(getByText('Username')).toBeInTheDocument(); expect(getByDisplayValue('jane-doe')).toBeInTheDocument(); @@ -22,7 +22,7 @@ describe('TextField', () => { it('Trims leading and trailing whitespace from a TextField with a trimmed prop', async () => { const { getByDisplayValue, getByLabelText } = renderWithTheme( - + , ); const input = getByLabelText('Username'); @@ -33,13 +33,13 @@ describe('TextField', () => { expect( getByDisplayValue('test', { normalizer: getDefaultNormalizer({ trim: false }), // Prevent default trim by DOM Testing Library - }) + }), ).toBeInTheDocument(); }); it('Does not trim leading and trailing whitespace from a TextField without "trimmed" prop', async () => { const { getByDisplayValue, getByLabelText } = renderWithTheme( - + , ); const input = getByLabelText('Username'); @@ -50,13 +50,13 @@ describe('TextField', () => { expect( getByDisplayValue(' test ', { normalizer: getDefaultNormalizer({ trim: false }), - }) + }), ).toBeInTheDocument(); }); it('Renders an error message on error', async () => { const { getByText } = renderWithTheme( - + , ); expect(getByText(/There was an error/i)).toBeInTheDocument(); }); @@ -70,7 +70,7 @@ describe('TextField', () => { label={'Money'} type={'number'} value={'100'} - /> + />, ); expect(getByText('Money')).toBeInTheDocument(); @@ -82,7 +82,13 @@ describe('TextField', () => { it('accepts a min and max value for a type of number and clamps the value within the range', () => { const { getByTestId } = renderWithTheme( - + , ); const input = getByTestId('textfield-input'); expect(input?.getAttribute('value')).toBe('5'); @@ -94,7 +100,7 @@ describe('TextField', () => { it('renders a helper text with an input id', () => { const { getByText } = renderWithTheme( - + , ); expect(getByText('Helper text')).toBeInTheDocument(); @@ -104,7 +110,7 @@ describe('TextField', () => { it('renders a helper text with a label', () => { const { getByText } = renderWithTheme( - + , ); const helperText = getByText('Helper text'); @@ -115,7 +121,7 @@ describe('TextField', () => { it('renders a helper text with a fallback id', () => { const { getByText } = renderWithTheme( - + , ); const helperText = getByText('Helper text'); diff --git a/packages/ui/src/components/TextField/TextField.tsx b/packages/ui/src/components/TextField/TextField.tsx index 62909e3f9ad..c9ee4281a3a 100644 --- a/packages/ui/src/components/TextField/TextField.tsx +++ b/packages/ui/src/components/TextField/TextField.tsx @@ -170,12 +170,8 @@ export const TextField = (props: TextFieldProps) => { const [_value, setValue] = React.useState(value ?? ''); const theme = useTheme(); - const { - errorScrollClassName, - errorTextId, - helperTextId, - validInputId, - } = useFieldIds({ errorGroup, hasError: Boolean(errorText), inputId, label }); + const { errorScrollClassName, errorTextId, helperTextId, validInputId } = + useFieldIds({ errorGroup, hasError: Boolean(errorText), inputId, label }); const isControlled = value !== undefined; @@ -186,7 +182,7 @@ export const TextField = (props: TextFieldProps) => { }, [value, isControlled]); const handleBlur = ( - e: React.FocusEvent + e: React.FocusEvent, ) => { if (trimmed) { const trimmedValue = e.target.value.trim(); @@ -246,14 +242,14 @@ export const TextField = (props: TextFieldProps) => { } } }, - [min, max, type, onChange] + [min, max, type, onChange], ); const labelSuffixText = required ? '(required)' : optional - ? '(optional)' - : null; + ? '(optional)' + : null; return ( { }} > {label} @@ -299,11 +295,11 @@ export const TextField = (props: TextFieldProps) => { {labelTooltipText && ( @@ -312,11 +308,11 @@ export const TextField = (props: TextFieldProps) => { {helperText && helperTextPosition === 'top' && ( {helperText} @@ -332,6 +328,17 @@ export const TextField = (props: TextFieldProps) => { <_TextField {...textFieldProps} {...dataAttrs} + className={className} + error={!!error || !!errorText} + fullWidth + helperText={''} + /** + * Set _helperText_ and _label_ to no value because we want to + * have the ability to put the helper text under the label at the top. + */ + label={''} + onBlur={handleBlur} + onChange={handleChange} slotProps={{ htmlInput: { 'aria-describedby': helperText ? helperTextId : undefined, @@ -379,17 +386,6 @@ export const TextField = (props: TextFieldProps) => { }), ...props.sx, }} - className={className} - error={!!error || !!errorText} - fullWidth - helperText={''} - /** - * Set _helperText_ and _label_ to no value because we want to - * have the ability to put the helper text under the label at the top. - */ - label={''} - onBlur={handleBlur} - onChange={handleChange} type={type} /* * Let us explicitly pass an empty string to the input @@ -402,15 +398,15 @@ export const TextField = (props: TextFieldProps) => { {tooltipText && ( { {errorText && ( { top: 42, width: '100%', }} - data-qa-textfield-error-text={label} - role="alert" > {errorText} diff --git a/packages/ui/src/components/Toggle/Toggle.test.tsx b/packages/ui/src/components/Toggle/Toggle.test.tsx index 4c38268a966..08843037edb 100644 --- a/packages/ui/src/components/Toggle/Toggle.test.tsx +++ b/packages/ui/src/components/Toggle/Toggle.test.tsx @@ -13,7 +13,7 @@ describe('Toggle component', () => { }); it('should render a tooltip button', async () => { const screen = renderWithTheme( - + , ); const tooltipButton = screen.getByRole('button'); expect(tooltipButton).toBeInTheDocument(); diff --git a/packages/ui/src/components/TooltipIcon/TooltipIcon.stories.tsx b/packages/ui/src/components/TooltipIcon/TooltipIcon.stories.tsx index 8b2c1122da9..211c9308c76 100644 --- a/packages/ui/src/components/TooltipIcon/TooltipIcon.stories.tsx +++ b/packages/ui/src/components/TooltipIcon/TooltipIcon.stories.tsx @@ -22,8 +22,7 @@ export const Default: Story = { export const VariableWidth: Story = { args: { status: 'help', - text: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', width: 500, }, render: (args) => , diff --git a/packages/ui/src/components/Typography/Typography.tsx b/packages/ui/src/components/Typography/Typography.tsx index 0d476773079..504e0f553fb 100644 --- a/packages/ui/src/components/Typography/Typography.tsx +++ b/packages/ui/src/components/Typography/Typography.tsx @@ -10,5 +10,5 @@ export interface TypographyProps extends Omit<_TypographyProps, 'fontFamily'> { export const Typography = React.forwardRef( (props, ref) => { return <_Typography {...props} ref={ref} />; - } + }, ); diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 375e7648336..7b087ca2809 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -4,10 +4,16 @@ export * from './Autocomplete'; export * from './BetaChip'; export * from './Box'; export * from './Button'; -export * from './Chip'; export * from './Checkbox'; +export * from './Chip'; export * from './CircleProgress'; export * from './ClickAwayListener'; +export * from './DatePicker/DateField'; +export * from './DatePicker/DateRangePicker'; +export * from './DatePicker/DateTimeField'; +export * from './DatePicker/DateTimeRangePicker'; +export * from './DatePicker/TimePicker'; +export * from './DatePicker/TimeZoneSelect'; export * from './Dialog'; export * from './DialogTitle'; export * from './Divider'; @@ -18,6 +24,7 @@ export * from './FormControl'; export * from './FormControlLabel'; export * from './FormHelperText'; export * from './H1Header'; +export * from './Hidden/Hidden'; export * from './IconButton'; export * from './Input'; export * from './InputAdornment'; @@ -25,6 +32,8 @@ export * from './InputLabel'; export * from './List'; export * from './ListItem'; export * from './ListItemOption'; +export * from './NewFeatureChip'; +export * from './NotFound/NotFound'; export * from './Notice'; export * from './Paper'; export * from './Radio'; @@ -34,14 +43,7 @@ export * from './Stack'; export * from './SvgIcon'; export * from './TextField'; export * from './Toggle'; -export * from './NewFeatureChip'; export * from './Tooltip'; export * from './TooltipIcon'; export * from './Typography'; export * from './VisibilityTooltip'; -export * from './DatePicker/DateRangePicker'; -export * from './DatePicker/DateTimeRangePicker'; -export * from './DatePicker/DateField'; -export * from './DatePicker/DateTimeField'; -export * from './DatePicker/TimePicker'; -export * from './DatePicker/TimeZoneSelect'; diff --git a/packages/ui/src/foundations/themes/dark.ts b/packages/ui/src/foundations/themes/dark.ts index 92701d79f4a..f9f95453dcf 100644 --- a/packages/ui/src/foundations/themes/dark.ts +++ b/packages/ui/src/foundations/themes/dark.ts @@ -5,11 +5,11 @@ import { Badge, Border, Button, - Component, Color, - Font, + Component, Content, Dropdown, + Font, GlobalHeader, Interaction, NotificationToast, diff --git a/packages/ui/src/foundations/themes/index.ts b/packages/ui/src/foundations/themes/index.ts index 53dc46aa7ef..82f52537661 100644 --- a/packages/ui/src/foundations/themes/index.ts +++ b/packages/ui/src/foundations/themes/index.ts @@ -43,8 +43,7 @@ type Fonts = { }; type MergeTypes = Omit & - Omit & - { [K in keyof A & keyof B]: A[K] | B[K] }; + Omit & { [K in keyof A & keyof B]: A[K] | B[K] }; type LightModeColors = typeof color; type DarkModeColors = typeof customDarkModeOptions.color; diff --git a/packages/ui/src/foundations/utils.test.ts b/packages/ui/src/foundations/utils.test.ts index d4b49f77611..4e15ed847e8 100644 --- a/packages/ui/src/foundations/utils.test.ts +++ b/packages/ui/src/foundations/utils.test.ts @@ -40,16 +40,16 @@ describe('spacingFunction', () => { it('should handle multiple spacing values correctly', () => { expect(spacingFunction(4, 8)).toBe(`${Spacing.S4} ${Spacing.S8}`); expect(spacingFunction(4, 8, 16)).toBe( - `${Spacing.S4} ${Spacing.S8} ${Spacing.S16}` + `${Spacing.S4} ${Spacing.S8} ${Spacing.S16}`, ); expect(spacingFunction(4, 8, 16, 24)).toBe( - `${Spacing.S4} ${Spacing.S8} ${Spacing.S16} ${Spacing.S24}` + `${Spacing.S4} ${Spacing.S8} ${Spacing.S16} ${Spacing.S24}`, ); }); it('should limit to 4 values even if more are provided', () => { expect(spacingFunction(4, 8, 16, 24, 32)).toBe( - `${Spacing.S4} ${Spacing.S8} ${Spacing.S16} ${Spacing.S24}` + `${Spacing.S4} ${Spacing.S8} ${Spacing.S16} ${Spacing.S24}`, ); }); }); diff --git a/packages/ui/src/foundations/utils.ts b/packages/ui/src/foundations/utils.ts index ce3fa2e2726..cc7f8ce1f24 100644 --- a/packages/ui/src/foundations/utils.ts +++ b/packages/ui/src/foundations/utils.ts @@ -49,7 +49,7 @@ export const spacingFunction = (...factors: number[]): string => { // Find the closest matching token, rounds down. const availablePixels = Object.keys(spacingValueMap).map(Number); const closestPixel = availablePixels.reduce((prev, curr) => - Math.abs(curr - factor) < Math.abs(prev - factor) ? curr : prev + Math.abs(curr - factor) < Math.abs(prev - factor) ? curr : prev, ); const token = spacingValueMap[closestPixel]; diff --git a/packages/ui/src/utilities/error.test.ts b/packages/ui/src/utilities/error.test.ts new file mode 100644 index 00000000000..d5153d8670a --- /dev/null +++ b/packages/ui/src/utilities/error.test.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; + +import { getErrorText } from './error'; + +describe('getErrorText', () => { + it('should return a string error text', () => { + expect(getErrorText('Not Found')).toBe('Not Found'); + }); + + it('should return an APIError error text', () => { + expect(getErrorText([{ reason: 'Not Found' }])).toBe('Not Found'); + }); +}); diff --git a/packages/ui/src/utilities/error.ts b/packages/ui/src/utilities/error.ts new file mode 100644 index 00000000000..965ca1ac3a4 --- /dev/null +++ b/packages/ui/src/utilities/error.ts @@ -0,0 +1,18 @@ +/** + * Interface to define the shape of Cloud Manager's APIError type. + * This is an identical version of the type defined in api-v4, which we redeclare here to avoid a dependency on api-v4 in ui. + */ +export interface APIError { + field?: string; + reason: string; +} + +export const getErrorText = ( + error: APIError[] | null | string | undefined, +): null | string | undefined => { + if (Array.isArray(error)) { + return error[0]?.reason; + } + + return error; +}; diff --git a/packages/ui/src/utilities/index.ts b/packages/ui/src/utilities/index.ts index ced345df765..2e3ceb8b524 100644 --- a/packages/ui/src/utilities/index.ts +++ b/packages/ui/src/utilities/index.ts @@ -1,4 +1,4 @@ +export * from './clamp'; export * from './convertToKebabCase'; export * from './omittedProps'; -export * from './clamp'; export * from './stringUtils'; diff --git a/packages/ui/src/utilities/omittedProps.test.tsx b/packages/ui/src/utilities/omittedProps.test.tsx index 685498c9ac6..27999ce562f 100644 --- a/packages/ui/src/utilities/omittedProps.test.tsx +++ b/packages/ui/src/utilities/omittedProps.test.tsx @@ -30,7 +30,7 @@ describe('omittedProps utility', () => { color="red" data-testid="styled-component" extraProp="extra" - /> + />, ); const component = screen.getByTestId('styled-component'); diff --git a/packages/ui/src/utilities/omittedProps.ts b/packages/ui/src/utilities/omittedProps.ts index 49af7e93bbd..2e6749a4874 100644 --- a/packages/ui/src/utilities/omittedProps.ts +++ b/packages/ui/src/utilities/omittedProps.ts @@ -10,9 +10,10 @@ * shouldForwardProp: omittedProps(['compactX', 'compactY']), * })(({ theme, ...props }) => ({ ... })); */ -export const omittedProps = (props: Array) => ( - prop: keyof Props -): boolean => !props.includes(prop); +export const omittedProps = + (props: Array) => + (prop: keyof Props): boolean => + !props.includes(prop); /** * Helper to filter out props we spread into a component. @@ -26,11 +27,11 @@ export const omittedProps = (props: Array) => ( */ export const omitProps = < Props extends NonNullable, - Keys extends keyof Props & string + Keys extends keyof Props & string, >( props: Props, - toRemove: Keys[] & string[] + toRemove: Keys[] & string[], ) => Object.fromEntries( - Object.entries(props).filter(([key]) => !toRemove.includes(key)) + Object.entries(props).filter(([key]) => !toRemove.includes(key)), ) as Omit; diff --git a/packages/ui/src/utilities/testHelpers.tsx b/packages/ui/src/utilities/testHelpers.tsx index bbeedc455bc..9401dd63af6 100644 --- a/packages/ui/src/utilities/testHelpers.tsx +++ b/packages/ui/src/utilities/testHelpers.tsx @@ -20,7 +20,7 @@ export const wrapWithTheme = (ui: any, options: Options = {}) => ( export const renderWithTheme = ( ui: React.ReactNode, - options: Options = {} + options: Options = {}, ): RenderResult => { const renderResult = render(wrapWithTheme(ui, options)); return { diff --git a/packages/ui/src/utilities/timezones.ts b/packages/ui/src/utilities/timezones.ts index 0888381c189..4588d57199a 100644 --- a/packages/ui/src/utilities/timezones.ts +++ b/packages/ui/src/utilities/timezones.ts @@ -1,7 +1,6 @@ /* This file borrowed from https://github.com/vahnag/react-timezone */ /* Timezones are borrowed from Google Calendar */ -// eslint-disable-next-line max-len // [...$0.children].map(el => ({ label: (el.getAttribute('aria-label')|| '').replace(/\(.*?\)(.+)/, '$1').trim(), name: el.getAttribute('data-value'), offset: +(el.getAttribute('aria-label')|| '').replace(/\(.*?(-?[0-9]{2}):([0-9]{2})\).*/, (all, one, two) => +one + (two / 60) * (one > 0 ? 1 : -1)) })) export const timezones = [ diff --git a/packages/utilities/src/__data__/regionsData.ts b/packages/utilities/src/__data__/regionsData.ts index 6a7ed940d47..0c5858c2e20 100644 --- a/packages/utilities/src/__data__/regionsData.ts +++ b/packages/utilities/src/__data__/regionsData.ts @@ -1,4 +1,4 @@ -import { Region } from '@linode/api-v4/lib/regions'; +import type { Region } from '@linode/api-v4/lib/regions'; export const regions: Region[] = [ { @@ -22,10 +22,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 10, }, resolvers: { - ipv4: - '172.105.34.5, 172.105.35.5, 172.105.36.5, 172.105.37.5, 172.105.38.5, 172.105.39.5, 172.105.40.5, 172.105.41.5, 172.105.42.5, 172.105.43.5', - ipv6: - '2400:8904::f03c:91ff:fea5:659, 2400:8904::f03c:91ff:fea5:9282, 2400:8904::f03c:91ff:fea5:b9b3, 2400:8904::f03c:91ff:fea5:925a, 2400:8904::f03c:91ff:fea5:22cb, 2400:8904::f03c:91ff:fea5:227a, 2400:8904::f03c:91ff:fea5:924c, 2400:8904::f03c:91ff:fea5:f7e2, 2400:8904::f03c:91ff:fea5:2205, 2400:8904::f03c:91ff:fea5:9207', + ipv4: '172.105.34.5, 172.105.35.5, 172.105.36.5, 172.105.37.5, 172.105.38.5, 172.105.39.5, 172.105.40.5, 172.105.41.5, 172.105.42.5, 172.105.43.5', + ipv6: '2400:8904::f03c:91ff:fea5:659, 2400:8904::f03c:91ff:fea5:9282, 2400:8904::f03c:91ff:fea5:b9b3, 2400:8904::f03c:91ff:fea5:925a, 2400:8904::f03c:91ff:fea5:22cb, 2400:8904::f03c:91ff:fea5:227a, 2400:8904::f03c:91ff:fea5:924c, 2400:8904::f03c:91ff:fea5:f7e2, 2400:8904::f03c:91ff:fea5:2205, 2400:8904::f03c:91ff:fea5:9207', }, site_type: 'core', status: 'ok', @@ -51,10 +49,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: null, }, resolvers: { - ipv4: - '172.105.0.5, 172.105.3.5, 172.105.4.5, 172.105.5.5, 172.105.6.5, 172.105.7.5, 172.105.8.5, 172.105.9.5, 172.105.10.5, 172.105.11.5', - ipv6: - '2600:3c04::f03c:91ff:fea9:f63, 2600:3c04::f03c:91ff:fea9:f6d, 2600:3c04::f03c:91ff:fea9:f80, 2600:3c04::f03c:91ff:fea9:f0f, 2600:3c04::f03c:91ff:fea9:f99, 2600:3c04::f03c:91ff:fea9:fbd, 2600:3c04::f03c:91ff:fea9:fdd, 2600:3c04::f03c:91ff:fea9:fe2, 2600:3c04::f03c:91ff:fea9:f68, 2600:3c04::f03c:91ff:fea9:f4a', + ipv4: '172.105.0.5, 172.105.3.5, 172.105.4.5, 172.105.5.5, 172.105.6.5, 172.105.7.5, 172.105.8.5, 172.105.9.5, 172.105.10.5, 172.105.11.5', + ipv6: '2600:3c04::f03c:91ff:fea9:f63, 2600:3c04::f03c:91ff:fea9:f6d, 2600:3c04::f03c:91ff:fea9:f80, 2600:3c04::f03c:91ff:fea9:f0f, 2600:3c04::f03c:91ff:fea9:f99, 2600:3c04::f03c:91ff:fea9:fbd, 2600:3c04::f03c:91ff:fea9:fdd, 2600:3c04::f03c:91ff:fea9:fe2, 2600:3c04::f03c:91ff:fea9:f68, 2600:3c04::f03c:91ff:fea9:f4a', }, site_type: 'core', status: 'ok', @@ -79,10 +75,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.105.166.5, 172.105.169.5, 172.105.168.5, 172.105.172.5, 172.105.162.5, 172.105.170.5, 172.105.167.5, 172.105.171.5, 172.105.181.5, 172.105.161.5', - ipv6: - '2400:8907::f03c:92ff:fe6e:ec8, 2400:8907::f03c:92ff:fe6e:98e4, 2400:8907::f03c:92ff:fe6e:1c58, 2400:8907::f03c:92ff:fe6e:c299, 2400:8907::f03c:92ff:fe6e:c210, 2400:8907::f03c:92ff:fe6e:c219, 2400:8907::f03c:92ff:fe6e:1c5c, 2400:8907::f03c:92ff:fe6e:c24e, 2400:8907::f03c:92ff:fe6e:e6b, 2400:8907::f03c:92ff:fe6e:e3d', + ipv4: '172.105.166.5, 172.105.169.5, 172.105.168.5, 172.105.172.5, 172.105.162.5, 172.105.170.5, 172.105.167.5, 172.105.171.5, 172.105.181.5, 172.105.161.5', + ipv6: '2400:8907::f03c:92ff:fe6e:ec8, 2400:8907::f03c:92ff:fe6e:98e4, 2400:8907::f03c:92ff:fe6e:1c58, 2400:8907::f03c:92ff:fe6e:c299, 2400:8907::f03c:92ff:fe6e:c210, 2400:8907::f03c:92ff:fe6e:c219, 2400:8907::f03c:92ff:fe6e:1c5c, 2400:8907::f03c:92ff:fe6e:c24e, 2400:8907::f03c:92ff:fe6e:e6b, 2400:8907::f03c:92ff:fe6e:e3d', }, site_type: 'core', status: 'ok', @@ -110,10 +104,37 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, 139.144.192.68', - ipv6: - '2600:3c05::f03c:93ff:feb6:43b6, 2600:3c05::f03c:93ff:feb6:4365, 2600:3c05::f03c:93ff:feb6:43c2, 2600:3c05::f03c:93ff:feb6:e441, 2600:3c05::f03c:93ff:feb6:94ef, 2600:3c05::f03c:93ff:feb6:94ba, 2600:3c05::f03c:93ff:feb6:94a8, 2600:3c05::f03c:93ff:feb6:9413, 2600:3c05::f03c:93ff:feb6:9443, 2600:3c05::f03c:93ff:feb6:94e0', + ipv4: '139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, 139.144.192.68', + ipv6: '2600:3c05::f03c:93ff:feb6:43b6, 2600:3c05::f03c:93ff:feb6:4365, 2600:3c05::f03c:93ff:feb6:43c2, 2600:3c05::f03c:93ff:feb6:e441, 2600:3c05::f03c:93ff:feb6:94ef, 2600:3c05::f03c:93ff:feb6:94ba, 2600:3c05::f03c:93ff:feb6:94a8, 2600:3c05::f03c:93ff:feb6:9413, 2600:3c05::f03c:93ff:feb6:9443, 2600:3c05::f03c:93ff:feb6:94e0', + }, + site_type: 'core', + status: 'ok', + }, + { + capabilities: [ + 'Linodes', + 'NodeBalancers', + 'Block Storage', + 'Object Storage', + 'Kubernetes', + 'Cloud Firewall', + 'Vlans', + 'VPCs', + 'Managed Databases', + 'Metadata', + 'Premium Plans', + 'Placement Group', + ], + country: 'no', + id: 'no-east', + label: 'Oslo', + placement_group_limits: { + maximum_linodes_per_pg: 10, + maximum_pgs_per_customer: 5, + }, + resolvers: { + ipv4: '139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, 139.144.192.68', + ipv6: '2600:3c05::f03c:93ff:feb6:43b6, 2600:3c05::f03c:93ff:feb6:4365, 2600:3c05::f03c:93ff:feb6:43c2, 2600:3c05::f03c:93ff:feb6:e441, 2600:3c05::f03c:93ff:feb6:94ef, 2600:3c05::f03c:93ff:feb6:94ba, 2600:3c05::f03c:93ff:feb6:94a8, 2600:3c05::f03c:93ff:feb6:9413, 2600:3c05::f03c:93ff:feb6:9443, 2600:3c05::f03c:93ff:feb6:94e0', }, site_type: 'core', status: 'ok', @@ -140,10 +161,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.0.17, 172.232.0.16, 172.232.0.21, 172.232.0.13, 172.232.0.22, 172.232.0.9, 172.232.0.19, 172.232.0.20, 172.232.0.15, 172.232.0.18', - ipv6: - '2600:3c06::f03c:93ff:fed0:e5fc, 2600:3c06::f03c:93ff:fed0:e54b, 2600:3c06::f03c:93ff:fed0:e572, 2600:3c06::f03c:93ff:fed0:e530, 2600:3c06::f03c:93ff:fed0:e597, 2600:3c06::f03c:93ff:fed0:e511, 2600:3c06::f03c:93ff:fed0:e5f2, 2600:3c06::f03c:93ff:fed0:e5bf, 2600:3c06::f03c:93ff:fed0:e529, 2600:3c06::f03c:93ff:fed0:e5a3', + ipv4: '172.232.0.17, 172.232.0.16, 172.232.0.21, 172.232.0.13, 172.232.0.22, 172.232.0.9, 172.232.0.19, 172.232.0.20, 172.232.0.15, 172.232.0.18', + ipv6: '2600:3c06::f03c:93ff:fed0:e5fc, 2600:3c06::f03c:93ff:fed0:e54b, 2600:3c06::f03c:93ff:fed0:e572, 2600:3c06::f03c:93ff:fed0:e530, 2600:3c06::f03c:93ff:fed0:e597, 2600:3c06::f03c:93ff:fed0:e511, 2600:3c06::f03c:93ff:fed0:e5f2, 2600:3c06::f03c:93ff:fed0:e5bf, 2600:3c06::f03c:93ff:fed0:e529, 2600:3c06::f03c:93ff:fed0:e5a3', }, site_type: 'core', status: 'ok', @@ -170,10 +189,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.32.21, 172.232.32.23, 172.232.32.17, 172.232.32.18, 172.232.32.16, 172.232.32.22, 172.232.32.20, 172.232.32.14, 172.232.32.11, 172.232.32.12', - ipv6: - '2600:3c07::f03c:93ff:fef2:2e63, 2600:3c07::f03c:93ff:fef2:2ec7, 2600:3c07::f03c:93ff:fef2:0dee, 2600:3c07::f03c:93ff:fef2:0d25, 2600:3c07::f03c:93ff:fef2:0de0, 2600:3c07::f03c:93ff:fef2:2e29, 2600:3c07::f03c:93ff:fef2:0dda, 2600:3c07::f03c:93ff:fef2:0d82, 2600:3c07::f03c:93ff:fef2:b3ac, 2600:3c07::f03c:93ff:fef2:b3a8', + ipv4: '172.232.32.21, 172.232.32.23, 172.232.32.17, 172.232.32.18, 172.232.32.16, 172.232.32.22, 172.232.32.20, 172.232.32.14, 172.232.32.11, 172.232.32.12', + ipv6: '2600:3c07::f03c:93ff:fef2:2e63, 2600:3c07::f03c:93ff:fef2:2ec7, 2600:3c07::f03c:93ff:fef2:0dee, 2600:3c07::f03c:93ff:fef2:0d25, 2600:3c07::f03c:93ff:fef2:0de0, 2600:3c07::f03c:93ff:fef2:2e29, 2600:3c07::f03c:93ff:fef2:0dda, 2600:3c07::f03c:93ff:fef2:0d82, 2600:3c07::f03c:93ff:fef2:b3ac, 2600:3c07::f03c:93ff:fef2:b3a8', }, site_type: 'core', status: 'ok', @@ -200,10 +217,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.160.19, 172.232.160.21, 172.232.160.17, 172.232.160.15, 172.232.160.18, 172.232.160.8, 172.232.160.12, 172.232.160.11, 172.232.160.14, 172.232.160.16', - ipv6: - '2600:3c0a::f03c:93ff:fe54:c6da, 2600:3c0a::f03c:93ff:fe54:c691, 2600:3c0a::f03c:93ff:fe54:c68d, 2600:3c0a::f03c:93ff:fe54:c61e, 2600:3c0a::f03c:93ff:fe54:c653, 2600:3c0a::f03c:93ff:fe54:c64c, 2600:3c0a::f03c:93ff:fe54:c68a, 2600:3c0a::f03c:93ff:fe54:c697, 2600:3c0a::f03c:93ff:fe54:c60f, 2600:3c0a::f03c:93ff:fe54:c6a0', + ipv4: '172.232.160.19, 172.232.160.21, 172.232.160.17, 172.232.160.15, 172.232.160.18, 172.232.160.8, 172.232.160.12, 172.232.160.11, 172.232.160.14, 172.232.160.16', + ipv6: '2600:3c0a::f03c:93ff:fe54:c6da, 2600:3c0a::f03c:93ff:fe54:c691, 2600:3c0a::f03c:93ff:fe54:c68d, 2600:3c0a::f03c:93ff:fe54:c61e, 2600:3c0a::f03c:93ff:fe54:c653, 2600:3c0a::f03c:93ff:fe54:c64c, 2600:3c0a::f03c:93ff:fe54:c68a, 2600:3c0a::f03c:93ff:fe54:c697, 2600:3c0a::f03c:93ff:fe54:c60f, 2600:3c0a::f03c:93ff:fe54:c6a0', }, site_type: 'core', status: 'ok', @@ -230,10 +245,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.233.0.4, 172.233.0.9, 172.233.0.7, 172.233.0.12, 172.233.0.5, 172.233.0.13, 172.233.0.10, 172.233.0.6, 172.233.0.8, 172.233.0.11', - ipv6: - '2600:3c0d::f03c:93ff:fe3d:51cb, 2600:3c0d::f03c:93ff:fe3d:51a7, 2600:3c0d::f03c:93ff:fe3d:51a9, 2600:3c0d::f03c:93ff:fe3d:5119, 2600:3c0d::f03c:93ff:fe3d:51fe, 2600:3c0d::f03c:93ff:fe3d:517c, 2600:3c0d::f03c:93ff:fe3d:5144, 2600:3c0d::f03c:93ff:fe3d:5170, 2600:3c0d::f03c:93ff:fe3d:51cc, 2600:3c0d::f03c:93ff:fe3d:516c', + ipv4: '172.233.0.4, 172.233.0.9, 172.233.0.7, 172.233.0.12, 172.233.0.5, 172.233.0.13, 172.233.0.10, 172.233.0.6, 172.233.0.8, 172.233.0.11', + ipv6: '2600:3c0d::f03c:93ff:fe3d:51cb, 2600:3c0d::f03c:93ff:fe3d:51a7, 2600:3c0d::f03c:93ff:fe3d:51a9, 2600:3c0d::f03c:93ff:fe3d:5119, 2600:3c0d::f03c:93ff:fe3d:51fe, 2600:3c0d::f03c:93ff:fe3d:517c, 2600:3c0d::f03c:93ff:fe3d:5144, 2600:3c0d::f03c:93ff:fe3d:5170, 2600:3c0d::f03c:93ff:fe3d:51cc, 2600:3c0d::f03c:93ff:fe3d:516c', }, site_type: 'core', status: 'ok', @@ -259,10 +272,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.233.33.36, 172.233.33.38, 172.233.33.35, 172.233.33.39, 172.233.33.34, 172.233.33.33, 172.233.33.31, 172.233.33.30, 172.233.33.37, 172.233.33.32', - ipv6: - '2600:3c0e::f03c:93ff:fe9d:2d10, 2600:3c0e::f03c:93ff:fe9d:2d89, 2600:3c0e::f03c:93ff:fe9d:2d79, 2600:3c0e::f03c:93ff:fe9d:2d96, 2600:3c0e::f03c:93ff:fe9d:2da5, 2600:3c0e::f03c:93ff:fe9d:2d34, 2600:3c0e::f03c:93ff:fe9d:2d68, 2600:3c0e::f03c:93ff:fe9d:2d17, 2600:3c0e::f03c:93ff:fe9d:2d45, 2600:3c0e::f03c:93ff:fe9d:2d5c', + ipv4: '172.233.33.36, 172.233.33.38, 172.233.33.35, 172.233.33.39, 172.233.33.34, 172.233.33.33, 172.233.33.31, 172.233.33.30, 172.233.33.37, 172.233.33.32', + ipv6: '2600:3c0e::f03c:93ff:fe9d:2d10, 2600:3c0e::f03c:93ff:fe9d:2d89, 2600:3c0e::f03c:93ff:fe9d:2d79, 2600:3c0e::f03c:93ff:fe9d:2d96, 2600:3c0e::f03c:93ff:fe9d:2da5, 2600:3c0e::f03c:93ff:fe9d:2d34, 2600:3c0e::f03c:93ff:fe9d:2d68, 2600:3c0e::f03c:93ff:fe9d:2d17, 2600:3c0e::f03c:93ff:fe9d:2d45, 2600:3c0e::f03c:93ff:fe9d:2d5c', }, site_type: 'core', status: 'ok', @@ -288,10 +299,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.128.24, 172.232.128.26, 172.232.128.20, 172.232.128.22, 172.232.128.25, 172.232.128.19, 172.232.128.23, 172.232.128.18, 172.232.128.21, 172.232.128.27', - ipv6: - '2600:3c09::f03c:93ff:fea9:4dbe, 2600:3c09::f03c:93ff:fea9:4d63, 2600:3c09::f03c:93ff:fea9:4dce, 2600:3c09::f03c:93ff:fea9:4dbb, 2600:3c09::f03c:93ff:fea9:4d99, 2600:3c09::f03c:93ff:fea9:4d26, 2600:3c09::f03c:93ff:fea9:4de0, 2600:3c09::f03c:93ff:fea9:4d69, 2600:3c09::f03c:93ff:fea9:4dbf, 2600:3c09::f03c:93ff:fea9:4da6', + ipv4: '172.232.128.24, 172.232.128.26, 172.232.128.20, 172.232.128.22, 172.232.128.25, 172.232.128.19, 172.232.128.23, 172.232.128.18, 172.232.128.21, 172.232.128.27', + ipv6: '2600:3c09::f03c:93ff:fea9:4dbe, 2600:3c09::f03c:93ff:fea9:4d63, 2600:3c09::f03c:93ff:fea9:4dce, 2600:3c09::f03c:93ff:fea9:4dbb, 2600:3c09::f03c:93ff:fea9:4d99, 2600:3c09::f03c:93ff:fea9:4d26, 2600:3c09::f03c:93ff:fea9:4de0, 2600:3c09::f03c:93ff:fea9:4d69, 2600:3c09::f03c:93ff:fea9:4dbf, 2600:3c09::f03c:93ff:fea9:4da6', }, site_type: 'core', status: 'ok', @@ -318,10 +327,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.96.17, 172.232.96.26, 172.232.96.19, 172.232.96.20, 172.232.96.25, 172.232.96.21, 172.232.96.18, 172.232.96.22, 172.232.96.23, 172.232.96.24', - ipv6: - '2600:3c08::f03c:93ff:fe7c:1135, 2600:3c08::f03c:93ff:fe7c:11f8, 2600:3c08::f03c:93ff:fe7c:11d2, 2600:3c08::f03c:93ff:fe7c:11a7, 2600:3c08::f03c:93ff:fe7c:11ad, 2600:3c08::f03c:93ff:fe7c:110a, 2600:3c08::f03c:93ff:fe7c:11f9, 2600:3c08::f03c:93ff:fe7c:1137, 2600:3c08::f03c:93ff:fe7c:11db, 2600:3c08::f03c:93ff:fe7c:1164', + ipv4: '172.232.96.17, 172.232.96.26, 172.232.96.19, 172.232.96.20, 172.232.96.25, 172.232.96.21, 172.232.96.18, 172.232.96.22, 172.232.96.23, 172.232.96.24', + ipv6: '2600:3c08::f03c:93ff:fe7c:1135, 2600:3c08::f03c:93ff:fe7c:11f8, 2600:3c08::f03c:93ff:fe7c:11d2, 2600:3c08::f03c:93ff:fe7c:11a7, 2600:3c08::f03c:93ff:fe7c:11ad, 2600:3c08::f03c:93ff:fe7c:110a, 2600:3c08::f03c:93ff:fe7c:11f9, 2600:3c08::f03c:93ff:fe7c:1137, 2600:3c08::f03c:93ff:fe7c:11db, 2600:3c08::f03c:93ff:fe7c:1164', }, site_type: 'core', status: 'ok', @@ -348,10 +355,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.233.64.44, 172.233.64.43, 172.233.64.37, 172.233.64.40, 172.233.64.46, 172.233.64.41, 172.233.64.39, 172.233.64.42, 172.233.64.45, 172.233.64.38', - ipv6: - '2400:8905::f03c:93ff:fe9d:b085, 2400:8905::f03c:93ff:fe9d:b012, 2400:8905::f03c:93ff:fe9d:b09b, 2400:8905::f03c:93ff:fe9d:b0d8, 2400:8905::f03c:93ff:fe9d:259f, 2400:8905::f03c:93ff:fe9d:b006, 2400:8905::f03c:93ff:fe9d:b084, 2400:8905::f03c:93ff:fe9d:b0ce, 2400:8905::f03c:93ff:fe9d:25ea, 2400:8905::f03c:93ff:fe9d:b086', + ipv4: '172.233.64.44, 172.233.64.43, 172.233.64.37, 172.233.64.40, 172.233.64.46, 172.233.64.41, 172.233.64.39, 172.233.64.42, 172.233.64.45, 172.233.64.38', + ipv6: '2400:8905::f03c:93ff:fe9d:b085, 2400:8905::f03c:93ff:fe9d:b012, 2400:8905::f03c:93ff:fe9d:b09b, 2400:8905::f03c:93ff:fe9d:b0d8, 2400:8905::f03c:93ff:fe9d:259f, 2400:8905::f03c:93ff:fe9d:b006, 2400:8905::f03c:93ff:fe9d:b084, 2400:8905::f03c:93ff:fe9d:b0ce, 2400:8905::f03c:93ff:fe9d:25ea, 2400:8905::f03c:93ff:fe9d:b086', }, site_type: 'core', status: 'ok', @@ -377,10 +382,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.192.19, 172.232.192.18, 172.232.192.16, 172.232.192.20, 172.232.192.24, 172.232.192.21, 172.232.192.22, 172.232.192.17, 172.232.192.15, 172.232.192.23', - ipv6: - '2600:3c0b::f03c:93ff:feba:d513, 2600:3c0b::f03c:93ff:feba:d5c3, 2600:3c0b::f03c:93ff:feba:d597, 2600:3c0b::f03c:93ff:feba:d5fb, 2600:3c0b::f03c:93ff:feba:d51f, 2600:3c0b::f03c:93ff:feba:d58e, 2600:3c0b::f03c:93ff:feba:d5d5, 2600:3c0b::f03c:93ff:feba:d534, 2600:3c0b::f03c:93ff:feba:d57c, 2600:3c0b::f03c:93ff:feba:d529', + ipv4: '172.232.192.19, 172.232.192.18, 172.232.192.16, 172.232.192.20, 172.232.192.24, 172.232.192.21, 172.232.192.22, 172.232.192.17, 172.232.192.15, 172.232.192.23', + ipv6: '2600:3c0b::f03c:93ff:feba:d513, 2600:3c0b::f03c:93ff:feba:d5c3, 2600:3c0b::f03c:93ff:feba:d597, 2600:3c0b::f03c:93ff:feba:d5fb, 2600:3c0b::f03c:93ff:feba:d51f, 2600:3c0b::f03c:93ff:feba:d58e, 2600:3c0b::f03c:93ff:feba:d5d5, 2600:3c0b::f03c:93ff:feba:d534, 2600:3c0b::f03c:93ff:feba:d57c, 2600:3c0b::f03c:93ff:feba:d529', }, site_type: 'core', status: 'ok', @@ -408,10 +411,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.233.160.34, 172.233.160.27, 172.233.160.30, 172.233.160.29, 172.233.160.32, 172.233.160.28, 172.233.160.33, 172.233.160.26, 172.233.160.25, 172.233.160.31', - ipv6: - '2a01:7e04::f03c:93ff:fead:d31f, 2a01:7e04::f03c:93ff:fead:d37f, 2a01:7e04::f03c:93ff:fead:d30c, 2a01:7e04::f03c:93ff:fead:d318, 2a01:7e04::f03c:93ff:fead:d316, 2a01:7e04::f03c:93ff:fead:d339, 2a01:7e04::f03c:93ff:fead:d367, 2a01:7e04::f03c:93ff:fead:d395, 2a01:7e04::f03c:93ff:fead:d3d0, 2a01:7e04::f03c:93ff:fead:d38e', + ipv4: '172.233.160.34, 172.233.160.27, 172.233.160.30, 172.233.160.29, 172.233.160.32, 172.233.160.28, 172.233.160.33, 172.233.160.26, 172.233.160.25, 172.233.160.31', + ipv6: '2a01:7e04::f03c:93ff:fead:d31f, 2a01:7e04::f03c:93ff:fead:d37f, 2a01:7e04::f03c:93ff:fead:d30c, 2a01:7e04::f03c:93ff:fead:d318, 2a01:7e04::f03c:93ff:fead:d316, 2a01:7e04::f03c:93ff:fead:d339, 2a01:7e04::f03c:93ff:fead:d367, 2a01:7e04::f03c:93ff:fead:d395, 2a01:7e04::f03c:93ff:fead:d3d0, 2a01:7e04::f03c:93ff:fead:d38e', }, site_type: 'core', status: 'ok', @@ -437,10 +438,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.232.224.23, 172.232.224.32, 172.232.224.26, 172.232.224.27, 172.232.224.21, 172.232.224.24, 172.232.224.22, 172.232.224.20, 172.232.224.31, 172.232.224.28', - ipv6: - '2600:3c0c::f03c:93ff:feed:a90b, 2600:3c0c::f03c:93ff:feed:a9a5, 2600:3c0c::f03c:93ff:feed:a935, 2600:3c0c::f03c:93ff:feed:a930, 2600:3c0c::f03c:93ff:feed:a95c, 2600:3c0c::f03c:93ff:feed:a9ad, 2600:3c0c::f03c:93ff:feed:a9f2, 2600:3c0c::f03c:93ff:feed:a9ff, 2600:3c0c::f03c:93ff:feed:a9c8, 2600:3c0c::f03c:93ff:feed:a96b', + ipv4: '172.232.224.23, 172.232.224.32, 172.232.224.26, 172.232.224.27, 172.232.224.21, 172.232.224.24, 172.232.224.22, 172.232.224.20, 172.232.224.31, 172.232.224.28', + ipv6: '2600:3c0c::f03c:93ff:feed:a90b, 2600:3c0c::f03c:93ff:feed:a9a5, 2600:3c0c::f03c:93ff:feed:a935, 2600:3c0c::f03c:93ff:feed:a930, 2600:3c0c::f03c:93ff:feed:a95c, 2600:3c0c::f03c:93ff:feed:a9ad, 2600:3c0c::f03c:93ff:feed:a9f2, 2600:3c0c::f03c:93ff:feed:a9ff, 2600:3c0c::f03c:93ff:feed:a9c8, 2600:3c0c::f03c:93ff:feed:a96b', }, site_type: 'core', status: 'ok', @@ -468,10 +467,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '172.233.128.45, 172.233.128.38, 172.233.128.53, 172.233.128.37, 172.233.128.34, 172.233.128.36, 172.233.128.33, 172.233.128.39, 172.233.128.43, 172.233.128.44', - ipv6: - '2a01:7e03::f03c:93ff:feb1:b789, 2a01:7e03::f03c:93ff:feb1:b717, 2a01:7e03::f03c:93ff:feb1:b707, 2a01:7e03::f03c:93ff:feb1:b7ab, 2a01:7e03::f03c:93ff:feb1:b7e2, 2a01:7e03::f03c:93ff:feb1:b709, 2a01:7e03::f03c:93ff:feb1:b7a6, 2a01:7e03::f03c:93ff:feb1:b750, 2a01:7e03::f03c:93ff:feb1:b76e, 2a01:7e03::f03c:93ff:feb1:b7a2', + ipv4: '172.233.128.45, 172.233.128.38, 172.233.128.53, 172.233.128.37, 172.233.128.34, 172.233.128.36, 172.233.128.33, 172.233.128.39, 172.233.128.43, 172.233.128.44', + ipv6: '2a01:7e03::f03c:93ff:feb1:b789, 2a01:7e03::f03c:93ff:feb1:b717, 2a01:7e03::f03c:93ff:feb1:b707, 2a01:7e03::f03c:93ff:feb1:b7ab, 2a01:7e03::f03c:93ff:feb1:b7e2, 2a01:7e03::f03c:93ff:feb1:b709, 2a01:7e03::f03c:93ff:feb1:b7a6, 2a01:7e03::f03c:93ff:feb1:b750, 2a01:7e03::f03c:93ff:feb1:b76e, 2a01:7e03::f03c:93ff:feb1:b7a2', }, site_type: 'core', status: 'ok', @@ -497,10 +494,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '72.14.179.5, 72.14.188.5, 173.255.199.5, 66.228.53.5, 96.126.122.5, 96.126.124.5, 96.126.127.5, 198.58.107.5, 198.58.111.5, 23.239.24.5', - ipv6: - '2600:3c00::2, 2600:3c00::9, 2600:3c00::7, 2600:3c00::5, 2600:3c00::3, 2600:3c00::8, 2600:3c00::6, 2600:3c00::4, 2600:3c00::c, 2600:3c00::b', + ipv4: '72.14.179.5, 72.14.188.5, 173.255.199.5, 66.228.53.5, 96.126.122.5, 96.126.124.5, 96.126.127.5, 198.58.107.5, 198.58.111.5, 23.239.24.5', + ipv6: '2600:3c00::2, 2600:3c00::9, 2600:3c00::7, 2600:3c00::5, 2600:3c00::3, 2600:3c00::8, 2600:3c00::6, 2600:3c00::4, 2600:3c00::c, 2600:3c00::b', }, site_type: 'core', status: 'ok', @@ -524,10 +519,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 1, }, resolvers: { - ipv4: - '173.230.145.5, 173.230.147.5, 173.230.155.5, 173.255.212.5, 173.255.219.5, 173.255.241.5, 173.255.243.5, 173.255.244.5, 74.207.241.5, 74.207.242.5', - ipv6: - '2600:3c01::2, 2600:3c01::9, 2600:3c01::5, 2600:3c01::7, 2600:3c01::3, 2600:3c01::8, 2600:3c01::4, 2600:3c01::b, 2600:3c01::c, 2600:3c01::6', + ipv4: '173.230.145.5, 173.230.147.5, 173.230.155.5, 173.255.212.5, 173.255.219.5, 173.255.241.5, 173.255.243.5, 173.255.244.5, 74.207.241.5, 74.207.242.5', + ipv6: '2600:3c01::2, 2600:3c01::9, 2600:3c01::5, 2600:3c01::7, 2600:3c01::3, 2600:3c01::8, 2600:3c01::4, 2600:3c01::b, 2600:3c01::c, 2600:3c01::6', }, site_type: 'core', status: 'ok', @@ -556,10 +549,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '74.207.231.5, 173.230.128.5, 173.230.129.5, 173.230.136.5, 173.230.140.5, 66.228.59.5, 66.228.62.5, 50.116.35.5, 50.116.41.5, 23.239.18.5', - ipv6: - '2600:3c02::3, 2600:3c02::5, 2600:3c02::4, 2600:3c02::6, 2600:3c02::c, 2600:3c02::7, 2600:3c02::2, 2600:3c02::9, 2600:3c02::8, 2600:3c02::b', + ipv4: '74.207.231.5, 173.230.128.5, 173.230.129.5, 173.230.136.5, 173.230.140.5, 66.228.59.5, 66.228.62.5, 50.116.35.5, 50.116.41.5, 23.239.18.5', + ipv6: '2600:3c02::3, 2600:3c02::5, 2600:3c02::4, 2600:3c02::6, 2600:3c02::c, 2600:3c02::7, 2600:3c02::2, 2600:3c02::9, 2600:3c02::8, 2600:3c02::b', }, site_type: 'core', status: 'ok', @@ -588,10 +579,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '66.228.42.5, 96.126.106.5, 50.116.53.5, 50.116.58.5, 50.116.61.5, 50.116.62.5, 66.175.211.5, 97.107.133.4, 207.192.69.4, 207.192.69.5', - ipv6: - '2600:3c03::7, 2600:3c03::4, 2600:3c03::9, 2600:3c03::6, 2600:3c03::3, 2600:3c03::c, 2600:3c03::5, 2600:3c03::b, 2600:3c03::2, 2600:3c03::8', + ipv4: '66.228.42.5, 96.126.106.5, 50.116.53.5, 50.116.58.5, 50.116.61.5, 50.116.62.5, 66.175.211.5, 97.107.133.4, 207.192.69.4, 207.192.69.5', + ipv6: '2600:3c03::7, 2600:3c03::4, 2600:3c03::9, 2600:3c03::6, 2600:3c03::3, 2600:3c03::c, 2600:3c03::5, 2600:3c03::b, 2600:3c03::2, 2600:3c03::8', }, site_type: 'core', status: 'ok', @@ -616,10 +605,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '178.79.182.5, 176.58.107.5, 176.58.116.5, 176.58.121.5, 151.236.220.5, 212.71.252.5, 212.71.253.5, 109.74.192.20, 109.74.193.20, 109.74.194.20', - ipv6: - '2a01:7e00::9, 2a01:7e00::3, 2a01:7e00::c, 2a01:7e00::5, 2a01:7e00::6, 2a01:7e00::8, 2a01:7e00::b, 2a01:7e00::4, 2a01:7e00::7, 2a01:7e00::2', + ipv4: '178.79.182.5, 176.58.107.5, 176.58.116.5, 176.58.121.5, 151.236.220.5, 212.71.252.5, 212.71.253.5, 109.74.192.20, 109.74.193.20, 109.74.194.20', + ipv6: '2a01:7e00::9, 2a01:7e00::3, 2a01:7e00::c, 2a01:7e00::5, 2a01:7e00::6, 2a01:7e00::8, 2a01:7e00::b, 2a01:7e00::4, 2a01:7e00::7, 2a01:7e00::2', }, site_type: 'core', status: 'ok', @@ -646,10 +633,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '139.162.11.5, 139.162.13.5, 139.162.14.5, 139.162.15.5, 139.162.16.5, 139.162.21.5, 139.162.27.5, 103.3.60.18, 103.3.60.19, 103.3.60.20', - ipv6: - '2400:8901::5, 2400:8901::4, 2400:8901::b, 2400:8901::3, 2400:8901::9, 2400:8901::2, 2400:8901::8, 2400:8901::7, 2400:8901::c, 2400:8901::6', + ipv4: '139.162.11.5, 139.162.13.5, 139.162.14.5, 139.162.15.5, 139.162.16.5, 139.162.21.5, 139.162.27.5, 103.3.60.18, 103.3.60.19, 103.3.60.20', + ipv6: '2400:8901::5, 2400:8901::4, 2400:8901::b, 2400:8901::3, 2400:8901::9, 2400:8901::2, 2400:8901::8, 2400:8901::7, 2400:8901::c, 2400:8901::6', }, site_type: 'core', status: 'ok', @@ -677,10 +662,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', - ipv6: - '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', + ipv4: '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', + ipv6: '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', }, site_type: 'core', status: 'ok', @@ -695,10 +678,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', - ipv6: - '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', + ipv4: '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', + ipv6: '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', }, site_type: 'distributed', status: 'ok', @@ -713,10 +694,8 @@ export const regions: Region[] = [ maximum_pgs_per_customer: 5, }, resolvers: { - ipv4: - '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', - ipv6: - '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', + ipv4: '139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5', + ipv6: '2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8', }, site_type: 'distributed', status: 'ok', diff --git a/packages/utilities/src/factories/accountAvailability.ts b/packages/utilities/src/factories/accountAvailability.ts index 1d427dcf5b7..d295a86e0ed 100644 --- a/packages/utilities/src/factories/accountAvailability.ts +++ b/packages/utilities/src/factories/accountAvailability.ts @@ -1,15 +1,13 @@ -import { Factory } from './factoryProxy'; - import { pickRandom } from '../helpers'; +import { Factory } from './factoryProxy'; import type { AccountAvailability } from '@linode/api-v4'; -export const accountAvailabilityFactory = Factory.Sync.makeFactory( - { +export const accountAvailabilityFactory = + Factory.Sync.makeFactory({ region: pickRandom(['us-mia', 'ap-south', 'ap-northeast']), unavailable: pickRandom([ ['Block Storage'], ['Linodes', 'Block Storage', 'Kubernetes', 'NodeBalancers'], ]), - } -); + }); diff --git a/packages/utilities/src/factories/factoryProxy.ts b/packages/utilities/src/factories/factoryProxy.ts index 86020e79085..16fc81a8099 100644 --- a/packages/utilities/src/factories/factoryProxy.ts +++ b/packages/utilities/src/factories/factoryProxy.ts @@ -15,7 +15,7 @@ const factoryProxyHandler = { get( target: typeof Factory, prop: keyof typeof Factory, - receiver: typeof Factory + receiver: typeof Factory, ) { if (prop === 'each') { return (fn: (index: number) => number | string) => { diff --git a/packages/utilities/src/factories/grants.ts b/packages/utilities/src/factories/grants.ts index ab992b5382a..d364456861c 100644 --- a/packages/utilities/src/factories/grants.ts +++ b/packages/utilities/src/factories/grants.ts @@ -37,10 +37,11 @@ export const grantsFactory = Factory.Sync.makeFactory({ add_domains: true, add_firewalls: true, add_images: true, - add_kubernetes: true, add_linodes: true, + add_lkes: true, add_longview: true, add_nodebalancers: true, + add_kubernetes: true, add_stackscripts: true, add_volumes: true, add_vpcs: true, @@ -62,6 +63,13 @@ export const grantsFactory = Factory.Sync.makeFactory({ permissions: 'read_only', }, ], + lkecluster: [ + { + id: 123, + label: 'example-entity', + permissions: 'read_only', + }, + ], longview: [ { id: 123, diff --git a/packages/utilities/src/factories/linodeInterface.ts b/packages/utilities/src/factories/linodeInterface.ts index 7c6a422f2ee..e1aef5c9cc0 100644 --- a/packages/utilities/src/factories/linodeInterface.ts +++ b/packages/utilities/src/factories/linodeInterface.ts @@ -4,8 +4,8 @@ import { Factory } from './factoryProxy'; import type { LinodeInterface, LinodeInterfaceSettings } from '@linode/api-v4'; -export const linodeInterfaceSettingsFactory = Factory.Sync.makeFactory( - { +export const linodeInterfaceSettingsFactory = + Factory.Sync.makeFactory({ network_helper: false, default_route: { ipv4_interface_id: 1, @@ -13,11 +13,10 @@ export const linodeInterfaceSettingsFactory = Factory.Sync.makeFactory( - { +export const linodeInterfaceFactoryVlan = + Factory.Sync.makeFactory({ created: '2025-03-19T03:58:04', default_route: { ipv4: true, @@ -32,11 +31,10 @@ export const linodeInterfaceFactoryVlan = Factory.Sync.makeFactory( - { +export const linodeInterfaceFactoryVPC = + Factory.Sync.makeFactory({ created: '2025-03-19T03:58:04', default_route: { ipv4: true, @@ -64,11 +62,10 @@ export const linodeInterfaceFactoryVPC = Factory.Sync.makeFactory( - { +export const linodeInterfaceFactoryPublic = + Factory.Sync.makeFactory({ created: '2025-03-19T03:58:04', default_route: { ipv4: true, @@ -95,5 +92,4 @@ export const linodeInterfaceFactoryPublic = Factory.Sync.makeFactory( resolvers: resolverFactory.build(), site_type: 'core', status: 'ok', - } + }, ); -export const regionAvailabilityFactory = Factory.Sync.makeFactory( - { +export const regionAvailabilityFactory = + Factory.Sync.makeFactory({ available: false, plan: 'g6-standard-7', region: 'us-east', - } -); + }); diff --git a/packages/utilities/src/helpers/accountCapabilities.test.ts b/packages/utilities/src/helpers/accountCapabilities.test.ts index 981c55725f0..4f47ac6c7cf 100644 --- a/packages/utilities/src/helpers/accountCapabilities.test.ts +++ b/packages/utilities/src/helpers/accountCapabilities.test.ts @@ -13,7 +13,7 @@ describe('isFeatureEnabledV2', () => { it('returns `true` when the flag is on and the account capability is present', () => { expect(isFeatureEnabledV2('Object Storage', true, ['Object Storage'])).toBe( - true + true, ); }); @@ -33,13 +33,13 @@ describe('isFeatureEnabled', () => { it('returns `true` when the flag is off, but the account capability is present', () => { expect(isFeatureEnabled('Object Storage', false, ['Object Storage'])).toBe( - true + true, ); }); it('returns `true` when both the flag is on and the account capability is present', () => { expect(isFeatureEnabled('Object Storage', true, ['Object Storage'])).toBe( - true + true, ); }); }); diff --git a/packages/utilities/src/helpers/accountCapabilities.ts b/packages/utilities/src/helpers/accountCapabilities.ts index 1827187dd32..820134eb0ef 100644 --- a/packages/utilities/src/helpers/accountCapabilities.ts +++ b/packages/utilities/src/helpers/accountCapabilities.ts @@ -11,7 +11,7 @@ import type { AccountCapability } from '@linode/api-v4'; export const isFeatureEnabledV2 = ( featureName: AccountCapability, isFeatureFlagEnabled: boolean, - capabilities: AccountCapability[] + capabilities: AccountCapability[], ) => { return isFeatureFlagEnabled && capabilities.includes(featureName); }; @@ -34,7 +34,7 @@ export const isFeatureEnabledV2 = ( export const isFeatureEnabled = ( featureName: AccountCapability, isFeatureFlagEnabled: boolean, - capabilities: AccountCapability[] + capabilities: AccountCapability[], ) => { return isFeatureFlagEnabled || capabilities.includes(featureName); }; diff --git a/packages/utilities/src/helpers/arePropsEqual.ts b/packages/utilities/src/helpers/arePropsEqual.ts index 9f7023f4161..e4d63fbf699 100644 --- a/packages/utilities/src/helpers/arePropsEqual.ts +++ b/packages/utilities/src/helpers/arePropsEqual.ts @@ -7,7 +7,7 @@ export const arePropsEqual = ( props: (keyof T)[], prevProps: T, - nextProps: T + nextProps: T, ): boolean => { let areEqual = true; props.forEach((prop) => { diff --git a/packages/utilities/src/helpers/betaUtils.test.ts b/packages/utilities/src/helpers/betaUtils.test.ts index d5800f6e9de..043a14e2be1 100644 --- a/packages/utilities/src/helpers/betaUtils.test.ts +++ b/packages/utilities/src/helpers/betaUtils.test.ts @@ -1,19 +1,18 @@ import { DateTime } from 'luxon'; import { beforeEach, describe, expect, it } from 'vitest'; +import { accountBetaFactory, betaFactory } from '../factories'; import { - hasStarted, canEnd, - willEnd, - willStart, + getBetaStatus, hasEnded, + hasStarted, isCustomerEnrolled, wasCustomerEnrolled, - getBetaStatus, + willEnd, + willStart, } from './betaUtils'; -import { accountBetaFactory, betaFactory } from '../factories'; - const generateTestBetas = () => ({ activeNeverEndingBeta: betaFactory.build({ started: DateTime.now().minus({ days: 30 }).toISO(), diff --git a/packages/utilities/src/helpers/betaUtils.ts b/packages/utilities/src/helpers/betaUtils.ts index 9298858af47..bc69cce6418 100644 --- a/packages/utilities/src/helpers/betaUtils.ts +++ b/packages/utilities/src/helpers/betaUtils.ts @@ -1,6 +1,7 @@ -import { AccountBeta, Beta } from '@linode/api-v4'; import { DateTime } from 'luxon'; +import type { AccountBeta, Beta } from '@linode/api-v4'; + type BetaStatus = 'active' | 'available' | 'historical' | 'no_status'; type GenericBeta = AccountBeta | Beta; type GenericBetaByStatus = { diff --git a/packages/utilities/src/helpers/createDevicesFromStrings.ts b/packages/utilities/src/helpers/createDevicesFromStrings.ts index e3a6fff9dbf..66e214b08d5 100644 --- a/packages/utilities/src/helpers/createDevicesFromStrings.ts +++ b/packages/utilities/src/helpers/createDevicesFromStrings.ts @@ -1,4 +1,4 @@ -import { Devices } from '@linode/api-v4/lib/linodes'; +import type { Devices } from '@linode/api-v4/lib/linodes'; type DiskRecord = Record<'disk_id', number>; @@ -18,7 +18,7 @@ export interface DevicesAsStrings { /** * The `value` should be formatted as volume-123, disk-123, etc., */ -const createTypeRecord = (value?: string): DiskRecord | VolumeRecord | null => { +const createTypeRecord = (value?: string): DiskRecord | null | VolumeRecord => { if (value === null || value === undefined || value === 'none') { return null; } @@ -37,7 +37,7 @@ const createTypeRecord = (value?: string): DiskRecord | VolumeRecord | null => { }; export const createDevicesFromStrings = ( - devices: DevicesAsStrings + devices: DevicesAsStrings, ): Devices => ({ sda: createTypeRecord(devices.sda), sdb: createTypeRecord(devices.sdb), diff --git a/packages/utilities/src/helpers/createStringsFromDevices.ts b/packages/utilities/src/helpers/createStringsFromDevices.ts index d31f27dff46..76380462fe7 100644 --- a/packages/utilities/src/helpers/createStringsFromDevices.ts +++ b/packages/utilities/src/helpers/createStringsFromDevices.ts @@ -1,13 +1,13 @@ +import type { DevicesAsStrings } from './createDevicesFromStrings'; import type { Devices, DiskDevice, VolumeDevice, } from '@linode/api-v4/lib/linodes'; -import type { DevicesAsStrings } from './createDevicesFromStrings'; const rdx = ( result: DevicesAsStrings, - [key, device]: [string, DiskDevice | VolumeDevice | null] + [key, device]: [string, DiskDevice | null | VolumeDevice], ) => { if (device === null) { return result; @@ -28,7 +28,7 @@ const isDisk = (device: DiskDevice | VolumeDevice): device is DiskDevice => { return typeof (device as DiskDevice).disk_id === 'number'; }; const isVolume = ( - device: DiskDevice | VolumeDevice + device: DiskDevice | VolumeDevice, ): device is VolumeDevice => { return typeof (device as VolumeDevice).volume_id === 'number'; }; diff --git a/packages/utilities/src/helpers/deepStringTransform.ts b/packages/utilities/src/helpers/deepStringTransform.ts index b50306c2331..8c30595c467 100644 --- a/packages/utilities/src/helpers/deepStringTransform.ts +++ b/packages/utilities/src/helpers/deepStringTransform.ts @@ -2,7 +2,7 @@ // function to the value recursively. Useful for redacting string patterns. export const deepStringTransform = ( value: any, - fn: (s: string) => string + fn: (s: string) => string, ): any => { if (typeof value === 'string') { return fn(value); diff --git a/packages/utilities/src/helpers/doesRegionSupportFeature.test.ts b/packages/utilities/src/helpers/doesRegionSupportFeature.test.ts index 366d5eb4120..49116cb3688 100644 --- a/packages/utilities/src/helpers/doesRegionSupportFeature.test.ts +++ b/packages/utilities/src/helpers/doesRegionSupportFeature.test.ts @@ -1,7 +1,6 @@ -import { regions } from '../__data__'; - import { describe, expect, it } from 'vitest'; +import { regions } from '../__data__'; import { doesRegionSupportFeature } from './doesRegionSupportFeature'; const blockStorage = 'Block Storage'; @@ -9,13 +8,13 @@ const blockStorage = 'Block Storage'; describe('does region support Block Storage', () => { it('returns true if the region supports Block Storage', () => { expect(doesRegionSupportFeature('us-central', regions, blockStorage)).toBe( - true + true, ); }); it('returns false if the region does not support Block Storage', () => { expect( - doesRegionSupportFeature('ap-northeast-1a', regions, blockStorage) + doesRegionSupportFeature('ap-northeast-1a', regions, blockStorage), ).toBe(false); }); }); diff --git a/packages/utilities/src/helpers/doesRegionSupportFeature.ts b/packages/utilities/src/helpers/doesRegionSupportFeature.ts index 03fe162eb15..c8b5bc71347 100644 --- a/packages/utilities/src/helpers/doesRegionSupportFeature.ts +++ b/packages/utilities/src/helpers/doesRegionSupportFeature.ts @@ -1,9 +1,9 @@ -import { Capabilities, Region } from '@linode/api-v4/lib/regions'; +import type { Capabilities, Region } from '@linode/api-v4/lib/regions'; export const doesRegionSupportFeature = ( region: string, regionsData: Region[], - feature: Capabilities + feature: Capabilities, ) => { const regionMetaData = regionsData.find((thisRegion) => { return thisRegion.id === region; @@ -16,7 +16,7 @@ export const doesRegionSupportFeature = ( export const regionsWithFeature = ( regionsData: Region[], - feature: Capabilities + feature: Capabilities, ) => { return regionsData.filter((region) => region.capabilities.includes(feature)); }; diff --git a/packages/utilities/src/helpers/formatDuration.test.ts b/packages/utilities/src/helpers/formatDuration.test.ts index 281615d66fb..9b4b57f6ad9 100644 --- a/packages/utilities/src/helpers/formatDuration.test.ts +++ b/packages/utilities/src/helpers/formatDuration.test.ts @@ -1,6 +1,5 @@ -import { describe, expect, it } from 'vitest'; - import { Duration } from 'luxon'; +import { describe, expect, it } from 'vitest'; import { formatDuration } from './formatDuration'; diff --git a/packages/utilities/src/helpers/formatDuration.ts b/packages/utilities/src/helpers/formatDuration.ts index 759701cc79e..8efaef66145 100644 --- a/packages/utilities/src/helpers/formatDuration.ts +++ b/packages/utilities/src/helpers/formatDuration.ts @@ -1,4 +1,4 @@ -import { Duration } from 'luxon'; +import type { Duration } from 'luxon'; /** * Will format duration (for server tasks) in hours, minutes and seconds * We do not handle larger units as this is not really a use case diff --git a/packages/utilities/src/helpers/formatUptime.test.ts b/packages/utilities/src/helpers/formatUptime.test.ts index fb2738f4617..d9947a9e54a 100644 --- a/packages/utilities/src/helpers/formatUptime.test.ts +++ b/packages/utilities/src/helpers/formatUptime.test.ts @@ -1,6 +1,5 @@ -import { describe, expect, it } from 'vitest'; - import { Duration } from 'luxon'; +import { describe, expect, it } from 'vitest'; import { formatUptime } from './formatUptime'; @@ -29,15 +28,17 @@ describe('Formatting uptime', () => { it('should handle all the things', () => { expect( - formatUptime(60 * 60 * 24 * 9 + 60 * 60 * 19 + 60 * 45 + 45) + formatUptime(60 * 60 * 24 * 9 + 60 * 60 * 19 + 60 * 45 + 45), ).toMatch('9d 19h 45m'); }); it('should handle durations longer than a month', () => { expect( formatUptime( - Duration.fromObject({ days: 438, hours: 10, minutes: 15 }).as('seconds') - ) + Duration.fromObject({ days: 438, hours: 10, minutes: 15 }).as( + 'seconds', + ), + ), ).toMatch('438d 10h 15m'); }); @@ -49,8 +50,8 @@ describe('Formatting uptime', () => { hours: 8, minutes: 15, seconds: 54, - }).as('seconds') - ) + }).as('seconds'), + ), ).toMatch('438d 8h 15m'); }); }); diff --git a/packages/utilities/src/helpers/formatUptime.ts b/packages/utilities/src/helpers/formatUptime.ts index 44c99b207db..35c8bf08b52 100644 --- a/packages/utilities/src/helpers/formatUptime.ts +++ b/packages/utilities/src/helpers/formatUptime.ts @@ -12,7 +12,7 @@ export const formatUptime = (uptime: number) => { .minus({ days, }) - .as('hours') + .as('hours'), ); const minutes = Math.floor( duration @@ -20,7 +20,7 @@ export const formatUptime = (uptime: number) => { days, hours, }) - .as('minutes') + .as('minutes'), ); const seconds = Math.floor( duration @@ -29,7 +29,7 @@ export const formatUptime = (uptime: number) => { hours, minutes, }) - .as('seconds') + .as('seconds'), ); if (days > 0) { return `${days}d ${hours}h ${minutes}m`; diff --git a/packages/utilities/src/helpers/getAll.ts b/packages/utilities/src/helpers/getAll.ts index f1c97a605dd..74234a1472c 100644 --- a/packages/utilities/src/helpers/getAll.ts +++ b/packages/utilities/src/helpers/getAll.ts @@ -13,13 +13,13 @@ export interface APIResponsePage { export type GetFunction = ( params?: Params, - filters?: Filter + filters?: Filter, ) => Promise>; export type GetFromEntity = ( entityId?: number, params?: Params, - filters?: Filter + filters?: Filter, ) => Promise>; export interface GetAllData { @@ -53,53 +53,52 @@ export interface GetAllData { export const getAll: ( getter: GetFunction, pageSize?: number, - cb?: (results: number) => void -) => (params?: Params, filter?: Filter) => Promise> = ( - getter, - pageSize = API_MAX_PAGE_SIZE, - cb -) => (params?: Params, filter?: Filter) => { - const pagination = { ...params, page_size: pageSize }; - return getter(pagination, filter).then( - ({ data: firstPageData, page, pages, results }) => { - // If we only have one page, return it. - if (page === pages) { - return { - data: firstPageData, - results, - }; - } + cb?: (results: number) => void, +) => (params?: Params, filter?: Filter) => Promise> = + (getter, pageSize = API_MAX_PAGE_SIZE, cb) => + (params?: Params, filter?: Filter) => { + const pagination = { ...params, page_size: pageSize }; + return getter(pagination, filter).then( + ({ data: firstPageData, page, pages, results }) => { + // If we only have one page, return it. + if (page === pages) { + return { + data: firstPageData, + results, + }; + } - // If the number of results is over the threshold, use the callback - // to mark the account as large - if (cb) { - cb(results); - } + // If the number of results is over the threshold, use the callback + // to mark the account as large + if (cb) { + cb(results); + } - // Create an iterable list of the remaining pages. - const remainingPages = range(page + 1, pages + 1); + // Create an iterable list of the remaining pages. + const remainingPages = range(page + 1, pages + 1); - const promises: Promise[] = []; - remainingPages.forEach((thisPage) => { - const promise = getter({ ...pagination, page: thisPage }, filter).then( - (response) => response.data + const promises: Promise[] = []; + remainingPages.forEach((thisPage) => { + const promise = getter( + { ...pagination, page: thisPage }, + filter, + ).then((response) => response.data); + promises.push(promise); + }); + // + return ( + Promise.all(promises) + /** We're given data[][], so we flatten that, and append the first page response. */ + .then((resultPages) => { + const combinedData = resultPages.reduce((result, nextPage) => { + return [...result, ...nextPage]; + }, firstPageData); + return { + data: combinedData, + results, + }; + }) ); - promises.push(promise); - }); - // - return ( - Promise.all(promises) - /** We're given data[][], so we flatten that, and append the first page response. */ - .then((resultPages) => { - const combinedData = resultPages.reduce((result, nextPage) => { - return [...result, ...nextPage]; - }, firstPageData); - return { - data: combinedData, - results, - }; - }) - ); - } - ); -}; + }, + ); + }; diff --git a/packages/utilities/src/helpers/getDisplayName.ts b/packages/utilities/src/helpers/getDisplayName.ts index acc8ad78bb9..a24fbf3a72a 100644 --- a/packages/utilities/src/helpers/getDisplayName.ts +++ b/packages/utilities/src/helpers/getDisplayName.ts @@ -1,4 +1,4 @@ -import * as React from 'react'; +import type * as React from 'react'; export const getDisplayName =

(Component: React.ComponentType

) => { return Component.displayName || Component.name || 'Component'; diff --git a/packages/utilities/src/helpers/getIsLegacyInterfaceArray.test.ts b/packages/utilities/src/helpers/getIsLegacyInterfaceArray.test.ts index d8d6d0d2b53..d27dceed6bf 100644 --- a/packages/utilities/src/helpers/getIsLegacyInterfaceArray.test.ts +++ b/packages/utilities/src/helpers/getIsLegacyInterfaceArray.test.ts @@ -3,8 +3,8 @@ import { describe, expect, it } from 'vitest'; import { linodeConfigInterfaceFactory, linodeInterfaceFactoryPublic, - linodeInterfaceFactoryVPC, linodeInterfaceFactoryVlan, + linodeInterfaceFactoryVPC, } from '../factories'; import { getIsLegacyInterfaceArray } from './getIsLegacyInterfaceArray'; diff --git a/packages/utilities/src/helpers/getUserTimezone.test.ts b/packages/utilities/src/helpers/getUserTimezone.test.ts index 694f8ad6be0..7bf1fde64bf 100644 --- a/packages/utilities/src/helpers/getUserTimezone.test.ts +++ b/packages/utilities/src/helpers/getUserTimezone.test.ts @@ -1,9 +1,8 @@ -import { describe, expect, it } from 'vitest'; - import { DateTime } from 'luxon'; +import { describe, expect, it } from 'vitest'; -import { getUserTimezone } from './getUserTimezone'; import { profileFactory } from '../factories/profile'; +import { getUserTimezone } from './getUserTimezone'; import type { Profile } from '@linode/api-v4/lib/profile'; diff --git a/packages/utilities/src/helpers/groupByTags.test.ts b/packages/utilities/src/helpers/groupByTags.test.ts index 275ea9a8a5f..1f00f5492f4 100644 --- a/packages/utilities/src/helpers/groupByTags.test.ts +++ b/packages/utilities/src/helpers/groupByTags.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { NONE, groupByTags } from './groupByTags'; +import { groupByTags, NONE } from './groupByTags'; /** * [Tag, Linode[]]s */ diff --git a/packages/utilities/src/helpers/initWindows.ts b/packages/utilities/src/helpers/initWindows.ts index 26ef3ec0597..b202fce38d1 100644 --- a/packages/utilities/src/helpers/initWindows.ts +++ b/packages/utilities/src/helpers/initWindows.ts @@ -4,7 +4,7 @@ import { DateTime } from 'luxon'; export const initWindows = (timezone: string, unshift?: boolean) => { let windows = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22].map((hour) => { const start = DateTime.fromObject({ hour }, { zone: 'utc' }).setZone( - timezone + timezone, ); const finish = start.plus({ hours: 2 }); return [ diff --git a/packages/utilities/src/helpers/isToday.test.ts b/packages/utilities/src/helpers/isToday.test.ts index 004b052e546..c72c3a916b1 100644 --- a/packages/utilities/src/helpers/isToday.test.ts +++ b/packages/utilities/src/helpers/isToday.test.ts @@ -1,6 +1,5 @@ -import { describe, expect, it } from 'vitest'; - import { DateTime } from 'luxon'; +import { describe, expect, it } from 'vitest'; import { isToday } from './isToday'; @@ -9,8 +8,8 @@ describe('isToday helper utility', () => { expect( isToday( DateTime.local().valueOf() / 1000, - DateTime.local().plus({ hours: 5 }).valueOf() / 1000 - ) + DateTime.local().plus({ hours: 5 }).valueOf() / 1000, + ), ).toBe(true); }); @@ -18,8 +17,8 @@ describe('isToday helper utility', () => { expect( isToday( DateTime.local().valueOf() / 1000, - DateTime.local().valueOf() / 1000 - ) + DateTime.local().valueOf() / 1000, + ), ).toBe(true); }); @@ -27,14 +26,14 @@ describe('isToday helper utility', () => { expect( isToday( DateTime.local().valueOf() / 1000, - DateTime.local().plus({ hours: 25 }).valueOf() / 1000 - ) + DateTime.local().plus({ hours: 25 }).valueOf() / 1000, + ), ).toBe(false); expect( isToday( DateTime.local().valueOf() / 1000, - DateTime.local().plus({ months: 1 }).valueOf() / 1000 - ) + DateTime.local().plus({ months: 1 }).valueOf() / 1000, + ), ).toBe(false); }); }); diff --git a/packages/utilities/src/helpers/link.ts b/packages/utilities/src/helpers/link.ts index 08d8f7aafda..17ecbb537d6 100644 --- a/packages/utilities/src/helpers/link.ts +++ b/packages/utilities/src/helpers/link.ts @@ -14,7 +14,7 @@ export const opensInNewTab = (href: string) => { * @returns string */ export const flattenChildrenIntoAriaLabel = ( - children: React.ReactNode + children: React.ReactNode, ): string => { if (typeof children === 'string') { return children; diff --git a/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.test.ts b/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.test.ts index 9c9da2e0941..476c7573c8f 100644 --- a/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.test.ts +++ b/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.test.ts @@ -28,7 +28,7 @@ describe('manually setting VPC Configs to active', () => { const linodeInterface = updatedConfigs[0].interfaces[i]; if (linodeInterface.purpose !== 'vpc') { expect(linodeInterface.active).toEqual( - oldConfigState.interfaces?.[i].active + oldConfigState.interfaces?.[i].active, ); } else { expect(linodeInterface.active).toBe(true); diff --git a/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.ts b/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.ts index 71dc0f7b09c..bbcf9915345 100644 --- a/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.ts +++ b/packages/utilities/src/helpers/manuallySetVPCConfigInterfacesToActive.ts @@ -4,7 +4,7 @@ import type { Config } from '@linode/api-v4'; // to this in order to address the flickering 'Reboot Needed' status issue (see PR#9893). // NOTE: This logic only works for linodes with one configuration/one vpc interface, and will lead to VERY CONFUSING results for linodes with multiple configurations. export const manuallySetVPCConfigInterfacesToActive = ( - configs: Config[] + configs: Config[], ): Config[] => { return configs.map((config) => { return { diff --git a/packages/utilities/src/helpers/mapIdsToDevices.test.ts b/packages/utilities/src/helpers/mapIdsToDevices.test.ts index b379a125582..5c4045571f3 100644 --- a/packages/utilities/src/helpers/mapIdsToDevices.test.ts +++ b/packages/utilities/src/helpers/mapIdsToDevices.test.ts @@ -1,9 +1,9 @@ -import { linodeFactory, nodeBalancerFactory } from '../factories'; -import { describe, it, expect } from 'vitest'; +import { describe, expect, it } from 'vitest'; +import { linodeFactory, nodeBalancerFactory } from '../factories'; import { mapIdsToDevices } from './mapIdsToDevices'; -import type { NodeBalancer, Linode } from '@linode/api-v4'; +import type { Linode, NodeBalancer } from '@linode/api-v4'; describe('mapIdsToDevices', () => { const linodes = linodeFactory.buildList(5); @@ -15,7 +15,7 @@ describe('mapIdsToDevices', () => { it('works with a single NodeBalancer ID', () => { expect(mapIdsToDevices(1, nodebalancers)).toBe( - nodebalancers[0] + nodebalancers[0], ); }); diff --git a/packages/utilities/src/helpers/mapIdsToDevices.ts b/packages/utilities/src/helpers/mapIdsToDevices.ts index 065b86ff360..d0a724f8860 100644 --- a/packages/utilities/src/helpers/mapIdsToDevices.ts +++ b/packages/utilities/src/helpers/mapIdsToDevices.ts @@ -6,11 +6,11 @@ type Device = Linode | NodeBalancer; export const mapIdsToDevices = ( ids: null | number | number[], - devices: T[] = [] -): T | T[] | null => { + devices: T[] = [], +): null | T | T[] => { const deviceMap = new Map( // Even though the types extend Device. type insertion is still required here - devices.map((device) => [device.id, device]) + devices.map((device) => [device.id, device]), ); if (Array.isArray(ids)) { return ids.map((id) => deviceMap.get(id)).filter(isNotNullOrUndefined); diff --git a/packages/utilities/src/helpers/metadata.ts b/packages/utilities/src/helpers/metadata.ts index 316de26ad72..7c3209a3f6c 100644 --- a/packages/utilities/src/helpers/metadata.ts +++ b/packages/utilities/src/helpers/metadata.ts @@ -14,7 +14,7 @@ export const utoa = (data: string) => { export const regionSupportsMetadata = ( regionsData: Region[], - region: string + region: string, ) => { return ( regionsData diff --git a/packages/utilities/src/helpers/minute-conversion.test.ts b/packages/utilities/src/helpers/minute-conversion.test.ts index f99b80b5879..fda522ec2af 100644 --- a/packages/utilities/src/helpers/minute-conversion.test.ts +++ b/packages/utilities/src/helpers/minute-conversion.test.ts @@ -28,14 +28,14 @@ describe('Human-Readable Minute Conversion', () => { it('should return days, hours, and minutes', () => { expect(generateMigrationTimeString(1440)).toBe(`1 day and 0 minutes`); expect(generateMigrationTimeString(1500)).toBe( - `1 day, 1 hour, and 0 minutes` + `1 day, 1 hour, and 0 minutes`, ); expect(generateMigrationTimeString(2800)).toBe( - `1 day, 22 hours, and 40 minutes` + `1 day, 22 hours, and 40 minutes`, ); expect(generateMigrationTimeString(0)).toBe(`0 minutes`); expect(generateMigrationTimeString(2820)).toBe( - `1 day, 23 hours, and 0 minutes` + `1 day, 23 hours, and 0 minutes`, ); expect(generateMigrationTimeString(2880)).toBe(`2 days and 0 minutes`); }); diff --git a/packages/utilities/src/helpers/minute-conversion.ts b/packages/utilities/src/helpers/minute-conversion.ts index 3812e14cf95..7399c85d60e 100644 --- a/packages/utilities/src/helpers/minute-conversion.ts +++ b/packages/utilities/src/helpers/minute-conversion.ts @@ -18,7 +18,7 @@ import { pluralize } from './pluralize'; export const convertMinutesTo = ( minutes: number, conversion: 'days' | 'hours', - includeRemainder: boolean = false + includeRemainder: boolean = false, ): string => { if (conversion === 'hours') { return includeRemainder @@ -45,27 +45,27 @@ export const generateMigrationTimeString = (migrationTimeInMins: number) => { const daysAndMinutes = convertMinutesTo( migrationTimeInMins, 'days', - true + true, ).split(','); if (+daysAndMinutes[1] >= 60) { const [hours, minutes] = convertMinutesTo( +daysAndMinutes[1], 'hours', - true + true, ).split(','); return `${pluralize('day', 'days', +daysAndMinutes[0])}, ${pluralize( 'hour', 'hours', - +hours + +hours, )}, and ${pluralize('minute', 'minutes', +minutes)}`; } return `${pluralize('day', 'days', +daysAndMinutes[0])} and ${pluralize( 'minute', 'minutes', - +daysAndMinutes[1] + +daysAndMinutes[1], )}`; } @@ -74,13 +74,13 @@ export const generateMigrationTimeString = (migrationTimeInMins: number) => { const hoursAndMinutes = convertMinutesTo( migrationTimeInMins, 'hours', - true + true, ).split(','); return `${pluralize('hour', 'hours', +hoursAndMinutes[0])} and ${pluralize( 'minute', 'minutes', - +hoursAndMinutes[1] + +hoursAndMinutes[1], )}`; } @@ -101,7 +101,7 @@ export const formatEventSeconds = (seconds: null | number) => { : `${pluralize('hour', 'hours', hours)}, ${pluralize( 'minute', 'minutes', - minutes + minutes, )}`; } @@ -114,7 +114,7 @@ export const formatEventSeconds = (seconds: null | number) => { : `${pluralize('minute', 'minutes', minutes)}, ${pluralize( 'second', 'seconds', - secs + secs, )}`; } diff --git a/packages/utilities/src/helpers/mockLocalStorage.ts b/packages/utilities/src/helpers/mockLocalStorage.ts index cd3bf97992a..40c5dfe185d 100644 --- a/packages/utilities/src/helpers/mockLocalStorage.ts +++ b/packages/utilities/src/helpers/mockLocalStorage.ts @@ -9,6 +9,8 @@ * }); */ export class LocalStorageMock { + store: any = {}; + clear() { this.store = {}; } @@ -24,6 +26,4 @@ export class LocalStorageMock { setItem(key: string, value: string) { this.store[key] = value.toString(); } - - store: any = {}; } diff --git a/packages/utilities/src/helpers/nullOrUndefined.ts b/packages/utilities/src/helpers/nullOrUndefined.ts index 125bb25278a..2dcbe377080 100644 --- a/packages/utilities/src/helpers/nullOrUndefined.ts +++ b/packages/utilities/src/helpers/nullOrUndefined.ts @@ -1,8 +1,8 @@ export const isNullOrUndefined = ( - value: unknown + value: unknown, ): value is null | undefined => { return value === null || value === undefined; }; -export const isNotNullOrUndefined = (el: T | null | undefined): el is T => +export const isNotNullOrUndefined = (el: null | T | undefined): el is T => !isNullOrUndefined(el); diff --git a/packages/utilities/src/helpers/pathOr.ts b/packages/utilities/src/helpers/pathOr.ts index be60f181ac2..1912602dfce 100644 --- a/packages/utilities/src/helpers/pathOr.ts +++ b/packages/utilities/src/helpers/pathOr.ts @@ -8,7 +8,7 @@ export const pathOr = ( defaultValue: T, path: (number | string)[], - object: O + object: O, ): T => { if (object === undefined) { return defaultValue; diff --git a/packages/utilities/src/helpers/planNotices.ts b/packages/utilities/src/helpers/planNotices.ts index e4ecf764d57..75dd371792c 100644 --- a/packages/utilities/src/helpers/planNotices.ts +++ b/packages/utilities/src/helpers/planNotices.ts @@ -64,15 +64,15 @@ export const getCapabilityFromPlanType = ( planType: LinodeTypeClass, ): Capabilities => { switch (planType) { + case 'accelerated': { + return 'NETINT Quadra T1U'; + } case 'gpu': { return 'GPU Linodes'; } case 'premium': { return 'Premium Plans'; } - case 'accelerated': { - return 'NETINT Quadra T1U'; - } default: { return 'Linodes'; } diff --git a/packages/utilities/src/helpers/pluralize.ts b/packages/utilities/src/helpers/pluralize.ts index 7dd429efe7b..506c4c8eafd 100644 --- a/packages/utilities/src/helpers/pluralize.ts +++ b/packages/utilities/src/helpers/pluralize.ts @@ -1,7 +1,7 @@ export const pluralize = ( single: string, plural: string, - value: number | string + value: number | string, ) => { return value === 1 ? `${value} ${single}` : `${value} ${plural}`; }; diff --git a/packages/utilities/src/helpers/queryParams.test.ts b/packages/utilities/src/helpers/queryParams.test.ts index 4ab259996ab..c643192e83e 100644 --- a/packages/utilities/src/helpers/queryParams.test.ts +++ b/packages/utilities/src/helpers/queryParams.test.ts @@ -30,30 +30,30 @@ describe('Url/query parsing utilities', () => { describe('getQueryParam method', () => { it('should get the value of a query parameter', () => { expect(getQueryParamFromQueryString('?query=false', 'query')).toEqual( - 'false' + 'false', ); }); it('should return the default value if no value is present', () => { expect( - getQueryParamFromQueryString('?query=', 'notaquery', 'defaultQuery') + getQueryParamFromQueryString('?query=', 'notaquery', 'defaultQuery'), ).toEqual('defaultQuery'); }); it('should handle a blank param value', () => { expect( - getQueryParamFromQueryString('?query=', 'query', 'defaultQuery') + getQueryParamFromQueryString('?query=', 'query', 'defaultQuery'), ).toEqual(''); }); it('should not care about the initial ?', () => { expect(getQueryParamFromQueryString('query=blue', 'query')).toEqual( - 'blue' + 'blue', ); }); it('should return a single query param from a URL string', () => { expect( getQueryParamFromQueryString( 'https://example.com/?query=false&this=that', - 'this' - ) + 'this', + ), ).toBe('that'); }); it('should return the default value if no value is present', () => { @@ -61,8 +61,8 @@ describe('Url/query parsing utilities', () => { getQueryParamFromQueryString( 'https://example.com/?query=', 'notaquery', - 'defaultQuery' - ) + 'defaultQuery', + ), ).toEqual('defaultQuery'); }); }); diff --git a/packages/utilities/src/helpers/queryParams.ts b/packages/utilities/src/helpers/queryParams.ts index dc84fe377d2..cdc00fd2e5a 100644 --- a/packages/utilities/src/helpers/queryParams.ts +++ b/packages/utilities/src/helpers/queryParams.ts @@ -16,7 +16,7 @@ export interface BaseQueryParams { * // { query: 'false', this: 'that' } */ export const getQueryParamsFromQueryString = ( - queryString: string + queryString: string, ): T => Object.fromEntries(new URLSearchParams(queryString)) as T; /** @@ -33,7 +33,7 @@ export const getQueryParamsFromQueryString = ( export const getQueryParamFromQueryString = ( queryString: string, paramName: string, - defaultValue: string = '' + defaultValue: string = '', ) => { const params = new URLSearchParams(queryString); return params.get(paramName) ?? defaultValue; diff --git a/packages/utilities/src/helpers/redactAccessToken.test.ts b/packages/utilities/src/helpers/redactAccessToken.test.ts index b0b6614428d..1f060a7ed55 100644 --- a/packages/utilities/src/helpers/redactAccessToken.test.ts +++ b/packages/utilities/src/helpers/redactAccessToken.test.ts @@ -19,7 +19,7 @@ describe('redactAccessToken', () => { const url = `http://www.linode.com?something#whatever&access_token=ABC123`; const result = redactAccessToken(url); expect(result).toBe( - `http://www.linode.com?something#whatever&access_token=REDACTED` + `http://www.linode.com?something#whatever&access_token=REDACTED`, ); }); }); diff --git a/packages/utilities/src/helpers/reduceAsync.ts b/packages/utilities/src/helpers/reduceAsync.ts index 356e42512ab..a602a340b7b 100644 --- a/packages/utilities/src/helpers/reduceAsync.ts +++ b/packages/utilities/src/helpers/reduceAsync.ts @@ -12,7 +12,7 @@ export async function reduceAsync( arr: T[], fn: (accumulator: R, current: T, index: number, array: T[]) => Promise, - initialValue: R + initialValue: R, ): Promise { let accumulator = initialValue; diff --git a/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.test.tsx b/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.test.tsx index 789a2e566b3..db3576f659c 100644 --- a/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.test.tsx +++ b/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.test.tsx @@ -1,5 +1,4 @@ import React from 'react'; - import { describe, expect, it } from 'vitest'; import { replaceNewlinesWithLineBreaks } from './replaceNewlinesWithLineBreaks'; diff --git a/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.tsx b/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.tsx index 6d71c664d01..51c96d1f283 100644 --- a/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.tsx +++ b/packages/utilities/src/helpers/replaceNewlinesWithLineBreaks.tsx @@ -9,5 +9,5 @@ export const replaceNewlinesWithLineBreaks = (text: string) => {text}
- ) + ), ); diff --git a/packages/utilities/src/helpers/rootManager.test.ts b/packages/utilities/src/helpers/rootManager.test.ts index 3ae2c4f7492..4cb1fc6bf06 100644 --- a/packages/utilities/src/helpers/rootManager.test.ts +++ b/packages/utilities/src/helpers/rootManager.test.ts @@ -1,5 +1,4 @@ import { createRoot } from 'react-dom/client'; - import { beforeEach, describe, expect, it, vi } from 'vitest'; import { getRoot, rootInstances } from './rootManager'; diff --git a/packages/utilities/src/helpers/rootManager.ts b/packages/utilities/src/helpers/rootManager.ts index 313c1b83d80..267ee9f5a33 100644 --- a/packages/utilities/src/helpers/rootManager.ts +++ b/packages/utilities/src/helpers/rootManager.ts @@ -1,5 +1,4 @@ import { createRoot } from 'react-dom/client'; - import type { Root } from 'react-dom/client'; export const rootInstances = new Map(); diff --git a/packages/utilities/src/helpers/scrollErrorIntoView.ts b/packages/utilities/src/helpers/scrollErrorIntoView.ts index 3ea821ac59e..f89e8e099d5 100644 --- a/packages/utilities/src/helpers/scrollErrorIntoView.ts +++ b/packages/utilities/src/helpers/scrollErrorIntoView.ts @@ -4,7 +4,7 @@ */ export const scrollErrorIntoView = ( errorGroup?: string, - options?: ScrollIntoViewOptions + options?: ScrollIntoViewOptions, ) => { const errorScrollClassSelector = errorGroup ? `.error-for-scroll-${errorGroup}` diff --git a/packages/utilities/src/helpers/scrollErrorIntoViewV2.ts b/packages/utilities/src/helpers/scrollErrorIntoViewV2.ts index 25c3250f041..5cba1240951 100644 --- a/packages/utilities/src/helpers/scrollErrorIntoViewV2.ts +++ b/packages/utilities/src/helpers/scrollErrorIntoViewV2.ts @@ -10,7 +10,7 @@ * @param formContainerRef A React ref to the form element (or a form container since we're not always semantically aligned on form markup) that contains a potential field error. */ export const scrollErrorIntoViewV2 = ( - formContainerRef: React.RefObject + formContainerRef: React.RefObject, ) => { if (!formContainerRef.current) { return; @@ -23,7 +23,7 @@ export const scrollErrorIntoViewV2 = ( formContainerRef.current ) { const errorElement = formContainerRef.current.querySelector( - '[class*="error-for-scroll"]' + '[class*="error-for-scroll"]', ); if (errorElement) { errorElement.scrollIntoView({ diff --git a/packages/utilities/src/helpers/scrollTo.ts b/packages/utilities/src/helpers/scrollTo.ts index b3445ea42d9..bf7933e0fe5 100644 --- a/packages/utilities/src/helpers/scrollTo.ts +++ b/packages/utilities/src/helpers/scrollTo.ts @@ -1,4 +1,4 @@ -import * as React from 'react'; +import type * as React from 'react'; /** * @param [ref] {React.RefObject} - If provided with a React Ref Object we will scroll to the * top of it. diff --git a/packages/utilities/src/helpers/sort-by.ts b/packages/utilities/src/helpers/sort-by.ts index f5089295e94..410a1b872d5 100644 --- a/packages/utilities/src/helpers/sort-by.ts +++ b/packages/utilities/src/helpers/sort-by.ts @@ -67,7 +67,7 @@ export const sortByArrayLength = (a: any[], b: any[], order: SortOrder) => { export const sortByVersion = ( a: string, b: string, - order: SortOrder + order: SortOrder, ): number => { const aParts = a.split('.'); const bParts = b.split('.'); diff --git a/packages/utilities/src/helpers/splitAt.ts b/packages/utilities/src/helpers/splitAt.ts index c88618533a1..571751e6150 100644 --- a/packages/utilities/src/helpers/splitAt.ts +++ b/packages/utilities/src/helpers/splitAt.ts @@ -13,6 +13,6 @@ export function splitAt(index: number, input: string): [string, string]; * splitAt(3, [1, 2, 3, 4, 5]); // [[1, 2, 3], [4, 5]] * splitAt(3, "hello"); // ["hel", "lo"] */ -export function splitAt(index: number, input: T[] | string) { +export function splitAt(index: number, input: string | T[]) { return [input.slice(0, index), input.slice(index)]; } diff --git a/packages/utilities/src/helpers/statMetrics.test.ts b/packages/utilities/src/helpers/statMetrics.test.ts index 0f16afb32d9..b7faf5c9c66 100644 --- a/packages/utilities/src/helpers/statMetrics.test.ts +++ b/packages/utilities/src/helpers/statMetrics.test.ts @@ -29,7 +29,7 @@ describe('Stat Metrics', () => { getMetrics([ [0, 0], [0, 0], - ]).max + ]).max, ).toBe(0); }); @@ -40,20 +40,20 @@ describe('Stat Metrics', () => { getMetrics([ [0, 0], [0, 0], - ]).average + ]).average, ).toBe(0); expect( getMetrics([ [0, 0], [0, 1], - ]).average + ]).average, ).toBe(0.5); expect( getMetrics([ [0, 0], [0, 3], [0, 12], - ]).average + ]).average, ).toBe(5); }); @@ -95,7 +95,7 @@ describe('Stat Metrics', () => { getMetrics([ [3, 'hello'], ['hello', 3], - ] as any) + ] as any), ).toEqual({ average: 1.5, last: 3, @@ -113,7 +113,7 @@ describe('total traffic', () => { expect(totalTraffic.outTraffic).toBe(10800); expect(totalTraffic.combinedTraffic).toBe(16200); expect(totalTraffic.combinedTraffic).toEqual( - totalTraffic.inTraffic + totalTraffic.outTraffic + totalTraffic.inTraffic + totalTraffic.outTraffic, ); }); }); diff --git a/packages/utilities/src/helpers/statMetrics.tsx b/packages/utilities/src/helpers/statMetrics.tsx index 224b9674f98..e8107476280 100644 --- a/packages/utilities/src/helpers/statMetrics.tsx +++ b/packages/utilities/src/helpers/statMetrics.tsx @@ -64,7 +64,7 @@ export const getTotalTraffic = ( outBits: number, length: number, inBitsV6?: number, - outBitsV6?: number + outBitsV6?: number, ): TotalTrafficResults => { if (inBitsV6) { inBits += inBitsV6; diff --git a/packages/utilities/src/helpers/stringUtils.ts b/packages/utilities/src/helpers/stringUtils.ts index c183b3af87d..1cf1637c82e 100644 --- a/packages/utilities/src/helpers/stringUtils.ts +++ b/packages/utilities/src/helpers/stringUtils.ts @@ -16,7 +16,7 @@ export const truncateAndJoinList = ( strList: string[], max = 100, - total?: number + total?: number, ) => { const count = strList.length; return count > max diff --git a/packages/utilities/src/helpers/truncate.test.ts b/packages/utilities/src/helpers/truncate.test.ts index c7c36bbbcca..56cd50a4fc8 100644 --- a/packages/utilities/src/helpers/truncate.test.ts +++ b/packages/utilities/src/helpers/truncate.test.ts @@ -8,12 +8,12 @@ describe('truncate', () => { hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world hello world`, - 140 + 140, ); const stringUnder140 = truncate( 'hello world hello world hello world hello world', - 140 + 140, ); it('string over 140 + 4 chars should contain an ellipses as last 3 chars', () => { diff --git a/packages/utilities/src/helpers/unitConversions.test.ts b/packages/utilities/src/helpers/unitConversions.test.ts index 5c86d56bf15..0938d837301 100644 --- a/packages/utilities/src/helpers/unitConversions.test.ts +++ b/packages/utilities/src/helpers/unitConversions.test.ts @@ -1,13 +1,14 @@ import { describe, expect, it } from 'vitest'; import { - ReadableBytesOptions, convertBytesToTarget, convertMegabytesTo, convertStorageUnit, readableBytes, } from './unitConversions'; +import type { ReadableBytesOptions } from './unitConversions'; + describe('conversion helper functions', () => { describe('readableBytes', () => { it('should return "0 bytes" if bytes === 0', () => { @@ -21,10 +22,10 @@ describe('conversion helper functions', () => { expect(readableBytes(-1048576).value).toBe(-1); expect( - readableBytes(-1048576, { handleNegatives: false }).formatted + readableBytes(-1048576, { handleNegatives: false }).formatted, ).toBe('0 bytes'); expect(readableBytes(-0.5, { handleNegatives: false }).formatted).toBe( - '0 bytes' + '0 bytes', ); }); @@ -74,37 +75,37 @@ describe('conversion helper functions', () => { it('respects rounding when given specific units', () => { expect(readableBytes(1024 * 9.723, { round: { KB: 3 } }).formatted).toBe( - '9.723 KB' + '9.723 KB', ); expect(readableBytes(1024 * 9.723, { round: { MB: 3 } }).formatted).toBe( - '9.72 KB' + '9.72 KB', ); expect( - readableBytes(1024 * 1024 * 143.22, { round: { MB: 2 } }).formatted + readableBytes(1024 * 1024 * 143.22, { round: { MB: 2 } }).formatted, ).toBe('143.22 MB'); }); it("doesn't return units higher than the specific max unit", () => { expect( - readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'MB' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'MB' }).formatted, ).toBe('51200 MB'); expect( - readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'KB' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'KB' }).formatted, ).toBe('52428800 KB'); expect( - readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'bytes' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { maxUnit: 'bytes' }).formatted, ).toBe('53687091200 bytes'); }); it('returns the given unit if specified', () => { expect( - readableBytes(1024 * 1024 * 1024 * 50, { unit: 'MB' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { unit: 'MB' }).formatted, ).toBe('51200 MB'); expect( - readableBytes(1024 * 1024 * 1024 * 50, { unit: 'GB' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { unit: 'GB' }).formatted, ).toBe('50 GB'); expect( - readableBytes(1024 * 1024 * 1024 * 50, { unit: 'TB' }).formatted + readableBytes(1024 * 1024 * 1024 * 50, { unit: 'TB' }).formatted, ).toBe('0.05 TB'); }); @@ -113,7 +114,7 @@ describe('conversion helper functions', () => { expect(readableBytes(0.5).formatted).toBe('0.5 bytes'); expect(readableBytes(-0.5).formatted).toBe('-0.5 bytes'); expect(readableBytes(0.01, { maxUnit: 'bytes' }).formatted).toBe( - '0.01 bytes' + '0.01 bytes', ); expect(readableBytes(0.5, { unit: 'MB' }).formatted).toBe('0 MB'); expect(readableBytes(0.3, { round: 0 }).formatted).toBe('0 bytes'); @@ -148,7 +149,7 @@ describe('conversion helper functions', () => { expect(readableBytes(1048576, { unitLabels }).unit).toBe('Megabytes'); expect(readableBytes(1073741824, { unitLabels }).unit).toBe('Gigabytes'); expect(readableBytes(1073741824 * 10000, { unitLabels }).unit).toBe( - 'Terabytes' + 'Terabytes', ); }); @@ -174,10 +175,10 @@ describe('conversion helper functions', () => { it('handles base 10 when the option is given', () => { expect(readableBytes(1000, { base10: true }).formatted).toBe('1 KB'); expect(readableBytes(1000 * 1000, { base10: true }).formatted).toBe( - '1 MB' + '1 MB', ); expect( - readableBytes(1000 * 1000 * 1000, { base10: true }).formatted + readableBytes(1000 * 1000 * 1000, { base10: true }).formatted, ).toBe('1 GB'); }); }); diff --git a/packages/utilities/src/hooks/useDebouncedValue.test.ts b/packages/utilities/src/hooks/useDebouncedValue.test.ts index 3776723a2ce..e0d7bd920e9 100644 --- a/packages/utilities/src/hooks/useDebouncedValue.test.ts +++ b/packages/utilities/src/hooks/useDebouncedValue.test.ts @@ -9,7 +9,7 @@ describe('useDebouncedValue', () => { const { rerender, result } = renderHook( ({ value }) => useDebouncedValue(value, 500), - { initialProps: { value: 'test' } } + { initialProps: { value: 'test' } }, ); expect(result.current).toBe('test'); diff --git a/packages/utilities/src/hooks/useDialog.ts b/packages/utilities/src/hooks/useDialog.ts index 86d786a121b..18f9e7c79c1 100644 --- a/packages/utilities/src/hooks/useDialog.ts +++ b/packages/utilities/src/hooks/useDialog.ts @@ -50,7 +50,7 @@ export interface DialogState { */ export const useDialog = ( - request: (params?: T) => Promise + request: (params?: T) => Promise, ): { closeDialog: () => void; dialog: DialogState; diff --git a/packages/utilities/src/hooks/useEditableLabelState.ts b/packages/utilities/src/hooks/useEditableLabelState.ts index b03671162b8..b64356e83bd 100644 --- a/packages/utilities/src/hooks/useEditableLabelState.ts +++ b/packages/utilities/src/hooks/useEditableLabelState.ts @@ -2,9 +2,8 @@ import * as React from 'react'; export const useEditableLabelState = () => { const [editableLabel, setEditableLabel] = React.useState(''); - const [editableLabelError, setEditableLabelError] = React.useState( - '' - ); + const [editableLabelError, setEditableLabelError] = + React.useState(''); const resetEditableLabel = () => { setEditableLabelError(''); diff --git a/packages/utilities/src/hooks/useErrors.ts b/packages/utilities/src/hooks/useErrors.ts index a6ece6d959a..cd093cd9649 100644 --- a/packages/utilities/src/hooks/useErrors.ts +++ b/packages/utilities/src/hooks/useErrors.ts @@ -7,7 +7,7 @@ import type { APIError } from '@linode/api-v4/lib/types'; export const useErrors = (): [ APIError[], React.Dispatch>, - () => void + () => void, ] => { const [errors, setErrors] = React.useState([]); diff --git a/packages/utilities/src/hooks/useFormValidateOnChange.ts b/packages/utilities/src/hooks/useFormValidateOnChange.ts index 2b15a173182..b57e99bc52c 100644 --- a/packages/utilities/src/hooks/useFormValidateOnChange.ts +++ b/packages/utilities/src/hooks/useFormValidateOnChange.ts @@ -7,9 +7,8 @@ import { useState } from 'react'; * @returns { hasFormBeenSubmitted: boolean, setHasFormBeenSubmitted: (value: boolean) => void } */ export const useFormValidateOnChange = () => { - const [hasFormBeenSubmitted, _setHasFormBeenSubmitted] = useState( - false - ); + const [hasFormBeenSubmitted, _setHasFormBeenSubmitted] = + useState(false); const setHasFormBeenSubmitted = (value: boolean) => { _setHasFormBeenSubmitted(value); diff --git a/packages/utilities/src/hooks/useFormattedDate.test.ts b/packages/utilities/src/hooks/useFormattedDate.test.ts index 05779761922..52d4fa11bbb 100644 --- a/packages/utilities/src/hooks/useFormattedDate.test.ts +++ b/packages/utilities/src/hooks/useFormattedDate.test.ts @@ -1,8 +1,9 @@ import { renderHook } from '@testing-library/react'; -import { useFormattedDate } from './useFormattedDate'; import { DateTime } from 'luxon'; import { describe, expect, it } from 'vitest'; +import { useFormattedDate } from './useFormattedDate'; + describe('useFormattedDate', () => { it('returns the correctly formatted date', () => { const { result } = renderHook(() => useFormattedDate()); diff --git a/packages/utilities/src/hooks/useOpenClose.ts b/packages/utilities/src/hooks/useOpenClose.ts index 34766e95f96..9f8199b74bf 100644 --- a/packages/utilities/src/hooks/useOpenClose.ts +++ b/packages/utilities/src/hooks/useOpenClose.ts @@ -21,7 +21,7 @@ const defaultState = { // Useful for components that render several drawers, modals, etc. which need // independent open/close state. This hooks provides a common interface. export const useOpenClose = ( - initialState: OpenCloseState = defaultState + initialState: OpenCloseState = defaultState, ): OpenClose => { const [entity, setEntity] = React.useState(initialState); diff --git a/packages/utilities/src/hooks/useScript.ts b/packages/utilities/src/hooks/useScript.ts index 6491f67bf10..839c577854e 100644 --- a/packages/utilities/src/hooks/useScript.ts +++ b/packages/utilities/src/hooks/useScript.ts @@ -17,7 +17,7 @@ interface ScriptOptions { */ export const loadScript = ( src: string, - options?: ScriptOptions + options?: ScriptOptions, ): Promise => { return new Promise((resolve, reject) => { // Allow falsy src value if waiting on other data needed for @@ -29,7 +29,7 @@ export const loadScript = ( // Fetch existing script element by src // It may have been added by another instance of this hook let script = document.querySelector( - `script[src='${src}']` + `script[src='${src}']`, ) as HTMLScriptElement; if (!script) { // Create script @@ -79,7 +79,7 @@ export const loadScript = ( */ export const useScript = ( src: string, - location?: ScriptLocation + location?: ScriptLocation, ): ScriptStatus => { const [status, setStatus] = useState(src ? 'loading' : 'idle'); @@ -103,7 +103,7 @@ export const useScript = ( */ export const useLazyScript = ( src: string, - location?: ScriptLocation + location?: ScriptLocation, ): { load: () => void; status: ScriptStatus; diff --git a/packages/utilities/src/types/LinodeCreateType.ts b/packages/utilities/src/types/LinodeCreateType.ts index 9176f1aaaaa..1a90cd74b36 100644 --- a/packages/utilities/src/types/LinodeCreateType.ts +++ b/packages/utilities/src/types/LinodeCreateType.ts @@ -2,6 +2,6 @@ export type LinodeCreateType = | 'Backups' | 'Clone Linode' | 'Images' - | 'OS' | 'One-Click' + | 'OS' | 'StackScripts'; diff --git a/packages/utilities/src/types/ManagerPreferences.ts b/packages/utilities/src/types/ManagerPreferences.ts index 643d3de0266..6fa41902ff1 100644 --- a/packages/utilities/src/types/ManagerPreferences.ts +++ b/packages/utilities/src/types/ManagerPreferences.ts @@ -31,6 +31,7 @@ export type ManagerPreferences = Partial<{ domains_group_by_tag: boolean; firewall_beta_notification: boolean; gst_banner_dismissed: boolean; + isAclpAlertsBeta: boolean; isAclpMetricsBeta: boolean; isTableStripingEnabled: boolean; linode_news_banner_dismissed: boolean; diff --git a/packages/validation/CHANGELOG.md b/packages/validation/CHANGELOG.md index 7072f4167cd..27f7bf0ddce 100644 --- a/packages/validation/CHANGELOG.md +++ b/packages/validation/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2025-05-20] - v0.66.0 + +### Upcoming Features: + +- Add new LKE-E schema for nodePoolBetaSchema ([#12188](https://github.com/linode/manager/pull/12188)) + ## [2025-05-06] - v0.65.0 ### Added: diff --git a/packages/validation/package.json b/packages/validation/package.json index 64cf9a3a3a1..9beaee549f7 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,6 +1,6 @@ { "name": "@linode/validation", - "version": "0.65.0", + "version": "0.66.0", "description": "Yup validation schemas for use with the Linode APIv4", "type": "module", "main": "lib/index.cjs", diff --git a/packages/validation/src/account.schema.ts b/packages/validation/src/account.schema.ts index f8bf04d4c25..77629fec657 100644 --- a/packages/validation/src/account.schema.ts +++ b/packages/validation/src/account.schema.ts @@ -43,7 +43,7 @@ export const CreditCardSchema = object({ .max(23, 'Credit card number must be between 13 and 23 characters.'), expiry_year: number() .test('length', 'Expiration year must be 2 or 4 digits.', (value) => - [2, 4].includes(String(value).length) + [2, 4].includes(String(value).length), ) .required('Expiration year is required.') .typeError('Expiration year must be a number.') @@ -63,7 +63,7 @@ export const CreditCardSchema = object({ export const PaymentMethodSchema = object({ type: mixed().oneOf( ['credit_card', 'payment_method_nonce'], - 'Type must be credit_card or payment_method_nonce.' + 'Type must be credit_card or payment_method_nonce.', ), data: object().when('type', { is: 'credit_card', @@ -74,7 +74,7 @@ export const PaymentMethodSchema = object({ }), }), is_default: boolean().required( - 'You must indicate if this should be your default method of payment.' + 'You must indicate if this should be your default method of payment.', ), }); @@ -87,7 +87,7 @@ export const CreateUserSchema = object({ .required('Email address is required.') .email('Must be a valid email address.'), restricted: boolean().required( - 'You must indicate if this user should have restricted access.' + 'You must indicate if this user should have restricted access.', ), }); @@ -104,7 +104,7 @@ const GrantSchema = object({ permissions: string() .oneOf( ['read_only', 'read_write'], - 'Permissions must be null, read_only, or read_write.' + 'Permissions must be null, read_only, or read_write.', ) .nullable('Permissions must be null, read_only, or read_write.'), }); diff --git a/packages/validation/src/buckets.schema.ts b/packages/validation/src/buckets.schema.ts index 6d3db40472d..4ec30b0bc97 100644 --- a/packages/validation/src/buckets.schema.ts +++ b/packages/validation/src/buckets.schema.ts @@ -11,11 +11,11 @@ export const CreateBucketSchema = object() .matches(/^\S*$/, 'Bucket name must not contain spaces.') .matches( /^[a-z0-9].*[a-z0-9]$/, - 'Bucket name must start and end with a lowercase letter or number.' + 'Bucket name must start and end with a lowercase letter or number.', ) .matches( /^(?!.*[.-]{2})[a-z0-9.-]+$/, - 'Bucket name must contain only lowercase letters, numbers, periods (.), and hyphens (-). Adjacent periods and hyphens are not allowed.' + 'Bucket name must contain only lowercase letters, numbers, periods (.), and hyphens (-). Adjacent periods and hyphens are not allowed.', ) .max(63, 'Bucket name must be between 3 and 63 characters.') .test( @@ -33,9 +33,9 @@ export const CreateBucketSchema = object() return !buckets.some( (bucket) => bucket.label === value && - (bucket.cluster === cluster || bucket.region === region) + (bucket.cluster === cluster || bucket.region === region), ); - } + }, ), cluster: string().when('region', { is: (region: string) => !region || region.length === 0, @@ -59,7 +59,7 @@ export const CreateBucketSchema = object() .optional(), s3_endpoint: string().optional(), }, - [['cluster', 'region']] + [['cluster', 'region']], ) .test('cors-enabled-check', 'Invalid CORS configuration.', function (value) { const { endpoint_type, cors_enabled } = value; diff --git a/packages/validation/src/firewalls.schema.ts b/packages/validation/src/firewalls.schema.ts index 869ba87cab7..70240b65d1d 100644 --- a/packages/validation/src/firewalls.schema.ts +++ b/packages/validation/src/firewalls.schema.ts @@ -6,7 +6,7 @@ import { array, number, object, string } from 'yup'; export const IP_ERROR_MESSAGE = 'Must be a valid IPv4 or IPv6 address or range.'; -export const validateIP = (ipAddress?: string | null): boolean => { +export const validateIP = (ipAddress?: null | string): boolean => { // ''is falsy, so we must specify that it is OK if (ipAddress !== '' && !ipAddress) { return false; diff --git a/packages/validation/src/images.schema.ts b/packages/validation/src/images.schema.ts index de9470a17eb..9ac35a1c027 100644 --- a/packages/validation/src/images.schema.ts +++ b/packages/validation/src/images.schema.ts @@ -5,7 +5,7 @@ const labelSchema = string() .max(50, 'Label must be between 1 and 50 characters.') .matches( /^[a-zA-Z0-9,.?\-_\s']+$/, - 'Image labels cannot contain special characters.' + 'Image labels cannot contain special characters.', ); export const baseImageSchema = object({ diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts index 9c9518920e7..3e47615f8c1 100644 --- a/packages/validation/src/index.ts +++ b/packages/validation/src/index.ts @@ -1,5 +1,6 @@ export * from './account.schema'; export * from './buckets.schema'; +export * from './cloudpulse.schema'; export * from './databases.schema'; export * from './domains.schema'; export * from './firewalls.schema'; @@ -20,4 +21,3 @@ export * from './transfers.schema'; export * from './twofactor.schema'; export * from './volumes.schema'; export * from './vpcs.schema'; -export * from './cloudpulse.schema'; diff --git a/packages/validation/src/kubernetes.schema.ts b/packages/validation/src/kubernetes.schema.ts index e6ddee873de..40683c4197c 100644 --- a/packages/validation/src/kubernetes.schema.ts +++ b/packages/validation/src/kubernetes.schema.ts @@ -1,11 +1,20 @@ +import { array, boolean, number, object, string } from 'yup'; + import { validateIP } from './firewalls.schema'; -import { array, number, object, string, boolean } from 'yup'; export const nodePoolSchema = object({ type: string(), count: number(), }); +export const nodePoolBetaSchema = nodePoolSchema.concat( + object({ + upgrade_strategy: string(), + k8_version: string(), + firewall_id: number(), + }), +); + export const clusterLabelSchema = string() .required('Label is required.') /** diff --git a/packages/validation/src/linodes.schema.ts b/packages/validation/src/linodes.schema.ts index 59e46d9ae6f..3e2d635cf25 100644 --- a/packages/validation/src/linodes.schema.ts +++ b/packages/validation/src/linodes.schema.ts @@ -1,14 +1,15 @@ -import { array, boolean, lazy, mixed, number, object, string } from 'yup'; // We must use a default export for ipaddr.js so our packages node compatibility // Refer to https://github.com/linode/manager/issues/8675 import ipaddr from 'ipaddr.js'; +import { array, boolean, lazy, mixed, number, object, string } from 'yup'; + import { vpcsValidateIP } from './vpcs.schema'; const VPC_INTERFACE_IP_RULE = 'A VPC interface must have an IPv4, an IPv6, or both, but not neither.'; // Functions for test validations -const validateIP = (ipAddress?: string | null) => { +const validateIP = (ipAddress?: null | string) => { if (!ipAddress) { return true; } @@ -23,7 +24,7 @@ const validateIP = (ipAddress?: string | null) => { return true; }; -const test_vpcsValidateIP = (value?: string | null) => { +const test_vpcsValidateIP = (value?: null | string) => { // Since the field is optional, return true here to prevent an incorrect test failure. if (value === undefined || value === null) { return true; @@ -36,7 +37,7 @@ const test_vpcsValidateIP = (value?: string | null) => { }); }; -const validateIPv6PrefixLengthIs64 = (value?: string | null) => { +const validateIPv6PrefixLengthIs64 = (value?: null | string) => { if (value === undefined || value === null) { return false; } @@ -823,4 +824,5 @@ export const CreateLinodeSchema = object({ firewall_id: number().nullable().notRequired(), placement_group: PlacementGroupPayloadSchema.notRequired().default(undefined), disk_encryption: DiskEncryptionSchema, + maintenance_policy_id: number().notRequired().nullable(), }); diff --git a/packages/validation/src/networking.schema.ts b/packages/validation/src/networking.schema.ts index 9628c74f75a..3c78cbf583c 100644 --- a/packages/validation/src/networking.schema.ts +++ b/packages/validation/src/networking.schema.ts @@ -9,7 +9,7 @@ export const allocateIPSchema = object().shape({ .required() .matches( /^ipv4$/, - 'Only IPv4 address may be allocated through this endpoint.' + 'Only IPv4 address may be allocated through this endpoint.', ), public: boolean().required(), linode_id: number().required(), diff --git a/packages/validation/src/objectStorageKeys.schema.ts b/packages/validation/src/objectStorageKeys.schema.ts index 4c1369055d2..24a520a21cd 100644 --- a/packages/validation/src/objectStorageKeys.schema.ts +++ b/packages/validation/src/objectStorageKeys.schema.ts @@ -1,4 +1,4 @@ -import { object, string, array } from 'yup'; +import { array, object, string } from 'yup'; const labelErrorMessage = 'Label must be between 3 and 50 characters.'; @@ -24,7 +24,7 @@ export const updateObjectStorageKeysSchema = object({ .of(string()) .min( 1, - `Select at least one region. To remove all regions, use 'Revoke' in the actions menu and remove the access key.` + `Select at least one region. To remove all regions, use 'Revoke' in the actions menu and remove the access key.`, ) .notRequired(), }); diff --git a/packages/validation/src/placement-groups.schema.ts b/packages/validation/src/placement-groups.schema.ts index ce4eddff3d1..4e1498e7c3e 100644 --- a/packages/validation/src/placement-groups.schema.ts +++ b/packages/validation/src/placement-groups.schema.ts @@ -10,7 +10,7 @@ export const createPlacementGroupSchema = object({ placement_group_type: string().required('Placement Group Type is required.'), region: string().required('Region is required.'), placement_group_policy: string().required( - 'Placement Group Policy is required.' + 'Placement Group Policy is required.', ), }); diff --git a/packages/validation/src/profile.schema.ts b/packages/validation/src/profile.schema.ts index 55b741d7108..19a12dae31a 100644 --- a/packages/validation/src/profile.schema.ts +++ b/packages/validation/src/profile.schema.ts @@ -1,5 +1,5 @@ -import { array, boolean, number, object, string } from 'yup'; import { isPossiblePhoneNumber } from 'libphonenumber-js'; +import { array, boolean, number, object, string } from 'yup'; export const createPersonalAccessTokenSchema = object({ scopes: string(), @@ -48,7 +48,7 @@ export const SendCodeToPhoneNumberSchema = object({ return false; } return isPossiblePhoneNumber(phone_number, iso_code); - } + }, ), }); @@ -64,7 +64,7 @@ export const VerifyPhoneNumberCodeSchema = object({ } return /^\d+$/.test(value); - } + }, ), }); @@ -77,7 +77,7 @@ export const SecurityQuestionsSchema = object({ .min(3, 'Answers must be at least 3 characters.') .max(17, 'Answers must be at most 17 characters.') .required('You must provide an answer to each security question.'), - }).required() + }).required(), ) .length(3, 'You must answer all 3 security questions.') .required(), diff --git a/packages/validation/src/volumes.schema.ts b/packages/validation/src/volumes.schema.ts index 0c782ff7cc2..1a16c0de0ab 100644 --- a/packages/validation/src/volumes.schema.ts +++ b/packages/validation/src/volumes.schema.ts @@ -1,4 +1,5 @@ import { array, number, object, string } from 'yup'; + import { MAX_VOLUME_SIZE } from './constants'; const createSizeValidation = (minSize: number = 10) => @@ -8,7 +9,7 @@ const createSizeValidation = (minSize: number = 10) => .min(minSize, `Size must be between ${minSize} and ${MAX_VOLUME_SIZE}.`) .max( MAX_VOLUME_SIZE, - `Size must be between ${minSize} and ${MAX_VOLUME_SIZE}.` + `Size must be between ${minSize} and ${MAX_VOLUME_SIZE}.`, ) .required(`A size is required.`); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89847fe662c..f4825b5d186 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -177,8 +177,8 @@ importers: specifier: ^7.27.0 version: 7.27.0(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@mui/material@6.4.5(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@6.4.3(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(dayjs@1.11.13)(luxon@3.4.4)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@paypal/react-paypal-js': - specifier: ^7.8.3 - version: 7.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^8.8.3 + version: 8.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@reach/tabs': specifier: ^0.18.0 version: 0.18.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -389,7 +389,7 @@ importers: version: 8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3) '@storybook/react-vite': specifier: ^8.6.7 - version: 8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.39.0)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.40.1)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) '@storybook/theming': specifier: ^8.6.7 version: 8.6.9(storybook@8.6.9(prettier@3.5.3)) @@ -488,7 +488,7 @@ importers: version: 4.4.5 '@vitejs/plugin-react-swc': specifier: ^3.7.2 - version: 3.7.2(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 3.7.2(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) '@vitest/coverage-v8': specifier: ^3.1.2 version: 3.1.2(vitest@3.1.2) @@ -527,7 +527,7 @@ importers: version: 1.14.0(cypress@14.3.0) cypress-vite: specifier: ^1.6.0 - version: 1.6.0(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 1.6.0(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) dotenv: specifier: ^16.0.3 version: 16.4.5 @@ -565,11 +565,11 @@ importers: specifier: 4.0.1 version: 4.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.9(prettier@3.5.3)) vite: - specifier: ^6.3.2 - version: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + specifier: ^6.3.4 + version: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) vite-plugin-svgr: specifier: ^3.2.0 - version: 3.3.0(rollup@4.39.0)(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 3.3.0(rollup@4.40.1)(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) packages/queries: dependencies: @@ -617,8 +617,8 @@ importers: specifier: ^4.0.3 version: 4.2.0 vite: - specifier: ^6.3.2 - version: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + specifier: ^6.3.4 + version: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) packages/shared: dependencies: @@ -667,7 +667,7 @@ importers: version: 18.3.1 vite-plugin-svgr: specifier: ^3.2.0 - version: 3.3.0(rollup@4.39.0)(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 3.3.0(rollup@4.40.1)(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) packages/ui: dependencies: @@ -737,7 +737,7 @@ importers: version: 18.3.1 vite-plugin-svgr: specifier: ^3.2.0 - version: 3.3.0(rollup@4.39.0)(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + version: 3.3.0(rollup@4.40.1)(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) packages/utilities: dependencies: @@ -1112,8 +1112,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.2': - resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} + '@esbuild/aix-ppc64@0.25.3': + resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1124,8 +1124,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.2': - resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} + '@esbuild/android-arm64@0.25.3': + resolution: {integrity: sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1136,8 +1136,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.2': - resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} + '@esbuild/android-arm@0.25.3': + resolution: {integrity: sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1148,8 +1148,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.2': - resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} + '@esbuild/android-x64@0.25.3': + resolution: {integrity: sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1160,8 +1160,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.2': - resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} + '@esbuild/darwin-arm64@0.25.3': + resolution: {integrity: sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1172,8 +1172,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.2': - resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} + '@esbuild/darwin-x64@0.25.3': + resolution: {integrity: sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1184,8 +1184,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.2': - resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} + '@esbuild/freebsd-arm64@0.25.3': + resolution: {integrity: sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1196,8 +1196,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.2': - resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} + '@esbuild/freebsd-x64@0.25.3': + resolution: {integrity: sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1208,8 +1208,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.2': - resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} + '@esbuild/linux-arm64@0.25.3': + resolution: {integrity: sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1220,8 +1220,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.2': - resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} + '@esbuild/linux-arm@0.25.3': + resolution: {integrity: sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1232,8 +1232,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.2': - resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} + '@esbuild/linux-ia32@0.25.3': + resolution: {integrity: sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1244,8 +1244,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.2': - resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} + '@esbuild/linux-loong64@0.25.3': + resolution: {integrity: sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1256,8 +1256,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.2': - resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} + '@esbuild/linux-mips64el@0.25.3': + resolution: {integrity: sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1268,8 +1268,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.2': - resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} + '@esbuild/linux-ppc64@0.25.3': + resolution: {integrity: sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1280,8 +1280,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.2': - resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} + '@esbuild/linux-riscv64@0.25.3': + resolution: {integrity: sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1292,8 +1292,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.2': - resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} + '@esbuild/linux-s390x@0.25.3': + resolution: {integrity: sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1304,8 +1304,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.2': - resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} + '@esbuild/linux-x64@0.25.3': + resolution: {integrity: sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1316,8 +1316,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.25.2': - resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} + '@esbuild/netbsd-arm64@0.25.3': + resolution: {integrity: sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1328,8 +1328,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.2': - resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} + '@esbuild/netbsd-x64@0.25.3': + resolution: {integrity: sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1340,8 +1340,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.2': - resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} + '@esbuild/openbsd-arm64@0.25.3': + resolution: {integrity: sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1352,8 +1352,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.2': - resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} + '@esbuild/openbsd-x64@0.25.3': + resolution: {integrity: sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1364,8 +1364,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.2': - resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} + '@esbuild/sunos-x64@0.25.3': + resolution: {integrity: sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1376,8 +1376,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.2': - resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} + '@esbuild/win32-arm64@0.25.3': + resolution: {integrity: sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1388,8 +1388,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.2': - resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} + '@esbuild/win32-ia32@0.25.3': + resolution: {integrity: sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1400,8 +1400,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.2': - resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} + '@esbuild/win32-x64@0.25.3': + resolution: {integrity: sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1806,14 +1806,14 @@ packages: '@paypal/accelerated-checkout-loader@1.1.0': resolution: {integrity: sha512-S2KkIpq15VnxYyI0tycvfYiNsqdsg2a92El2huYUVLsWnBbubl8toYK8khaP5nnxZ0MGl9mEB9Y9axmfOw2Yvg==} - '@paypal/paypal-js@5.1.6': - resolution: {integrity: sha512-1upF06pv0AUtTftRVSra44p8ibqGa3ruKLArvdhpZla25zcrND7R+nDUIMrJ0iteVYZowhujZStFs6NoruExfg==} + '@paypal/paypal-js@8.2.0': + resolution: {integrity: sha512-hLg5wNORW3WiyMiRNJOm6cN2IqjPlClpxd971bEdm0LNpbbejQZYtesb0/0arTnySSbGcxg7MxjkZ/N5Z5qBNQ==} - '@paypal/react-paypal-js@7.8.3': - resolution: {integrity: sha512-7sD5JFA0IH9kysyGFv5DTmtPn54vLWZ0DLhdjUvsjqZnoEs11mJJJlTsTA7MkIO3jBAJOWlfoA4wLYzmy68C4g==} + '@paypal/react-paypal-js@8.8.3': + resolution: {integrity: sha512-H5s3EU7S+RFaLad3BmV9nSAmD3iaJI14mCtbngpqMm4ruMNGHjOTaSTX3jAAk/ghmzGAda2GMfyiYondO4F21Q==} peerDependencies: - react: '>=16.3.0' - react-dom: '>=16.3.0' + react: ^16.8.0 || ^17 || ^18 || ^19 + react-dom: ^16.8.0 || ^17 || ^18 || ^19 '@paypal/sdk-constants@1.0.150': resolution: {integrity: sha512-ETm/mtiTBw4gHPdKo3GXzSQyXfZKevSg+ujfEvZbLT9gCc/YFmTBnWDroqmzOeuSXnf2Ll4bBSp3xbr47NQbUQ==} @@ -1879,8 +1879,8 @@ packages: cpu: [arm] os: [android] - '@rollup/rollup-android-arm-eabi@4.39.0': - resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} + '@rollup/rollup-android-arm-eabi@4.40.1': + resolution: {integrity: sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==} cpu: [arm] os: [android] @@ -1889,8 +1889,8 @@ packages: cpu: [arm64] os: [android] - '@rollup/rollup-android-arm64@4.39.0': - resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} + '@rollup/rollup-android-arm64@4.40.1': + resolution: {integrity: sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==} cpu: [arm64] os: [android] @@ -1899,8 +1899,8 @@ packages: cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-arm64@4.39.0': - resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} + '@rollup/rollup-darwin-arm64@4.40.1': + resolution: {integrity: sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==} cpu: [arm64] os: [darwin] @@ -1909,8 +1909,8 @@ packages: cpu: [x64] os: [darwin] - '@rollup/rollup-darwin-x64@4.39.0': - resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} + '@rollup/rollup-darwin-x64@4.40.1': + resolution: {integrity: sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==} cpu: [x64] os: [darwin] @@ -1919,8 +1919,8 @@ packages: cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.39.0': - resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} + '@rollup/rollup-freebsd-arm64@4.40.1': + resolution: {integrity: sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==} cpu: [arm64] os: [freebsd] @@ -1929,8 +1929,8 @@ packages: cpu: [x64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.39.0': - resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} + '@rollup/rollup-freebsd-x64@4.40.1': + resolution: {integrity: sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==} cpu: [x64] os: [freebsd] @@ -1939,8 +1939,8 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': - resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} + '@rollup/rollup-linux-arm-gnueabihf@4.40.1': + resolution: {integrity: sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==} cpu: [arm] os: [linux] @@ -1949,8 +1949,8 @@ packages: cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.39.0': - resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} + '@rollup/rollup-linux-arm-musleabihf@4.40.1': + resolution: {integrity: sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==} cpu: [arm] os: [linux] @@ -1959,8 +1959,8 @@ packages: cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.39.0': - resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} + '@rollup/rollup-linux-arm64-gnu@4.40.1': + resolution: {integrity: sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==} cpu: [arm64] os: [linux] @@ -1969,8 +1969,8 @@ packages: cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.39.0': - resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} + '@rollup/rollup-linux-arm64-musl@4.40.1': + resolution: {integrity: sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==} cpu: [arm64] os: [linux] @@ -1979,8 +1979,8 @@ packages: cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': - resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} + '@rollup/rollup-linux-loongarch64-gnu@4.40.1': + resolution: {integrity: sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==} cpu: [loong64] os: [linux] @@ -1989,8 +1989,8 @@ packages: cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': - resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': + resolution: {integrity: sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==} cpu: [ppc64] os: [linux] @@ -1999,13 +1999,13 @@ packages: cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.39.0': - resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} + '@rollup/rollup-linux-riscv64-gnu@4.40.1': + resolution: {integrity: sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.39.0': - resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} + '@rollup/rollup-linux-riscv64-musl@4.40.1': + resolution: {integrity: sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==} cpu: [riscv64] os: [linux] @@ -2014,8 +2014,8 @@ packages: cpu: [s390x] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.39.0': - resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} + '@rollup/rollup-linux-s390x-gnu@4.40.1': + resolution: {integrity: sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==} cpu: [s390x] os: [linux] @@ -2024,8 +2024,8 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.39.0': - resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} + '@rollup/rollup-linux-x64-gnu@4.40.1': + resolution: {integrity: sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==} cpu: [x64] os: [linux] @@ -2034,8 +2034,8 @@ packages: cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.39.0': - resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} + '@rollup/rollup-linux-x64-musl@4.40.1': + resolution: {integrity: sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==} cpu: [x64] os: [linux] @@ -2044,8 +2044,8 @@ packages: cpu: [arm64] os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.39.0': - resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} + '@rollup/rollup-win32-arm64-msvc@4.40.1': + resolution: {integrity: sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==} cpu: [arm64] os: [win32] @@ -2054,8 +2054,8 @@ packages: cpu: [ia32] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.39.0': - resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} + '@rollup/rollup-win32-ia32-msvc@4.40.1': + resolution: {integrity: sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==} cpu: [ia32] os: [win32] @@ -2064,8 +2064,8 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.39.0': - resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} + '@rollup/rollup-win32-x64-msvc@4.40.1': + resolution: {integrity: sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==} cpu: [x64] os: [win32] @@ -3800,8 +3800,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.25.2: - resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} + esbuild@0.25.3: + resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==} engines: {node: '>=18'} hasBin: true @@ -5870,8 +5870,8 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rollup@4.39.0: - resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} + rollup@4.40.1: + resolution: {integrity: sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -6599,8 +6599,8 @@ packages: peerDependencies: vite: ^2.6.0 || 3 || 4 - vite@6.3.2: - resolution: {integrity: sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==} + vite@6.3.4: + resolution: {integrity: sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -7251,151 +7251,151 @@ snapshots: '@esbuild/aix-ppc64@0.25.1': optional: true - '@esbuild/aix-ppc64@0.25.2': + '@esbuild/aix-ppc64@0.25.3': optional: true '@esbuild/android-arm64@0.25.1': optional: true - '@esbuild/android-arm64@0.25.2': + '@esbuild/android-arm64@0.25.3': optional: true '@esbuild/android-arm@0.25.1': optional: true - '@esbuild/android-arm@0.25.2': + '@esbuild/android-arm@0.25.3': optional: true '@esbuild/android-x64@0.25.1': optional: true - '@esbuild/android-x64@0.25.2': + '@esbuild/android-x64@0.25.3': optional: true '@esbuild/darwin-arm64@0.25.1': optional: true - '@esbuild/darwin-arm64@0.25.2': + '@esbuild/darwin-arm64@0.25.3': optional: true '@esbuild/darwin-x64@0.25.1': optional: true - '@esbuild/darwin-x64@0.25.2': + '@esbuild/darwin-x64@0.25.3': optional: true '@esbuild/freebsd-arm64@0.25.1': optional: true - '@esbuild/freebsd-arm64@0.25.2': + '@esbuild/freebsd-arm64@0.25.3': optional: true '@esbuild/freebsd-x64@0.25.1': optional: true - '@esbuild/freebsd-x64@0.25.2': + '@esbuild/freebsd-x64@0.25.3': optional: true '@esbuild/linux-arm64@0.25.1': optional: true - '@esbuild/linux-arm64@0.25.2': + '@esbuild/linux-arm64@0.25.3': optional: true '@esbuild/linux-arm@0.25.1': optional: true - '@esbuild/linux-arm@0.25.2': + '@esbuild/linux-arm@0.25.3': optional: true '@esbuild/linux-ia32@0.25.1': optional: true - '@esbuild/linux-ia32@0.25.2': + '@esbuild/linux-ia32@0.25.3': optional: true '@esbuild/linux-loong64@0.25.1': optional: true - '@esbuild/linux-loong64@0.25.2': + '@esbuild/linux-loong64@0.25.3': optional: true '@esbuild/linux-mips64el@0.25.1': optional: true - '@esbuild/linux-mips64el@0.25.2': + '@esbuild/linux-mips64el@0.25.3': optional: true '@esbuild/linux-ppc64@0.25.1': optional: true - '@esbuild/linux-ppc64@0.25.2': + '@esbuild/linux-ppc64@0.25.3': optional: true '@esbuild/linux-riscv64@0.25.1': optional: true - '@esbuild/linux-riscv64@0.25.2': + '@esbuild/linux-riscv64@0.25.3': optional: true '@esbuild/linux-s390x@0.25.1': optional: true - '@esbuild/linux-s390x@0.25.2': + '@esbuild/linux-s390x@0.25.3': optional: true '@esbuild/linux-x64@0.25.1': optional: true - '@esbuild/linux-x64@0.25.2': + '@esbuild/linux-x64@0.25.3': optional: true '@esbuild/netbsd-arm64@0.25.1': optional: true - '@esbuild/netbsd-arm64@0.25.2': + '@esbuild/netbsd-arm64@0.25.3': optional: true '@esbuild/netbsd-x64@0.25.1': optional: true - '@esbuild/netbsd-x64@0.25.2': + '@esbuild/netbsd-x64@0.25.3': optional: true '@esbuild/openbsd-arm64@0.25.1': optional: true - '@esbuild/openbsd-arm64@0.25.2': + '@esbuild/openbsd-arm64@0.25.3': optional: true '@esbuild/openbsd-x64@0.25.1': optional: true - '@esbuild/openbsd-x64@0.25.2': + '@esbuild/openbsd-x64@0.25.3': optional: true '@esbuild/sunos-x64@0.25.1': optional: true - '@esbuild/sunos-x64@0.25.2': + '@esbuild/sunos-x64@0.25.3': optional: true '@esbuild/win32-arm64@0.25.1': optional: true - '@esbuild/win32-arm64@0.25.2': + '@esbuild/win32-arm64@0.25.3': optional: true '@esbuild/win32-ia32@0.25.1': optional: true - '@esbuild/win32-ia32@0.25.2': + '@esbuild/win32-ia32@0.25.3': optional: true '@esbuild/win32-x64@0.25.1': optional: true - '@esbuild/win32-x64@0.25.2': + '@esbuild/win32-x64@0.25.3': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@9.23.0(jiti@2.4.2))': @@ -7600,12 +7600,12 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: glob: 10.4.5 magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.7.3) - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) optionalDependencies: typescript: 5.7.3 @@ -7820,13 +7820,13 @@ snapshots: envify: 4.1.0 typescript: 4.9.5 - '@paypal/paypal-js@5.1.6': + '@paypal/paypal-js@8.2.0': dependencies: promise-polyfill: 8.3.0 - '@paypal/react-paypal-js@7.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@paypal/react-paypal-js@8.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@paypal/paypal-js': 5.1.6 + '@paypal/paypal-js': 8.2.0 '@paypal/sdk-constants': 1.0.150 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -7878,129 +7878,129 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@rollup/pluginutils@5.1.3(rollup@4.39.0)': + '@rollup/pluginutils@5.1.3(rollup@4.40.1)': dependencies: '@types/estree': 1.0.7 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.1 '@rollup/rollup-android-arm-eabi@4.34.8': optional: true - '@rollup/rollup-android-arm-eabi@4.39.0': + '@rollup/rollup-android-arm-eabi@4.40.1': optional: true '@rollup/rollup-android-arm64@4.34.8': optional: true - '@rollup/rollup-android-arm64@4.39.0': + '@rollup/rollup-android-arm64@4.40.1': optional: true '@rollup/rollup-darwin-arm64@4.34.8': optional: true - '@rollup/rollup-darwin-arm64@4.39.0': + '@rollup/rollup-darwin-arm64@4.40.1': optional: true '@rollup/rollup-darwin-x64@4.34.8': optional: true - '@rollup/rollup-darwin-x64@4.39.0': + '@rollup/rollup-darwin-x64@4.40.1': optional: true '@rollup/rollup-freebsd-arm64@4.34.8': optional: true - '@rollup/rollup-freebsd-arm64@4.39.0': + '@rollup/rollup-freebsd-arm64@4.40.1': optional: true '@rollup/rollup-freebsd-x64@4.34.8': optional: true - '@rollup/rollup-freebsd-x64@4.39.0': + '@rollup/rollup-freebsd-x64@4.40.1': optional: true '@rollup/rollup-linux-arm-gnueabihf@4.34.8': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': + '@rollup/rollup-linux-arm-gnueabihf@4.40.1': optional: true '@rollup/rollup-linux-arm-musleabihf@4.34.8': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.39.0': + '@rollup/rollup-linux-arm-musleabihf@4.40.1': optional: true '@rollup/rollup-linux-arm64-gnu@4.34.8': optional: true - '@rollup/rollup-linux-arm64-gnu@4.39.0': + '@rollup/rollup-linux-arm64-gnu@4.40.1': optional: true '@rollup/rollup-linux-arm64-musl@4.34.8': optional: true - '@rollup/rollup-linux-arm64-musl@4.39.0': + '@rollup/rollup-linux-arm64-musl@4.40.1': optional: true '@rollup/rollup-linux-loongarch64-gnu@4.34.8': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': + '@rollup/rollup-linux-loongarch64-gnu@4.40.1': optional: true '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.40.1': optional: true '@rollup/rollup-linux-riscv64-gnu@4.34.8': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.39.0': + '@rollup/rollup-linux-riscv64-gnu@4.40.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.39.0': + '@rollup/rollup-linux-riscv64-musl@4.40.1': optional: true '@rollup/rollup-linux-s390x-gnu@4.34.8': optional: true - '@rollup/rollup-linux-s390x-gnu@4.39.0': + '@rollup/rollup-linux-s390x-gnu@4.40.1': optional: true '@rollup/rollup-linux-x64-gnu@4.34.8': optional: true - '@rollup/rollup-linux-x64-gnu@4.39.0': + '@rollup/rollup-linux-x64-gnu@4.40.1': optional: true '@rollup/rollup-linux-x64-musl@4.34.8': optional: true - '@rollup/rollup-linux-x64-musl@4.39.0': + '@rollup/rollup-linux-x64-musl@4.40.1': optional: true '@rollup/rollup-win32-arm64-msvc@4.34.8': optional: true - '@rollup/rollup-win32-arm64-msvc@4.39.0': + '@rollup/rollup-win32-arm64-msvc@4.40.1': optional: true '@rollup/rollup-win32-ia32-msvc@4.34.8': optional: true - '@rollup/rollup-win32-ia32-msvc@4.39.0': + '@rollup/rollup-win32-ia32-msvc@4.40.1': optional: true '@rollup/rollup-win32-x64-msvc@4.34.8': optional: true - '@rollup/rollup-win32-x64-msvc@4.39.0': + '@rollup/rollup-win32-x64-msvc@4.40.1': optional: true '@sentry-internal/feedback@7.120.0': @@ -8177,13 +8177,13 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-vite@8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': + '@storybook/builder-vite@8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: '@storybook/csf-plugin': 8.6.9(storybook@8.6.9(prettier@3.5.3)) browser-assert: 1.2.1 storybook: 8.6.9(prettier@3.5.3) ts-dedent: 2.2.0 - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) '@storybook/components@8.4.5(storybook@8.6.9(prettier@3.5.3))': dependencies: @@ -8202,8 +8202,8 @@ snapshots: '@storybook/theming': 8.6.9(storybook@8.6.9(prettier@3.5.3)) better-opn: 3.0.2 browser-assert: 1.2.1 - esbuild: 0.25.2 - esbuild-register: 3.6.0(esbuild@0.25.2) + esbuild: 0.25.3 + esbuild-register: 3.6.0(esbuild@0.25.3) jsdoc-type-pratt-parser: 4.1.0 process: 0.11.10 recast: 0.23.9 @@ -8250,11 +8250,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.6.9(prettier@3.5.3) - '@storybook/react-vite@8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.39.0)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': + '@storybook/react-vite@8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.40.1)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) - '@rollup/pluginutils': 5.1.3(rollup@4.39.0) - '@storybook/builder-vite': 8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + '@rollup/pluginutils': 5.1.3(rollup@4.40.1) + '@storybook/builder-vite': 8.6.9(storybook@8.6.9(prettier@3.5.3))(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) '@storybook/react': 8.6.9(@storybook/test@8.6.9(storybook@8.6.9(prettier@3.5.3)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.6.9(prettier@3.5.3))(typescript@5.7.3) find-up: 5.0.0 magic-string: 0.30.17 @@ -8264,7 +8264,7 @@ snapshots: resolve: 1.22.8 storybook: 8.6.9(prettier@3.5.3) tsconfig-paths: 4.2.0 - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) optionalDependencies: '@storybook/test': 8.6.9(storybook@8.6.9(prettier@3.5.3)) transitivePeerDependencies: @@ -8840,10 +8840,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react-swc@3.7.2(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': + '@vitejs/plugin-react-swc@3.7.2(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: '@swc/core': 1.10.11 - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) transitivePeerDependencies: - '@swc/helpers' @@ -8879,14 +8879,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.2(msw@2.6.5(@types/node@20.17.6)(typescript@5.7.3))(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': + '@vitest/mocker@3.1.2(msw@2.6.5(@types/node@20.17.6)(typescript@5.7.3))(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: '@vitest/spy': 3.1.2 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: msw: 2.6.5(@types/node@20.17.6)(typescript@5.7.3) - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) '@vitest/pretty-format@2.0.5': dependencies: @@ -9610,11 +9610,11 @@ snapshots: dependencies: cypress: 14.3.0 - cypress-vite@1.6.0(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)): + cypress-vite@1.6.0(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)): dependencies: chokidar: 3.6.0 debug: 4.4.0(supports-color@8.1.1) - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) transitivePeerDependencies: - supports-color @@ -10045,10 +10045,10 @@ snapshots: es-toolkit@1.27.0: {} - esbuild-register@3.6.0(esbuild@0.25.2): + esbuild-register@3.6.0(esbuild@0.25.3): dependencies: debug: 4.4.0(supports-color@8.1.1) - esbuild: 0.25.2 + esbuild: 0.25.3 transitivePeerDependencies: - supports-color @@ -10080,33 +10080,33 @@ snapshots: '@esbuild/win32-ia32': 0.25.1 '@esbuild/win32-x64': 0.25.1 - esbuild@0.25.2: + esbuild@0.25.3: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.2 - '@esbuild/android-arm': 0.25.2 - '@esbuild/android-arm64': 0.25.2 - '@esbuild/android-x64': 0.25.2 - '@esbuild/darwin-arm64': 0.25.2 - '@esbuild/darwin-x64': 0.25.2 - '@esbuild/freebsd-arm64': 0.25.2 - '@esbuild/freebsd-x64': 0.25.2 - '@esbuild/linux-arm': 0.25.2 - '@esbuild/linux-arm64': 0.25.2 - '@esbuild/linux-ia32': 0.25.2 - '@esbuild/linux-loong64': 0.25.2 - '@esbuild/linux-mips64el': 0.25.2 - '@esbuild/linux-ppc64': 0.25.2 - '@esbuild/linux-riscv64': 0.25.2 - '@esbuild/linux-s390x': 0.25.2 - '@esbuild/linux-x64': 0.25.2 - '@esbuild/netbsd-arm64': 0.25.2 - '@esbuild/netbsd-x64': 0.25.2 - '@esbuild/openbsd-arm64': 0.25.2 - '@esbuild/openbsd-x64': 0.25.2 - '@esbuild/sunos-x64': 0.25.2 - '@esbuild/win32-arm64': 0.25.2 - '@esbuild/win32-ia32': 0.25.2 - '@esbuild/win32-x64': 0.25.2 + '@esbuild/aix-ppc64': 0.25.3 + '@esbuild/android-arm': 0.25.3 + '@esbuild/android-arm64': 0.25.3 + '@esbuild/android-x64': 0.25.3 + '@esbuild/darwin-arm64': 0.25.3 + '@esbuild/darwin-x64': 0.25.3 + '@esbuild/freebsd-arm64': 0.25.3 + '@esbuild/freebsd-x64': 0.25.3 + '@esbuild/linux-arm': 0.25.3 + '@esbuild/linux-arm64': 0.25.3 + '@esbuild/linux-ia32': 0.25.3 + '@esbuild/linux-loong64': 0.25.3 + '@esbuild/linux-mips64el': 0.25.3 + '@esbuild/linux-ppc64': 0.25.3 + '@esbuild/linux-riscv64': 0.25.3 + '@esbuild/linux-s390x': 0.25.3 + '@esbuild/linux-x64': 0.25.3 + '@esbuild/netbsd-arm64': 0.25.3 + '@esbuild/netbsd-x64': 0.25.3 + '@esbuild/openbsd-arm64': 0.25.3 + '@esbuild/openbsd-x64': 0.25.3 + '@esbuild/sunos-x64': 0.25.3 + '@esbuild/win32-arm64': 0.25.3 + '@esbuild/win32-ia32': 0.25.3 + '@esbuild/win32-x64': 0.25.3 escalade@3.2.0: {} @@ -12570,30 +12570,30 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.34.8 fsevents: 2.3.3 - rollup@4.39.0: + rollup@4.40.1: dependencies: '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.39.0 - '@rollup/rollup-android-arm64': 4.39.0 - '@rollup/rollup-darwin-arm64': 4.39.0 - '@rollup/rollup-darwin-x64': 4.39.0 - '@rollup/rollup-freebsd-arm64': 4.39.0 - '@rollup/rollup-freebsd-x64': 4.39.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.39.0 - '@rollup/rollup-linux-arm-musleabihf': 4.39.0 - '@rollup/rollup-linux-arm64-gnu': 4.39.0 - '@rollup/rollup-linux-arm64-musl': 4.39.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.39.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-musl': 4.39.0 - '@rollup/rollup-linux-s390x-gnu': 4.39.0 - '@rollup/rollup-linux-x64-gnu': 4.39.0 - '@rollup/rollup-linux-x64-musl': 4.39.0 - '@rollup/rollup-win32-arm64-msvc': 4.39.0 - '@rollup/rollup-win32-ia32-msvc': 4.39.0 - '@rollup/rollup-win32-x64-msvc': 4.39.0 + '@rollup/rollup-android-arm-eabi': 4.40.1 + '@rollup/rollup-android-arm64': 4.40.1 + '@rollup/rollup-darwin-arm64': 4.40.1 + '@rollup/rollup-darwin-x64': 4.40.1 + '@rollup/rollup-freebsd-arm64': 4.40.1 + '@rollup/rollup-freebsd-x64': 4.40.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.1 + '@rollup/rollup-linux-arm-musleabihf': 4.40.1 + '@rollup/rollup-linux-arm64-gnu': 4.40.1 + '@rollup/rollup-linux-arm64-musl': 4.40.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.1 + '@rollup/rollup-linux-riscv64-gnu': 4.40.1 + '@rollup/rollup-linux-riscv64-musl': 4.40.1 + '@rollup/rollup-linux-s390x-gnu': 4.40.1 + '@rollup/rollup-linux-x64-gnu': 4.40.1 + '@rollup/rollup-linux-x64-musl': 4.40.1 + '@rollup/rollup-win32-arm64-msvc': 4.40.1 + '@rollup/rollup-win32-ia32-msvc': 4.40.1 + '@rollup/rollup-win32-x64-msvc': 4.40.1 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -13444,7 +13444,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) transitivePeerDependencies: - '@types/node' - jiti @@ -13459,25 +13459,25 @@ snapshots: - tsx - yaml - vite-plugin-svgr@3.3.0(rollup@4.39.0)(typescript@5.7.3)(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)): + vite-plugin-svgr@3.3.0(rollup@4.40.1)(typescript@5.7.3)(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)): dependencies: - '@rollup/pluginutils': 5.1.3(rollup@4.39.0) + '@rollup/pluginutils': 5.1.3(rollup@4.40.1) '@svgr/core': 8.1.0(typescript@5.7.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.7.3)) - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1): + vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1): dependencies: - esbuild: 0.25.2 - fdir: 6.4.3(picomatch@4.0.2) + esbuild: 0.25.3 + fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 postcss: 8.5.3 - rollup: 4.39.0 - tinyglobby: 0.2.12 + rollup: 4.40.1 + tinyglobby: 0.2.13 optionalDependencies: '@types/node': 20.17.6 fsevents: 2.3.3 @@ -13489,7 +13489,7 @@ snapshots: vitest@3.1.2(@types/debug@4.1.12)(@types/node@20.17.6)(@vitest/ui@3.1.2)(jiti@2.4.2)(jsdom@24.1.3)(msw@2.6.5(@types/node@20.17.6)(typescript@5.7.3))(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1): dependencies: '@vitest/expect': 3.1.2 - '@vitest/mocker': 3.1.2(msw@2.6.5(@types/node@20.17.6)(typescript@5.7.3))(vite@6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) + '@vitest/mocker': 3.1.2(msw@2.6.5(@types/node@20.17.6)(typescript@5.7.3))(vite@6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1)) '@vitest/pretty-format': 3.1.2 '@vitest/runner': 3.1.2 '@vitest/snapshot': 3.1.2 @@ -13506,7 +13506,7 @@ snapshots: tinyglobby: 0.2.13 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.3.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) + vite: 6.3.4(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) vite-node: 3.1.2(@types/node@20.17.6)(jiti@2.4.2)(terser@5.36.0)(tsx@4.19.3)(yaml@2.6.1) why-is-node-running: 2.3.0 optionalDependencies: diff --git a/scripts/changelog/changeset.mjs b/scripts/changelog/changeset.mjs index 767e3d8a713..fc465eec03b 100644 --- a/scripts/changelog/changeset.mjs +++ b/scripts/changelog/changeset.mjs @@ -59,7 +59,32 @@ async function generateChangeset() { type: "input", prefix: `📝 Description`, name: "description", - message: "\nDescribe the change (don't include the PR number):", + message: "\nBriefly describe the change (see https://linode.github.io/manager/CONTRIBUTING.html#writing-a-changeset for best practices):", + validate: (input) => { + const trimmed = input.trim(); + + if (trimmed.length < 1) { + return "Description must be between 1-150 characters. Please add a description."; + } + + if (trimmed.length > 150) { + return "Description must be no more than 150 characters. Please summarize your changes."; + } + + if (/#[0-9]+/.test(trimmed) || /\bPR\s?#?\d+\b/i.test(trimmed)) { + return "Description should not include the PR number (e.g., #123 or PR 456)."; + } + + if (!/^[A-Z]/.test(trimmed)) { + return "Description should start with a capital letter."; + } + + if (/[.]$/.test(trimmed)) { + return "Description should not end with a period."; + } + + return true; + }, }, ]); const { commit } = await inquirer.prompt([