Skip to content

Commit f75e629

Browse files
authored
[LG-5432] feat(suggestions): add apply state and improve component flexibility (#3033)
* feat(suggestions): add apply state, remove fixed width, and spread props to root node * docs(suggestions): update README * chore(suggestions): changeset * chore: lint fix * test(suggestions): remove redundant tests
1 parent 036315f commit f75e629

File tree

7 files changed

+57
-38
lines changed

7 files changed

+57
-38
lines changed

.changeset/puny-laws-thank.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@lg-chat/suggestions': minor
3+
---
4+
5+
[LG-5432](https://jira.mongodb.org/browse/LG-5432): add `'apply'` state value to conditionally render apply button. `'unset'` state will now no longer render the apply button. Also enables HTMLDivElement props to spread to the root container node and removes the fixed width. Styles can be further customized using `className` prop.

chat/suggestions/README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,20 @@ const configurationParameters = [
3737
{ key: 'vCPUs', value: '2 vCPUs' },
3838
];
3939

40-
// Basic suggestion card with apply button
40+
// Basic suggestion card
4141
<SuggestedActions
4242
state={State.Unset}
4343
configurationParameters={configurationParameters}
4444
onClickApply={() => console.log('Apply clicked')}
4545
/>
4646

47+
// Apply state with apply button
48+
<SuggestedActions
49+
state={State.Apply}
50+
configurationParameters={configurationParameters}
51+
onClickApply={() => console.log('Apply clicked')}
52+
/>
53+
4754
// Success state with applied parameters
4855
<SuggestedActions
4956
state={State.Success}
@@ -75,7 +82,8 @@ The `State` enum provides the following options:
7582

7683
| State | Value | Description |
7784
| --------- | ----------- | ------------------------------------------------------ |
78-
| `Unset` | `'unset'` | Shows configuration suggestions with an "Apply" button |
85+
| `Unset` | `'unset'` | Shows configuration suggestions |
86+
| `Apply` | `'apply'` | Shows configuration suggestions with an "Apply" button |
7987
| `Success` | `'success'` | Shows success banner with applied parameters |
8088
| `Error` | `'error'` | Shows error banner with failed parameters |
8189

@@ -93,16 +101,16 @@ interface ConfigurationParameter {
93101

94102
The component automatically filters and displays parameters based on their state:
95103

96-
- **Table**: Shows parameters with `unset` state (or no state)
104+
- **Table**: Shows parameters with `unset` or `apply` state (or no state)
97105
- **Success Banner**: Shows parameters with `success` state
98106
- **Error Banner**: Shows parameters with `error` state
99107

100108
## Properties
101109

102110
| Prop | Type | Description | Default |
103111
| ------------------------- | ------------------------- | -------------------------------------------------------------------------------------------- | ------- |
104-
| `state` | `State` | Determines the current state and rendering behavior of the suggestion card | |
105112
| `configurationParameters` | `ConfigurationParameters` | Array of configuration parameters, each with key, value, and optional state | |
106-
| `onClickApply` | `() => void` | Callback fired when the user clicks the "Apply" button (shown when `state` is `State.Unset`) | |
107113
| `darkMode` | `boolean` | Determines if the component is rendered in dark mode | `false` |
114+
| `onClickApply` | `() => void` | Callback fired when the user clicks the "Apply" button (shown when `state` is `State.Apply`) | |
115+
| `state` | `State` | Determines the current state and rendering behavior of the suggestion card | |
108116
| `...` | `HTMLElementProps<'div'>` | Props spread on root element | |

chat/suggestions/src/SuggestedActions/SuggestedActions.spec.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ describe('chat/suggestions', () => {
185185
describe('Apply button', () => {
186186
test('renders when state is Unset', () => {
187187
renderSuggestedActions({ state: State.Unset });
188+
expect(
189+
screen.getByText('Apply configuration to your cluster?'),
190+
).toBeInTheDocument();
191+
});
192+
193+
test('renders when state is Apply', () => {
194+
renderSuggestedActions({ state: State.Apply });
188195
const button = screen.getByRole('button', {
189196
name: /apply these suggestions/i,
190197
});
@@ -205,9 +212,9 @@ describe('chat/suggestions', () => {
205212
).not.toBeInTheDocument();
206213
});
207214

208-
test('calls onClickApply when clicked', () => {
215+
test('calls onClickApply when clicked in Apply state', () => {
209216
const onClickApply = jest.fn();
210-
renderSuggestedActions({ state: State.Unset, onClickApply });
217+
renderSuggestedActions({ state: State.Apply, onClickApply });
211218

212219
const button = screen.getByRole('button', {
213220
name: /apply these suggestions/i,
@@ -216,16 +223,6 @@ describe('chat/suggestions', () => {
216223

217224
expect(onClickApply).toHaveBeenCalledTimes(1);
218225
});
219-
220-
test('has correct button attributes', () => {
221-
renderSuggestedActions({ state: State.Unset });
222-
const button = screen.getByRole('button', {
223-
name: /apply these suggestions/i,
224-
});
225-
226-
expect(button).toHaveAttribute('type', 'button');
227-
expect(button).not.toBeDisabled();
228-
});
229226
});
230227

231228
describe('Status banner', () => {

chat/suggestions/src/SuggestedActions/SuggestedActions.styles.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { css } from '@leafygreen-ui/emotion';
1+
import { css, cx } from '@leafygreen-ui/emotion';
22
import { Theme } from '@leafygreen-ui/lib';
33
import {
44
borderRadius,
@@ -8,15 +8,16 @@ import {
88
typeScales,
99
} from '@leafygreen-ui/tokens';
1010

11-
const DIVIDER_WIDTH = 353;
12-
13-
export const dividerStyles = css`
14-
width: ${DIVIDER_WIDTH}px;
11+
export const baseContainerStyles = css`
12+
width: 100%;
1513
display: flex;
1614
flex-direction: column;
1715
gap: ${spacing[400]}px;
1816
`;
1917

18+
export const getContainerStyles = (className?: string) =>
19+
cx(baseContainerStyles, className);
20+
2021
export const getSuggestedActionsWrapperStyles = (theme: Theme) => css`
2122
background-color: ${color[theme].background.secondary.default};
2223
border: 1px solid ${color[theme].border.secondary.default};

chat/suggestions/src/SuggestedActions/SuggestedActions.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { StatusBanner } from '../StatusBanner/StatusBanner';
1212
import {
1313
applyButtonStyles,
1414
boldedTextStyle,
15-
dividerStyles,
15+
getContainerStyles,
1616
getSuggestedActionsWrapperStyles,
1717
tableCellStyles,
1818
tableHeaderStyles,
@@ -21,13 +21,17 @@ import {
2121
import { SuggestedActionsProps } from './SuggestedActions.types';
2222

2323
const SuggestedActions = forwardRef<HTMLDivElement, SuggestedActionsProps>(
24-
(props: SuggestedActionsProps, fwdRef: React.Ref<HTMLDivElement>) => {
25-
const {
26-
state,
24+
(
25+
{
26+
className,
2727
configurationParameters,
28-
onClickApply,
2928
darkMode: darkModeProp,
30-
} = props;
29+
onClickApply,
30+
state,
31+
...rest
32+
},
33+
fwdRef,
34+
) => {
3135
const { theme, darkMode } = useDarkMode(darkModeProp);
3236

3337
// Filter parameters by state
@@ -40,7 +44,7 @@ const SuggestedActions = forwardRef<HTMLDivElement, SuggestedActionsProps>(
4044

4145
return (
4246
<LeafyGreenProvider darkMode={darkMode}>
43-
<div ref={fwdRef} className={dividerStyles}>
47+
<div ref={fwdRef} className={getContainerStyles(className)} {...rest}>
4448
<div className={getSuggestedActionsWrapperStyles(theme)}>
4549
<div className={boldedTextStyle}>
4650
Apply configuration to your cluster?
@@ -53,7 +57,7 @@ const SuggestedActions = forwardRef<HTMLDivElement, SuggestedActionsProps>(
5357
</tr>
5458
))}
5559
</table>
56-
{state === State.Unset && (
60+
{state === State.Apply && (
5761
<Button
5862
className={applyButtonStyles}
5963
variant="primary"

chat/suggestions/src/SuggestedActions/SuggestedActions.types.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,23 @@ import { ConfigurationParameters, State } from '../shared.types';
55
export interface SuggestedActionsProps
66
extends HTMLElementProps<'div'>,
77
DarkModeProps {
8-
/**
9-
* Determines rendering of the SuggestedActions:
10-
* - `'Unset'` will render suggestions and the "Apply" button
11-
* - `'Success'` will render success banner with applied suggestions
12-
* - `'Error'` will render error banner with instructions to manually apply suggestions
13-
*/
14-
state: State;
158
/**
169
* Configuration parameters with their individual state values.
17-
* Each parameter includes a key, value, and state (unset/success/error).
10+
* Each parameter includes a key, value, and state (unset/apply/success/error).
1811
*/
1912
configurationParameters: ConfigurationParameters;
13+
2014
/**
2115
* Callback fired when the user clicks the "Apply" button
2216
*/
2317
onClickApply: () => void;
18+
19+
/**
20+
* Determines rendering of the SuggestedActions:
21+
* - `'Unset'` will render suggestions
22+
* - `'Apply'` will render suggestions and the "Apply" button
23+
* - `'Success'` will render success banner with applied suggestions
24+
* - `'Error'` will render error banner with instructions to manually apply suggestions
25+
*/
26+
state: State;
2427
}

chat/suggestions/src/shared.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44
export const State = {
55
Unset: 'unset',
6+
Apply: 'apply',
67
Success: 'success',
78
Error: 'error',
89
} as const;

0 commit comments

Comments
 (0)