Skip to content

Commit

Permalink
Merge pull request #3329 from dlabrecq/cost-models-layout
Browse files Browse the repository at this point in the history
Update cost models settings layout per mocks
  • Loading branch information
dlabrecq authored Aug 10, 2023
2 parents 42512d6 + 2d5d7bb commit f8c1617
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 89 deletions.
10 changes: 8 additions & 2 deletions locales/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -1376,10 +1376,10 @@
"value": "Should not exceed 100 characters"
}
],
"costModelsLastChange": [
"costModelsLastUpdated": [
{
"type": 0,
"value": "Last change"
"value": "Last updated"
}
],
"costModelsPopover": [
Expand Down Expand Up @@ -11230,6 +11230,12 @@
"value": "Failed to get RBAC information"
}
],
"readOnly": [
{
"type": 0,
"value": "Read only"
}
],
"readOnlyPermissions": [
{
"type": 0,
Expand Down
3 changes: 2 additions & 1 deletion locales/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
"costModelsFilterPlaceholder": "Filter by name...",
"costModelsFilterTagKey": "Filter by tag key",
"costModelsInfoTooLong": "Should not exceed 100 characters",
"costModelsLastChange": "Last change",
"costModelsLastUpdated": "Last updated",
"costModelsPopover": "A cost model allows you to associate a price to metrics provided by your sources to charge for utilization of resources. {learnMore}",
"costModelsPopoverAriaLabel": "Cost model info popover",
"costModelsPopoverButtonAriaLabel": "Opens a dialog with cost model info",
Expand Down Expand Up @@ -484,6 +484,7 @@
"rawCostTitle": "Raw cost",
"rbacErrorDesc": "There was a problem receiving user permissions. Refreshing this page may fix it. If it does not, please contact your admin.",
"rbacErrorTitle": "Failed to get RBAC information",
"readOnly": "Read only",
"readOnlyPermissions": "You have read only permissions",
"recommended": "Recommended",
"redHatStatusUrl": "https://status.redhat.com",
Expand Down
5 changes: 3 additions & 2 deletions src/__mocks__/react-intl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ const mockedReactIntl = jest.genMockFromModule('react-intl') as any;
const intl = {
formatDate: jest.fn(() => ''), // Dates won't match snapshots during PR builds
formatDateTimeRange: jest.fn(() => ''), // Dates won't match snapshots during PR builds
formatMessage: ({ defaultMessage }, params?) => {
formatMessage: jest.fn(({ defaultMessage }, params?) => {
if (!params) {
return defaultMessage;
}
return defaultMessage + JSON.stringify(params);
},
}),
formatNumber: jest.fn(v => v),
};

mockedReactIntl.createIntl = () => intl;
mockedReactIntl.defineMessages = jest.fn(v => v);
mockedReactIntl.injectIntl = jest.fn(v => v);
// mockedReactIntl.injectIntl = Component => props => <Component {...props} intl={intl} />;
mockedReactIntl.useIntl = () => intl;

module.exports = mockedReactIntl;
13 changes: 9 additions & 4 deletions src/locales/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,10 +610,10 @@ export default defineMessages({
description: 'Should not exceed 100 characters',
id: 'costModelsInfoTooLong',
},
costModelsLastChange: {
defaultMessage: 'Last change',
description: 'Last change',
id: 'costModelsLastChange',
costModelsLastUpdated: {
defaultMessage: 'Last updated',
description: 'Last updated',
id: 'costModelsLastUpdated',
},
costModelsPopover: {
defaultMessage:
Expand Down Expand Up @@ -3014,6 +3014,11 @@ export default defineMessages({
description: 'RBAC error title',
id: 'rbacErrorTitle',
},
readOnly: {
defaultMessage: 'Read only',
description: 'Read only',
id: 'readOnly',
},
readOnlyPermissions: {
defaultMessage: 'You have read only permissions',
description: 'You have read only permissions',
Expand Down
2 changes: 1 addition & 1 deletion src/routes/costModels/costModelsDetails/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class CostModelsTableBase extends React.Component<CostModelsTableProps, CostMode
},
{ title: intl.formatMessage(messages.costModelsAssignedSources) },
{
title: intl.formatMessage(messages.costModelsLastChange),
title: intl.formatMessage(messages.costModelsLastUpdated),
data: { orderName: 'updated_timestamp' },
...(rows.length && { transforms: [sortable] }),
},
Expand Down
17 changes: 10 additions & 7 deletions src/routes/settings/costModels/components/readOnlyTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { Tooltip } from '@patternfly/react-core';
import messages from 'locales/messages';
import React from 'react';
import { useIntl } from 'react-intl';

interface ReadOnlyTooltipBase {
tooltip?: string;
children: JSX.Element;
isDisabled: boolean;
}

export const ReadOnlyTooltip: React.FC<ReadOnlyTooltipBase> = ({
children,
tooltip = 'You have read only permissions',
isDisabled,
}) => {
const ReadOnlyTooltip: React.FC<ReadOnlyTooltipBase> = ({ children, tooltip, isDisabled }) => {
const intl = useIntl();
const content = tooltip ? tooltip : intl.formatMessage(messages.readOnlyPermissions);

return isDisabled ? (
<Tooltip isContentLeftAligned content={<div>{tooltip}</div>}>
<div aria-label="Read only">{children}</div>
<Tooltip isContentLeftAligned content={<div>{content}</div>}>
<div aria-label={intl.formatMessage(messages.readOnly)}>{children}</div>
</Tooltip>
) : (
children
);
};

export { ReadOnlyTooltip };
2 changes: 1 addition & 1 deletion src/routes/settings/costModels/costModel/distribution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ const DistributionCardBase: React.FC<Props> = ({
<ReadOnlyTooltip key="edit" isDisabled={!isWritePermission}>
<Button
aria-label={intl.formatMessage(messages.costModelsDistributionEdit)}
variant={ButtonVariant.link}
isAriaDisabled={!isWritePermission}
onClick={() => setCostModelDialog({ isOpen: true, name: 'updateDistribution' })}
variant={ButtonVariant.link}
>
{intl.formatMessage(messages.edit)}
</Button>
Expand Down
47 changes: 30 additions & 17 deletions src/routes/settings/costModels/costModel/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { CostModel } from 'api/costModels';
import messages from 'locales/messages';
import React from 'react';
import type { WrappedComponentProps } from 'react-intl';
import { injectIntl } from 'react-intl';
import { useIntl } from 'react-intl';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { routes } from 'routes';
Expand Down Expand Up @@ -54,7 +54,6 @@ const Header: React.FC<Props> = ({
current,
deleteCostModel,
deleteError,
intl,
isDeleteProcessing,
isDialogOpen,
isWritePermission,
Expand All @@ -65,6 +64,18 @@ const Header: React.FC<Props> = ({
tabIndex,
}) => {
const [dropdownIsOpen, setDropdownIsOpen] = React.useState(false);
const intl = useIntl();

const dateTime: any = intl.formatDate(current.updated_timestamp, {
day: 'numeric',
hour: 'numeric',
hour12: false,
minute: 'numeric',
month: 'short',
timeZone: 'UTC',
timeZoneName: 'short',
year: 'numeric',
});

return (
<>
Expand Down Expand Up @@ -161,6 +172,10 @@ const Header: React.FC<Props> = ({
</Split>
<TextContent style={styles.currency}>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>
{intl.formatMessage(messages.costModelsLastUpdated)}
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>{dateTime}</TextListItem>
<TextListItem component={TextListItemVariants.dt}>{intl.formatMessage(messages.currency)}</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{intl.formatMessage(messages.currencyOptions, { units: current.currency || 'USD' })}
Expand Down Expand Up @@ -209,19 +224,17 @@ const Header: React.FC<Props> = ({
);
};

export default injectIntl(
withRouter(
connect(
createMapStateToProps(state => ({
isDialogOpen: costModelsSelectors.isDialogOpen(state)('costmodel'),
isDeleteProcessing: costModelsSelectors.deleteProcessing(state),
deleteError: costModelsSelectors.deleteError(state),
isWritePermission: rbacSelectors.isCostModelWritePermission(state),
})),
{
setDialogOpen: costModelsActions.setCostModelDialog,
deleteCostModel: costModelsActions.deleteCostModel,
}
)(Header)
)
export default withRouter(
connect(
createMapStateToProps(state => ({
isDialogOpen: costModelsSelectors.isDialogOpen(state)('costmodel'),
isDeleteProcessing: costModelsSelectors.deleteProcessing(state),
deleteError: costModelsSelectors.deleteError(state),
isWritePermission: rbacSelectors.isCostModelWritePermission(state),
})),
{
setDialogOpen: costModelsActions.setCostModelDialog,
deleteCostModel: costModelsActions.deleteCostModel,
}
)(Header)
);
2 changes: 1 addition & 1 deletion src/routes/settings/costModels/costModel/markup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ const MarkupCardBase: React.FC<Props> = ({
<ReadOnlyTooltip key="edit" isDisabled={!isWritePermission}>
<Button
aria-label={intl.formatMessage(messages.editMarkup)}
variant={ButtonVariant.link}
isAriaDisabled={!isWritePermission}
onClick={() => setCostModelDialog({ isOpen: true, name: 'updateMarkup' })}
variant={ButtonVariant.link}
>
{intl.formatMessage(messages.edit)}
</Button>
Expand Down
46 changes: 16 additions & 30 deletions src/routes/settings/costModels/costModel/sourcesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { IAction, IRow } from '@patternfly/react-table';
import { ActionsColumn, TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { Button, ButtonVariant } from '@patternfly/react-core';
import { MinusCircleIcon } from '@patternfly/react-icons/dist/esm/icons/minus-circle-icon';
import type { IRow } from '@patternfly/react-table';
import { TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { TableGridBreakpoint } from '@patternfly/react-table';
import messages from 'locales/messages';
import React from 'react';
import type { WrappedComponentProps } from 'react-intl';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { ReadOnlyTooltip } from 'routes/settings/costModels/components/readOnlyTooltip';
import { createMapStateToProps } from 'store/common';
import { costModelsSelectors } from 'store/costModels';
import { rbacSelectors } from 'store/rbac';
Expand All @@ -22,26 +25,6 @@ interface SourcesTableStateProps {
type SourcesTableProps = SourcesTableOwnProps & SourcesTableStateProps & WrappedComponentProps;

const SourcesTable: React.FC<SourcesTableProps> = ({ canWrite, costModels, intl, showDeleteDialog }) => {
const getActions = (): IAction[] => {
if (canWrite) {
return [
{
title: intl.formatMessage(messages.costModelsSourceDelete),
onClick: (_evt, rowIndex: number) => showDeleteDialog(rowIndex),
},
];
}
return [
{
style: { pointerEvents: 'auto' },
tooltip: intl.formatMessage(messages.readOnlyPermissions),
isDisabled: true,
title: intl.formatMessage(messages.costModelsSourceDelete),
},
];
};

const actions = getActions();
const rows: (IRow | string[])[] = costModels.length > 0 ? costModels[0].sources.map(source => [source.name]) : [];

return (
Expand All @@ -61,14 +44,17 @@ const SourcesTable: React.FC<SourcesTableProps> = ({ canWrite, costModels, intl,
<Tr key={rowIndex}>
<Td>{r}</Td>
<Td isActionCell>
<ActionsColumn
items={actions.map(a => {
return {
...a,
onClick: () => a.onClick(null, rowIndex, r, null),
};
})}
></ActionsColumn>
<ReadOnlyTooltip key="action" isDisabled={!canWrite}>
<Button
aria-label={intl.formatMessage(messages.costModelsSourceDelete)}
isAriaDisabled={!canWrite}
isSmall
onClick={() => showDeleteDialog(rowIndex)}
variant={ButtonVariant.plain}
>
<MinusCircleIcon />
</Button>
</ReadOnlyTooltip>
</Td>
</Tr>
))}
Expand Down
42 changes: 19 additions & 23 deletions src/routes/settings/costModels/costModelsDetails/table.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { ICell, IRowData, ThProps } from '@patternfly/react-table';
import { ActionsColumn, TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { Button, ButtonVariant } from '@patternfly/react-core';
import { MinusCircleIcon } from '@patternfly/react-icons/dist/esm/icons/minus-circle-icon';
import type { ICell, ThProps } from '@patternfly/react-table';
import { TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { sortable, TableGridBreakpoint } from '@patternfly/react-table';
import type { CostModel } from 'api/costModels';
import { intl as defaultIntl } from 'components/i18n';
Expand All @@ -9,14 +11,15 @@ import type { WrappedComponentProps } from 'react-intl';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import type { Dispatch } from 'redux';
import { ReadOnlyTooltip } from 'routes/settings/costModels/components/readOnlyTooltip';
import { createMapStateToProps } from 'store/common';
import { costModelsActions, costModelsSelectors } from 'store/costModels';
import { rbacSelectors } from 'store/rbac';
import type { RouterComponentProps } from 'utils/router';
import { withRouter } from 'utils/router';

import type { CostModelsQuery } from './utils/query';
import { createActions, createOnSort, getRowsByStateName } from './utils/table';
import { createOnSort, getRowsByStateName } from './utils/table';

interface CostModelsTableOwnProps {
actionResolver?: any;
Expand Down Expand Up @@ -75,7 +78,7 @@ class CostModelsTableBase extends React.Component<CostModelsTableProps, CostMode
},
{ title: intl.formatMessage(messages.costModelsAssignedSources) },
{
title: intl.formatMessage(messages.costModelsLastChange),
title: intl.formatMessage(messages.costModelsLastUpdated),
data: { orderName: 'updated_timestamp' },
...(rows.length && { transforms: [sortable] }),
},
Expand All @@ -85,16 +88,6 @@ class CostModelsTableBase extends React.Component<CostModelsTableProps, CostMode
},
] as ICell[];

const actions = createActions(stateName, canWrite, [
{
title: intl.formatMessage(messages.delete),
tooltip: intl.formatMessage(messages.readOnlyPermissions),
onClick: (_evt: React.MouseEvent, _rowIx: number, rowData: IRowData) => {
openDeleteDialog(rowData.data);
},
} as any,
]);

const onSort = createOnSort(cells, query, router);
const getSortParams = (columnIndex: number): ThProps['sort'] => ({
sortBy: {
Expand Down Expand Up @@ -137,16 +130,19 @@ class CostModelsTableBase extends React.Component<CostModelsTableProps, CostMode
{c.title ? c.title : c}
</Td>
))}
{!r.heightAuto && (
{!r.heightAuto && stateName === 'success' && (
<Td isActionCell>
<ActionsColumn
items={actions.map(a => {
return {
...a,
onClick: _evt => a.onClick(_evt, rowIndex, r, null),
};
})}
/>
<ReadOnlyTooltip key="action" isDisabled={!canWrite}>
<Button
aria-label={intl.formatMessage(messages.delete)}
isAriaDisabled={!canWrite}
isSmall
onClick={() => openDeleteDialog(r.data)}
variant={ButtonVariant.plain}
>
<MinusCircleIcon />
</Button>
</ReadOnlyTooltip>
</Td>
)}
</Tr>
Expand Down

0 comments on commit f8c1617

Please sign in to comment.