Skip to content

Commit

Permalink
Feature/cv2 2502 load tags on demand (#2104)
Browse files Browse the repository at this point in the history
* CV2-2502: intial commit

* CV2-2502: remove pagination form TeamTag and show first 100 tags

* CV2-2502: apply search tag for media page

* [WIP] Attempt at using a refetchContainer

* WIP TagList; TagPicker; TeamTagsQueryRenderer

* load more on scroll to bottom

* Fix unit tests

* Add missing propType

* Restore pagination on team tag settings

---------

Co-authored-by: Sawy <[email protected]>
  • Loading branch information
amoedoamorim and melsawy authored Sep 13, 2024
1 parent 24d7b54 commit d92b3a7
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 65 deletions.

This file was deleted.

80 changes: 80 additions & 0 deletions src/app/components/team/TeamTags/PaginatedTeamTags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* eslint-disable relay/unused-fields */
import React from 'react';
import { createPaginationContainer, graphql } from 'react-relay/compat';
import TeamTagsComponent from './TeamTagsComponent';
import { parseStringUnixTimestamp } from '../../../helpers';

// Query that is called for subsequent "load more" pagination calls
// see https://meedan.atlassian.net/wiki/spaces/ENG/pages/1185316865/How+to+paginate+in+Relay+1.7#Modifying-MediaSuggestions
const teamTagsQuery = graphql`
query PaginatedTeamTagsQuery($teamSlug: String!, $pageSize: Int!, $after: String, $keyword: String) {
team(slug: $teamSlug) {
id
dbid
permissions
get_rules
rules_json_schema
...PaginatedTeamTags_root
}
}
`;

const PaginatedTeamTags = createPaginationContainer(
props => (
<TeamTagsComponent
pageSize={props.pageSize}
permissions={props.parentProps.team.permissions}
relay={props.relay}
rules={props.parentProps.team.get_rules}
rulesSchema={JSON.parse(props.parentProps.team.rules_json_schema)}
searchTerm={props.searchTerm}
// total of ALL tags
setSearchTerm={props.setSearchTerm}
// total number of search results
tags={props.root.tag_texts ? props.root.tag_texts.edges.map(({ node }) => ({ ...node, updated_at: parseStringUnixTimestamp(node.updated_at) })) : []}
teamDbid={props.parentProps.team.dbid}
teamId={props.parentProps.team.id}
totalCount={props.root.tag_texts?.totalCount}
totalTags={props.root.tag_texts_count}
/>
),
{ // assign graphql fragment to a key called `root`
root: graphql`
fragment PaginatedTeamTags_root on Team {
tag_texts_count
tag_texts(first: $pageSize, after: $after, keyword: $keyword) @connection(key: "PaginatedTeamTags_tag_texts"){
edges {
node {
id
text
tags_count
updated_at
}
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
`,
},
{ // configuration object
direction: 'forward',
query: teamTagsQuery,
getConnectionFromProps: props => props.root.tag_texts,
getFragmentVariables: (previousVars, pageSize) => ({
...previousVars,
pageSize,
}),
getVariables: (props, paginationInfo, fragmentVariables) => ({
pageSize: fragmentVariables.pageSize,
ids: fragmentVariables.ids,
after: paginationInfo.cursor,
keyword: fragmentVariables.keyword,
}),
},
);

export default PaginatedTeamTags;
75 changes: 73 additions & 2 deletions src/app/components/team/TeamTags/TeamTagsComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ import SaveTag from './SaveTag';
import TeamTagsActions from './TeamTagsActions';
import BlankState from '../../layout/BlankState';
import ButtonMain from '../../cds/buttons-checkboxes-chips/ButtonMain';
import Tooltip from '../../cds/alerts-and-prompts/Tooltip';
import NextIcon from '../../../icons/chevron_right.svg';
import PrevIcon from '../../../icons/chevron_left.svg';
import SearchField from '../../search/SearchField';
import TimeBefore from '../../TimeBefore';
import SettingsHeader from '../SettingsHeader';
import MediasLoading from '../../media/MediasLoading';
import Can from '../../Can';
import styles from './TeamTagsComponent.module.css';
import settingsStyles from '../Settings.module.css';
Expand All @@ -30,10 +34,13 @@ const TeamTagsComponent = ({
tags,
teamDbid,
teamId,
totalCount,
totalTags,
}) => {
const teamSlug = window.location.pathname.match(/^\/([^/]+)/)[1];
const [showCreateTag, setShowCreateTag] = React.useState(false);
const [cursor, setCursor] = React.useState(0);
const [isPaginationLoading, setIsPaginationLoading] = React.useState(false);

const handleSearchFieldClear = () => {
setSearchTerm('');
Expand Down Expand Up @@ -88,6 +95,69 @@ const TeamTagsComponent = ({
/>
}
/>
{ totalTags > pageSize && // only display paginator if there are more than pageSize worth of tags overall in the database
<div className={styles['tags-wrapper']}>
<Tooltip
arrow
title={
<FormattedMessage defaultMessage="Previous page" description="Pagination button to go to previous page" id="search.previousPage" />
}
>
<span>
<ButtonMain
disabled={isPaginationLoading || cursor - pageSize < 0}
iconCenter={<PrevIcon />}
size="default"
theme="info"
variant="text"
onClick={() => {
if (cursor - pageSize >= 0) {
setCursor(cursor - pageSize);
}
}}
/>
</span>
</Tooltip>
<span className={cx('typography-button', styles['tags-header-count'])}>
<FormattedMessage
defaultMessage="{totalCount, plural, one {1 / 1} other {{from} - {to} / #}}"
description="Pagination count of items returned"
id="searchResults.itemsCount"
values={{
from: cursor + 1,
to: Math.min(cursor + pageSize, totalCount),
totalCount,
}}
/>
</span>
<Tooltip
title={
<FormattedMessage defaultMessage="Next page" description="Pagination button to go to next page" id="search.nextPage" />
}
>
<span>
<ButtonMain
disabled={isPaginationLoading || cursor + pageSize >= totalCount}
iconCenter={<NextIcon />}
size="default"
theme="info"
variant="text"
onClick={() => {
if (relay.hasMore() && !relay.isLoading() && (cursor + pageSize >= tags.length)) {
setIsPaginationLoading(true);
relay.loadMore(pageSize, () => {
setCursor(cursor + pageSize);
setIsPaginationLoading(false);
});
} else if (cursor + pageSize < tags.length) {
setCursor(cursor + pageSize);
}
}}
/>
</span>
</Tooltip>
</div>
}
<div className={cx(settingsStyles['setting-details-wrapper'])}>
{totalTags === 0 ?
<BlankState>
Expand Down Expand Up @@ -126,8 +196,9 @@ const TeamTagsComponent = ({
<TableCell className={styles['table-col-head-action']} padding="checkbox" />
</TableRow>
</TableHead>
<TableBody>
{ tags.map(tag => (
{ isPaginationLoading && <MediasLoading size="medium" theme="grey" variant="inline" /> }
<TableBody className={isPaginationLoading && styles['tags-hide']}>
{ tags.slice(cursor, cursor + pageSize).map(tag => (
<TableRow className="team-tags__row" key={tag.id}>
<TableCell>
{tag.text}
Expand Down
34 changes: 8 additions & 26 deletions src/app/components/team/TeamTags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import React from 'react';
import { QueryRenderer, graphql } from 'react-relay/compat';
import Relay from 'react-relay/classic';
import PropTypes from 'prop-types';
import TeamTagsComponent from './TeamTagsComponent';
import { parseStringUnixTimestamp } from '../../../helpers';
import PaginatedTeamTags from './PaginatedTeamTags';

const TeamTags = (props) => {
const pageSize = 100;
Expand All @@ -13,45 +12,28 @@ const TeamTags = (props) => {
return (<QueryRenderer
environment={Relay.Store}
query={graphql`
query TeamTagsQuery($teamSlug: String!, $pageSize: Int!, $keyword: String) {
query TeamTagsQuery($teamSlug: String!, $pageSize: Int!, $after: String, $keyword: String) {
team(slug: $teamSlug) {
id
dbid
permissions
get_rules
rules_json_schema
tag_texts_count
tag_texts(first: $pageSize, keyword: $keyword) {
edges {
node {
id
text
tags_count
updated_at
}
}
totalCount
}
...PaginatedTeamTags_root
}
}
`}
render={({ error, props: innerProps }) => {
if (!error && innerProps) {
const { team } = innerProps;

return (
<TeamTagsComponent
<PaginatedTeamTags
pageSize={pageSize}
permissions={innerProps.team.permissions}
relay={innerProps.relay}
rules={innerProps.team.get_rules}
rulesSchema={JSON.parse(innerProps.team.rules_json_schema)}
parentProps={innerProps}
root={team}
searchTerm={searchTerm}
// total of ALL tags
setSearchTerm={setSearchTerm}
// total number of search results
tags={innerProps.team.tag_texts ? innerProps.team.tag_texts.edges.map(({ node }) => ({ ...node, updated_at: parseStringUnixTimestamp(node.updated_at) })) : []}
teamDbid={innerProps.team.dbid}
teamId={innerProps.team.id}
totalTags={innerProps.team.tag_texts_count}
/>
);
}
Expand Down

0 comments on commit d92b3a7

Please sign in to comment.