Unverified Commit df559ade authored by Marcos Iglesias's avatar Marcos Iglesias Committed by GitHub

feat: Adds Shimmer loader to the Table Issues and Footer (#483)

* Adds loading state to Table Issues and Footer

* Updates spacing on issues loader

* Updates issues block height to adapt to the content's height

* Prettier errors

* Reducing number of lines

* Retriveing pre-commit hook

* Fixing linting issues
parent 2718eb5f
......@@ -11,14 +11,14 @@ jest.spyOn(DateUtils, 'formatDateTimeLong').mockReturnValue(MOCK_DATE_STRING);
describe('Footer', () => {
let props: FooterProps;
let subject;
let wrapper;
beforeEach(() => {
props = {
lastIndexed: 1555632106,
getLastIndexed: jest.fn(),
};
subject = shallow(<Footer {...props} />);
wrapper = shallow(<Footer {...props} />);
});
describe('componentDidMount', () => {
......@@ -29,25 +29,34 @@ describe('Footer', () => {
describe('render', () => {
it('calls generateDateTimeString if this.state.lastIndexed', () => {
jest.spyOn(subject.instance(), 'generateDateTimeString');
subject.instance().render();
expect(subject.instance().generateDateTimeString).toHaveBeenCalled();
jest.spyOn(wrapper.instance(), 'generateDateTimeString');
wrapper.instance().render();
expect(wrapper.instance().generateDateTimeString).toHaveBeenCalled();
});
it('renders correct content if this.state.lastIndexed', () => {
const expectedText = `Amundsen was last indexed on ${MOCK_DATE_STRING}`;
expect(subject.find('#footer').props().children).toBeTruthy();
expect(subject.find('#footer').text()).toEqual(expectedText);
});
it('renders no content if this.state.lastIndexed is null', () => {
subject.setProps({ lastIndexed: null });
expect(subject.find('#footer').props().children).toBeFalsy();
expect(wrapper.find('#footer').props().children).toBeTruthy();
expect(wrapper.find('#footer').text()).toEqual(expectedText);
});
it('renders no content if this.state.lastIndexed is undefined', () => {
subject.setProps({ lastIndexed: undefined });
expect(subject.find('#footer').props().children).toBeFalsy();
describe('when state.lastIndexed is falsy', () => {
it('renders the shimmering loader if this.state.lastIndexed is null', () => {
const expected = 1;
wrapper.setProps({ lastIndexed: null });
expect(wrapper.find('ShimmeringFooterLoader').length).toEqual(expected);
});
it('renders the shimmering loader if this.state.lastIndexed is undefined', () => {
const expected = 1;
wrapper.setProps({ lastIndexed: undefined });
expect(wrapper.find('ShimmeringFooterLoader').length).toEqual(expected);
});
});
});
});
......
......@@ -20,6 +20,14 @@ interface DispatchFromProps {
export type FooterProps = StateFromProps & DispatchFromProps;
const ShimmeringFooterLoader: React.FC = () => {
return (
<div className="shimmer-footer">
<div className="shimmer-footer-row is-shimmer-animated" />
</div>
);
};
export class Footer extends React.Component<FooterProps> {
componentDidMount() {
this.props.getLastIndexed();
......@@ -30,12 +38,14 @@ export class Footer extends React.Component<FooterProps> {
};
render() {
let content;
let content = <ShimmeringFooterLoader />;
if (this.props.lastIndexed) {
content = (
<div>{`Amundsen was last indexed on ${this.generateDateTimeString()}`}</div>
);
}
return (
<footer>
<div className="phantom-div" />
......
@import 'variables';
$shimmer-loader-height: 20px;
/* TODO: Not the greatest sticky footer implementation */
.footer {
background-color: $white;
......@@ -22,3 +24,16 @@
padding: 20px;
width: 100%;
}
.shimmer-footer {
height: $shimmer-loader-height;
width: 100%;
text-align: center;
margin: 0 auto;
}
.shimmer-footer-row {
height: $shimmer-loader-height - $spacer-1;
display: inline-block;
width: 33%;
}
......@@ -6,7 +6,6 @@ import AppConfig from 'config/config';
import globalState from 'fixtures/globalState';
import { NO_DATA_ISSUES_TEXT } from 'components/TableDetail/TableIssues/constants';
import ReportTableIssue from 'components/TableDetail/ReportTableIssue';
import {
TableIssues,
TableIssueProps,
......@@ -15,8 +14,6 @@ import {
} from '.';
describe('TableIssues', () => {
const setStateSpy = jest.spyOn(TableIssues.prototype, 'setState');
const setup = (propOverrides?: Partial<TableIssueProps>) => {
const props: TableIssueProps = {
isLoading: false,
......@@ -37,19 +34,22 @@ describe('TableIssues', () => {
AppConfig.issueTracking.enabled = true;
});
it('renders LoadingSpinner if loading', () => {
const { props, wrapper } = setup({ isLoading: true });
expect(wrapper.find('LoadingSpinner').exists()).toBe(true);
it('renders Shimmer loader if loading', () => {
const { wrapper } = setup({ isLoading: true });
const expected = 1;
const actual = wrapper.find('ShimmeringIssuesLoader').length;
expect(actual).toEqual(expected);
});
it('renders text if no issues', () => {
const { props, wrapper } = setup({ issues: [] });
const { wrapper } = setup({ issues: [] });
expect(wrapper.find('.issue-banner').text()).toEqual(NO_DATA_ISSUES_TEXT);
});
it('renders issues if they exist', () => {
AppConfig.issueTracking.enabled = true;
const { props, wrapper } = setup({
const { wrapper } = setup({
issues: [
{
issue_key: 'issue_key',
......@@ -68,7 +68,7 @@ describe('TableIssues', () => {
});
it('renders no link to issues if no issues', () => {
const { props, wrapper } = setup({
const { wrapper } = setup({
issues: [],
total: 0,
allIssuesUrl: null,
......@@ -77,7 +77,7 @@ describe('TableIssues', () => {
});
it('renders link if there are issues', () => {
const { props, wrapper } = setup({
const { wrapper } = setup({
issues: [
{
issue_key: 'issue_key',
......
......@@ -32,6 +32,15 @@ export type TableIssueProps = StateFromProps &
DispatchFromProps &
ComponentProps;
const ShimmeringIssuesLoader: React.FC = () => {
return (
<div className="shimmer-issues">
<div className="shimmer-issues-row shimmer-issues-line--1 is-shimmer-animated" />
<div className="shimmer-issues-row shimmer-issues-line--2 is-shimmer-animated" />
</div>
);
};
export class TableIssues extends React.Component<TableIssueProps> {
componentDidMount() {
this.props.getIssues(this.props.tableKey);
......@@ -109,7 +118,7 @@ export class TableIssues extends React.Component<TableIssueProps> {
<>
{this.renderIssueTitle()}
<div className="table-issues">
<LoadingSpinner />
<ShimmeringIssuesLoader />
</div>
</>
);
......
@import 'variables';
$issue-banner-height: 40px;
$shimmer-line-height: 16px;
$shimmer-loader-lines: 1, 2;
.table-issues {
margin-bottom: $spacer-1;
......@@ -8,7 +12,7 @@
color: $text-secondary;
display: flex;
flex-direction: row;
height: 40px;
height: $issue-banner-height;
line-height: 24px;
padding: $spacer-1;
......@@ -17,7 +21,7 @@
}
.table-issue-priority {
line-height: 20px;
line-height: $issue-banner-height / 2;
}
}
......@@ -72,8 +76,19 @@
background-color: rgba($priority-bg-color, 0.1);
}
.loading-spinner {
margin-top: auto;
.shimmer-issues {
width: 100%;
}
.shimmer-issues-row {
margin-bottom: $spacer-1;
height: $shimmer-line-height;
}
@each $line in $shimmer-loader-lines {
.shimmer-issues-line--#{$line} {
width: percentage(random(100) / 100);
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment