feat(sh-admin): introducing last active status to users table and individual user's page in dashboard (#4077)

Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
Joel Jacob Stephen
2024-06-26 12:30:40 +05:30
committed by GitHub
parent 25fd35770a
commit b3e42bf7c3
6 changed files with 23 additions and 19 deletions

View File

@@ -279,6 +279,7 @@
"invited_on": "Invited On", "invited_on": "Invited On",
"invited_users": "Invited Users", "invited_users": "Invited Users",
"invitee_email": "Invitee Email", "invitee_email": "Invitee Email",
"last_active_on": "Last Active",
"load_info_error": "Unable to load user info", "load_info_error": "Unable to load user info",
"load_list_error": "Unable to Load Users List", "load_list_error": "Unable to Load Users List",
"make_admin": "Make Admin", "make_admin": "Make Admin",
@@ -286,6 +287,7 @@
"no_invite": "No pending invites found", "no_invite": "No pending invites found",
"no_shared_requests": "No shared requests created by the user", "no_shared_requests": "No shared requests created by the user",
"no_users": "No users found", "no_users": "No users found",
"not_available": "Not Available",
"not_found": "User not found", "not_found": "User not found",
"pending_invites": "Pending Invites", "pending_invites": "Pending Invites",
"remove_admin_privilege": "Remove Admin Privilege", "remove_admin_privilege": "Remove Admin Privilege",

View File

@@ -17,23 +17,13 @@ declare module '@vue/runtime-core' {
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'] HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'] HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'] HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'] HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'] HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'] HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'] HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'] HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']
HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable']
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
IconLucideSearch: typeof import('~icons/lucide/search')['default']
IconLucideUser: typeof import('~icons/lucide/user')['default']
SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default'] SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default']
SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default'] SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default']
SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default'] SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default']

View File

@@ -100,6 +100,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useMutation } from '@urql/vue'; import { useMutation } from '@urql/vue';
import { useTimeAgo } from '@vueuse/core';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useI18n } from '~/composables/i18n'; import { useI18n } from '~/composables/i18n';
@@ -133,7 +134,7 @@ const getCreatedDateAndTime = (date: string) =>
format(new Date(date), 'd-MM-yyyy hh:mm a'); format(new Date(date), 'd-MM-yyyy hh:mm a');
// User Info // User Info
const { uid, displayName, email, createdOn } = props.user; const { uid, displayName, email, createdOn, lastActiveOn } = props.user;
const userInfo = { const userInfo = {
uid: { uid: {
@@ -156,6 +157,13 @@ const userInfo = {
label: t('users.created_on'), label: t('users.created_on'),
value: getCreatedDateAndTime(createdOn), value: getCreatedDateAndTime(createdOn),
}, },
lastActiveOn: {
condition: lastActiveOn,
label: t('users.last_active_on'),
value: lastActiveOn
? useTimeAgo(lastActiveOn).value
: t('users.not_available'),
},
}; };
// Contains the actual user name // Contains the actual user name

View File

@@ -7,6 +7,7 @@ query UserInfo($uid: ID!) {
isAdmin isAdmin
photoURL photoURL
createdOn createdOn
lastActiveOn
} }
} }
} }

View File

@@ -7,6 +7,7 @@ query UsersListV2($searchString: String, $skip: Int, $take: Int) {
isAdmin isAdmin
photoURL photoURL
createdOn createdOn
lastActiveOn
} }
} }
} }

View File

@@ -62,10 +62,10 @@
</div> </div>
</template> </template>
<template #head> <template #head>
<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.name') }}</th>
<th class="px-6 py-2">{{ t('users.email') }}</th> <th class="px-6 py-2">{{ t('users.email') }}</th>
<th class="px-6 py-2">{{ t('users.date') }}</th> <th class="px-6 py-2">{{ t('users.created_on') }}</th>
<th class="px-6 py-2">{{ t('users.last_active_on') }}</th>
<!-- Empty header for Action Button --> <!-- Empty header for Action Button -->
<th class="w-20 px-6 py-2"></th> <th class="w-20 px-6 py-2"></th>
</template> </template>
@@ -79,10 +79,6 @@
</template> </template>
<template #body="{ row: user }"> <template #body="{ row: user }">
<td class="py-2 px-7 max-w-[8rem] truncate">
{{ user.uid }}
</td>
<td class="py-2 px-7"> <td class="py-2 px-7">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<span> <span>
@@ -109,6 +105,8 @@
</div> </div>
</td> </td>
<td class="py-2 px-7">{{ getLastActiveOn(user.lastActiveOn) }}</td>
<td @click.stop class="flex justify-end w-20"> <td @click.stop class="flex justify-end w-20">
<div class="mt-2 mr-5"> <div class="mt-2 mr-5">
<tippy interactive trigger="click" theme="popover"> <tippy interactive trigger="click" theme="popover">
@@ -245,6 +243,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useMutation, useQuery } from '@urql/vue'; import { useMutation, useQuery } from '@urql/vue';
import { useTimeAgo } from '@vueuse/core';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { computed, onUnmounted, ref, watch } from 'vue'; import { computed, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@@ -277,15 +276,18 @@ import IconX from '~icons/lucide/x';
const t = useI18n(); const t = useI18n();
const toast = useToast(); const toast = useToast();
// Time and Date Helpers
const getCreatedDate = (date: string) => format(new Date(date), 'dd-MM-yyyy'); const getCreatedDate = (date: string) => format(new Date(date), 'dd-MM-yyyy');
const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a'); const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a');
const getLastActiveOn = (date: string | null) =>
date ? useTimeAgo(date).value : t('users.not_available');
// Table Headings // Table Headings
const headings = [ const headings = [
{ key: 'uid', label: t('users.id') },
{ key: 'displayName', label: t('users.name') }, { key: 'displayName', label: t('users.name') },
{ key: 'email', label: t('users.email') }, { key: 'email', label: t('users.email') },
{ key: 'createdOn', label: t('users.date') }, { key: 'createdOn', label: t('users.created_on') },
{ key: 'lastActiveOn', label: t('users.last_active_on') },
{ key: '', label: '' }, { key: '', label: '' },
]; ];