feat(ui) - pagination wip
This commit is contained in:
parent
667808b275
commit
09aca1e61d
12 changed files with 123 additions and 83 deletions
|
|
@ -13,7 +13,8 @@ import withLocationHandlers from "HOCs/withLocationHandlers";
|
|||
import { fetch as fetchFilterVariables } from 'Duck/sources';
|
||||
import { fetchSources } from 'Duck/customField';
|
||||
import { RehydrateSlidePanel } from './WatchDogs/components';
|
||||
import { setActiveTab, setFunnelPage } from 'Duck/sessions';
|
||||
import { setFunnelPage } from 'Duck/sessions';
|
||||
import { setActiveTab } from 'Duck/search';
|
||||
import SessionsMenu from './SessionsMenu/SessionsMenu';
|
||||
import { LAST_7_DAYS } from 'Types/app/period';
|
||||
import { resetFunnel } from 'Duck/funnels';
|
||||
|
|
@ -51,12 +52,12 @@ const allowedQueryKeys = [
|
|||
variables: state.getIn([ 'customFields', 'list' ]),
|
||||
sources: state.getIn([ 'customFields', 'sources' ]),
|
||||
filterValues: state.get('filterValues'),
|
||||
activeTab: state.getIn([ 'sessions', 'activeTab' ]),
|
||||
favoriteList: state.getIn([ 'sessions', 'favoriteList' ]),
|
||||
currentProjectId: state.getIn([ 'user', 'siteId' ]),
|
||||
sites: state.getIn([ 'site', 'list' ]),
|
||||
watchdogs: state.getIn(['watchdogs', 'list']),
|
||||
activeFlow: state.getIn([ 'filters', 'activeFlow' ]),
|
||||
sessions: state.getIn([ 'sessions', 'list' ]),
|
||||
}), {
|
||||
fetchFavoriteSessionList,
|
||||
applyFilter,
|
||||
|
|
@ -91,7 +92,9 @@ export default class BugFinder extends React.PureComponent {
|
|||
// keys: this.props.sources.filter(({type}) => type === 'logTool').map(({ label, key }) => ({ type: 'ERROR', source: key, label: label, key, icon: 'integrations/' + key, isFilter: false })).toJS()
|
||||
// };
|
||||
// });
|
||||
props.fetchSessions();
|
||||
if (props.sessions.size === 0) {
|
||||
props.fetchSessions();
|
||||
}
|
||||
props.resetFunnel();
|
||||
props.resetFunnelFilters();
|
||||
props.fetchFunnelsList(LAST_7_DAYS)
|
||||
|
|
@ -115,7 +118,6 @@ export default class BugFinder extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { activeFlow, activeTab } = this.props;
|
||||
const { showRehydratePanel } = this.state;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { fetchSessions, addFilterByKeyAndValue, updateCurrentPage } from 'Duck/s
|
|||
import SessionItem from 'Shared/SessionItem';
|
||||
import SessionListHeader from './SessionListHeader';
|
||||
import { FilterKey } from 'Types/filter/filterType';
|
||||
import { sliceListPerPage } from 'App/utils';
|
||||
|
||||
const ALL = 'all';
|
||||
const PER_PAGE = 5;
|
||||
|
|
@ -16,7 +15,7 @@ var timeoutId;
|
|||
shouldAutorefresh: state.getIn([ 'filters', 'appliedFilter', 'events' ]).size === 0,
|
||||
savedFilters: state.getIn([ 'filters', 'list' ]),
|
||||
loading: state.getIn([ 'sessions', 'loading' ]),
|
||||
activeTab: state.getIn([ 'sessions', 'activeTab' ]),
|
||||
activeTab: state.getIn([ 'search', 'activeTab' ]),
|
||||
allList: state.getIn([ 'sessions', 'list' ]),
|
||||
total: state.getIn([ 'sessions', 'total' ]),
|
||||
filters: state.getIn([ 'search', 'instance', 'filters' ]),
|
||||
|
|
@ -90,6 +89,7 @@ export default class SessionList extends React.PureComponent {
|
|||
activeTab,
|
||||
metaList,
|
||||
currentPage,
|
||||
total,
|
||||
} = this.props;
|
||||
const _filterKeys = filters.map(i => i.key);
|
||||
const hasUserFilter = _filterKeys.includes(FilterKey.USERID) || _filterKeys.includes(FilterKey.USERANONYMOUSID);
|
||||
|
|
@ -120,7 +120,7 @@ export default class SessionList extends React.PureComponent {
|
|||
}
|
||||
>
|
||||
<Loader loading={ loading }>
|
||||
{ sliceListPerPage(list, currentPage, PER_PAGE).map(session => (
|
||||
{ list.map(session => (
|
||||
<SessionItem
|
||||
key={ session.sessionId }
|
||||
session={ session }
|
||||
|
|
@ -130,11 +130,13 @@ export default class SessionList extends React.PureComponent {
|
|||
/>
|
||||
))}
|
||||
</Loader>
|
||||
<Pagination
|
||||
page={currentPage}
|
||||
totalPages={Math.ceil(list.size / PER_PAGE)}
|
||||
onPageChange={(page) => this.props.updateCurrentPage(page)}
|
||||
/>
|
||||
<div className="w-full flex items-center justify-center py-6">
|
||||
<Pagination
|
||||
page={currentPage}
|
||||
totalPages={Math.ceil(total / PER_PAGE)}
|
||||
onPageChange={(page) => this.props.updateCurrentPage(page)}
|
||||
/>
|
||||
</div>
|
||||
{/* <LoadMoreButton
|
||||
className="mt-12 mb-12"
|
||||
displayedCount={displayedCount}
|
||||
|
|
|
|||
|
|
@ -64,5 +64,5 @@ function SessionListHeader({
|
|||
};
|
||||
|
||||
export default connect(state => ({
|
||||
activeTab: state.getIn([ 'sessions', 'activeTab' ]),
|
||||
activeTab: state.getIn([ 'search', 'activeTab' ]),
|
||||
}), { applyFilter })(SessionListHeader);
|
||||
|
|
|
|||
|
|
@ -1,30 +1,20 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux';
|
||||
import cn from 'classnames';
|
||||
import { SideMenuitem, SavedSearchList, Progress, Popup, Icon, CircularLoader } from 'UI'
|
||||
import { SideMenuitem, SavedSearchList, Progress, Popup } from 'UI'
|
||||
import stl from './sessionMenu.css';
|
||||
import { fetchWatchdogStatus } from 'Duck/watchdogs';
|
||||
import { setActiveFlow, clearEvents } from 'Duck/filters';
|
||||
import { setActiveTab } from 'Duck/sessions';
|
||||
import { clearEvents } from 'Duck/filters';
|
||||
import { issues_types } from 'Types/session/issue'
|
||||
import { fetchList as fetchSessionList } from 'Duck/sessions';
|
||||
|
||||
function SessionsMenu(props) {
|
||||
const {
|
||||
activeFlow, activeTab, watchdogs = [], keyMap, wdTypeCount,
|
||||
fetchWatchdogStatus, toggleRehydratePanel, filters, sessionsLoading } = props;
|
||||
const { activeTab, keyMap, wdTypeCount, toggleRehydratePanel } = props;
|
||||
|
||||
const onMenuItemClick = (filter) => {
|
||||
props.onMenuItemClick(filter)
|
||||
|
||||
if (activeFlow && activeFlow.type === 'flows') {
|
||||
props.setActiveFlow(null)
|
||||
}
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// fetchWatchdogStatus()
|
||||
// }, [])
|
||||
|
||||
|
||||
const capturingAll = props.captureRate && props.captureRate.get('captureAll');
|
||||
|
||||
|
|
@ -66,36 +56,13 @@ function SessionsMenu(props) {
|
|||
{ issues_types.filter(item => item.visible).map(item => (
|
||||
<SideMenuitem
|
||||
key={item.key}
|
||||
disabled={!keyMap[item.type] && !wdTypeCount[item.type]}
|
||||
// disabled={!keyMap[item.type] && !wdTypeCount[item.type]}
|
||||
active={activeTab.type === item.type}
|
||||
title={item.name} iconName={item.icon}
|
||||
onClick={() => onMenuItemClick(item)}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* <div className={stl.divider} />
|
||||
<div className="my-3">
|
||||
<SideMenuitem
|
||||
title={
|
||||
<div className="flex items-center">
|
||||
<div>Assist</div>
|
||||
{ activeTab.type === 'live' && (
|
||||
<div
|
||||
className="ml-4 h-5 w-6 flex items-center justify-center"
|
||||
onClick={() => !sessionsLoading && props.fetchSessionList(filters.toJS())}
|
||||
>
|
||||
{ sessionsLoading ? <CircularLoader className="ml-1" /> : <Icon name="sync-alt" size="14" />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
iconName="person"
|
||||
active={activeTab.type === 'live'}
|
||||
onClick={() => onMenuItemClick({ name: 'Assist', type: 'live' })}
|
||||
/>
|
||||
|
||||
</div> */}
|
||||
|
||||
<div className={stl.divider} />
|
||||
<div className="my-3">
|
||||
<SideMenuitem
|
||||
|
|
@ -113,13 +80,12 @@ function SessionsMenu(props) {
|
|||
}
|
||||
|
||||
export default connect(state => ({
|
||||
activeTab: state.getIn([ 'sessions', 'activeTab' ]),
|
||||
activeTab: state.getIn([ 'search', 'activeTab' ]),
|
||||
keyMap: state.getIn([ 'sessions', 'keyMap' ]),
|
||||
wdTypeCount: state.getIn([ 'sessions', 'wdTypeCount' ]),
|
||||
activeFlow: state.getIn([ 'filters', 'activeFlow' ]),
|
||||
captureRate: state.getIn(['watchdogs', 'captureRate']),
|
||||
filters: state.getIn([ 'filters', 'appliedFilter' ]),
|
||||
sessionsLoading: state.getIn([ 'sessions', 'fetchLiveListRequest', 'loading' ]),
|
||||
}), {
|
||||
fetchWatchdogStatus, setActiveFlow, clearEvents, setActiveTab, fetchSessionList
|
||||
fetchWatchdogStatus, clearEvents, fetchSessionList
|
||||
})(SessionsMenu);
|
||||
|
|
|
|||
|
|
@ -10,8 +10,12 @@ interface Props {
|
|||
}
|
||||
export default function Pagination(props: Props) {
|
||||
const { page, totalPages, onPageChange, limit = 5 } = props;
|
||||
|
||||
const [currentPage, setCurrentPage] = React.useState(page);
|
||||
// const []
|
||||
React.useMemo(
|
||||
() => setCurrentPage(page),
|
||||
[page],
|
||||
);
|
||||
|
||||
const changePage = (page: number) => {
|
||||
if (page > 0 && page <= totalPages) {
|
||||
|
|
@ -19,6 +23,7 @@ export default function Pagination(props: Props) {
|
|||
setCurrentPage(page);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
|
|
@ -31,7 +36,7 @@ export default function Pagination(props: Props) {
|
|||
<span className="mr-2 color-gray-medium">Page</span>
|
||||
<input
|
||||
type="number"
|
||||
className={cn("py-1 px-2 bg-white border rounded w-16", { "opacity-50 cursor-default": totalPages === 1 })}
|
||||
className={cn("py-1 px-2 bg-white border border-gray-light rounded w-16", { "opacity-50 cursor-default": totalPages === 1 })}
|
||||
value={currentPage}
|
||||
min={1}
|
||||
max={totalPages}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { FilterKey } from 'Types/filter/filterType';
|
||||
import { FilterKey, IssueType } from 'Types/filter/filterType';
|
||||
|
||||
export const options = [
|
||||
{ key: 'on', text: 'on', value: 'on' },
|
||||
|
|
@ -93,18 +93,18 @@ export const methodOptions = [
|
|||
]
|
||||
|
||||
export const issueOptions = [
|
||||
{ text: 'Click Rage', value: 'click_rage' },
|
||||
{ text: 'Dead Click', value: 'dead_click' },
|
||||
{ text: 'Excessive Scrolling', value: 'excessive_scrolling' },
|
||||
{ text: 'Bad Request', value: 'bad_request' },
|
||||
{ text: 'Missing Resource', value: 'missing_resource' },
|
||||
{ text: 'Memory', value: 'memory' },
|
||||
{ text: 'CPU', value: 'cpu' },
|
||||
{ text: 'Slow Resource', value: 'slow_resource' },
|
||||
{ text: 'Slow Page Load', value: 'slow_page_load' },
|
||||
{ text: 'Crash', value: 'crash' },
|
||||
{ text: 'Custom', value: 'custom' },
|
||||
{ text: 'JS Exception', value: 'js_exception' },
|
||||
{ text: 'Click Rage', value: IssueType.CLICK_RAGE },
|
||||
{ text: 'Dead Click', value: IssueType.DEAD_CLICK },
|
||||
{ text: 'Excessive Scrolling', value: IssueType.EXCESSIVE_SCROLLING },
|
||||
{ text: 'Bad Request', value: IssueType.BAD_REQUEST },
|
||||
{ text: 'Missing Resource', value: IssueType.MISSING_RESOURCE },
|
||||
{ text: 'Memory', value: IssueType.MEMORY },
|
||||
{ text: 'CPU', value: IssueType.CPU },
|
||||
{ text: 'Slow Resource', value: IssueType.SLOW_RESOURCE },
|
||||
{ text: 'Slow Page Load', value: IssueType.SLOW_PAGE_LOAD },
|
||||
{ text: 'Crash', value: IssueType.CRASH },
|
||||
{ text: 'Custom', value: IssueType.CUSTOM },
|
||||
{ text: 'Error', value: IssueType.JS_EXCEPTION },
|
||||
]
|
||||
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import SavedFilter from 'Types/filter/savedFilter';
|
|||
import { errors as errorsRoute, isRoute } from "App/routes";
|
||||
import { fetchList as fetchSessionList } from './sessions';
|
||||
import { fetchList as fetchErrorsList } from './errors';
|
||||
import { FilterCategory, FilterKey } from 'Types/filter/filterType';
|
||||
import { FilterCategory, FilterKey, IssueType } from 'Types/filter/filterType';
|
||||
import { filtersMap, liveFiltersMap, generateFilterOptions, generateLiveFilterOptions } from 'Types/filter/newFilter';
|
||||
|
||||
const ERRORS_ROUTE = errorsRoute();
|
||||
|
|
@ -29,6 +29,7 @@ const UPDATE = `${name}/UPDATE`;
|
|||
const APPLY = `${name}/APPLY`;
|
||||
const SET_ALERT_METRIC_ID = `${name}/SET_ALERT_METRIC_ID`;
|
||||
const UPDATE_CURRENT_PAGE = `${name}/UPDATE_CURRENT_PAGE`;
|
||||
const SET_ACTIVE_TAB = `${name}/SET_ACTIVE_TAB`;
|
||||
|
||||
const REFRESH_FILTER_OPTIONS = 'filters/REFRESH_FILTER_OPTIONS';
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ const initialState = Map({
|
|||
savedSearch: new SavedFilter({}),
|
||||
filterSearchList: {},
|
||||
currentPage: 1,
|
||||
activeTab: {name: 'All', type: 'all' },
|
||||
});
|
||||
|
||||
// Metric - Series - [] - filters
|
||||
|
|
@ -64,7 +66,7 @@ function reducer(state = initialState, action = {}) {
|
|||
case APPLY:
|
||||
return action.fromUrl
|
||||
? state.set('instance', Filter(action.filter))
|
||||
: state.mergeIn(['instance'], action.filter);
|
||||
: state.mergeIn(['instance'], action.filter).set('currentPage', 1);
|
||||
case success(FETCH):
|
||||
return state.set("instance", action.data);
|
||||
case success(FETCH_LIST):
|
||||
|
|
@ -87,6 +89,8 @@ function reducer(state = initialState, action = {}) {
|
|||
return state.mergeIn([ 'savedSearch' ], action.instance);
|
||||
case UPDATE_CURRENT_PAGE:
|
||||
return state.set('currentPage', action.page);
|
||||
case SET_ACTIVE_TAB:
|
||||
return state.set('activeTab', action.tab).set('currentPage', 1);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
|
@ -125,6 +129,18 @@ export const filterMap = ({category, value, key, operator, sourceOperator, sourc
|
|||
const reduceThenFetchResource = actionCreator => (...args) => (dispatch, getState) => {
|
||||
dispatch(actionCreator(...args));
|
||||
const filter = getState().getIn([ 'search', 'instance']).toData();
|
||||
|
||||
const activeTab = getState().getIn([ 'search', 'activeTab']);
|
||||
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark') {
|
||||
const tmpFilter = filtersMap[FilterKey.ISSUE];
|
||||
tmpFilter.value = [activeTab.type]
|
||||
filter.filters = filter.filters.concat(tmpFilter)
|
||||
}
|
||||
|
||||
if (activeTab.type === 'bookmark') {
|
||||
filter.bookmarked = true
|
||||
}
|
||||
|
||||
filter.filters = filter.filters.map(filterMap);
|
||||
filter.limit = 5;
|
||||
filter.page = getState().getIn([ 'search', 'currentPage']);
|
||||
|
|
@ -139,6 +155,11 @@ export const edit = reduceThenFetchResource((instance) => ({
|
|||
instance,
|
||||
}));
|
||||
|
||||
export const setActiveTab = reduceThenFetchResource((tab) => ({
|
||||
type: SET_ACTIVE_TAB,
|
||||
tab
|
||||
}));
|
||||
|
||||
export const remove = (id) => (dispatch, getState) => {
|
||||
return dispatch({
|
||||
types: REMOVE.array,
|
||||
|
|
@ -158,6 +179,11 @@ export const applyFilter = reduceThenFetchResource((filter, fromUrl=false) => ({
|
|||
fromUrl,
|
||||
}));
|
||||
|
||||
export const updateCurrentPage = reduceThenFetchResource((page) => ({
|
||||
type: UPDATE_CURRENT_PAGE,
|
||||
page,
|
||||
}));
|
||||
|
||||
export const applySavedSearch = (filter) => (dispatch, getState) => {
|
||||
dispatch(edit({ filters: filter ? filter.filter.filters : [] }));
|
||||
return dispatch({
|
||||
|
|
@ -274,11 +300,4 @@ export const refreshFilterOptions = () => {
|
|||
return {
|
||||
type: REFRESH_FILTER_OPTIONS
|
||||
}
|
||||
}
|
||||
|
||||
export function updateCurrentPage(page) {
|
||||
return {
|
||||
type: UPDATE_CURRENT_PAGE,
|
||||
page,
|
||||
};
|
||||
}
|
||||
|
|
@ -60,7 +60,6 @@ const initialState = Map({
|
|||
funnelPage: Map(),
|
||||
timelinePointer: null,
|
||||
sessionPath: '',
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const reducer = (state = initialState, action = {}) => {
|
||||
|
|
@ -130,7 +129,6 @@ const reducer = (state = initialState, action = {}) => {
|
|||
.set('favoriteList', list.filter(({ favorite }) => favorite))
|
||||
.set('total', total)
|
||||
.set('keyMap', keyMap)
|
||||
.set('total', total)
|
||||
.set('wdTypeCount', wdTypeCount);
|
||||
case SET_AUTOPLAY_VALUES: {
|
||||
const sessionIds = state.get('sessionIds')
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
.color-white { color: $white }
|
||||
.color-borderColor { color: $borderColor }
|
||||
|
||||
/* color */
|
||||
/* hover color */
|
||||
.hover-main:hover { color: $main }
|
||||
.hover-gray-light-shade:hover { color: $gray-light-shade }
|
||||
.hover-gray-lightest:hover { color: $gray-lightest }
|
||||
|
|
@ -92,3 +92,33 @@
|
|||
.hover-pink:hover { color: $pink }
|
||||
.hover-white:hover { color: $white }
|
||||
.hover-borderColor:hover { color: $borderColor }
|
||||
|
||||
.border-main { border-color: $main }
|
||||
.border-gray-light-shade { border-color: $gray-light-shade }
|
||||
.border-gray-lightest { border-color: $gray-lightest }
|
||||
.border-gray-light { border-color: $gray-light }
|
||||
.border-gray-medium { border-color: $gray-medium }
|
||||
.border-gray-dark { border-color: $gray-dark }
|
||||
.border-gray-darkest { border-color: $gray-darkest }
|
||||
.border-teal { border-color: $teal }
|
||||
.border-teal-dark { border-color: $teal-dark }
|
||||
.border-teal-light { border-color: $teal-light }
|
||||
.border-tealx { border-color: $tealx }
|
||||
.border-tealx-light { border-color: $tealx-light }
|
||||
.border-tealx-light-border { border-color: $tealx-light-border }
|
||||
.border-orange { border-color: $orange }
|
||||
.border-yellow { border-color: $yellow }
|
||||
.border-yellow2 { border-color: $yellow2 }
|
||||
.border-orange-dark { border-color: $orange-dark }
|
||||
.border-green { border-color: $green }
|
||||
.border-green2 { border-color: $green2 }
|
||||
.border-green-dark { border-color: $green-dark }
|
||||
.border-red { border-color: $red }
|
||||
.border-red2 { border-color: $red2 }
|
||||
.border-blue { border-color: $blue }
|
||||
.border-blue2 { border-color: $blue2 }
|
||||
.border-active-blue { border-color: $active-blue }
|
||||
.border-active-blue-border { border-color: $active-blue-border }
|
||||
.border-pink { border-color: $pink }
|
||||
.border-white { border-color: $white }
|
||||
.border-borderColor { border-color: $borderColor }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,21 @@ export enum FilterCategory {
|
|||
PERFORMANCE = "Performance",
|
||||
};
|
||||
|
||||
export enum IssueType {
|
||||
CLICK_RAGE = "click_rage",
|
||||
DEAD_CLICK = "dead_click",
|
||||
EXCESSIVE_SCROLLING = "excessive_scrolling",
|
||||
BAD_REQUEST = "bad_request",
|
||||
MISSING_RESOURCE = "missing_resource",
|
||||
MEMORY = "memory",
|
||||
CPU = "cpu",
|
||||
SLOW_RESOURCE = "slow_resource",
|
||||
SLOW_PAGE_LOAD = "slow_page_load",
|
||||
CRASH = "crash",
|
||||
CUSTOM = "custom",
|
||||
JS_EXCEPTION = "js_exception",
|
||||
}
|
||||
|
||||
export enum FilterType {
|
||||
STRING = "STRING",
|
||||
ISSUE = "ISSUE",
|
||||
|
|
|
|||
|
|
@ -237,5 +237,6 @@ export const isGreaterOrEqualVersion = (version, compareTo) => {
|
|||
export const sliceListPerPage = (list, page, perPage = 10) => {
|
||||
const start = page * perPage;
|
||||
const end = start + perPage;
|
||||
console.log(start, end)
|
||||
return list.slice(start, end);
|
||||
}
|
||||
|
|
@ -12,7 +12,9 @@ ${ colors.map(color => `.fill-${ color } { fill: $${ color } }`).join('\n') }
|
|||
/* color */
|
||||
${ colors.map(color => `.color-${ color } { color: $${ color } }`).join('\n') }
|
||||
|
||||
/* color */
|
||||
/* hover color */
|
||||
${ colors.map(color => `.hover-${ color }:hover { color: $${ color } }`).join('\n') }
|
||||
|
||||
${ colors.map(color => `.border-${ color } { border-color: $${ color } }`).join('\n') }
|
||||
`)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue