Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Release v1.96.2 - stagingmaster #9345

Merged
merged 14 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/manager/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@ 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/).

## [2023-06-27] - v1.96.1
## [2023-06-29] - v1.96.2

### Fixed:
- Issue where Cloud Manager was not displaying all linodes capable of being "cloned" ([#9294](https://github.com/linode/manager/pull/9294))
- Firewall custom ports validation w/ unit tests ([#9336](https://github.com/linode/manager/pull/9336))

### Tech Stories:

- React Query - Linodes - General Refactors ([#9294](https://github.com/linode/manager/pull/9294))

## [2023-06-27] - v1.96.1

### Fixed:

Expand Down
2 changes: 1 addition & 1 deletion packages/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "linode-manager",
"author": "Linode",
"description": "The Linode Manager website",
"version": "1.96.1",
"version": "1.96.2",
"private": true,
"bugs": {
"url": "https://github.com/Linode/manager/issues"
Expand Down
16 changes: 0 additions & 16 deletions packages/manager/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { ADOBE_ANALYTICS_URL, NUM_ADOBE_SCRIPTS } from './constants';
import { reportException } from './exceptionReporting';
import { useAuthentication } from './hooks/useAuthentication';
import useFeatureFlagsLoad from './hooks/useFeatureFlagLoad';
import useLinodes from './hooks/useLinodes';
import { loadScript } from './hooks/useScript';
import { oauthClientsEventHandler } from './queries/accountOAuth';
import { databaseEventsHandler } from './queries/databases';
Expand Down Expand Up @@ -59,12 +58,6 @@ const BaseApp = withFeatureFlagProvider(

const { enqueueSnackbar } = useSnackbar();

const {
linodes: {
error: { read: linodesError },
},
} = useLinodes();

const [goToOpen, setGoToOpen] = React.useState(false);

const theme = preferences?.theme;
Expand Down Expand Up @@ -263,15 +256,6 @@ const BaseApp = withFeatureFlagProvider(
};
}, [handleMigrationEvent]);

/**
* in the event that we encounter an "invalid OAuth token" error from the API,
* we can simply refrain from rendering any content since the user will
* imminently be redirected to the login page.
*/
if (hasOauthError(linodesError)) {
return null;
}

return (
<ErrorBoundary fallback={<TheApplicationIsOnFire />}>
{/** Accessibility helper */}
Expand Down
121 changes: 35 additions & 86 deletions packages/manager/src/containers/withLinodes.container.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,40 @@
import { Linode } from '@linode/api-v4/lib/linodes';
import { APIError, Filter, Params } from '@linode/api-v4/lib/types';
import { path } from 'ramda';
import { connect, InferableComponentEnhancerWithProps } from 'react-redux';
import { ApplicationState } from 'src/store';
import { requestLinodes } from 'src/store/linodes/linode.requests';
import { State } from 'src/store/linodes/linodes.reducer';
import { LinodeWithMaintenanceAndDisplayStatus } from 'src/store/linodes/types';
import { ThunkDispatch } from 'src/store/types';
import { GetAllData } from 'src/utilities/getAll';

export interface DispatchProps {
getLinodes: (
params?: Params,
filters?: Filter
) => Promise<GetAllData<Linode>>;
import React from 'react';
import { CreateLinodeRequest, Linode } from '@linode/api-v4/lib/linodes';
import { APIError } from '@linode/api-v4/lib/types';
import {
useAllLinodesQuery,
useCreateLinodeMutation,
} from 'src/queries/linodes/linodes';

interface Actions {
createLinode: (data: CreateLinodeRequest) => Promise<Linode>;
}

/* tslint:disable-next-line */
export interface StateProps {
linodesError?: APIError[];
linodesLoading: State['loading'];
linodesData: LinodeWithMaintenanceAndDisplayStatus[];
linodesLastUpdated: State['lastUpdated'];
linodesResults: State['results'];
export interface WithLinodesProps {
linodesError: APIError[] | null;
linodesLoading: boolean;
linodesData: Linode[] | undefined;
linodeActions: Actions;
}

type MapProps<ReduxStateProps, OwnProps> = (
ownProps: OwnProps,
linodes: Linode[],
loading: boolean,
error?: APIError[]
) => ReduxStateProps & Partial<StateProps>;

export type Props = DispatchProps & StateProps;

interface Connected {
<ReduxStateProps, OwnProps>(
mapStateToProps: MapProps<ReduxStateProps, OwnProps>
): InferableComponentEnhancerWithProps<
ReduxStateProps & Partial<StateProps> & DispatchProps & OwnProps,
OwnProps
>;
<ReduxStateProps, OwnProps>(): InferableComponentEnhancerWithProps<
ReduxStateProps & DispatchProps & OwnProps,
OwnProps
>;
}

const connected: Connected = <ReduxState extends {}, OwnProps extends {}>(
mapStateToProps?: MapProps<ReduxState, OwnProps>
) =>
connect<
(ReduxState & Partial<StateProps>) | StateProps,
DispatchProps,
OwnProps,
ApplicationState
>(
(state, ownProps) => {
const {
loading,
error,
itemsById,
lastUpdated,
results,
} = state.__resources.linodes;
const linodes = Object.values(itemsById);
if (mapStateToProps) {
return mapStateToProps(
ownProps,
linodes,
loading,
path(['read'], error)
);
}

return {
linodesError: path(['read'], error),
linodesLoading: loading,
linodesData: linodes,
linodesResults: results,
linodesLastUpdated: lastUpdated,
};
export const withLinodes = <Props>(
Component: React.ComponentType<Props & WithLinodesProps>
) => (props: Props) => {
const {
data: linodesData,
isLoading: linodesLoading,
error: linodesError,
} = useAllLinodesQuery();

const { mutateAsync: createLinode } = useCreateLinodeMutation();

return React.createElement(Component, {
...props,
linodesData,
linodesLoading,
linodesError,
linodeActions: {
createLinode,
},
(dispatch: ThunkDispatch) => ({
getLinodes: (params, filter) =>
dispatch(requestLinodes({ params, filter })),
})
);

export default connected;
});
};
26 changes: 8 additions & 18 deletions packages/manager/src/features/Account/EnableManaged.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,20 @@ import Typography from 'src/components/core/Typography';
import ExternalLink from 'src/components/ExternalLink';
import Grid from '@mui/material/Unstable_Grid2';
import { SupportLink } from 'src/components/SupportLink';
import withLinodes, {
DispatchProps,
} from 'src/containers/withLinodes.container';
import { pluralize } from 'src/utilities/pluralize';
import { updateAccountSettingsData } from 'src/queries/accountSettings';
import { useQueryClient } from 'react-query';
import { useLinodesQuery } from 'src/queries/linodes/linodes';

interface Props {
isManaged: boolean;
}

interface StateProps {
linodeCount: number;
}

type CombinedProps = Props & StateProps & DispatchProps;

interface ContentProps {
isManaged: boolean;
openConfirmationModal: () => void;
}

export const ManagedContent = (props: ContentProps) => {
const { isManaged, openConfirmationModal } = props;

Expand Down Expand Up @@ -66,13 +59,16 @@ export const ManagedContent = (props: ContentProps) => {
);
};

export const EnableManaged = (props: CombinedProps) => {
const { isManaged, linodeCount } = props;
export const EnableManaged = (props: Props) => {
const { isManaged } = props;
const queryClient = useQueryClient();
const { data: linodes } = useLinodesQuery();
const [isOpen, setOpen] = React.useState<boolean>(false);
const [error, setError] = React.useState<string | undefined>();
const [isLoading, setLoading] = React.useState<boolean>(false);

const linodeCount = linodes?.results ?? 0;

const handleClose = () => {
setOpen(false);
setError(undefined);
Expand All @@ -94,7 +90,7 @@ export const EnableManaged = (props: CombinedProps) => {
.catch(handleError);
};

const actions = () => (
const actions = (
<ActionsPanel>
<Button buttonType="secondary" onClick={handleClose} data-qa-cancel>
Cancel
Expand Down Expand Up @@ -137,9 +133,3 @@ export const EnableManaged = (props: CombinedProps) => {
</>
);
};

export default withLinodes<StateProps, Props>(
(ownProps, entities, loading, error) => ({
linodeCount: entities.length,
})
)(EnableManaged);
41 changes: 14 additions & 27 deletions packages/manager/src/features/Account/GlobalSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
import { Linode } from '@linode/api-v4/lib/linodes';
import { APIError } from '@linode/api-v4/lib/types';
import { useSnackbar } from 'notistack';
import { isEmpty } from 'ramda';
import * as React from 'react';
import { connect, MapDispatchToProps } from 'react-redux';
import { RouteComponentProps } from 'react-router-dom';
import { compose } from 'recompose';
import { AnyAction } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import { CircleProgress } from 'src/components/CircleProgress';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { useReduxLoad } from 'src/hooks/useReduxLoad';
import { ApplicationState } from 'src/store';
import { handleOpen } from 'src/store/backupDrawer';
import { getLinodesWithoutBackups } from 'src/store/selectors/getLinodesWithBackups';
import { MapState } from 'src/store/types';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
import AutoBackups from './AutoBackups';
import EnableManaged from './EnableManaged';
import { EnableManaged } from './EnableManaged';
import EnableObjectStorage from './EnableObjectStorage';
import NetworkHelper from './NetworkHelper';
import CloseAccountSetting from './CloseAccountSetting';
import {
useAccountSettings,
useMutateAccountSettings,
} from 'src/queries/accountSettings';
import { useAllLinodesQuery } from 'src/queries/linodes/linodes';

interface StateProps {
linodesWithoutBackups: Linode[];
}

interface DispatchProps {
interface Props {
actions: {
openBackupsDrawer: () => void;
};
}

type CombinedProps = StateProps & DispatchProps & RouteComponentProps<{}>;

const GlobalSettings = (props: CombinedProps) => {
const GlobalSettings = (props: Props) => {
const {
actions: { openBackupsDrawer },
linodesWithoutBackups,
} = props;

const {
Expand All @@ -50,12 +38,15 @@ const GlobalSettings = (props: CombinedProps) => {
error: accountSettingsError,
} = useAccountSettings();

const { data: linodes } = useAllLinodesQuery();

const linodesWithoutBackups =
linodes?.filter((linode) => !linode.backups.enabled) ?? [];

const { enqueueSnackbar } = useSnackbar();

const { mutateAsync: updateAccount } = useMutateAccountSettings();

const { _loading } = useReduxLoad(['linodes']);

const displayError = (errors: APIError[] | undefined) => {
if (!errors) {
return;
Expand All @@ -70,9 +61,10 @@ const GlobalSettings = (props: CombinedProps) => {
});
};

if (accountSettingsLoading || _loading) {
if (accountSettingsLoading) {
return <CircleProgress />;
}

if (accountSettingsError) {
return (
<ErrorState
Expand Down Expand Up @@ -119,11 +111,8 @@ const GlobalSettings = (props: CombinedProps) => {
</div>
);
};
const mapStateToProps: MapState<StateProps, {}> = (state) => ({
linodesWithoutBackups: getLinodesWithoutBackups(state.__resources),
});

const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (
const mapDispatchToProps: MapDispatchToProps<Props, {}> = (
dispatch: ThunkDispatch<ApplicationState, undefined, AnyAction>
) => {
return {
Expand All @@ -133,8 +122,6 @@ const mapDispatchToProps: MapDispatchToProps<DispatchProps, {}> = (
};
};

const connected = connect(mapStateToProps, mapDispatchToProps);

const enhanced = compose<CombinedProps, {}>(connected)(GlobalSettings);
const connected = connect(undefined, mapDispatchToProps);

export default enhanced;
export default connected(GlobalSettings);
Loading