refactor: consolidated admin dashboard improvements (#3790)

Co-authored-by: jamesgeorge007 <jamesgeorge998001@gmail.com>
This commit is contained in:
Joel Jacob Stephen
2024-02-02 15:17:25 +05:30
committed by GitHub
parent aab76f1358
commit 3d6adcc39d
20 changed files with 763 additions and 716 deletions

View File

@@ -4,7 +4,9 @@
<HoppSmartSpinner />
</div>
<div v-if="team" class="flex flex-col">
<div v-else-if="error">{{ t('teams.load_info_error') }}</div>
<div v-else-if="team" class="flex flex-col">
<div class="flex items-center space-x-4">
<button
class="p-2 rounded-3xl bg-divider hover:bg-dividerDark transition flex justify-center items-center"
@@ -27,19 +29,16 @@
<HoppSmartTabs v-model="selectedOptionTab" render-inactive-tabs>
<HoppSmartTab :id="'details'" :label="t('teams.details')">
<TeamsDetails
:team="team"
:teamName="teamName"
v-model:showRenameInput="showRenameInput"
@rename-team="renameTeamName"
v-model:team="team"
@delete-team="deleteTeam"
class="py-8 px-4"
/>
</HoppSmartTab>
<HoppSmartTab :id="'members'" :label="t('teams.team_members')">
<TeamsMembers @update-team="updateTeam()" class="py-8 px-4" />
<TeamsMembers v-model:team="team" class="py-8 px-4" />
</HoppSmartTab>
<HoppSmartTab :id="'invites'" :label="t('teams.invites')">
<TeamsPendingInvites :editingTeamID="team.id" />
<TeamsPendingInvites v-model:team="team" />
</HoppSmartTab>
</HoppSmartTabs>
@@ -55,24 +54,24 @@
</template>
<script setup lang="ts">
import { useClientHandle, useMutation } from '@urql/vue';
import { computed, onMounted, ref, watch } from 'vue';
import { useMutation } from '@urql/vue';
import { computed, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from '~/composables/i18n';
import { useToast } from '~/composables/toast';
import { useClientHandler } from '~/composables/useClientHandler';
import {
RemoveTeamDocument,
RenameTeamDocument,
TeamInfoDocument,
TeamMemberRole,
TeamInfoQuery,
} from '../../helpers/backend/graphql';
import { HoppSmartTabs } from '@hoppscotch/ui';
import { useI18n } from '~/composables/i18n';
const t = useI18n();
const toast = useToast();
const route = useRoute();
const router = useRouter();
// Tabs
type OptionTabs = 'details' | 'members' | 'invites';
const selectedOptionTab = ref<OptionTabs>('details');
@@ -90,59 +89,24 @@ const currentTabName = computed(() => {
}
});
// Get the details of the team
// Get Team Info
const {
fetching,
error,
data: teamInfo,
fetchData: getTeamInfo,
} = useClientHandler(TeamInfoDocument, {
teamID: route.params.id.toString(),
});
const team = ref<TeamInfoQuery['infra']['teamInfo'] | undefined>();
const teamName = ref('');
const route = useRoute();
const fetching = ref(true);
const { client } = useClientHandle();
const getTeamInfo = async () => {
fetching.value = true;
const result = await client
.query(TeamInfoDocument, { teamID: route.params.id.toString() })
.toPromise();
if (result.error) {
return toast.error(`${t('team.load_info_error')}`);
}
if (result.data?.infra.teamInfo) {
team.value = result.data.infra.teamInfo;
teamName.value = team.value.name;
}
fetching.value = false;
};
onMounted(async () => await getTeamInfo());
const updateTeam = async () => await getTeamInfo();
// Rename the team name
const showRenameInput = ref(false);
const teamRename = useMutation(RenameTeamDocument);
const renameTeamName = async (teamName: string) => {
if (!team.value) return;
if (team.value.name === teamName) {
showRenameInput.value = false;
return;
}
const variables = { uid: team.value.id, name: teamName };
await teamRename.executeMutation(variables).then((result) => {
if (result.error) {
toast.error(`${t('state.rename_team_failure')}`);
} else {
showRenameInput.value = false;
if (team.value) {
team.value.name = teamName;
toast.success(`${t('state.rename_team_success')}`);
}
}
});
};
onMounted(async () => {
await getTeamInfo();
team.value = teamInfo.value?.infra.teamInfo;
});
// Delete team from the infra
const router = useRouter();
const confirmDeletion = ref(false);
const teamDeletion = useMutation(RemoveTeamDocument);
const deleteTeamUID = ref<string | null>(null);
@@ -155,42 +119,18 @@ const deleteTeam = (id: string) => {
const deleteTeamMutation = async (id: string | null) => {
if (!id) {
confirmDeletion.value = false;
toast.error(`${t('state.delete_team_failure')}`);
toast.error(t('state.delete_team_failure'));
return;
}
const variables = { uid: id };
await teamDeletion.executeMutation(variables).then((result) => {
if (result.error) {
toast.error(`${t('state.delete_team_failure')}`);
} else {
toast.success(`${t('state.delete_team_success')}`);
}
});
const result = await teamDeletion.executeMutation(variables);
if (result.error) {
toast.error(t('state.delete_team_failure'));
} else {
toast.success(t('state.delete_team_success'));
}
confirmDeletion.value = false;
deleteTeamUID.value = null;
router.push('/teams');
};
// Update Roles of Members
const roleUpdates = ref<
{
userID: string;
role: TeamMemberRole;
}[]
>([]);
watch(
() => team.value,
(teamDetails) => {
const members = teamDetails?.teamMembers ?? [];
// Remove deleted members
roleUpdates.value = roleUpdates.value.filter(
(update) =>
members.findIndex(
(y: { user: { uid: string } }) => y.user.uid === update.userID
) !== -1
);
}
);
</script>

View File

@@ -122,7 +122,15 @@
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import { useMutation, useQuery } from '@urql/vue';
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from '~/composables/i18n';
import { useToast } from '~/composables/toast';
import { usePagedQuery } from '~/composables/usePagedQuery';
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
import IconAddUsers from '~icons/lucide/plus';
import IconTrash from '~icons/lucide/trash';
import {
CreateTeamDocument,
MetricsDocument,
@@ -130,18 +138,10 @@ import {
TeamListDocument,
UsersListDocument,
} from '../../helpers/backend/graphql';
import { usePagedQuery } from '~/composables/usePagedQuery';
import { computed, ref, watch } from 'vue';
import { useMutation, useQuery } from '@urql/vue';
import { useToast } from '~/composables/toast';
import IconAddUsers from '~icons/lucide/plus';
import IconTrash from '~icons/lucide/trash';
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
import { useI18n } from '~/composables/i18n';
const t = useI18n();
const toast = useToast();
// Get Users List
const { data } = useQuery({ query: MetricsDocument });
const usersPerPage = computed(() => data.value?.infra.usersCount || 10000);
@@ -174,55 +174,50 @@ const {
);
// Create Team
const createTeamMutation = useMutation(CreateTeamDocument);
const showCreateTeamModal = ref(false);
const createTeamLoading = ref(false);
const createTeamMutation = useMutation(CreateTeamDocument);
const createTeam = async (newTeamName: string, ownerEmail: string) => {
if (newTeamName.length < 6) {
toast.error(`${t('state.team_name_long')}`);
toast.error(t('state.team_name_too_short'));
return;
}
if (ownerEmail.length === 0) {
toast.error(`${t('state.enter_team_email')}`);
toast.error(t('state.enter_team_email'));
return;
}
createTeamLoading.value = true;
const userUid =
usersList.value.find((user) => user.email === ownerEmail)?.uid || '';
const variables = { name: newTeamName.trim(), userUid: userUid };
await createTeamMutation.executeMutation(variables).then((result) => {
if (result.error) {
if (result.error.toString() == '[GraphQL] user/not_found') {
toast.error(`${t('state.user_not_found')}`);
} else {
toast.error(`${t('state.create_team_failure')}`);
}
createTeamLoading.value = false;
const result = await createTeamMutation.executeMutation(variables);
if (result.error) {
if (result.error.toString() == '[GraphQL] user/not_found') {
toast.error(t('state.user_not_found'));
} else {
toast.success(`${t('state.create_team_success')}`);
showCreateTeamModal.value = false;
createTeamLoading.value = false;
refetch();
toast.error(t('state.create_team_failure'));
}
});
createTeamLoading.value = false;
} else {
toast.success(t('state.create_team_success'));
showCreateTeamModal.value = false;
createTeamLoading.value = false;
refetch();
}
};
// Go To Individual Team Details Page
const router = useRouter();
const goToTeamDetails = (teamId: string) => router.push('/teams/' + teamId);
// Reload Teams Page when routed back to the teams page
const route = useRoute();
watch(
() => route.params.id,
() => window.location.reload()
);
// Team Deletion
const teamDeletion = useMutation(RemoveTeamDocument);
const confirmDeletion = ref(false);
const deleteTeamID = ref<string | null>(null);
const teamDeletion = useMutation(RemoveTeamDocument);
const deleteTeam = (id: string) => {
confirmDeletion.value = true;
@@ -232,20 +227,19 @@ const deleteTeam = (id: string) => {
const deleteTeamMutation = async (id: string | null) => {
if (!id) {
confirmDeletion.value = false;
toast.error(`${t('state.delete_team_failure')}`);
toast.error(t('state.delete_team_failure'));
return;
}
const variables = { uid: id };
await teamDeletion.executeMutation(variables).then((result) => {
if (result.error) {
toast.error(`${t('state.delete_team_failure')}`);
} else {
teamsList.value = teamsList.value.filter((team) => team.id !== id);
toast.success(`${t('state.delete_team_success')}`);
}
});
const result = await teamDeletion.executeMutation(variables);
if (result.error) {
toast.error(t('state.delete_team_failure'));
} else {
teamsList.value = teamsList.value.filter((team) => team.id !== id);
toast.success(t('state.delete_team_success'));
}
confirmDeletion.value = false;
deleteTeamID.value = null;
router.push('/teams');
};
</script>