Skip to content

feat(client): implemented infinite scrolling on table modals in Team …#684

Merged
johbaxter merged 2 commits intodevfrom
589-allow-infinite-scrolling-on-tables-in-team-pages-in-teams-permissions
Mar 10, 2025
Merged

feat(client): implemented infinite scrolling on table modals in Team …#684
johbaxter merged 2 commits intodevfrom
589-allow-infinite-scrolling-on-tables-in-team-pages-in-teams-permissions

Conversation

@j-arias-dev
Copy link
Copy Markdown
Contributor

@j-arias-dev j-arias-dev commented Mar 10, 2025

Description

Implemented infinite scrolling and search functionality on table modal search inputs on the Team Permissions page.

Changes Made

  • Added infinite scrolling and search functionality to the Autocomplete component for members, projects, and engine in the modal
  • Added limit, offset, searchTerm data fields to the getNonTeamUsers, getUnassignedTeamProjects, and getUnassignedTeamEngines pixel calls.
  • Added ID to the project and engine dropdown labels

How to Test

  1. Steps to reproduce/test the behavior
    On the Team Permissions page, when you click "Add Members", "Add Projects", or "Add Engines", it brings up a modal with a search input.
  • Test the infinite scroll functionality within the autocomplete search component.
  • When typing in the search input, check the network console to ensure that the search triggers a query to the back-end.
  1. Expected outcomes
    As you scroll near the bottom of the search component, a query gets called to grab the next set of 10 items.
    When typing in the search input, the search triggers a query to the back-end.

Notes

@github-actions
Copy link
Copy Markdown

@CodiumAI-Agent /describe

@j-arias-dev j-arias-dev self-assigned this Mar 10, 2025
@QodoAI-Agent
Copy link
Copy Markdown

Title

feat(client): implemented infinite scrolling on table modals in Team …


User description

Description

Implemented infinite scrolling and search functionality on table modal search inputs on the Team Permissions page.

Changes Made

  • Added infinite scrolling functionality to the Autocomplete component for members, projects, and engine in the modal
  • Added limit, offset, searchTerm data fields to the getNonTeamUsers, getUnassignedTeamProjects, and getUnassignedTeamEngines pixel calls.

How to Test

  1. Steps to reproduce/test the behavior
    On the Team Permissions page, when you click "Add Members", "Add Projects", or "Add Engines", it brings up a modal with a search input.
  • Test the infinite scroll functionality within the autocomplete search component.
  • When typing in the search input, check the network console to ensure that the search triggers a query to the back-end.
  1. Expected outcomes

Notes


PR Type

  • Enhancement

Description

  • Added infinite scroll and search in team modals.

  • Integrated offset, limit, and loading state management.

  • Updated Autocomplete for engines, members, and projects.

  • Extended API calls with new pagination parameters.


Changes walkthrough 📝

Relevant files
Enhancement
TeamEnginesTable.tsx
Infinite scroll and search integration for engines table 

packages/client/src/components/teams/TeamEnginesTable.tsx

  • Introduced AUTOCOMPLETE_LIMIT and AUTOCOMPLETE_OFFSET constants.
  • Added searchEngineInput, offset, isScrollBottom, canCollect,
    isLoading, and searchLoading states.
  • Implemented nearBottom scroll detection and infinite scrolling.
  • Modified getEngines function to handle pagination and search.
  • +100/-8 
    TeamMembersTable.tsx
    Infinite scroll and search integration for members table 

    packages/client/src/components/teams/TeamMembersTable.tsx

  • Added AUTOCOMPLETE constants and searchMemberInput, offset,
    isScrollBottom states.
  • Implemented infinite scrolling detection with
    getAdditionalUsersNonGroup.
  • Enhanced getUsersNonGroup function for pagination and search.
  • Improved Autocomplete component with input and scroll event handlers.
  • +103/-10
    TeamProjectsTable.tsx
    Infinite scroll and search integration for projects table

    packages/client/src/components/teams/TeamProjectsTable.tsx

  • Added AUTOCOMPLETE_LIMIT and AUTOCOMPLETE_OFFSET constants.
  • Introduced searchProjectInput, offset, isScrollBottom, and respective
    loading states.
  • Updated getProjects function to support infinite scrolling and search.
  • Enhanced Autocomplete component behavior with input and list scroll
    handlers.
  • +100/-8 
    monolith.store.ts
    API update for paginated team modals data retrieval           

    packages/client/src/stores/monolith/monolith.store.ts

  • Modified getNonTeamUsers to include limit, offset, and searchTerm.
  • Updated getUnassignedTeamProjects with pagination and search
    parameters.
  • Extended getUnassignedTeamEngines to accept new query parameters.
  • +29/-3   

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @github-actions
    Copy link
    Copy Markdown

    @CodiumAI-Agent /review

    @QodoAI-Agent
    Copy link
    Copy Markdown

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Parameter Handling

    The new additions for API calls include parameters (limit, offset, searchTerm) that are conditionally added based on truthiness. Since a value of 0 or an empty string is falsy in JavaScript, these checks might unintentionally skip valid values. Consider using explicit checks (e.g., comparing to undefined) to ensure proper parameter passing.

    /**
     * @name getNonTeamUsers
     * @param groupId
     */
    async getNonTeamUsers(
        groupId: string,
        limit: number,
        offset: number,
        searchTerm: string,
    ) {
        let url = `${Env.MODULE}/api/auth/admin/`;
    
        url += 'group/getNonGroupMembers';
    
        const params = {};
    
        groupId && (params['groupId'] = groupId);
        limit && (params['limit'] = limit);
        offset && (params['offset'] = offset);
        searchTerm && (params['searchTerm'] = searchTerm);
    State & Scroll Management

    The implementation for infinite scrolling and search (including state resets in onInputChange and useEffect dependency on offset and searchEngineInput) should be closely validated to ensure that data isn’t accidentally cleared or fetched multiple times. Verify that scroll detection via nearBottom and state updates (e.g., offset increments) work together as expected.

    const [engines, setEngines] = useState(null);
    const [enginesCount, setEngineCount] = useState(null);
    const [hasEngines, setHasEngines] = useState(false);
    
    const limit = 5;
    const [searchEngineInput, setSearchEngineInput] = useState<string>('');
    const [offset, setOffset] = useState(AUTOCOMPLETE_OFFSET);
    const [isScrollBottom, setIsScrollBottom] = useState(false);
    const [canCollect, setCanCollect] = useState<boolean>(true);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [searchLoading, setSearchLoading] = useState(false);
    
    const nearBottom = (
        target: {
            scrollHeight?: number;
            scrollTop?: number;
            clientHeight?: number;
        } = {},
    ) => {
        const diff = Math.round(target.scrollHeight - target.scrollTop);
        return diff - 25 <= target.clientHeight;
    };
    
    /**
     * @name getAdditionalEngines
     */
    const getAdditionalEngines = () => {
        setOffset(offset + AUTOCOMPLETE_LIMIT);
    };
    
    const engineSearchRef = useRef(undefined);
    
    const { watch, setValue } = useForm<{
        SEARCH_FILTER: string;
    }>({
        defaultValues: {
            // Filters for engines table
            SEARCH_FILTER: '',
        },
    });
    
    const searchFilter = watch('SEARCH_FILTER');
    
    /**
     * @name useEffect
     * @desc - sets engines in react hook form
     */
    useEffect(() => {
        monolithStore
            .getTeamEngines(
                groupId,
                groupType,
                limit,
                enginesPage * limit - limit, // offset
                searchFilter,
            )
            .then((data) => {
                setEngines(data);
                setHasEngines(true);
            });
    }, []);
    
    useEffect(() => {
        if (isScrollBottom) {
            if (canCollect) {
                getAdditionalEngines();
            }
        }
    }, [isScrollBottom]);
    
    useEffect(() => {
        if (searchEngineInput) {
            setSearchLoading(true);
        }
        const timer = setTimeout(() => {
            if (!offset) {
                getEngines(false);
            } else {
                if (canCollect) {
                    getEngines(false);
                } else {
                    getEngines(true);
                }
            }
        }, 500);
        return () => clearTimeout(timer);
    }, [offset, searchEngineInput]);
    
    /**
     * @name submitNonGroupEngines
    Consistent Debouncing

    Similar infinite scrolling and debounced search logic have been applied here. Double-check that resetting of nonCredentialedUsers and managing of loading states do not lead to race conditions or unexpected behavior when rapidly changing the search input.

    const [teamMembers, setTeamMembers] = useState(null);
    const [memberCount, setMemberCount] = useState(null);
    const [hasMembers, setHasMembers] = useState(false);
    
    const limit = 5;
    const [searchMemberInput, setSearchMemberInput] = useState<string>('');
    const [offset, setOffset] = useState(AUTOCOMPLETE_OFFSET);
    const [isScrollBottom, setIsScrollBottom] = useState(false);
    const [canCollect, setCanCollect] = useState<boolean>(true);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [searchLoading, setSearchLoading] = useState(false);
    
    const nearBottom = (
        target: {
            scrollHeight?: number;
            scrollTop?: number;
            clientHeight?: number;
        } = {},
    ) => {
        const diff = Math.round(target.scrollHeight - target.scrollTop);
        return diff - 25 <= target.clientHeight;
    };
    
    /**
     * @name getAdditionalUsersNonGroup
     */
    const getAdditionalUsersNonGroup = () => {
        setOffset(offset + AUTOCOMPLETE_LIMIT);
    };
    
    const memberSearchRef = useRef(undefined);
    
    const { watch, setValue } = useForm<{
        SEARCH_FILTER: string;
    }>({
        defaultValues: {
            // Filters for Members table
            SEARCH_FILTER: '',
        },
    });
    
    const searchFilter = watch('SEARCH_FILTER');
    
    /**
     * @name useEffect
     * @desc - sets members in react hook form
     */
    useEffect(() => {
        monolithStore
            .getTeamUsers(
                groupId,
                limit,
                membersPage * limit - limit, // offset
                searchFilter,
            )
            .then((data) => {
                setTeamMembers(data);
                setHasMembers(true);
            });
    }, []);
    
    useEffect(() => {
        if (isScrollBottom) {
            if (canCollect) {
                getAdditionalUsersNonGroup();
            }
        }
    }, [isScrollBottom]);
    
    useEffect(() => {
        if (searchMemberInput) {
            setSearchLoading(true);
        }
        const timer = setTimeout(() => {
            if (!offset) {
                getUsersNonGroup(false);
            } else {
                if (canCollect) {
                    getUsersNonGroup(false);
                } else {
                    getUsersNonGroup(true);
                }
            }
        }, 500);
        return () => clearTimeout(timer);
    }, [offset, searchMemberInput]);

    @github-actions
    Copy link
    Copy Markdown

    @CodiumAI-Agent /improve

    @QodoAI-Agent
    Copy link
    Copy Markdown

    PR Code Suggestions ✨

    No code suggestions found for the PR.

    @j-arias-dev j-arias-dev requested a review from johbaxter March 10, 2025 14:03
    @j-arias-dev j-arias-dev marked this pull request as ready for review March 10, 2025 14:03
    @j-arias-dev j-arias-dev requested a review from a team as a code owner March 10, 2025 14:03
    @johbaxter johbaxter merged commit d340e9f into dev Mar 10, 2025
    3 checks passed
    @johbaxter johbaxter deleted the 589-allow-infinite-scrolling-on-tables-in-team-pages-in-teams-permissions branch March 10, 2025 15:30
    @github-actions
    Copy link
    Copy Markdown

    @CodiumAI-Agent /update_changelog

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    None yet

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    Allow infinite scrolling on tables in Team pages in Teams Permissions

    3 participants