-
Notifications
You must be signed in to change notification settings - Fork 19
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
Fix Admin-UI management bugs #1588
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1588 +/- ##
=============================================
- Coverage 81.43% 81.28% -0.15%
Complexity 1410 1410
=============================================
Files 364 364
Lines 9559 9576 +17
Branches 874 879 +5
=============================================
Hits 7784 7784
- Misses 1775 1792 +17 ☔ View full report in Codecov by Sentry. |
PILOS Run #1845
Run Properties:
|
Project |
PILOS
|
Branch Review |
develop
|
Run status |
Passed #1845
|
Run duration | 09m 00s |
Commit |
4f2f2982ec: Fix Admin-UI management bugs (#1588)
|
Committer | Samuel Weirich |
View all properties for this run ↗︎ |
Test results | |
---|---|
Failures |
0
|
Flaky |
0
|
Pending |
0
|
Skipped |
0
|
Passing |
240
|
View all changes introduced in this branch ↗︎ |
…ui-user-management # Conflicts: # database/seeders/RolesAndPermissionsSeeder.php
…ui-user-management
…ui-user-management
…ui-user-management
…ui-user-management # Conflicts: # resources/js/components/SettingsRoomTypesDeleteButton.vue # resources/js/views/AdminUsersIndex.vue
WalkthroughThis pull request introduces comprehensive improvements across various components in the application, focusing on error handling, loading states, and user interface interactions. The changes span multiple files, addressing issues with search functionality during loading, overlay display after errors, dialog button states, and form validation. Key modifications include disabling search inputs during data loading, showing reload buttons after loading errors, and ensuring dialog buttons are correctly disabled during actions. Changes
Assessment against linked issues
Possibly related PRs
Suggested reviewers
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
…ui-user-management # Conflicts: # resources/js/components/SettingsRoomTypesDeleteButton.vue
0a44ed5
to
1530eed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🔭 Outside diff range comments (1)
resources/js/views/AdminServersIndex.vue (1)
Line range hint
191-227
: Remove disabled state from router links.The
:disabled="isBusy"
binding on router links (as="router-link"
) is unnecessary and might impact user experience. Users should be able to navigate away during data loading operations.<Button v-if="userPermissions.can('view', slotProps.data)" v-tooltip="$t('admin.servers.view', { name: slotProps.data.name })" as="router-link" - :disabled="isBusy" :aria-label="$t('admin.servers.view', { name: slotProps.data.name })" :to="{ name: 'admin.servers.view', params: { id: slotProps.data.id } }" icon="fa-solid fa-eye" /> <Button v-if="userPermissions.can('update', slotProps.data)" v-tooltip="$t('admin.servers.edit', { name: slotProps.data.name })" as="router-link" - :disabled="isBusy" :aria-label="$t('admin.servers.edit', { name: slotProps.data.name })" :to="{ name: 'admin.servers.edit', params: { id: slotProps.data.id } }" severity="info" icon="fa-solid fa-edit" />
🧹 Nitpick comments (14)
app/Http/Requests/UpdateSettings.php (1)
80-80
: LGTM! Consider adding a comment to document the nullable field.The change to make
bbb_logo
nullable is correct and aligns with the ability to clear the logo in the UI.- 'bbb_logo' => ['nullable', 'string', 'max:255'], + 'bbb_logo' => ['nullable', 'string', 'max:255'], // Nullable to allow clearing the logoresources/js/views/AdminServersIndex.vue (1)
8-8
: LGTM! Consider adding a loading indicator.The disabled states correctly prevent duplicate API calls during loading. Consider adding a loading spinner to provide better visual feedback.
<InputText v-model="filter" :disabled="isBusy" + :loading="isBusy" :placeholder="$t('app.search')" @keyup.enter="loadData(1, false)" />
Also applies to: 14-14
resources/js/views/AdminServerPoolsView.vue (3)
33-34
: LGTM! Consider enhancing error state accessibility.The overlay implementation with retry functionality aligns well with the PR objectives to fix overlay reload buttons. The form's aria-hidden attribute during error states is a good accessibility practice.
Consider adding an aria-live region to announce loading errors to screen readers:
<OverlayComponent :show="isBusy || modelLoadingError"> <template #overlay> - <LoadingRetryButton + <LoadingRetryButton + aria-live="polite" :error="modelLoadingError" @reload="load" ></LoadingRetryButton> </template>
384-384
: Add defensive programming for stale error handling.While the property path correction is good, consider adding null checks to prevent potential runtime errors.
- name.value = staleError.new_model.name; + name.value = staleError?.new_model?.name ?? model.value.name;
Line range hint
33-182
: Consider enhancing error state feedback.While the loading and error states are handled well, consider improving the user experience during server loading errors:
- Add a toast notification when server loading fails
- Show an inline error message explaining why the servers couldn't be loaded
function loadServers(page = 1) { serversLoading.value = true; + const toast = useToast(); const config = { params: { page, }, }; api .call("servers", config) .then((response) => { serversLoadingError.value = false; servers.value = response.data.data; serversCurrentPage.value = page; serversHasNextPage.value = page < response.data.meta.last_page; }) .catch((error) => { serversMultiselectRef.value.deactivate(); serversLoadingError.value = true; + toast.add({ + severity: 'error', + summary: t('app.errors.loading_failed'), + detail: t('admin.servers.loading_failed'), + life: 3000 + }); api.error(error); }) .finally(() => { serversLoading.value = false; }); }resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue (3)
19-19
: Good use of optional chaining operator!The addition of the optional chaining operator (
?.
) is a good defensive programming practice that prevents potential runtime errors whencurrentUser
is null/undefined.Consider adding a computed property for better reusability and testing:
+ const canManageSuperuser = computed(() => authStore.currentUser?.superuser) - :disable-superuser="!authStore.currentUser?.superuser" + :disable-superuser="!canManageSuperuser"
Line range hint
27-31
: Consider adding a retry mechanism for role loading errors.While the error handling is comprehensive, users have no way to retry when role loading fails. This aligns with the PR objectives of improving error handling across admin views.
Consider adding a retry button when
rolesLoadingError
is true:<div class="flex justify-end"> + <Button + v-if="rolesLoadingError" + @click="$emit('retry-roles-loading')" + :label="$t('app.retry')" + icon="fa-solid fa-sync" + class="mr-2" + /> <Button v-if="!viewOnly && userPermissions.can('editUserRole', model)" :disabled="isBusy || rolesLoadingError || rolesLoading" type="submit" :loading="isBusy" :label="$t('app.save')" icon="fa-solid fa-save" /> </div>
Line range hint
108-142
: Enhance error handling in the save function.While the error handling is comprehensive, consider adding timeout handling and a retry mechanism for network failures to improve reliability.
Consider these improvements:
function save(event) { if (event) { event.preventDefault(); } isBusy.value = true; formErrors.clear(); api .call("users/" + model.value.id, { method: "put", + timeout: 5000, // 5 second timeout data: { roles: model.value.roles.map((role) => role.id), updated_at: model.value.updated_at, }, }) .then((response) => { emit("updateUser", response.data.data); }) .catch((error) => { + if (error.code === 'ECONNABORTED') { + api.error(new Error('Request timed out. Please try again.')); + return; + } if (error.response && error.response.status === env.HTTP_NOT_FOUND) { emit("notFoundError", error); } else if ( error.response && error.response.status === env.HTTP_UNPROCESSABLE_ENTITY ) { formErrors.set(error.response.data.errors); } else if ( error.response && error.response.status === env.HTTP_STALE_MODEL ) { emit("staleError", error.response.data); } else { api.error(error); } }) .finally(() => { isBusy.value = false; }); }resources/js/components/UserTabEmail.vue (3)
124-124
: LGTM! Consider additional defensive checks.The optional chaining operator is a good addition that prevents runtime errors when
currentUser
is undefined. However, consider adding a complete null check for both sides of the comparison for maximum robustness.- return authStore.currentUser?.id === props.user.id; + return authStore.currentUser?.id != null && props.user?.id != null && authStore.currentUser.id === props.user.id;
Line range hint
1-194
: Consider enhancing security feedback and validation.While the core security measures are solid (password verification, API throttling, email validation), consider these security enhancements:
- Add a visual indicator for remaining email change attempts before throttling
- Implement client-side password strength validation
- Add rate limiting information in the error message
Example implementation for attempt counter:
<div class="flex justify-end"> + <small v-if="remainingAttempts" class="text-gray-500 mr-2 self-center"> + {{ $t('auth.remaining_attempts', { count: remainingAttempts }) }} + </small> <Button v-if="!viewOnly && userPermissions.can('updateAttributes', user)" :disabled="isBusy"
Line range hint
134-194
: Enhance error handling and loading state feedback.While the current error handling is good, consider these improvements:
- Add loading state feedback:
function save(event) { if (event) { event.preventDefault(); } isBusy.value = true; + const loadingToast = toast.info(t('common.saving'), { timeout: false }); formErrors.clear(); validationRequiredEmail.value = null; // ... existing code ... .finally(() => { currentPassword.value = null; isBusy.value = false; + loadingToast.dismiss(); }); }
- Add explicit network error handling:
} else if (error.response.status === env.HTTP_EMAIL_CHANGE_THROTTLE) { toast.error(t("auth.throttle_email")); + } else if (!error.response) { + toast.error(t("errors.network")); } else { api.error(error); }
- Add cleanup on component unmount:
+import { computed, onBeforeMount, onBeforeUnmount, ref } from 'vue'; + +// ... existing code ... + +onBeforeUnmount(() => { + formErrors.clear(); + isBusy.value = false; +});resources/js/components/SettingsUsersResetPasswordButton.vue (1)
45-45
: LGTM! Consider enhancing error feedback.The addition of
:disabled="isBusy"
is correct and consistent. However, there's an opportunity to improve error handling.Consider adding specific error toast messages to match the success case:
.catch((error) => { - api.error(error); + toast.error( + t("admin.users.password_reset_error", { mail: props.email }) + ); + api.error(error); })resources/js/components/SettingsServerPoolsDeleteButton.vue (1)
45-45
: LGTM! Consider improving error state UX.The addition of
:disabled="isBusy"
is correct and consistent. However, there's an opportunity to improve the error state handling.Consider showing a "Retry" button when room types are affected:
-<template v-if="deleteFailedRoomTypes == null" #footer> +<template #footer> <Button :label="$t('app.no')" :disabled="isBusy" severity="secondary" - @click="modalVisible = false" + @click="handleClose" /> - <Button + <Button v-if="deleteFailedRoomTypes == null" :label="$t('app.yes')" :loading="isBusy" severity="danger" @click="deleteServerPool" /> + <Button v-else + :label="$t('app.retry')" + severity="secondary" + @click="retryDelete" + /> </template>Add the following methods:
function handleClose() { deleteFailedRoomTypes.value = null; modalVisible.value = false; } function retryDelete() { deleteFailedRoomTypes.value = null; deleteServerPool(); }resources/js/components/SettingsRoomTypesDeleteButton.vue (1)
32-76
: Improved error handling with reload capability.The addition of
InputGroup
with a reload button provides better user experience when loading replacement room types fails.Consider adding an aria-label to the reload button for better accessibility:
<Button v-if="replacementRoomTypesLoadingError" :disabled="isBusy" outlined severity="secondary" icon="fa-solid fa-sync" + :aria-label="$t('app.reload')" @click="loadReplacementRoomTypes()" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
CHANGELOG.md
(4 hunks)app/Http/Requests/UpdateSettings.php
(1 hunks)resources/js/components/RoleSelect.vue
(3 hunks)resources/js/components/SettingsRolesDeleteButton.vue
(1 hunks)resources/js/components/SettingsRoomTypesDeleteButton.vue
(5 hunks)resources/js/components/SettingsServerPoolsDeleteButton.vue
(1 hunks)resources/js/components/SettingsServersDeleteButton.vue
(1 hunks)resources/js/components/SettingsUsersDeleteButton.vue
(1 hunks)resources/js/components/SettingsUsersResetPasswordButton.vue
(1 hunks)resources/js/components/UserTabEmail.vue
(1 hunks)resources/js/components/UserTabSecurityRolesAndPermissionsSection.vue
(1 hunks)resources/js/views/AdminRolesIndex.vue
(1 hunks)resources/js/views/AdminRolesView.vue
(12 hunks)resources/js/views/AdminRoomTypesIndex.vue
(5 hunks)resources/js/views/AdminRoomTypesView.vue
(3 hunks)resources/js/views/AdminServerPoolsIndex.vue
(1 hunks)resources/js/views/AdminServerPoolsView.vue
(3 hunks)resources/js/views/AdminServersIndex.vue
(1 hunks)resources/js/views/AdminServersView.vue
(1 hunks)resources/js/views/AdminSettings.vue
(2 hunks)resources/js/views/AdminUsersIndex.vue
(5 hunks)resources/js/views/AdminUsersNew.vue
(1 hunks)tests/Backend/Feature/api/v1/SettingsTest.php
(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: Frontend Tests (5)
- GitHub Check: Frontend Tests (4)
- GitHub Check: Frontend Tests (3)
- GitHub Check: Frontend Tests (2)
- GitHub Check: Frontend Tests (1)
- GitHub Check: System Tests
- GitHub Check: Visual Tests
- GitHub Check: Backend
🔇 Additional comments (29)
tests/Backend/Feature/api/v1/SettingsTest.php (2)
907-907
: Fix indentation.The indentation was incorrect.
990-990
: LGTM! Test case aligns with validation rules.The test case correctly verifies that setting
bbb_logo
to an empty string clears the logo, which aligns with the nullable validation rule.resources/js/views/AdminSettings.vue (2)
131-133
: LGTM! Fixed error field name mismatch.The error field name now correctly matches the form field name
general_pagination_page_size
, fixing the validation error display.
1290-1292
: LGTM! Improved BBB logo form data handling.The logic for handling the BBB logo in form data has been improved:
- Properly handles logo deletion by setting an empty string
- Added null check before appending existing logo
resources/js/views/AdminServersIndex.vue (1)
Line range hint
71-77
: LGTM! Error handling implementation is robust.The error handling implementation correctly:
- Displays errors with retry functionality
- Reverts pagination state on error
- Provides visual feedback
resources/js/views/AdminServerPoolsView.vue (1)
162-162
: LGTM! Error message positioning improved.Moving the FormError component after the multiselect input improves the visual flow and helps users better understand validation errors.
resources/js/components/SettingsRolesDeleteButton.vue (1)
28-28
: LGTM! Consistent handling of busy state.The addition of
:disabled="isBusy"
to the "No" button aligns with the existing busy state handling in the dialog, preventing unintended user interactions during deletion operations.resources/js/components/SettingsServersDeleteButton.vue (1)
26-26
: LGTM! Consistent implementation.The addition of
:disabled="isBusy"
to the "No" button maintains consistency with other components and properly prevents user interaction during server deletion operations.resources/js/components/SettingsRoomTypesDeleteButton.vue (2)
85-85
: Enhanced user interaction control.Adding
:disabled="isBusy"
to the "No" button prevents user interaction during busy states.
126-126
: Improved error state management.The addition of
replacementRoomTypesLoadingError
ref and its management in theloadReplacementRoomTypes
function enhances error handling.Also applies to: 141-142, 158-158
resources/js/components/RoleSelect.vue (1)
4-4
: Improved template ref implementation.The change from using
ref
touseTemplateRef
with kebab-case template ref name follows Vue.js best practices for template refs.Let's verify if this pattern is consistently used across other components:
Also applies to: 97-97, 142-142
resources/js/views/AdminRolesIndex.vue (1)
8-8
: Enhanced loading state handling.Disabling search input and button during busy states prevents concurrent API calls and improves user experience.
Also applies to: 14-14
resources/js/views/AdminServerPoolsIndex.vue (1)
8-8
: Consistent loading state handling.The implementation matches AdminRolesIndex.vue, maintaining consistency in how loading states are handled across the application.
Let's verify if this pattern is consistently implemented across all admin index views:
Also applies to: 14-14
✅ Verification successful
Loading state handling is consistently implemented across admin views
The
:disabled="isBusy"
pattern is uniformly applied across all active admin index views (Roles, RoomTypes, ServerPools, Servers, Users) for search inputs, buttons, and navigation elements, maintaining a consistent user experience.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for other admin index views to ensure consistent loading state handling rg -l 'Admin.*Index\.vue$' --type vue | xargs rg -l ':disabled="isBusy"'Length of output: 1398
Script:
#!/bin/bash # Find all admin index views and check their loading state implementation fd -e vue | rg "Admin.*Index\.vue$" | while read -r file; do echo "=== $file ===" rg -A 1 -B 1 ':disabled="isBusy"' "$file" || echo "No matches found" echo doneLength of output: 3391
resources/js/views/AdminUsersNew.vue (1)
106-106
: LGTM! Good use of optional chaining.The addition of optional chaining (
?.
) when accessingauthStore.currentUser.superuser
prevents potential null reference errors.resources/js/views/AdminUsersIndex.vue (3)
25-25
: Improved multiselect behavior.The changes enhance the user experience by:
- Using a consistent ref attribute naming convention.
- Automatically closing the dropdown upon selection.
Also applies to: 34-34
251-251
: LGTM! Good modernization of template refs.Using
useTemplateRef
is a more modern and maintainable approach for handling template references.Also applies to: 287-287
324-324
: LGTM! Improved error handling.The error handling is now more consistent with the rest of the application.
resources/js/views/AdminServersView.vue (1)
Line range hint
32-37
: Enhanced error handling and user feedback.The changes improve the user experience by:
- Showing the overlay during loading errors
- Providing a retry button when loading fails
resources/js/views/AdminRolesView.vue (4)
4-7
: Improved conditional rendering.Good addition of
permissionsLoaded
check to prevent premature rendering of UI elements.
35-46
: Enhanced error handling with better user feedback.The overlay now properly handles both model and permissions loading errors, with a retry button for recovery.
401-408
: Good DRY implementation with computed property.The
formFieldsDisabled
computed property centralizes the disable logic, making it more maintainable and consistent.
363-364
: Improved permissions loading state management.The changes properly track permissions loading state and errors, ensuring better error handling and user feedback.
Also applies to: 465-465, 536-539
resources/js/views/AdminRoomTypesView.vue (2)
32-35
: LGTM! Enhanced error handling with LoadingRetryButton.The addition of LoadingRetryButton improves error recovery by allowing users to retry loading when errors occur.
138-138
: LGTM! Improved dropdown behavior.Setting
close-on-select
to true provides better UX by automatically closing the dropdown after selection.resources/js/components/SettingsUsersDeleteButton.vue (1)
42-42
: LGTM! Improved dialog button state management.Disabling the "No" button during busy states prevents potential race conditions and provides better user feedback.
resources/js/views/AdminRoomTypesIndex.vue (3)
8-8
: LGTM! Improved search interaction during loading.Disabling search input and button during loading prevents concurrent requests and provides better user feedback.
Also applies to: 14-14
41-41
: LGTM! Enhanced error handling with retry mechanism.The DataTable now properly shows loading state during errors and provides a retry button for recovery.
Also applies to: 69-71
165-165
: LGTM! Proper error state management.The loadingError state is properly initialized, cleared before loading, and set on error, ensuring accurate UI feedback.
Also applies to: 181-182, 190-190
CHANGELOG.md (1)
12-13
: LGTM! Comprehensive changelog updates.The changelog entries accurately document all changes and improvements made in PR #1588, including:
- Added loading retry buttons
- Changed multiselect dropdown behavior
- Fixed search functionality, overlay display, dialog buttons, and error handling
Also applies to: 26-27, 33-42, 348-348, 360-361, 366-366, 370-370
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
resources/js/components/TimezoneSelect.vue (3)
28-28
: LGTM! Consider enhancing accessibility further.The addition of the aria-label improves accessibility for screen readers. To make it even better, consider adding
aria-busy
when loading andaria-pressed
attributes.<Button v-if="loadingError" :disabled="loading" outlined severity="secondary" icon="fa-solid fa-sync" :aria-label="$t('app.reload')" + :aria-busy="loading" + :aria-pressed="false" data-test="timezone-reload-button" @click="loadTimezones()" />
Line range hint
34-57
: Consider adopting TypeScript for better type safety.The props are well-defined, but using TypeScript would provide better type safety and developer experience.
interface TimezoneSelectProps { placeholder: string | null invalid: boolean | null disabled: boolean required: boolean ariaLabelledby: string | null }
Line range hint
89-94
: Enhance error handling with specific error types.The error handling could be more specific to help users understand and resolve issues better.
}) .catch((error) => { loadingError.value = true; - api.error(error); + if (error.response?.status === 404) { + api.error(new Error($t('errors.timezone_not_found'))); + } else if (error.response?.status === 403) { + api.error(new Error($t('errors.timezone_access_denied'))); + } else { + api.error(error); + } })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
resources/js/components/RoleSelect.vue
(3 hunks)resources/js/components/SettingsRoomTypesDeleteButton.vue
(6 hunks)resources/js/components/TimezoneSelect.vue
(1 hunks)resources/js/views/AdminRoomTypesView.vue
(4 hunks)resources/js/views/AdminServerPoolsView.vue
(3 hunks)resources/js/views/AdminUsersIndex.vue
(6 hunks)resources/js/views/RoomsIndex.vue
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- resources/js/views/RoomsIndex.vue
🚧 Files skipped from review as they are similar to previous changes (5)
- resources/js/components/SettingsRoomTypesDeleteButton.vue
- resources/js/views/AdminRoomTypesView.vue
- resources/js/views/AdminUsersIndex.vue
- resources/js/components/RoleSelect.vue
- resources/js/views/AdminServerPoolsView.vue
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Docker Build
- GitHub Check: Backend
Fixes #1675
Fixes #1677
Fixes #1711
Fixes #1751
Type (Highlight the corresponding type)
Checklist
Changes
Other information
Summary by CodeRabbit
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Improvements
Performance