Skip to content

Commit

Permalink
Migrate optimizations summary to federated module
Browse files Browse the repository at this point in the history
  • Loading branch information
dlabrecq committed Oct 17, 2023
1 parent 2432e9e commit 119b269
Show file tree
Hide file tree
Showing 19 changed files with 269 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Follow the prompts that follow.

2. Open the following URL
```
https://stage.foo.redhat.com:1337/beta/openshift/cost-management-mfe
https://stage.foo.redhat.com:1337/beta/microfrontend/cost-management
```

## Releasing the Koku-ui MFE
Expand Down
6 changes: 3 additions & 3 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ After releasing to each staging environment, open an incognito window and view o

Please ensure expected changes have been updated before releasing to the next staging environment.

1. For stage-stable, view https://console.stage.redhat.com/openshift/cost-management-mfe/
2. For prod-beta, view https://console.redhat.com/beta/openshift/cost-management-mfe/
3. For prod-stable, view https://console.redhat.com/openshift/cost-management-mfe/
1. For stage-stable, view https://console.stage.redhat.com/microfrontend/cost-management/
2. For prod-beta, view https://console.redhat.com/beta/microfrontend/cost-management/
3. For prod-stable, view https://console.redhat.com/microfrontend/cost-management/

## Release notes

Expand Down
6 changes: 3 additions & 3 deletions deploy/frontend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ objects:
routes:
- appId: 'cost-management-mfe'
title: Overview
href: "/openshift/cost-management-mfe"
href: "/microfrontend/cost-management"
- appId: 'cost-management-mfe'
title: 'OpenShift'
href: '/openshift/cost-management-mfe/ocp'
href: '/microfrontend/cost-management/ocp'
module:
manifestLocation: "/apps/cost-management-mfe/fed-mods.json"
modules:
- id: "cost-management-mfe"
module: "./RootApp"
routes:
- pathname: /openshift/cost-management-mfe
- pathname: /microfrontend/cost-management
parameters:
- name: ENV_NAME
required: true
Expand Down
3 changes: 2 additions & 1 deletion fec.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class WatchRunPlugin {
}

module.exports = {
appUrl: '/openshift/cost-management-mfe',
appUrl: '/microfrontend/cost-management',
debug: true,
interceptChromeConfig: false, // Change to false after your app is registered in configuration files
proxyVerbose: true,
Expand Down Expand Up @@ -63,6 +63,7 @@ module.exports = {
'./RootApp': path.resolve(__dirname, './src/appEntry.tsx'),
// Shared component module path. Must include default export!
'./OptimizationsBadge': path.resolve(__dirname, './src/fed-modules/optimizationsBadge.tsx'),
'./OptimizationsSummary': path.resolve(__dirname, './src/fed-modules/optimizationsSummary.tsx'),
},
shared: [
{ 'react-redux': { version: dependencies['react-redux'] } },
Expand Down
6 changes: 6 additions & 0 deletions locales/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -10746,6 +10746,12 @@
"value": "Last 24 hrs"
}
],
"optimizationsSummaryDemo": [
{
"type": 0,
"value": "Optimizations Summary Demo"
}
],
"optimizationsTableAriaLabel": [
{
"type": 0,
Expand Down
1 change: 1 addition & 0 deletions locales/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@
"optimizationsNames": "{value, select, cluster {Cluster names} container {Container names} last_reported {Last reported} project {Project names} workload {Workload names} workload_type {Workload types} other {}}",
"optimizationsPerspective": "View optimizations based on",
"optimizationsShortTerm": "Last 24 hrs",
"optimizationsSummaryDemo": "Optimizations Summary Demo",
"optimizationsTableAriaLabel": "Optimizations table",
"optimizationsValue": "{value}{units}",
"optimizationsValues": "{value, select, cluster {Cluster name} container {Container name} last_reported {Last reported} project {Project name} workload {Workload name} workload_type {Workload type} other {}}",
Expand Down
3 changes: 2 additions & 1 deletion src/components/permissions/permissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ const PermissionsBase: React.FC<PermissionsProps> = ({
case formatPath(routes.ocpBreakdownOptimizations.path):
case formatPath(routes.ocpDetails.path):
return ocp;
case formatPath(routes.optimizationsBadgeDemo.path):
case formatPath(routes.optimizationsBadge.path):
case formatPath(routes.optimizationsBreakdown.path):
case formatPath(routes.optimizationsDetails.path):
case formatPath(routes.optimizationsSummary.path):
return ros;
case formatPath(routes.rhelBreakdown.path):
case formatPath(routes.rhelDetails.path):
Expand Down
26 changes: 26 additions & 0 deletions src/fed-modules/optimizationsSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable no-console */
import IntlProvider from '@redhat-cloud-services/frontend-components-translations/Provider';
import { getLocale } from 'components/i18n';
import React from 'react';
import { OptimizationsSummary } from 'routes/optimizations/optimizationsSummary';

// eslint-disable-next-line no-restricted-imports
import messages from '../../locales/data.json';

export interface OptimizationsSummaryOwnProps {
toPath?: string;
}

type OptimizationsSummaryProps = OptimizationsSummaryOwnProps;

const MfeOptimizationsSummary: React.FC<OptimizationsSummaryProps> = ({ toPath }: OptimizationsSummaryOwnProps) => {
const locale = getLocale();

return (
<IntlProvider defaultLocale="en" locale={locale} messages={messages[locale]} onError={console.log}>
<OptimizationsSummary toPath={toPath} />
</IntlProvider>
);
};

export default MfeOptimizationsSummary;
7 changes: 6 additions & 1 deletion src/locales/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2713,7 +2713,7 @@ export default defineMessages({
},
optimizationsDetails: {
defaultMessage: '{count, plural, =0 {No optimizations} =1 {{count} optimization} other {{count} optimizations}}',
description: 'Recommendation details',
description: 'Optimization details',
id: 'optimizationsDetails',
},
optimizationsInfo: {
Expand Down Expand Up @@ -2774,6 +2774,11 @@ export default defineMessages({
description: 'Last 24 hrs',
id: 'optimizationsShortTerm',
},
optimizationsSummaryDemo: {
defaultMessage: 'Optimizations Summary Demo',
description: 'Optimizations Summary Demo',
id: 'optimizationsSummaryDemo',
},
optimizationsTableAriaLabel: {
defaultMessage: 'Optimizations table',
description: 'Optimizations table',
Expand Down
16 changes: 13 additions & 3 deletions src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ const OptimizationsBreakdown = lazy(
const OptimizationsDetails = lazy(
() => import(/* webpackChunkName: "recommendations" */ 'routes/optimizations/optimizationsDetails')
);
const Overview = lazy(() => import(/* webpackChunkName: "overview" */ 'routes/overview'));
const OptimizationsSummaryDemo = lazy(
() =>
import(
/* webpackChunkName: "recommendations" */ 'routes/optimizations/optimizationsSummary/optimizationsSummaryDemo'
)
);
// const Overview = lazy(() => import(/* webpackChunkName: "overview" */ 'routes/overview'));
const RhelDetails = lazy(() => import(/* webpackChunkName: "rhelDetails" */ 'routes/details/rhelDetails'));
const RhelBreakdown = lazy(() => import(/* webpackChunkName: "rhelBreakdown" */ 'routes/details/rhelBreakdown'));
const Settings = lazy(() => import(/* webpackChunkName: "overview" */ 'routes/settings'));
Expand Down Expand Up @@ -96,7 +102,7 @@ const routes = {
element: userAccess(OcpDetails),
path: '/ocp',
},
optimizationsBadgeDemo: {
optimizationsBadge: {
element: userAccess(OptimizationsBadgeDemo),
path: '/optimizations/badge',
},
Expand All @@ -108,8 +114,12 @@ const routes = {
element: userAccess(OptimizationsDetails),
path: '/optimizations',
},
optimizationsSummary: {
element: userAccess(OptimizationsSummaryDemo),
path: '/optimizations/summary',
},
overview: {
element: userAccess(Overview),
element: userAccess(OptimizationsBadgeDemo),
path: '/',
},
rhelBreakdown: {
Expand Down
10 changes: 9 additions & 1 deletion src/routes/details/components/breakdown/breakdownBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,15 @@ class BreakdownBase extends React.Component<BreakdownProps, BreakdownState> {
<>
<TabTitleText>{this.getTabTitle(tab)}</TabTitleText>
{badge && (
<span>{<AsyncComponent scope="costManagementMfe" appName="cost-management-mfe" module="./Badge" />}</span>
<span>
{
<AsyncComponent
scope="costManagementMfe"
appName="cost-management-mfe"
module="./OptimizationsBadge"
/>
}
</span>
)}
</>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const OptimizationsBadge: React.FC<OptimizationsBadgeProps> = ({ filter, filterV

const count = report?.meta ? report.meta.count : 0;

return <Badge screenReaderText={intl.formatMessage(messages.optimizationsDetails, { count })}>{count}</Badge>;
return <Badge screenReaderText={intl.formatMessage(messages.optimizationsDetails, { count })}>{count} Test</Badge>;
};

const useMapToProps = ({ filter, filterValue }: OptimizationsBadgeOwnProps): OptimizationsBadgeStateProps => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { useIntl } from 'react-intl';

import { OptimizationsBadge } from './optimizationsBadge';

interface OptimizationsDetailsOwnProps {
interface OptimizationsBadgeOwnProps {
// TBD...
}

type OptimizationsDetailsProps = OptimizationsDetailsOwnProps;
type OptimizationsBadgeProps = OptimizationsBadgeOwnProps;

const OptimizationsBadgeDemo: React.FC<OptimizationsDetailsProps> = () => {
const OptimizationsBadgeDemo: React.FC<OptimizationsBadgeProps> = () => {
const intl = useIntl();

return (
Expand Down
2 changes: 2 additions & 0 deletions src/routes/optimizations/optimizationsSummary/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './optimizationsSummary';
export { default as OptimizationsSummaryDemo } from './optimizationsSummaryDemo';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import global_FontSize_md from '@patternfly/react-tokens/dist/js/global_FontSize_md';
import type React from 'react';

export const styles = {
infoIcon: {
fontSize: global_FontSize_md.value,
},
} as { [className: string]: React.CSSProperties };
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import url("~@patternfly/patternfly/base/patternfly-variables.css");

.skeleton {
height: 125px;
margin-bottom: var(--pf-v5-global--spacer--md);
margin-top: var(--pf-v5-global--spacer--md);
}

.summary {
height: 100%;
}
122 changes: 122 additions & 0 deletions src/routes/optimizations/optimizationsSummary/optimizationsSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {
Button,
ButtonVariant,
Card,
CardBody,
CardTitle,
Popover,
Skeleton,
Title,
TitleSizes,
} from '@patternfly/react-core';
import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons/dist/esm/icons/outlined-question-circle-icon';
import { getQuery } from 'api/queries/query';
import type { RosReport } from 'api/ros/ros';
import { RosPathsType, RosType } from 'api/ros/ros';
import type { AxiosError } from 'axios';
import messages from 'locales/messages';
import React, { useEffect } from 'react';
import { useIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import type { AnyAction } from 'redux';
import type { ThunkDispatch } from 'redux-thunk';
import { skeletonWidth } from 'routes/utils/skeleton';
import type { RootState } from 'store';
import { FetchStatus } from 'store/common';
import { rosActions, rosSelectors } from 'store/ros';

import { styles } from './optimizations.styles';

export interface OptimizationsSummaryOwnProps {
toPath?: string;
}

export interface OptimizationsSummaryStateProps {
report?: RosReport;
reportError?: AxiosError;
reportFetchStatus?: FetchStatus;
reportQueryString?: string;
}

type OptimizationsSummaryProps = OptimizationsSummaryOwnProps & OptimizationsSummaryStateProps;

const reportPathsType = RosPathsType.recommendations;
const reportType = RosType.ros;

const OptimizationsSummary: React.FC<OptimizationsSummaryProps> = ({ toPath }: OptimizationsSummaryOwnProps) => {
const intl = useIntl();
const { report, reportFetchStatus } = useMapToProps();

const count = report?.meta ? report.meta.count : 0;
const description = intl.formatMessage(messages.optimizationsDetails, { count });

return (
<Card className="summary">
<CardTitle>
<Title headingLevel="h2" size={TitleSizes.lg}>
{intl.formatMessage(messages.optimizations)} Test
<span style={styles.infoIcon}>
<Popover
aria-label={intl.formatMessage(messages.optimizationsInfoArialLabel)}
enableFlip
bodyContent={<p style={styles.infoTitle}>{intl.formatMessage(messages.optimizationsInfo)}</p>}
>
<Button
aria-label={intl.formatMessage(messages.optimizationsInfoButtonArialLabel)}
variant={ButtonVariant.plain}
>
<OutlinedQuestionCircleIcon />
</Button>
</Popover>
</span>
</Title>
</CardTitle>
<CardBody>
{reportFetchStatus === FetchStatus.inProgress ? (
<>
<Skeleton width="16%" />
<Skeleton className="skeleton" width={skeletonWidth.md} />
</>
) : toPath && count > 0 ? (
<Link to={toPath}>{description}</Link>
) : (
description
)}
</CardBody>
</Card>
);
};

const useMapToProps = (): OptimizationsSummaryStateProps => {
const dispatch: ThunkDispatch<RootState, any, AnyAction> = useDispatch();

const reportQuery: any = {
// TBD...
};
const reportQueryString = getQuery(reportQuery);
const report: any = useSelector((state: RootState) =>
rosSelectors.selectRos(state, reportPathsType, reportType, reportQueryString)
);
const reportFetchStatus = useSelector((state: RootState) =>
rosSelectors.selectRosFetchStatus(state, reportPathsType, reportType, reportQueryString)
);
const reportError = useSelector((state: RootState) =>
rosSelectors.selectRosError(state, reportPathsType, reportType, reportQueryString)
);

useEffect(() => {
if (!reportError && reportFetchStatus !== FetchStatus.inProgress) {
dispatch(rosActions.fetchRosReport(reportPathsType, reportType, reportQueryString));
}
}, [reportQueryString]);

return {
report,
reportError,
reportFetchStatus,
reportQueryString,
};
};

export { OptimizationsSummary };
Loading

0 comments on commit 119b269

Please sign in to comment.