Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sh-admin): enhanced user management in admin dashboard #3814

Conversation

JoelJacobStephen
Copy link
Contributor

@JoelJacobStephen JoelJacobStephen commented Feb 8, 2024

Ticket

Description

This PR brings a ton of features to improve user management in Admin Dashboard.

New Features

  1. Admins can now update the name of any user,
  2. Bulk actions are now possible in the users table. These actions include:
    • Elevation of multiple users to admin status,
    • Removal of admin status from multiple users,
    • Deletion of multiple users,
  3. Ability to search through the users table by name or email address of the users.
  4. New page based pagination system for the users table replacing the previous used scroll based pagination system.
  5. Ability to revoke pending invites from the pending invites page.

Additional Changes

Due to the changes introduced in HoppSmartTable, all tables in the admin dashboard have been updated to adhere to the new changes.

Screenshot

image

Checks

  • My pull request adheres to the code style of this project
  • My code requires changes to the documentation
  • I have updated the documentation as required
  • All the tests have passed

@JoelJacobStephen JoelJacobStephen changed the title feat: upgraded user management in admin dashboard feat(sh-admin): enhanced user management in admin dashboard Feb 15, 2024
@JoelJacobStephen JoelJacobStephen force-pushed the feat/dashboard-user-management branch 2 times, most recently from 5235739 to 7a6b792 Compare March 1, 2024 06:22
@JoelJacobStephen JoelJacobStephen force-pushed the feat/dashboard-user-management branch 2 times, most recently from 0239302 to 2753758 Compare March 7, 2024 14:20
@JoelJacobStephen JoelJacobStephen marked this pull request as ready for review March 8, 2024 04:39
Copy link
Member

@jamesgeorge007 jamesgeorge007 left a comment

Choose a reason for hiding this comment

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

Search and pagination don't play well in the user list view. The computation for total pages doesn't account for search in all cases.

@JoelJacobStephen
Copy link
Contributor Author

Search and pagination don't play well in the user list view. The computation for total pages doesn't account for search in all cases.

@jamesgeorge007 I've fixed the issue. You can test it now.

Copy link
Member

@jamesgeorge007 jamesgeorge007 left a comment

Choose a reason for hiding this comment

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

  • A search session has to ensure the page number gets reset to 1.
  • At times the entire list gets populated while clearing the search entry at once.

@JoelJacobStephen
Copy link
Contributor Author

  • A search session has to ensure the page number gets reset to 1.
  • At times the entire list gets populated while clearing the search entry at once.

@jamesgeorge007 I have resolved these issue.

Copy link
Member

Choose a reason for hiding this comment

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

There's an issue arising here while changing the admin status (making a user admin & vice versa) for a user and immediately selecting the row for which the action was performed won't result in the action bar (with toggle admin & delete actions) to show up. It shows up only during the second attempt.

Copy link
Member

Choose a reason for hiding this comment

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

This requires an update to @hoppscotch/ui and will be handled separately.

Copy link
Member

@jamesgeorge007 jamesgeorge007 left a comment

Choose a reason for hiding this comment

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

LGTM 🚀
Leaving a few pointers below for future reference.

Copy link
Member

Choose a reason for hiding this comment

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

To obtain the total search results, we could introduce a new alias type searchResults that takes in the searchString alone and returns the filtered entries to compute the total pages. We also use the @include directive to ensure the above field is fetched only if there's a search query supplied indicated by a new includeSearchResults argument.

query UsersListV2(
  $searchString: String
  $skip: Int
  $take: Int
  $includeSearchResults: Boolean!
) {
  infra {
    allUsersV2(searchString: $searchString, skip: $skip, take: $take) {
      uid
      displayName
      email
      isAdmin
      photoURL
      createdOn
    }
    searchResults: allUsersV2(searchString: $searchString)
      @include(if: $includeSearchResults) {
      uid
    }
  }
}

(x) => x.infra.allUsers,
(x) => x.uid,
UsersListV2Document,
(x) => x.infra.allUsersV2,
Copy link
Member

Choose a reason for hiding this comment

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

As mentioned above, we could compute the total count with the search results filter applied with modifications to the UsersListV2 GQL query. For the transformation function, we might need to account for the total count of search results x.infra.searchResults.length that also boils down to the requirement for an object. The newly introduced includeSearchResults argument can be supplied here and at the places where refetch is invoked where the value is supplied as searchQuery.value.length > 0 from the search handler where we'd need the total count for search results to update the computation for total pages.

Comment on lines +24 to +45
<div class="mb-3 flex items-center justify-end">
<HoppButtonSecondary
outline
filled
:icon="IconLeft"
:disabled="page === 1"
@click="changePage(PageDirection.Previous)"
/>

<div v-else-if="error">{{ t('users.load_list_error') }}</div>
<div class="flex h-full w-10 items-center justify-center">
<span>{{ page }}</span>
</div>

<HoppSmartTable v-else-if="usersList.length" :list="usersList">
<HoppButtonSecondary
outline
filled
:icon="IconRight"
:disabled="page >= totalPages"
@click="changePage(PageDirection.Next)"
/>
</div>

Copy link
Member

Choose a reason for hiding this comment

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

Displaying the pagination element is redundant if there is only one page. But, it might lead to layout shifts if the search results don't span multiple pages. We can perhaps move the pagination element along the line with the Invite Users & Pending Invites actions once it is moved out of the HoppSmartTable component; something to think about and decide later.

<HoppSmartTable
:headings="headings"
:list="finalUsersList"
:loading="showSpinner"
Copy link
Member

Choose a reason for hiding this comment

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

There's a slight difference in height compared to the spinner and the row with actual data. We could leverage the loading-state slot to implement a custom spinner to fine-tune the dimensions.

JoelJacobStephen and others added 27 commits March 13, 2024 14:22
- Show the error state within the table.
- Ensure the next pagination action remains disabled if the current page count exceeds the total page count accounting for the case with empty results.
- Move the debounce `setTimeout` ID outside the function body to achieve the expected behavior.
- Clear `setTimeout` IDs on page unmount.
@AndrewBastin AndrewBastin force-pushed the feat/dashboard-user-management branch from 0b81e6e to 6b43960 Compare March 13, 2024 08:52
Comment on lines +21 to +25
<HoppSmartTable
v-else-if="teamsList.length"
:headings="headings"
:list="teamsList"
@onRowClicked="goToTeamDetails"
Copy link
Member

Choose a reason for hiding this comment

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

can we add the loading state inside the table similar to the User table

Copy link
Member

Choose a reason for hiding this comment

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

@JoelJacobStephen, please make a note of these to address separately.

Comment on lines +28 to +32
<th class="px-6 py-2">{{ t('teams.id') }}</th>
<th class="px-6 py-2">{{ t('teams.name') }}</th>
<th class="px-6 py-2">{{ t('teams.members') }}</th>
<!-- Empty Heading for the Action Button -->
<th class="px-6 py-2"></th>
Copy link
Member

Choose a reason for hiding this comment

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

we can add a class and incorporate the cell styles in that.

Comment on lines +35 to +41
<td class="flex py-4 px-7 max-w-[16rem]">
<span class="truncate">
{{ team.id }}
</span>
</td>

<td class="py-4 px-7 min-w-[20rem]">
Copy link
Member

Choose a reason for hiding this comment

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

can we use similar padding that of the heading here ? px-6 py-2

Comment on lines +56 to +61
<HoppSmartInput
v-model="query"
styles="w-full bg-primary py-1"
input-styles="h-full border-none"
:placeholder="t('users.searchbar_placeholder')"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
<HoppSmartInput
v-model="query"
styles="w-full bg-primary py-1"
input-styles="h-full border-none"
:placeholder="t('users.searchbar_placeholder')"
/>
<HoppSmartInput
v-model="query"
styles="w-full bg-primary py-1"
input-styles="h-full border-none"
:placeholder="t('users.searchbar_placeholder')"
:autofocus="false"
/>

we can set autofocus false here

Comment on lines +65 to +68
<th class="px-6 py-2">{{ t('users.id') }}</th>
<th class="px-6 py-2">{{ t('users.name') }}</th>
<th class="px-6 py-2">{{ t('users.email') }}</th>
<th class="px-6 py-2">{{ t('users.date') }}</th>
Copy link
Member

Choose a reason for hiding this comment

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

can use common class name to incorporate the styles

@AndrewBastin AndrewBastin merged commit acfb018 into hoppscotch:release/2024.3.0 Mar 13, 2024
1 check passed
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.

None yet

4 participants