Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion static/app/components/replays/table/replayTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import type {Query} from 'history';
import {Alert} from 'sentry/components/core/alert';
import InteractionStateLayer from 'sentry/components/core/interactionStateLayer';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Pagination from 'sentry/components/pagination';
import type {ReplayTableColumn} from 'sentry/components/replays/table/replayTableColumns';
import ReplayTableHeader from 'sentry/components/replays/table/replayTableHeader';
import {SimpleTable} from 'sentry/components/tables/simpleTable';
import {t} from 'sentry/locale';
import type {Sort} from 'sentry/utils/discover/fields';
import type RequestError from 'sentry/utils/requestError/requestError';
import {ERROR_MAP} from 'sentry/utils/requestError/requestError';
import {useNavigate} from 'sentry/utils/useNavigate';
import useOrganization from 'sentry/utils/useOrganization';
import {makeReplaysPathname} from 'sentry/views/replays/pathnames';
import type {ReplayListRecord} from 'sentry/views/replays/types';
Expand All @@ -30,12 +32,14 @@ type Props = SortProps & {
replays: ReplayListRecord[];
showDropdownFilters: boolean;
highlightedRowIndex?: number;
pageLinks?: string | null;
query?: Query;
ref?: RefObject<HTMLDivElement | null>;
stickyHeader?: boolean;
};

export default function ReplayTable({
pageLinks,
query,
columns,
error,
Expand All @@ -52,6 +56,7 @@ export default function ReplayTable({
const gridTemplateColumns = columns.map(col => col.width ?? 'max-content').join(' ');
const hasInteractiveColumn = columns.some(col => col.interactive);
const organization = useOrganization();
const navigate = useNavigate();

if (isPending) {
return (
Expand Down Expand Up @@ -142,6 +147,17 @@ export default function ReplayTable({
))}
</RowWithScrollIntoView>
))}
{pageLinks ? (
<StyledPagination
pageLinks={pageLinks}
onCursor={(cursor, path, searchQuery) => {
navigate({
pathname: path,
query: {...searchQuery, cursor},
});
}}
/>
) : null}
Comment on lines +150 to +160
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBD, but if we want scrolling to work properly in playlist tab, we need to embed pagination into the table, otherwise we can't internally scroll the table. since we have:

| alert |
| table |
| pagination |

ideally, alert should be sticky at the top, along with the table headers, and pagination should only be visible when we scroll to the last row in the table.

In order to have table headers sticky, we would need the scroll to be internal to the table, which means the only way to see pagination only when we reach the last row in the table is for pagination to be embedded in the table. Otherwise, we would need pagination to always be visible as well, which is kind of a waste of pixels.

</StyledSimpleTable>
);
}
Expand All @@ -157,7 +173,7 @@ function RowWithScrollIntoView({
const rowRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (scrollIntoView) {
rowRef.current?.scrollIntoView();
rowRef.current?.scrollIntoView({block: 'center'});
}
}, [scrollIntoView]);
return (
Expand All @@ -176,6 +192,11 @@ const StyledSimpleTable = styled(SimpleTable)`
}
`;

const StyledPagination = styled(Pagination)`
margin: ${p => p.theme.space.md};
grid-column: 1 / -1;
`;

function getErrorMessage(fetchError: RequestError) {
if (typeof fetchError === 'string') {
return fetchError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,32 @@ interface Props {
currentReplay: ReplayListRecord | undefined;
isLoading: boolean;
replays: ReplayListRecord[];
pageLinks?: string | null;
}

const Context = createContext<{
currentReplayIndex: number;
isLoading: boolean;
pageLinks: string | null;
replays: ReplayListRecord[];
}>({currentReplayIndex: -1, replays: [], isLoading: false});
}>({currentReplayIndex: -1, replays: [], isLoading: false, pageLinks: null});

export function ReplayPlaylistProvider({
children,
currentReplay,
isLoading,
pageLinks = null,
replays,
}: Props) {
const currentReplayIndex = useMemo(
() => replays?.findIndex(r => r.id === currentReplay?.id) ?? -1,
[replays, currentReplay]
);
return <Context value={{replays, currentReplayIndex, isLoading}}>{children}</Context>;
return (
<Context value={{replays, currentReplayIndex, isLoading, pageLinks}}>
{children}
</Context>
);
}

export function useReplayPlaylist() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ export default function ReplayDetailsProviders({children, replay, projectSlug}:
? (query.referrer as ReplayListQueryReferrer)
: 'replayList',
});
const {data, isLoading} = useApiQuery<{
const {data, isLoading, getResponseHeader} = useApiQuery<{
data: ReplayListRecord[];
enabled: boolean;
}>(queryKey, {
staleTime: 0,
enabled: Boolean(playlistStart && playlistEnd),
});
const pageLinks = getResponseHeader?.('Link') ?? null;

const replays = useMemo(() => data?.data?.map(mapResponseToReplayRecord) ?? [], [data]);

Expand All @@ -109,6 +110,7 @@ export default function ReplayDetailsProviders({children, replay, projectSlug}:
<ReplayPlaylistProvider
currentReplay={replayRecord}
isLoading={isLoading}
pageLinks={pageLinks}
replays={replays}
>
{children}
Expand Down
15 changes: 7 additions & 8 deletions static/app/views/replays/detail/playlist/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const MOBILE_COLUMNS = [
];

export default function Playlist() {
const {replays, currentReplayIndex, isLoading} = useReplayPlaylist();
const {replays, currentReplayIndex, isLoading, pageLinks} = useReplayPlaylist();
const location = useLocation();
const [query] = useQueryState('query', parseAsString.withDefault(''));

Expand All @@ -46,13 +46,11 @@ export default function Playlist() {
<Flex height="100%" overflow="auto">
<Grid gap="md" rows={rows} height="100%" width="100%">
{query ? (
<Alert
variant="info"
showIcon
defaultExpanded
expand={<ProvidedFormattedQuery query={query} />}
>
<Text>{t('This playlist is filtered by:')} </Text>
<Alert variant="info" showIcon>
<Flex wrap="wrap" align="center">
<Text>{t('This playlist is filtered by')} </Text>
<ProvidedFormattedQuery query={query} />
</Flex>
</Alert>
) : null}
<ReplayTable
Expand All @@ -64,6 +62,7 @@ export default function Playlist() {
query={location.query}
replays={replays}
showDropdownFilters={false}
pageLinks={pageLinks}
stickyHeader
/>
</Grid>
Expand Down
Loading