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

Improve error handling in room stats and attendance #1600

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/Enums/CustomStatusCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum CustomStatusCodes: int
case ROOM_TYPE_INVALID = 467;
case FEATURE_DISABLED = 468;
case MEETING_ATTENDANCE_NOT_ENDED = 469;
case MEETING_ATTENDANCE_DISABLED = 470;
case EMAIL_CHANGE_THROTTLE = 471;
case JOIN_FAILED = 472;
case ROOM_ALREADY_RUNNING = 474;
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/api/v1/MeetingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public function attendance(Meeting $meeting)
// check if attendance recording is enabled for this meeting
if (! $meeting->record_attendance) {
Log::info('Failed to show attendace for meeting {meeting} of room {room}; attendance is disabled', ['room' => $meeting->room->getLogLabel(), 'meeting' => $meeting->id]);
abort(CustomStatusCodes::FEATURE_DISABLED->value, __('app.errors.meeting_attendance_disabled'));
abort(CustomStatusCodes::MEETING_ATTENDANCE_DISABLED->value, __('app.errors.meeting_attendance_disabled'));
}

// check if meeting is ended
Expand Down
4 changes: 2 additions & 2 deletions lang/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@
'errors' => [
'attendance_agreement_missing' => 'Consent to record attendance is required.',
'join_failed' => 'Joining the room has failed because a connection error has occurred.',
'meeting_attendance_disabled' => 'The logging of attendance is unavailable.',
'meeting_attendance_not_ended' => 'The logging of attendance is not yet completed for this room.',
'meeting_attendance_disabled' => 'Attendance logging was not active at this meeting.',
'meeting_attendance_not_ended' => 'The attendance logs are not yet available for this meeting as it has not yet ended.',
'meeting_statistics_disabled' => 'The usage data is unavailable.',
'membership_disabled' => 'Membership failed! Membership for this room is currently not available.',
'no_room_access' => 'You does not have the necessary permissions, to edit this room.',
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@eslint/json": "^0.7.0",
"@intlify/eslint-plugin-vue-i18n": "^3.0.0",
"cypress": "^13.16.0",
"cypress-set-device-pixel-ratio": "^1.0.7",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-cypress": "^4.1.0",
Expand Down
5 changes: 5 additions & 0 deletions resources/js/components/RoomTabHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@
:start="item.start"
:end="item.end"
:room-name="props.room.name"
@feature-disabled="loadData()"
@not-found="loadData()"
/>
<RoomTabHistoryAttendanceButton
v-if="item.attendance && item.end != null"
Expand All @@ -152,6 +154,9 @@
:start="item.start"
:end="item.end"
:room-name="props.room.name"
@not-found="loadData()"
@not-ended="loadData()"
@attendance-disabled="loadData()"
/>
</div>
</div>
Expand Down
53 changes: 46 additions & 7 deletions resources/js/components/RoomTabHistoryAttendanceButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
scroll-height="400px"
:value="attendance"
data-key="id"
:loading="isLoadingAction"
:loading="isLoadingAction || loadingError"
row-hover
:global-filter-fields="['name']"
:pt="{
Expand Down Expand Up @@ -101,14 +101,19 @@
/>
</div>
</template>
<template #loading>
<LoadingRetryButton :error="loadingError" @reload="loadData()" />
</template>

<template #empty>
<InlineNote v-if="attendance.length == 0">{{
$t("meetings.attendance.no_data")
}}</InlineNote>
<InlineNote v-else>{{
$t("meetings.attendance.no_data_filtered")
}}</InlineNote>
<div v-if="!isLoadingAction && !loadingError">
<InlineNote v-if="attendance.length == 0">{{
$t("meetings.attendance.no_data")
}}</InlineNote>
<InlineNote v-else>{{
$t("meetings.attendance.no_data_filtered")
}}</InlineNote>
</div>
</template>

<Column field="name" sortable :header="$t('app.user_name')">
Expand Down Expand Up @@ -160,6 +165,7 @@
import { useApi } from "../composables/useApi.js";
import "chartjs-adapter-date-fns";
import { useSettingsStore } from "../stores/settings.js";
import env from "../env.js";

const props = defineProps({
roomId: {
Expand Down Expand Up @@ -188,8 +194,11 @@
},
});

const emit = defineEmits(["notFound", "notEnded", "attendanceDisabled"]);

const modalVisible = ref(false);
const isLoadingAction = ref(false);
const loadingError = ref(false);
const attendance = ref([]);
const filters = ref({
global: { value: null, matchMode: "contains" },
Expand All @@ -199,19 +208,49 @@
const settingsStore = useSettingsStore();

function showModal() {
attendance.value = [];

Check warning on line 211 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L211

Added line #L211 was not covered by tests
modalVisible.value = true;
loadData();
}

function loadData() {
isLoadingAction.value = true;
loadingError.value = false;

Check warning on line 218 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L218

Added line #L218 was not covered by tests

api
.call("meetings/" + props.meetingId + "/attendance")
.then((response) => {
attendance.value = response.data.data;
})
.catch((error) => {
loadingError.value = true;

Check warning on line 226 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L226

Added line #L226 was not covered by tests

if (error.response) {

Check warning on line 228 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L228

Added line #L228 was not covered by tests
// meeting is still running, therefore attendance is not yet available
if (error.response.status === env.HTTP_MEETING_ATTENDANCE_NOT_ENDED) {
emit("notEnded");
modalVisible.value = false;

Check warning on line 232 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L230-L232

Added lines #L230 - L232 were not covered by tests
}

// attendance was not enabled for this meeting
if (error.response.status === env.HTTP_MEETING_ATTENDANCE_DISABLED) {
emit("attendanceDisabled");
modalVisible.value = false;

Check warning on line 238 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L236-L238

Added lines #L236 - L238 were not covered by tests
}

// meeting not found
if (error.response.status === env.HTTP_MEETING_ATTENDANCE_NOT_ENDED) {
emit("notEnded");
modalVisible.value = false;

Check warning on line 244 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L242-L244

Added lines #L242 - L244 were not covered by tests
}

// meeting not found
if (error.response.status === env.HTTP_NOT_FOUND) {
emit("notFound");
modalVisible.value = false;

Check warning on line 250 in resources/js/components/RoomTabHistoryAttendanceButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryAttendanceButton.vue#L248-L250

Added lines #L248 - L250 were not covered by tests
}
}

// error during stats loading
api.error(error, { redirectOnUnauthenticated: false });
})
Expand Down
38 changes: 36 additions & 2 deletions resources/js/components/RoomTabHistoryStatisticButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,18 @@
</InlineNote>

<OverlayComponent
:show="isLoadingAction"
:show="isLoadingAction || loadingError"
style="min-height: 100px"
class="mt-6"
>
<template #overlay>
<LoadingRetryButton
:error="loadingError"
@reload="loadData"
></LoadingRetryButton>
</template>
<Chart
v-if="!isLoadingAction"
v-if="!isLoadingAction && !loadingError"
type="line"
:data="chartData"
:options="chartOptions"
Expand All @@ -74,6 +80,7 @@
import { useColors } from "../composables/useColors.js";
import { useCssVar } from "@vueuse/core";
import { sansFontFamily } from "../font.js";
import env from "../env";

const props = defineProps({
roomId: {
Expand Down Expand Up @@ -102,8 +109,11 @@
},
});

const emit = defineEmits(["featureDisabled", "notFound"]);

const modalVisible = ref(false);
const isLoadingAction = ref(false);
const loadingError = ref(false);
const chartDataRows = ref({
participants: [],
voices: [],
Expand All @@ -115,12 +125,20 @@
const colors = useColors();

function showModal() {
// Reset chart data
chartDataRows.value = {

Check warning on line 129 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L129

Added line #L129 was not covered by tests
participants: [],
voices: [],
videos: [],
};

modalVisible.value = true;
loadData();
}

function loadData() {
isLoadingAction.value = true;
loadingError.value = false;

Check warning on line 141 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L141

Added line #L141 was not covered by tests

api
.call("meetings/" + props.meetingId + "/stats")
Expand All @@ -146,6 +164,22 @@
});
})
.catch((error) => {
loadingError.value = true;

Check warning on line 167 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L167

Added line #L167 was not covered by tests

if (error.response) {

Check warning on line 169 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L169

Added line #L169 was not covered by tests
// feature disabled
if (error.response.status === env.HTTP_FEATURE_DISABLED) {
emit("featureDisabled");
modalVisible.value = false;

Check warning on line 173 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L171-L173

Added lines #L171 - L173 were not covered by tests
}

// meeting not found
if (error.response.status === env.HTTP_NOT_FOUND) {
emit("notFound");
modalVisible.value = false;

Check warning on line 179 in resources/js/components/RoomTabHistoryStatisticButton.vue

View check run for this annotation

Codecov / codecov/patch

resources/js/components/RoomTabHistoryStatisticButton.vue#L177-L179

Added lines #L177 - L179 were not covered by tests
}
}

// error during stats loading
api.error(error, { redirectOnUnauthenticated: false });
})
Expand Down
3 changes: 3 additions & 0 deletions resources/js/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export default {
HTTP_ROOM_LIMIT_EXCEEDED: 463,
HTTP_ROLE_DELETE_LINKED_USERS: 464,
HTTP_ROLE_UPDATE_PERMISSION_LOST: 465,
HTTP_FEATURE_DISABLED: 468,
HTTP_MEETING_ATTENDANCE_NOT_ENDED: 469,
HTTP_MEETING_ATTENDANCE_DISABLED: 470,
HTTP_EMAIL_CHANGE_THROTTLE: 471,
HTTP_JOIN_FAILED: 472,
HTTP_ROOM_ALREADY_RUNNING: 474,
Expand Down
4 changes: 3 additions & 1 deletion tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ describe("Rooms view history meeting actions", function () {
});

it("show stats", function () {
cy.setDevicePixelRatio(2);

cy.visit("/rooms/abc-def-123#tab=history");

cy.wait("@roomRequest");
Expand Down Expand Up @@ -58,7 +60,7 @@ describe("Rooms view history meeting actions", function () {
cy.get('[data-test="chart"] > canvas').should(
"have.attr",
"width",
1163,
2326,
);

cy.get('[data-test="chart"] > canvas').then(($canvas) => {
Expand Down
Binary file modified tests/Frontend/fixtures/files/statsGraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tests/Frontend/support/e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ import "./commands/generalCommands.js";
import "./commands/roomCommands.js";
import "./commands/interceptCommands.js";
import "@cypress/code-coverage/support";
import "cypress-set-device-pixel-ratio";
Loading