Skip to content

Commit

Permalink
Merge pull request #60 from SafeExamBrowser/SEBSP-139
Browse files Browse the repository at this point in the history
Sebsp 139
  • Loading branch information
NadimETH authored Nov 6, 2024
2 parents 8dc20a5 + 7f7a621 commit e8dee46
Show file tree
Hide file tree
Showing 41 changed files with 494 additions and 495 deletions.
4 changes: 0 additions & 4 deletions client/src/components/layout/ContainerLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,6 @@
// {title: "6x6", value: 6},
];
//git tag
//@ts-ignore
// const gitTag = __GIT_TAG__;
//watchers
watch(languageToggle, () => {
locale.value = languageToggle.value === 0 ? "en" : "de";
Expand Down
27 changes: 25 additions & 2 deletions client/src/components/views/ExamsOverviewPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,21 @@
</v-data-table>
</v-col>
</v-row>

<AlertMsg
v-if="errorAvailable"
:alertProps="{
color: 'error',
type: 'snackbar',
textKey: 'api-error'
}">
</AlertMsg>

</template>

<script setup lang="ts">
import { ref, onBeforeMount, onUnmounted, watch } from "vue";
import * as groupService from "@/services/api-services/groupService";
import * as examsOverviewViewService from "@/services/component-services/examsOverviewViewService";
import { useAppBarStore, useTableStore } from "@/store/store";
import * as timeUtils from "@/utils/timeUtils";
import * as tableUtils from "@/utils/table/tableUtils";
Expand All @@ -113,6 +123,10 @@
]);
const noRunningExams = ref<boolean>(false);
//error handling
const errorAvailable = ref<boolean>();
onBeforeMount(async () => {
appBarStore.title = "Running Exams";
await getGroups();
Expand All @@ -131,11 +145,20 @@
});
async function getGroups(){
groups.value = await groupService.getGroups({
errorAvailable.value = false;
const groupsResponse: GroupObject | null = await examsOverviewViewService.getGroups({
pageSize: 500,
includePastExams: appBarStore.examOverviewShowPastExams,
includeUpcomingExams: appBarStore.examOverviewShowUpcomingExams
});
if(groupsResponse == null){
errorAvailable.value = true;
return;
}
groups.value = groupsResponse.content;
}
function getGalleryViewLink(index: number) {
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/views/LoginPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@

</v-form>

<div v-if="!settingsStore.isSebServerIntegratedMode" class="text-center mt-7">
<!-- <div v-if="!settingsStore.isSebServerIntegratedMode" class="text-center mt-7">
<span>
No Account?
</span>
Expand All @@ -88,7 +88,7 @@
@keydown="handleTabKeyEvent($event, 'navigate')">
<router-link :to=constants.REGISTER_ROUTE>Register</router-link>
</span>
</div>
</div> -->

</v-card-text>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,6 @@
onBeforeMount(async () => {
appBarStore.title = "Applications";
await getExamsStarted();
// console.log(await applicationsSearchViewService.getGroupIdsForExam(13))
// console.log(await applicationsSearchViewService.getDistinctMetadataAppForExam("13"))
// console.log(await applicationsSearchViewService.getDistinctMetadataWindowForExam("13", "SEB (Bundle ID: org.safeexambrowser.ios.seb)"))
// console.log(await applicationsSearchViewService.getUserListForApplicationSearch("13", "SEB (Bundle ID: org.safeexambrowser.ios.seb)", "quiz Dany | Testserver Exam-Moodle (Test)"))
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,6 @@
const screenshotTimestampsShortend: number[] = screenshotTimestamps.value.map(timestamp => Math.floor(timestamp / 1000));
const sliderTimeForIndexShortend: number = Math.floor(sliderTime.value / 1000);
console.log(screenshotTimestampsShortend + " --> " + sliderTimeForIndexShortend)
if(screenshotTimestampsShortend.includes(sliderTimeForIndexShortend)){
timestampsIndex.value = screenshotTimestampsShortend.indexOf(sliderTimeForIndexShortend);
Expand All @@ -312,14 +310,9 @@
return;
}
console.log(timestamps)
screenshotTimestamps.value = timestamps;
screenshotTimestampsFloored.value = timestamps.map(timestamp => Math.floor(timestamp / 1000));
console.log(screenshotTimestamps.value)
console.log(screenshotTimestampsFloored.value)
timestampsIndex.value = 0;
}
Expand Down Expand Up @@ -372,9 +365,6 @@
//=========interval=============
function startIntervalScreenshots(){
intervalScreenshots = setInterval(async () => {
console.log("timestampsIndex.value: " + timestampsIndex.value)
// console.log("screenshotTimestamps.value.length: " + screenshotTimestamps.value.length)
if(timestampsIndex.value == screenshotTimestamps.value.length-1){
stopIntervalScreenshots();
isPlaying.value = false;
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/views/search/SearchScreenshotsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@

<!------------content------------>
<template v-slot:item.data-table-expand="{internalItem, item, isExpanded, toggleExpand}">
<v-icon
<v-btn
v-if="item.timelineScreenshotDataList.length > 1"
tabindex="0"
variant="text"
@keydown.native.enter="toggleExpand(internalItem)"
@keydown.native.space="toggleExpand(internalItem)"
@click="toggleExpand(internalItem)"
:icon="isExpanded(internalItem) ? 'mdi-chevron-up' : 'mdi-chevron-down'" >
</v-icon>
</v-btn>
</template>

<template v-slot:expanded-row="{ columns, item, index }">
Expand Down
154 changes: 145 additions & 9 deletions client/src/components/views/search/SearchSessionTable.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
<template>
<v-data-table-server
show-expand
:show-select="isUserAdmin"
v-model="selectedSessionUuids"
select-strategy="page"
item-value="sessionUUID"
class="elevation-1"
@update:options="loadItems"
:loading="isLoading"
loading-text="Loading... Please wait"
:items="sessions?.content"
:items-length="totalItems"
:items-per-page="tableUtils.calcDefaultItemsPerPage(totalItems)"
:items-per-page-options="tableUtils.calcItemsPerPage(totalItems)"
:headers="sessionTableHeaders">

<template v-slot:headers="{ columns, isSorted, getSortIcon, toggleSort }">
<template v-slot:headers="{ columns, isSorted, getSortIcon, toggleSort, selectAll, allSelected, someSelected }">
<CustomTableHeader
v-if="isUserAdmin"
:columns="columns"
:is-sorted="isSorted"
:get-sort-icon="getSortIcon"
:toggle-sort="toggleSort"
:header-refs-prop="sessionTableHeadersRef"
:day="props.day"
:selectAll="selectAll"
:allSelected="allSelected"
:someSelected="someSelected"
tableKey="session"
@openDeleteSessionsDialog="openDeleteSessionsDialog">
</CustomTableHeader>
<CustomTableHeader
v-else
:columns="columns"
:is-sorted="isSorted"
:get-sort-icon="getSortIcon"
Expand Down Expand Up @@ -48,26 +67,88 @@
</template>

<template v-slot:item.data-table-expand="{internalItem, isExpanded, toggleExpand}">
<v-icon
<v-btn
tabindex="0"
variant="text"
@keydown.native.enter="searchTimeline(internalItem, isExpanded, toggleExpand)"
@keydown.native.space="searchTimeline(internalItem, isExpanded, toggleExpand)"
@click="searchTimeline(internalItem, isExpanded, toggleExpand)"
:icon="isExpanded(internalItem) ? 'mdi-chevron-up' : 'mdi-chevron-down'" >
</v-icon>
</v-btn>
</template>

<template v-slot:expanded-row="{ columns, item }">
<tr>
<td :colspan="columns.length">
<!--@vue-ignore-->
<SearchScreenshotsTable :timelineSearchResult="timelineSearchResults.find(i => i.sessionUUID == item.sessionUUID)"></SearchScreenshotsTable>
</td>
</tr>
</template>

</v-data-table-server>

<!-----------delete sessions confirmation---------->
<v-dialog
v-if="isUserAdmin"
v-model="dialog"
max-width="400"
>
<v-sheet elevation="2" class="pa-4 rounded-lg">

<v-row justify="end">
<v-col>
<div class="text-h6">
Delete selected sessions
</div>
</v-col>
</v-row>

<v-row>
<v-col>
<v-list>
<v-list-item v-for="sessionUuid in selectedSessionUuids"
:title="sessions?.content.find(i => i.sessionUUID == sessionUuid)?.clientName"
:subtitle="timeUtils.formatTimestampToTime(sessions?.content.find(i => i.sessionUUID == sessionUuid)?.startTime!)"
>
</v-list-item>
</v-list>
</v-col>
</v-row>


<v-row>
<v-col align="right">
<v-btn
rounded="sm"
color="black"
variant="outlined"
@click="closeDialog()">
Cancel
</v-btn>

<v-btn
rounded="sm"
color="error"
variant="flat"
class="ml-2"
@click="deleteSessions()">
Delete
</v-btn>
</v-col>
</v-row>
</v-sheet>
</v-dialog>
<!------------------------------------------------->

<AlertMsg
v-if="errorAvailable"
:alertProps="{
color: 'error',
type: 'snackbar',
textKey: 'api-error'
}">
</AlertMsg>

</template>


Expand All @@ -78,10 +159,12 @@
import SearchScreenshotsTable from "./SearchScreenshotsTable.vue";
import * as searchViewService from "@/services/component-services/searchViewService";
import CustomTableHeader from "@/utils/table/CustomTableHeader.vue";
import { useTableStore } from "@/store/store";
import { useTableStore, useUserAccountStore } from "@/store/store";
//store
const tableStore = useTableStore();
const userAccountStore = useUserAccountStore();
const isUserAdmin = ref<boolean>();
//props
const props = defineProps<{
Expand All @@ -97,8 +180,8 @@
const isLoading = ref<boolean>(true);
const totalItems = ref<number>(10);
//table
const selectedSessionUuids = ref<string[]>();
const isOnLoad = ref<boolean>(true);
const defaultSort: {key: string, order: string}[] = [{key: 'startTime', order: 'desc'}];
const sessionTableHeadersRef = ref<any[]>();
Expand All @@ -110,9 +193,18 @@
{title: "Exam Name", key: "exam.name", width: "20%"},
{title: "Slides", key: "nrOfScreenshots"},
{title: "Video", key: "proctoringViewLink", sortable: false}
]);
]);
//dialog - delete sessions
const dialog = ref(false);
//error handling
const errorAvailable = ref<boolean>();
//===========================data fetching=======================
async function loadItems(serverTablePaging: ServerTablePaging){
isUserAdmin.value = userAccountStore.userAccount?.roles.includes('ADMIN');
isLoading.value = true;
//current solution to default sort the table
//sort-by in data-table-server tag breaks the sorting as the headers are in a seperate component
Expand Down Expand Up @@ -156,16 +248,55 @@
addTableItemToRefs(timelineSearchResponse, toggleExpand, item);
}
//===============================================================
//===========================session deletion=======================
function openDeleteSessionsDialog(){
openDialog();
}
async function deleteSessions(){
errorAvailable.value = false;
if(selectedSessionUuids.value == null){
return;
}
const response = await searchViewService.deleteSessions(selectedSessionUuids.value);
if(response.data == null || response.status == 207){
errorAvailable.value = true;
return;
}
for(let i = 0; i < selectedSessionUuids.value.length; i++){
const index: number | any = sessions.value?.content.findIndex(y => y.sessionUUID == selectedSessionUuids.value![i]);
sessions.value?.content.splice(index, 1);
}
selectedSessionUuids.value = [];
closeDialog();
}
function openDialog(){
dialog.value = true;
}
function closeDialog(){
dialog.value = false;
}
//===============================================================
//===========================table=======================
function addTableItemToRefs(timelineSearchResponse: SearchTimeline, toggleExpand: Function, item: any){
timelineSearchResults.value.push(timelineSearchResponse);
toggleExpand(item);
}
function removeTableItemFromRefs(item: any, isExpanded: Function, toggleExpand: Function): boolean{
if(isExpanded(item)){
toggleExpand(item);
const index: number = timelineSearchResults.value.findIndex(i => i.sessionUUID == item.sessionUUID);
Expand All @@ -178,6 +309,11 @@
return false;
}
//===============================================================
</script>

<style scoped>
</script>
</style>
Loading

0 comments on commit e8dee46

Please sign in to comment.