diff --git a/packages/manager/.changeset/pr-10165-tech-stories-1707412665889.md b/packages/manager/.changeset/pr-10165-tech-stories-1707412665889.md new file mode 100644 index 00000000000..c791b2cee36 --- /dev/null +++ b/packages/manager/.changeset/pr-10165-tech-stories-1707412665889.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tech Stories +--- + +Update `launchdarkly-react-client-sdk` ([#10165](https://github.com/linode/manager/pull/10165)) diff --git a/packages/manager/package.json b/packages/manager/package.json index 2900cf692e7..c9f281dafb1 100644 --- a/packages/manager/package.json +++ b/packages/manager/package.json @@ -39,7 +39,7 @@ "ipaddr.js": "^1.9.1", "jspdf": "^2.3.1", "jspdf-autotable": "^3.5.14", - "launchdarkly-react-client-sdk": "^3.0.6", + "launchdarkly-react-client-sdk": "3.0.10", "libphonenumber-js": "^1.10.6", "lodash": "^4.17.21", "logic-query-parser": "^0.0.5", diff --git a/packages/manager/src/App.tsx b/packages/manager/src/App.tsx index 1247e6972c0..04c31a7aff0 100644 --- a/packages/manager/src/App.tsx +++ b/packages/manager/src/App.tsx @@ -6,7 +6,6 @@ import { DocumentTitleSegment, withDocumentTitleProvider, } from 'src/components/DocumentTitle'; -import withFeatureFlagConsumer from 'src/containers/withFeatureFlagConsumer.container'; import withFeatureFlagProvider from 'src/containers/withFeatureFlagProvider.container'; import TheApplicationIsOnFire from 'src/features/TheApplicationIsOnFire'; @@ -23,37 +22,35 @@ import { useSetupFeatureFlags } from './useSetupFeatureFlags'; export const App = () => ; const BaseApp = withDocumentTitleProvider( - withFeatureFlagProvider( - withFeatureFlagConsumer(() => { - const { isLoading } = useInitialRequests(); - - const { areFeatureFlagsLoading } = useSetupFeatureFlags(); - - if (isLoading || areFeatureFlagsLoading) { - return ; - } - - return ( - }> - {/** Accessibility helper */} - - Skip to main content - - - - - - - - ); - }) - ) + withFeatureFlagProvider(() => { + const { isLoading } = useInitialRequests(); + + const { areFeatureFlagsLoading } = useSetupFeatureFlags(); + + if (isLoading || areFeatureFlagsLoading) { + return ; + } + + return ( + }> + {/** Accessibility helper */} + + Skip to main content + + + + + + + + ); + }) ); const GlobalListeners = () => { diff --git a/packages/manager/src/containers/flags.container.ts b/packages/manager/src/containers/flags.container.ts new file mode 100644 index 00000000000..f276099513f --- /dev/null +++ b/packages/manager/src/containers/flags.container.ts @@ -0,0 +1,22 @@ +import * as React from 'react'; + +import { useFlags } from 'src/hooks/useFlags'; + +import type { FlagSet } from 'src/featureFlags'; + +export interface WithFeatureFlagProps { + flags: FlagSet; +} + +export const withFeatureFlags = ( + Component: React.ComponentType +) => { + return (props: Props) => { + const flags = useFlags(); + + return React.createElement(Component, { + ...props, + flags, + }); + }; +}; diff --git a/packages/manager/src/containers/withFeatureFlagConsumer.container.ts b/packages/manager/src/containers/withFeatureFlagConsumer.container.ts deleted file mode 100644 index 6ee9b19c54d..00000000000 --- a/packages/manager/src/containers/withFeatureFlagConsumer.container.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { LDClient as _LDClient } from 'launchdarkly-js-client-sdk'; -import { withLDConsumer } from 'launchdarkly-react-client-sdk'; -import { LDProps } from 'launchdarkly-react-client-sdk/lib/withLDConsumer'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'recompose'; - -import { FlagSet } from 'src/featureFlags'; -import { MockFeatureFlagState } from 'src/store/mockFeatureFlags'; -import { MapState } from 'src/store/types'; - -/* eslint-disable-next-line */ -export interface LDClient extends _LDClient {} - -export interface FeatureFlagConsumerProps { - flags: FlagSet; - ldClient: LDClient; -} - -// We have to provide an HOC around the `withLDConsumer` HOC in order to retrieve mock flags -// for the custom dev tools. -export const withFeatureFlagConsumer = ( - Component: React.ComponentType -) => { - class WrappedComponent extends React.Component { - render() { - return React.createElement(Component, { - ...this.props, - flags: { - // Real LD flags from `withLDConsumer()`. - ...this.props.flags, - // Mock flags from Redux. - ...this.props.mockFlags, - }, - }); - } - } - - const enhanced = compose(connected, withLDConsumer()); - - return enhanced(WrappedComponent); -}; - -export default withFeatureFlagConsumer; - -// Redux connection for the wrapped component. -interface StateProps { - mockFlags: MockFeatureFlagState; -} - -const mapStateToProps: MapState = (state) => ({ - mockFlags: state.mockFeatureFlags, -}); - -const connected = connect(mapStateToProps); diff --git a/packages/manager/src/features/Domains/DomainRecords.tsx b/packages/manager/src/features/Domains/DomainRecords.tsx index ff5ed92a118..1b85fa2debf 100644 --- a/packages/manager/src/features/Domains/DomainRecords.tsx +++ b/packages/manager/src/features/Domains/DomainRecords.tsx @@ -21,7 +21,6 @@ import { propEq, } from 'ramda'; import * as React from 'react'; -import { compose as recompose } from 'recompose'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { Button } from 'src/components/Button/Button'; @@ -37,9 +36,6 @@ import { TableHead } from 'src/components/TableHead'; import { TableRow } from 'src/components/TableRow'; import { TableRowEmpty } from 'src/components/TableRowEmpty/TableRowEmpty'; import { Typography } from 'src/components/Typography'; -import withFeatureFlags, { - FeatureFlagConsumerProps, -} from 'src/containers/withFeatureFlagConsumer.container'; import { getAPIErrorOrDefault, getErrorStringOrDefault, @@ -52,7 +48,7 @@ import { DomainRecordActionMenu } from './DomainRecordActionMenu'; import { DomainRecordDrawer } from './DomainRecordDrawer'; import { StyledDiv, StyledGrid, StyledTableCell } from './DomainRecords.styles'; -interface DomainRecordsProps { +interface Props { domain: Domain; domainRecords: DomainRecord[]; updateDomain: (data: { id: number } & UpdateDomainPayload) => Promise; @@ -79,8 +75,6 @@ interface State { types: IType[]; } -type CombinedProps = DomainRecordsProps & FeatureFlagConsumerProps; - interface IType { columns: { render: (r: Domain | DomainRecord) => JSX.Element | null | string; @@ -99,8 +93,8 @@ const createLink = (title: string, handler: () => void) => ( ); -class DomainRecords extends React.Component { - constructor(props: CombinedProps) { +class DomainRecords extends React.Component { + constructor(props: Props) { super(props); this.state = { confirmDialog: { @@ -112,7 +106,7 @@ class DomainRecords extends React.Component { }; } - componentDidUpdate(prevProps: CombinedProps) { + componentDidUpdate(prevProps: Props) { if ( !equals(prevProps.domainRecords, this.props.domainRecords) || !equals(prevProps.domain, this.props.domain) @@ -879,12 +873,10 @@ const prependLinodeNS = compose( ); const getNSRecords = compose< - DomainRecordsProps, + Props, DomainRecord[], DomainRecord[], DomainRecord[] >(prependLinodeNS, filter(typeEq('NS')), pathOr([], ['domainRecords'])); -export default recompose(withFeatureFlags)( - DomainRecords -); +export default DomainRecords; diff --git a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx index 265c82317e0..95cea371bd4 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx +++ b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreate.tsx @@ -33,10 +33,10 @@ import { WithAccountProps, withAccount, } from 'src/containers/account.container'; +import { WithFeatureFlagProps } from 'src/containers/flags.container'; import { DefaultProps as ImagesProps } from 'src/containers/images.container'; import { RegionsProps } from 'src/containers/regions.container'; import { WithTypesProps } from 'src/containers/types.container'; -import { FeatureFlagConsumerProps } from 'src/containers/withFeatureFlagConsumer.container'; import { WithLinodesProps } from 'src/containers/withLinodes.container'; import { EUAgreementCheckbox } from 'src/features/Account/Agreements/EUAgreementCheckbox'; import { regionSupportsMetadata } from 'src/features/Linodes/LinodesCreate/utilities'; @@ -170,7 +170,7 @@ type InnerProps = WithTypesRegionsAndImages & type CombinedProps = AllFormStateAndHandlers & AppsData & - FeatureFlagConsumerProps & + WithFeatureFlagProps & ImagesProps & InnerProps & ReduxStateProps & diff --git a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreateContainer.tsx b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreateContainer.tsx index 770e8708e11..daa6cc2c3d4 100644 --- a/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreateContainer.tsx +++ b/packages/manager/src/features/Linodes/LinodesCreate/LinodeCreateContainer.tsx @@ -26,6 +26,10 @@ import { WithEventsPollingActionProps, withEventsPollingActions, } from 'src/containers/events.container'; +import { + WithFeatureFlagProps, + withFeatureFlags, +} from 'src/containers/flags.container'; import withImages, { DefaultProps as ImagesProps, } from 'src/containers/images.container'; @@ -35,9 +39,6 @@ import { } from 'src/containers/profile.container'; import { RegionsProps, withRegions } from 'src/containers/regions.container'; import { WithTypesProps, withTypes } from 'src/containers/types.container'; -import withFlags, { - FeatureFlagConsumerProps, -} from 'src/containers/withFeatureFlagConsumer.container'; import { WithLinodesProps, withLinodes, @@ -136,7 +137,7 @@ type CombinedProps = WithSnackbarProps & WithTypesProps & WithLinodesProps & RegionsProps & - FeatureFlagConsumerProps & + WithFeatureFlagProps & RouteComponentProps<{}, any, any> & WithProfileProps & AgreementsProps & @@ -952,7 +953,7 @@ export default recompose( withTypes, connected, withSnackbar, - withFlags, + withFeatureFlags, withProfile, withAgreements, withQueryClient, diff --git a/packages/manager/src/features/Linodes/LinodesLanding/LinodesLanding.tsx b/packages/manager/src/features/Linodes/LinodesLanding/LinodesLanding.tsx index 5d37d449092..b39a91d10b3 100644 --- a/packages/manager/src/features/Linodes/LinodesLanding/LinodesLanding.tsx +++ b/packages/manager/src/features/Linodes/LinodesLanding/LinodesLanding.tsx @@ -15,7 +15,6 @@ import { WithProfileProps, withProfile, } from 'src/containers/profile.container'; -import withFeatureFlagConsumer from 'src/containers/withFeatureFlagConsumer.container'; import { BackupsCTA } from 'src/features/Backups/BackupsCTA'; import { MigrateLinode } from 'src/features/Linodes/MigrateLinode/MigrateLinode'; import { DialogType } from 'src/features/Linodes/types'; @@ -432,7 +431,6 @@ const sendGroupByAnalytic = (value: boolean) => { export const enhanced = compose( withRouter, - withFeatureFlagConsumer, withProfile ); diff --git a/packages/manager/src/features/Users/UserPermissions.tsx b/packages/manager/src/features/Users/UserPermissions.tsx index 89141431e01..70b815f7084 100644 --- a/packages/manager/src/features/Users/UserPermissions.tsx +++ b/packages/manager/src/features/Users/UserPermissions.tsx @@ -33,9 +33,10 @@ import { TabPanels } from 'src/components/Tabs/TabPanels'; import { Tabs } from 'src/components/Tabs/Tabs'; import { Toggle } from 'src/components/Toggle/Toggle'; import { Typography } from 'src/components/Typography'; -import withFlags, { - FeatureFlagConsumerProps, -} from 'src/containers/withFeatureFlagConsumer.container'; +import { + WithFeatureFlagProps, + withFeatureFlags, +} from 'src/containers/flags.container'; import { WithQueryClientProps, withQueryClient, @@ -89,7 +90,7 @@ interface State { type CombinedProps = Props & WithSnackbarProps & WithQueryClientProps & - FeatureFlagConsumerProps; + WithFeatureFlagProps; class UserPermissions extends React.Component { componentDidMount() { @@ -815,5 +816,5 @@ class UserPermissions extends React.Component { export default recompose( withSnackbar, withQueryClient, - withFlags + withFeatureFlags )(UserPermissions); diff --git a/packages/manager/src/utilities/testHelpers.tsx b/packages/manager/src/utilities/testHelpers.tsx index 0f872368071..228a8ea9de3 100644 --- a/packages/manager/src/utilities/testHelpers.tsx +++ b/packages/manager/src/utilities/testHelpers.tsx @@ -7,7 +7,7 @@ import { import userEvent from '@testing-library/user-event'; import mediaQuery from 'css-mediaquery'; import { Formik, FormikConfig, FormikValues } from 'formik'; -import { Provider as LDProvider } from 'launchdarkly-react-client-sdk/lib/context'; +import { LDProvider } from 'launchdarkly-react-client-sdk'; import { SnackbarProvider } from 'notistack'; import { mergeDeepRight } from 'ramda'; import * as React from 'react'; @@ -95,10 +95,10 @@ export const wrapWithTheme = (ui: any, options: Options = {}) => { diff --git a/yarn.lock b/yarn.lock index a7c93940f90..556a67e9095 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10202,10 +10202,10 @@ language-tags@=1.0.5: dependencies: language-subtag-registry "~0.3.2" -launchdarkly-js-client-sdk@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.1.3.tgz#e046439f0e4f0bfd6d38b9eaa4420a6e40ffc0c7" - integrity sha512-/JR/ri8z3bEj9RFTTKDjd+con4F1MsWUea1MmBDtFj4gDA0l9NDm1KzhMKiIeoBdmB2rSaeFYe4CaYOEp8IryA== +launchdarkly-js-client-sdk@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/launchdarkly-js-client-sdk/-/launchdarkly-js-client-sdk-3.1.4.tgz#e613cb53412533c07ccf140ae570fc994c59758d" + integrity sha512-yq0FeklpVuHMSRz7jfUAfyM7I/659RvGztqJ0Y9G5eN/ZrG1o2W61ZU0Nrv/gqZCtLXjarh/u1otxSFFBjTpHw== dependencies: escape-string-regexp "^4.0.0" launchdarkly-js-sdk-common "5.0.3" @@ -10219,13 +10219,13 @@ launchdarkly-js-sdk-common@5.0.3: fast-deep-equal "^2.0.1" uuid "^8.0.0" -launchdarkly-react-client-sdk@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/launchdarkly-react-client-sdk/-/launchdarkly-react-client-sdk-3.0.6.tgz#5c694a4a013757d2afb5213efd28d9c16af1595e" - integrity sha512-r7gSshScugjnJB4lJ6mAOMKpV4Pj/wUks3tsRHdfeXgER9jPdxmZOAkm0besMjK0S7lfQdjxJ2KIXrh+Mn1sQA== +launchdarkly-react-client-sdk@3.0.10: + version "3.0.10" + resolved "https://registry.yarnpkg.com/launchdarkly-react-client-sdk/-/launchdarkly-react-client-sdk-3.0.10.tgz#33816d939d9bd18b0723c0fd30b4772f2429f3de" + integrity sha512-ssb3KWe9z42+q8X2u32OrlDntGLsv0NP/p4E2Hx4O9RU0OeFm9v6omOlIk9SMsYEQD4QzLSXAp5L3cSN2ssLlA== dependencies: hoist-non-react-statics "^3.3.2" - launchdarkly-js-client-sdk "^3.1.3" + launchdarkly-js-client-sdk "^3.1.4" lodash.camelcase "^4.3.0" lazy-ass@^1.6.0: