Skip to content

Commit

Permalink
Migrate DetailsCard from ClassBased to Function based component (#2670)
Browse files Browse the repository at this point in the history
## Which problem is this PR solving?
- (#2610)

## Description of the changes
- This PR migrates Details Card from a class based to a function based
component.

## Checklist
- [x] I have read
https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md
- [x] I have signed all commits
- [x] I have added unit tests for the new functionality
- [ ] I have run lint and test steps successfully
  - for `jaeger`: `make lint test`
  - for `jaeger-ui`: `npm run lint` and `npm run test`

Signed-off-by: yaten2302 <yaten598@gmail.com>
  • Loading branch information
yaten2302 authored Feb 16, 2025
1 parent b8986b3 commit caed0b4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,20 @@ describe('DetailsCard', () => {
});

it('renders as collapsible', () => {
expect(shallow(<DetailsCard header={header} />).state('collapsed')).toBe(false);
expect(
shallow(<DetailsCard header={header} />)
.find('.DetailsCard--DetailsWrapper')
.hasClass('is-collapsed')
).toBe(false);

const wrapper = shallow(<DetailsCard collapsible header={header} />);
expect(wrapper.state('collapsed')).toBe(true);
expect(wrapper.find('.DetailsCard--DetailsWrapper').hasClass('is-collapsed')).toBe(true);
expect(wrapper).toMatchSnapshot();

wrapper.find('button').simulate('click');
expect(wrapper.state('collapsed')).toBe(false);
expect(wrapper.find('.DetailsCard--DetailsWrapper').hasClass('is-collapsed')).toBe(false);

wrapper.find('button').simulate('click');
expect(wrapper.state('collapsed')).toBe(true);
expect(wrapper.find('.DetailsCard--DetailsWrapper').hasClass('is-collapsed')).toBe(true);
});
});
77 changes: 28 additions & 49 deletions packages/jaeger-ui/src/components/common/DetailsCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import cx from 'classnames';
import { IoChevronDown } from 'react-icons/io5';

import { TColumnDefs, TDetails, TRow } from './types';
import DetailTable from './DetailTable';
import DetailList from './DetailList';
import DetailTable from './DetailTable';

import './index.css';

Expand All @@ -31,67 +31,46 @@ type TProps = {
header: string;
};

type TState = {
collapsed: boolean;
};

function isList(arr: string[] | TRow[]): arr is string[] {
return typeof arr[0] === 'string';
}

export default class DetailsCard extends React.PureComponent<TProps> {
state: TState;

constructor(props: TProps) {
super(props);

this.state = { collapsed: Boolean(props.collapsible) };
}

renderDetails() {
const { columnDefs, details } = this.props;
function DetailsCard({ className, collapsible = false, description, header, columnDefs, details }: TProps) {
const [isCollapsed, setIsCollapsed] = React.useState(Boolean(collapsible));

const renderDetails = () => {
if (Array.isArray(details)) {
if (details.length === 0) return null;

if (isList(details)) return <DetailList details={details} />;
return <DetailTable columnDefs={columnDefs} details={details} />;
}

return <span>{details}</span>;
}

toggleCollapse = () => {
this.setState((prevState: TState) => ({
collapsed: !prevState.collapsed,
}));
};

render() {
const { collapsed } = this.state;
const { className, collapsible, description, header } = this.props;

return (
<div className={cx('DetailsCard', className)}>
<div className="DetailsCard--ButtonHeaderWrapper">
{collapsible && (
<button
onClick={this.toggleCollapse}
type="button"
className={cx('DetailsCard--Collapser', { 'is-collapsed': collapsed })}
>
<IoChevronDown />
</button>
)}
<div className="DetailsCard--HeaderWrapper">
<span className="DetailsCard--Header">{header}</span>
{description && <p className="DetailsCard--Description">{description}</p>}
</div>
</div>
<div className={cx('DetailsCard--DetailsWrapper', { 'is-collapsed': collapsed })}>
{this.renderDetails()}
const toggleCollapsed = React.useCallback(() => setIsCollapsed(!isCollapsed), [isCollapsed]);

return (
<div className={cx('DetailsCard', className)}>
<div className="DetailsCard--ButtonHeaderWrapper">
{collapsible && (
<button
onClick={toggleCollapsed}
type="button"
className={cx('DetailsCard--Collapser', { 'is-collapsed': isCollapsed })}
>
<IoChevronDown />
</button>
)}
<div className="DetailsCard--HeaderWrapper">
<span className="DetailsCard--Header">{header}</span>
{description && <p className="DetailsCard--Description">{description}</p>}
</div>
</div>
);
}
<div className={cx('DetailsCard--DetailsWrapper', { 'is-collapsed': isCollapsed })}>
{renderDetails()}
</div>
</div>
);
}

export default DetailsCard;

0 comments on commit caed0b4

Please sign in to comment.