Erez Rokah 174d86f0a0
Feat: entry sorting (#3494)
* refactor: typescript search actions, add tests avoid duplicate search

* refactor: switch from promise chain to async/await in loadEntries

* feat: add sorting, initial commit

* fix: set isFetching to true on entries request

* fix: ui improvments and bug fixes

* test: fix tests

* feat(backend-gitlab): cache local tree)

* fix: fix prop type warning

* refactor: code cleanup

* feat(backend-bitbucket): add local tree caching support

* feat: swtich to orderBy and support multiple sort keys

* fix: backoff function

* fix: improve backoff

* feat: infer sortable fields

* feat: fetch file commit metadata - initial commit

* feat: extract file author and date, finalize GitLab & Bitbucket

* refactor: code cleanup

* feat: handle github rate limit errors

* refactor: code cleanup

* fix(github): add missing author and date when traversing cursor

* fix: add missing author and date when traversing cursor

* refactor: code cleanup

* refactor: code cleanup

* refactor: code cleanup

* test: fix tests

* fix: rebuild local tree when head doesn't exist in remote branch

* fix: allow sortable fields to be an empty array

* fix: allow translation of built in sort fields

* build: fix proxy server build

* fix: hide commit author and date fields by default on non git backends

* fix(algolia): add listAllEntries method for alogolia integration

* fix: handle sort fields overflow

* test(bitbucket): re-record some bitbucket e2e tests

* test(bitbucket): fix media library test

* refactor(gitgateway-gitlab): share request code and handle 404 errors

* fix: always show commit date by default

* docs: add sortableFields

* refactor: code cleanup

* improvement: drop multi-sort, rework sort UI

* chore: force main package bumps

Co-authored-by: Shawn Erquhart <shawn@erquh.art>
2020-03-31 23:13:27 -04:00

157 lines
3.3 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { css, keyframes } from '@emotion/core';
import CSSTransition from 'react-transition-group/CSSTransition';
import { colors, zIndex } from './styles';
const styles = {
disabled: css`
display: none;
`,
active: css`
display: block;
`,
enter: css`
opacity: 0.01;
`,
enterActive: css`
opacity: 1;
transition: opacity 500ms ease-in;
`,
exit: css`
opacity: 1;
`,
exitActive: css`
opacity: 0.01;
transition: opacity 300ms ease-in;
`,
};
const animations = {
loader: keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`,
};
const LoaderText = styled.div`
width: auto !important;
height: auto !important;
text-align: center;
color: #767676;
margin-top: 55px;
line-height: 35px;
`;
const LoaderItem = styled.div`
position: absolute;
white-space: nowrap;
transform: translateX(-50%);
`;
export class Loader extends React.Component {
static propTypes = {
children: PropTypes.node,
className: PropTypes.string,
};
state = {
currentItem: 0,
};
componentWillUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
}
setAnimation = () => {
if (this.interval) return;
const { children } = this.props;
this.interval = setInterval(() => {
const nextItem =
this.state.currentItem === children.length - 1 ? 0 : this.state.currentItem + 1;
this.setState({ currentItem: nextItem });
}, 5000);
};
renderChild = () => {
const { children } = this.props;
const { currentItem } = this.state;
if (!children) {
return null;
} else if (typeof children == 'string') {
return <LoaderText>{children}</LoaderText>;
} else if (Array.isArray(children)) {
this.setAnimation();
return (
<LoaderText>
<CSSTransition
className={{
enter: styles.enter,
enterActive: styles.enterActive,
exit: styles.exit,
exitActive: styles.exitActive,
}}
timeout={500}
>
<LoaderItem key={currentItem}>{children[currentItem]}</LoaderItem>
</CSSTransition>
</LoaderText>
);
}
};
render() {
const { className } = this.props;
return <div className={className}>{this.renderChild()}</div>;
}
}
const StyledLoader = styled(Loader)`
display: ${props => (props.active ? 'block' : 'none')};
position: absolute;
top: 50%;
left: 50%;
margin: 0px;
text-align: center;
z-index: ${zIndex.zIndex1000};
transform: translateX(-50%) translateY(-50%);
&:before,
&:after {
content: '';
position: absolute;
top: 0%;
left: 50%;
width: 2.28571429rem;
height: 2.28571429rem;
margin: 0em 0em 0em -1.14285714rem;
border-radius: 500rem;
border-style: solid;
border-width: 0.2em;
}
/* Static Shape */
&:before {
border-color: rgba(0, 0, 0, 0.1);
}
/* Active Shape */
&:after {
animation: ${animations.loader} 0.6s linear;
animation-iteration-count: infinite;
border-color: ${colors.active} transparent transparent;
box-shadow: 0px 0px 0px 1px transparent;
}
`;
export default StyledLoader;