mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-31 21:38:19 +03:00
Merge pull request #278 from acelaya-forks/feature/fix-default-grouping
Feature/fix default grouping
This commit is contained in:
commit
16ffbcfbc0
10 changed files with 70 additions and 24 deletions
23
CHANGELOG.md
23
CHANGELOG.md
|
@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
#### Added
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Changed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Deprecated
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Removed
|
||||
|
||||
* *Nothing*
|
||||
|
||||
#### Fixed
|
||||
|
||||
* [#276](https://github.com/shlinkio/shlink-web-client/issues/276) Fixed default grouping used for visits line chart, making it be dynamic depending on how old the short URL is.
|
||||
|
||||
|
||||
## 2.5.0 - 2020-05-31
|
||||
|
||||
#### Added
|
||||
|
|
|
@ -9,8 +9,8 @@ import DateRangeRow from '../utils/DateRangeRow';
|
|||
import Message from '../utils/Message';
|
||||
import { formatDate } from '../utils/helpers/date';
|
||||
import { useToggle } from '../utils/helpers/hooks';
|
||||
import SortableBarGraph from './SortableBarGraph';
|
||||
import GraphCard from './GraphCard';
|
||||
import SortableBarGraph from './helpers/SortableBarGraph';
|
||||
import GraphCard from './helpers/GraphCard';
|
||||
import LineChartCard from './helpers/LineChartCard';
|
||||
import VisitsTable from './VisitsTable';
|
||||
import { VisitsInfoType } from './types';
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Doughnut, HorizontalBar } from 'react-chartjs-2';
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { keys, values } from 'ramda';
|
||||
import { fillTheGaps } from '../utils/helpers/visits';
|
||||
import { fillTheGaps } from '../../utils/helpers/visits';
|
||||
import './GraphCard.scss';
|
||||
|
||||
const propTypes = {
|
|
@ -10,7 +10,7 @@ import {
|
|||
DropdownItem,
|
||||
} from 'reactstrap';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import { reverse } from 'ramda';
|
||||
import { always, cond, reverse } from 'ramda';
|
||||
import moment from 'moment';
|
||||
import { VisitType } from '../types';
|
||||
import { fillTheGaps } from '../../utils/helpers/visits';
|
||||
|
@ -52,6 +52,18 @@ const STEP_TO_DATE_FORMAT = {
|
|||
monthly: (date) => moment(date).format('YYYY-MM'),
|
||||
};
|
||||
|
||||
const determineInitialStep = (oldestVisitDate) => {
|
||||
const now = moment();
|
||||
const oldestDate = moment(oldestVisitDate);
|
||||
const matcher = cond([
|
||||
[ () => now.diff(oldestDate, 'day') <= 2, always('hourly') ], // Less than 2 days
|
||||
[ () => now.diff(oldestDate, 'month') <= 1, always('daily') ], // Between 2 days and 1 month
|
||||
[ () => now.diff(oldestDate, 'month') <= 6, always('weekly') ], // Between 1 and 6 months
|
||||
]);
|
||||
|
||||
return matcher() || 'monthly';
|
||||
};
|
||||
|
||||
const groupVisitsByStep = (step, visits) => visits.reduce((acc, visit) => {
|
||||
const key = STEP_TO_DATE_FORMAT[step](visit.date);
|
||||
|
||||
|
@ -93,7 +105,9 @@ const generateDataset = (stats, label, color) => ({
|
|||
});
|
||||
|
||||
const LineChartCard = ({ title, visits, highlightedVisits, highlightedLabel = 'Selected' }) => {
|
||||
const [ step, setStep ] = useState('monthly');
|
||||
const [ step, setStep ] = useState(
|
||||
visits.length > 0 ? determineInitialStep(visits[visits.length - 1].date) : 'monthly'
|
||||
);
|
||||
const [ skipNoVisits, toggleSkipNoVisits ] = useToggle(true);
|
||||
|
||||
const groupedVisitsWithGaps = useMemo(() => groupVisitsByStep(step, reverse(visits)), [ step, visits ]);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { fromPairs, head, keys, pipe, prop, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda';
|
||||
import SortingDropdown from '../utils/SortingDropdown';
|
||||
import PaginationDropdown from '../utils/PaginationDropdown';
|
||||
import { rangeOf } from '../utils/utils';
|
||||
import { roundTen } from '../utils/helpers/numbers';
|
||||
import SimplePaginator from '../common/SimplePaginator';
|
||||
import SortingDropdown from '../../utils/SortingDropdown';
|
||||
import PaginationDropdown from '../../utils/PaginationDropdown';
|
||||
import { rangeOf } from '../../utils/utils';
|
||||
import { roundTen } from '../../utils/helpers/numbers';
|
||||
import SimplePaginator from '../../common/SimplePaginator';
|
||||
import GraphCard from './GraphCard';
|
||||
|
||||
const propTypes = {
|
|
@ -4,8 +4,8 @@ import { identity } from 'ramda';
|
|||
import { Card, Progress } from 'reactstrap';
|
||||
import createVisitStats from '../../src/visits/VisitsStats';
|
||||
import Message from '../../src/utils/Message';
|
||||
import GraphCard from '../../src/visits/GraphCard';
|
||||
import SortableBarGraph from '../../src/visits/SortableBarGraph';
|
||||
import GraphCard from '../../src/visits/helpers/GraphCard';
|
||||
import SortableBarGraph from '../../src/visits/helpers/SortableBarGraph';
|
||||
import DateRangeRow from '../../src/utils/DateRangeRow';
|
||||
|
||||
describe('<VisitStats />', () => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { shallow } from 'enzyme';
|
||||
import { Doughnut, HorizontalBar } from 'react-chartjs-2';
|
||||
import { keys, values } from 'ramda';
|
||||
import GraphCard from '../../src/visits/GraphCard';
|
||||
import GraphCard from '../../../src/visits/helpers/GraphCard';
|
||||
|
||||
describe('<GraphCard />', () => {
|
||||
let wrapper;
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { shallow } from 'enzyme';
|
||||
import { CardHeader, DropdownItem } from 'reactstrap';
|
||||
import { Line } from 'react-chartjs-2';
|
||||
import moment from 'moment';
|
||||
import LineChartCard from '../../../src/visits/helpers/LineChartCard';
|
||||
import Checkbox from '../../../src/utils/Checkbox';
|
||||
|
||||
|
@ -22,19 +23,27 @@ describe('<LineChartCard />', () => {
|
|||
expect(header.html()).toContain('Cool title');
|
||||
});
|
||||
|
||||
it('renders group menu and selects active grouping item', () => {
|
||||
const wrapper = createWrapper();
|
||||
it.each([
|
||||
[[], 'monthly' ],
|
||||
[[{ date: moment().subtract(1, 'day').format() }], 'hourly' ],
|
||||
[[{ date: moment().subtract(3, 'day').format() }], 'daily' ],
|
||||
[[{ date: moment().subtract(2, 'month').format() }], 'weekly' ],
|
||||
[[{ date: moment().subtract(6, 'month').format() }], 'weekly' ],
|
||||
[[{ date: moment().subtract(7, 'month').format() }], 'monthly' ],
|
||||
[[{ date: moment().subtract(1, 'year').format() }], 'monthly' ],
|
||||
])('renders group menu and selects proper grouping item based on visits dates', (visits, expectedActiveItem) => {
|
||||
const wrapper = createWrapper(visits);
|
||||
const items = wrapper.find(DropdownItem);
|
||||
|
||||
expect(items).toHaveLength(4);
|
||||
expect(items.at(0).prop('children')).toEqual('Month');
|
||||
expect(items.at(0).prop('active')).toEqual(true);
|
||||
expect(items.at(0).prop('active')).toEqual(expectedActiveItem === 'monthly');
|
||||
expect(items.at(1).prop('children')).toEqual('Week');
|
||||
expect(items.at(1).prop('active')).toEqual(false);
|
||||
expect(items.at(1).prop('active')).toEqual(expectedActiveItem === 'weekly');
|
||||
expect(items.at(2).prop('children')).toEqual('Day');
|
||||
expect(items.at(2).prop('active')).toEqual(false);
|
||||
expect(items.at(2).prop('active')).toEqual(expectedActiveItem === 'daily');
|
||||
expect(items.at(3).prop('children')).toEqual('Hour');
|
||||
expect(items.at(3).prop('active')).toEqual(false);
|
||||
expect(items.at(3).prop('active')).toEqual(expectedActiveItem === 'hourly');
|
||||
});
|
||||
|
||||
it('renders chart with expected options', () => {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { keys, range, values } from 'ramda';
|
||||
import SortableBarGraph from '../../src/visits/SortableBarGraph';
|
||||
import GraphCard from '../../src/visits/GraphCard';
|
||||
import SortingDropdown from '../../src/utils/SortingDropdown';
|
||||
import PaginationDropdown from '../../src/utils/PaginationDropdown';
|
||||
import { rangeOf } from '../../src/utils/utils';
|
||||
import SortableBarGraph from '../../../src/visits/helpers/SortableBarGraph';
|
||||
import GraphCard from '../../../src/visits/helpers/GraphCard';
|
||||
import SortingDropdown from '../../../src/utils/SortingDropdown';
|
||||
import PaginationDropdown from '../../../src/utils/PaginationDropdown';
|
||||
import { rangeOf } from '../../../src/utils/utils';
|
||||
|
||||
describe('<SortableBarGraph />', () => {
|
||||
let wrapper;
|
Loading…
Reference in a new issue